Hey folks, we're are now making ephysics API more stable, almost all the features intended to go in are already implemented, so we are moving to the next step: adding support to physics on Edje.
There are many ways of doing this, so I'm sending a proposal with some possibilities so we could discuss before we start to implement it. Just to make it clearer. My proposal exposes a lot of ephysics, something very complete (for what I believe are valid use cases. Lot of things possible with ephysics API are not exposed), and that would require a lot of time to be completely done. So, it will be implemented gradually, covering the main use cases first. So initially would be possible to create a new world with a list of bodies, with most properties set using ephysics default. Later we would expose some more relevant properties. Implement programs / scripts. Then adding support to constraints, camera, etc etc... But would be good to define what would be the better, complete scenario. Thanks in advance, ====================================== PROPOSAL: SUPPORT PHYSICS ON EDJE === CHOICES === There are 3 main different ways to do it. The first one is described in details above, and has some alternatives explained. The other 2 can be understood with these details. 1) A single physics block that would be set per group, and all the rendered objects to be manipulated would be other groups. 2) A single physics block that would be set per group, and all the rendered objects to be manipulated would be other parts of this group. 3) A physics block to describe world, camera and constraints, that would be set per group. And extra physics blocks per part that should be associated to a body. Example: group { physics { world { ... } } parts { part { name: .. body_type: ... description { ... physics { // body props } } } } } Regarding programs, there are three main choices: 1) Physics world, camera, constraints and bodies have states with these objects attributes. Using STATE_SET as already exists on Edje would be the way to change it. Bodies can handle actions that should be set only via scripts, like apply_impulse, apply_force, set_velocity ... 2) No specific physics ACTIONs. Everything should be set via scripts. 3) Another types of ACTION would be declared, like PHYSICS_IMPULSE, PHYSICS_FORCE, etc. So it could be used without scripts. The main argument in using scripts is that hardly a user will want just to set a hardcoded property. Usually it will be based on body's and other parts current state, like using geometry or velocity, etc. So it would be required to get properties, do some calculation, set to body. PROGRAMS chapter exemplify it. Initially I would go with choices 1) and 1), but I would like to see what you think about it. === OVERVIEW === collections { ... group { ... parts {} physics { world {} camera {} bodies { body {} ... } constraints { constraint {} ... } } programs {} ... } === PHYSICS === The "physics" block contains all the other blocks related to physics. Blocks "world", "camera", "bodies" and "constraints" will be found inside it. Physics only will be enabled if at least one "body" is listed on "bodies" block. It should be included in group's block, since a physics world won't be shared between groups. === WORLD === The "world" block can have one or more description blocks. It's required to simulate physics between bodies. Only one world can be declared per group. Each "description" block is used to set all attributes required to configure a physics world. ... physics { world { name: "name"; description { state: "description_name" INDEX; inherit: "another_description" INDEX; rel1 { .. } rel2 { .. } rate: 30; gravity: 0 294 0; running: 1; light { light: "part_name"; all_bodies: 0; } simulation { fixed_time_step: 0.033; max_sub_steps: 3; } sleeping_time: 2.0; solver_iterations: 10; auto_delete { top: 1; bottom: 1; left: 1; right: 1; front: 0; back: 0; } stacking: 1; } } ... } ... --- name [world name] Define the name that refer to this world instance. state [a name for the description] [an index] Sets a name used to identify a description inside the world. Multiple descriptions are used to declare different states of the same world, like "paused" or "inverse gravity". All states declarations are also coupled with an index number between 0.0 and 1.0. All "world" block must have at least one description named "default 0.0". inherit [another description's name] [another description's index] When set, the description will inherit all the properties from the named description. The properties defined in this part will override the inherited properties, reducing the amount of necessary code for simple state changes. Note: inheritance in Edje is single level only. rel1/rel2: Almost the same used for parts. Offset would have a third parameter, for z-axis. >>> ALTERNATIVE: render_geometry { position: [x] [y] [z] size [w] [h] [d] } Position relative to group geometry. <<< rate [rate pixel / meter] Set rate between pixels on evas canvas and meters on physics world. It will be used by automatic updates of evas objects associated to physics bodies. By default rate is 30 pixels per meter. gravity [x] [y] [z] Three double values defining the gravity vector. Each one is the component of this same vector over each axis. Its unit is Evas Coordinates per second ^ 2. The default value is 0, 294, 0 since we've a default rate of 30 pixels. running [0 or 1] >>> It would be used to pause effects, not sure if would be useful here. <<< Takes a boolean value specifying if the world is paused or running. It's running by default (1). light This block configure the light to be used in the scene. It will perform lighting calculations on the evas map applied on evas objects associated with all the bodies to have light applied over. There are two ways of setting a body to receive lighting. One is to simple set all the bodies to be affected, with all_bodies. The other is disabling it and setting "light" property on each "body" block which light should be applied. light [part's name] This sets the part that is used as the "light" for calculating the brightness (based on how directly the part's surface is facing the light source point). Like the perspective point part, the center point is used and zplane is used for the z position (0 being the zero-plane where all 2D objects normally live) and positive values being further away into the distance. The light part color is used as the light color (alpha not used for light color). The color2 color is used for the ambient lighting when calculating brightness (alpha also not used). all_bodies [0 or 1] If enabled it will apply light over all the bodies, not considering if they have "light" property set or unset. If disabled, light still can be applied at each body individually using body's properties. >>> ALTERNATIVE light { point { position: x y z color: r g b } ambient: rgb all_bodies: [0 | 1] } First version é really cool, since you can animate the light part. Also, it's already used by the "map" block. <<< simulation <<< MUST PROBABLY WILL BE DROPPED SINCE IT'S REALLY CORNER CASE >>> It's a block used to set world simulation's fixed time step and max number of sub steps. Reducing the fixed time step improves collision quality, but impacts performance. Also, when this value is changed, the max number of sub steps need to be updated, otherwise the world may "lose time". The following equation must to be assured: time step < max_sub_steps * fixed_time_step; By default fixed time step is 1/60 seconds and the sub steps maximum amount is 3. fixed_time_step [time] Time of the internal simulation step, in seconds. Default is 1/60 seconds. max_sub_steps [steps] Integer used to specify the maximum number of steps that simulation is allowed to take at each simulation tick. Default value is 3. sleeping_time [max sleeping time] A double determining the duration in seconds a body under the linear and angular threshold is supposed to be marked as sleeping. Default is 2.0; solver_iterations [number of iterations used by constraint solver] <<< MUST PROBABLY WILL BE DROPPED SINCE IT'S REALLY CORNER CASE >>> It's a integer to set the number of iterations the constraint solver will will have for contact and joint constraints. The default value is set to 10. The greater number of iterations more quality and precise the result but with performance penalty. Hardly a value different from default will be required. linear_slop [linear slop used by the solver] <<< MUST PROBABLY WILL BE DROPPED SINCE IT'S REALLY CORNER CASE >>> Linear slop on sequential impulse is used as a factor for penetration. The penetration will the manifold distance + linear slop. The default value is set to 0 with a small value results in a smoother stabilization for stacking bodies. auto_delete This block lists all the boundaries of the world rendering area and should be used to enable or disable automatic deletion of bodies outside this area. All of them are disabled by default. top [0 or 1] Delete bodies when they're outside of render area by the top. bottom [0 or 1] Delete bodies when they're outside of render area by the bottom. right [0 or 1] Delete bodies when they're outside of render area by the right. left [0 or 1] Delete bodies when they're outside of render area by the left. front [0 or 1] Delete bodies when they're outside of render area by the front. back [0 or 1] Delete bodies when they're outside of render area by the back. stacking [0 or 1] Enable or disable stacking based on bodies z coordinates. Evas objects will be restacked at each simulation tick. It's enabled by default, and disabling it can lead to wrong scenarios when movement on Z axis is enabled or when cloths are used. But disabling it can save performance, so if you won't face these scenarios, it safe to disable it, since no evas object will be moved to be below or above others. === CAMERA === The "camera" block can have one or more description blocks. Only one "camera" block can be declared by group. Camera is used to change the position of the frame to be rendered. By default it matches world's rendering area. But it can be modified passing another top-left point position, so another region of the physics world will be rendered on the render area. So if you have a scene larger than the render area, camera handling can be very useful. Also it can be set to track a body. Each "description" block is used to set all attributes required to configure a camera. ... physics { camera { name: "name"; description { state: "description_name" INDEX; inherit: "another_description" INDEX; position: "part_name"; track { body: "name"; axis: 1 0; } perspective: "part_name"; } } ... } ... --- name [camera name] Define the name that refer to this camera instance. state [a name for the description] [an index] Sets a name used to identify a description inside the camera. Multiple descriptions are used to declare different states of the same camera, like "tracking a body" or "fixed at position X, Y, Z". All states declarations are also coupled with an index number between 0.0 and 1.0. All "camera" block must have at least one description named "default 0.0". inherit [another description's name] [another description's index] When set, the description will inherit all the properties from the named description. The properties defined in this part will override the inherited properties, reducing the amount of necessary code for simple state changes. Note: inheritance in Edje is single level only. position [another part's name] This sets the part that is used as the "central point of the camera". The center of this part will be used as the camera point, so size, color and visibility etc. are not relevant just center point is used. perspective [another part's name] This sets the part that is used as the "perspective point" for giving a scene a "3d look". The perspective point should have a perspective section that provides zplane and focal properties. The center of this part will be used as the focal point, so size, color and visibility etc. are not relevant just center point, zplane and focal are used. >>> ALTERNATIVE: First version is already used on map, and make it easy to be moved around. But another version could be: perspective { distance: x y; z0: z; focal_distance: f; enabled: [0 | 1] } <<< track It's a block used to set camera to track a body. When a body is tracked, the camera will move automatically, following this body. It will keeps the body centralized on rendered area. If it will be centralized horizontally and / or vertically depends if parameters horizontal and vertical are enabled. body [body's name] This sets the body to be tracked by the camera. axis [horizontal] [vertical] Two boolean values [0 or 1]. If horizontal is enabled the tracked body will be horizontally centralized in the rendered area. Disabled by default. If vertical is enabled the tracked body will be vertically centralized in the rendered area. Disabled by default. === BODIES === The "bodies" block is used to list the bodies that compose the world. A body is a representation of an object inside a physics world. It can be customized in many ways, setting collision shape, material, applying forces and velocity. It won't be visually represented per se. It need to be associated to one or more (using faces) parts so they will be rendered using it to be represented. Each "description" block is used to set all attributes required to configure a physics body. ... physics { bodies { body { name: "name"; type: RIGID_BOX; description { state: "description_name" INDEX; inherit: "another_description" INDEX; source: "group's name"; material: IRON; density: 80.3; mass: 66.6; rel1 { .. } rel2 { .. } use_part_geometry: 0; rotation: 1 1 0 0; restitution: 0.7; friction: 0.45; damping: 0.4 20; sleeping_threshold: 0.5 0.5; collision_groups: "group1" "group2" ...; velocity { linear: 10.2 1.3 0; angular: 0 0 2.2; } forces { central: 0 2.5 5; torque: 0 1.3 0; } faces { face { face: BOX_RIGHT; source: "group's name"; } face { face: BOX_LEFT; source: "group's name"; } ... } movement_freedom { linear: 1 1 0; angular: 0 0 1; } light_on: 1; backface_cull: 0; hardness: 1.0; // for soft bodies and cloths only anchor { // for cloths only body: "name"; side: ANCHOR_LEFT; nodes: 10 12 14 16 ...; } } } body {} ... } ... } ... --- name [body name] Define the name that refer to this body instance. type [TYPE] Set the type (all caps) from among the available body's shape types. It's set to RIGID_BOX by default. Valid types: * RIGID_BOX * RIGID_CIRCLE * SOFT_BOX * SOFT_CIRCLE * CLOTH * BOUNDARY_TOP * BOUNDARY_BOTTOM * BOUNDARY_RIGHT * BOUNDARY_LEFT * BOUNDARY_FRONT * BOUNDARY_BACK state [a name for the description] [an index] Sets a name used to identify a description inside the body. Multiple descriptions are used to declare different states of the same body, like "moving", "rotating" or "heavier". All states declarations are also coupled with an index number between 0.0 and 1.0. All "body" block must have at least one description named "default 0.0". inherit [another description's name] [another description's index] When set, the description will inherit all the properties from the named description. The properties defined in this part will override the inherited properties, reducing the amount of necessary code for simple state changes. Note: inheritance in Edje is single level only. source [group's name] This sets the group that is used as the object representing the physics body. A physics body isn't rendered per se. >>> ALTERNATIVE Using parts is possible too, but since ephysics sets a map and changes position, it could be harder to implement and a bit more error prone. In cases of mapping wanted, the user would need to set the part as group type, and use map inside this group. The negative point of using groups is that declaring groups is more verbose. But a macro could be used. The positive is that it could be set to many bodies. part [part's name] This sets the part that is used as the object representing the physics body. A physics body isn't rendered per se. <<< material [MATERIAL] Set the type (all caps) from among the available material types, it's set to CUSTOM by default. Each material has specific properties to be applied on the body, as density, friction and restitution. Valid types: * CUSTOM * CONCRETE * IRON * PLASTIC * POLYSTYRENE * RUBBER * WOOD density [material's density] The density of a material is its mass per unit volume. It will set the body mass considering its volume. While a density is set, resizing a body will always recalculate its mass. When a mass is explicitely set the density will be unset. mass [mass in kg] Double value used to set inertial mass of the body. It is a quantitative measure of an object's resistance to the change of its speed. If mass is set to 0 the body will have infinite mass, so it will be immovable, static. rel1/rel2: Almost the same used for parts. Offset would have a third parameter, for z-axis. >>> ALTERNATIVE: geometry { use_part_geometry: [0 | 1] position: [x] [y] [z] size [w] [h] [d] } Position relative to group geometry. <<< use_part_geometry [0 or 1] If enabled, rel1 / rel2 will be discarded and the body will be set with the same geometry set to the part specified in "part" property. If this part is resized later, body will be resized together. rotation [w x y z] Set body's rotation using quaternion representation. restitution [coefficient of restitution] The coefficient of restitution is proportion between speed after and before a collision. It's 0 by default. COR = relative speed after collision / relative speed before collision * elastically collide for COR == 1; * inelastically collide for 0 < COR < 1; * completely stop (no bouncing at all) for COR == 0. friction [coefficient of friction] Friction is used to make objects slide along each other realistically. The friction parameter is usually set between 0 and 1, but can be any non-negative value. A friction value of 0 turns off friction and a value of 1 makes the friction strong. By default friction value is 0.5 and simulation results will be better when friction in non-zero. damping [linear_damping] [angular_damping] Damping(linear and angular) values are applied to body's linear and angular velocity. By applying a bodies damping factor the user will face a velocity reduction, with a force applied to it - "like" air resistance. The force is applied to slow it down. sleeping_threshold [linear_threshold] [angular_threshold] These factors are used to determine whenever a rigid body is supposed to increment the sleeping time. Linear threshold is measured in Evas coordinates per second and angular threshold is measured in degrees per second. After every tick the sleeping time is incremented, if the body's linear and angular speed is less than the respective thresholds the sleeping time is incremented by the current time step (delta time). Reaching the max sleeping time the body is marked to sleep, that means the rigid body is to be deactivated. collision_groups ["name_of_group_1"] ["name_of_group_2"] ... If not added to any group the body will collide against any other body. Otherwise this body will collide only against those in the same groups. Groups don't need to be previously declared anywhere. They are created on demand when used by a body. <<< ALTERNATIVE collision_groups { group: "name_of_group_1"; group: "name_of_group_2"; group: "name_of_group_3"; ... } >>> velocity <<< PROBABLY IT WILL BE BETTER TO JUST SET IT VIA EMBRYO IT DOESN'T FIT WELL IN STATE >>> It's a block used to set body's angular and linear initial velocity. This velocity will be set when this body state is set, but will be increased or decreased considering many other properties and interactions with the world and other bodies or constraints. That's why it's said to be the INITIAL velocity. It's not necessarily constant. linear [x] [y] [z] Three double values for each component of linear velocity. Unit for linear velocity is Evas coordinates per second. angular [x] [y] [z] Three double values for angular velocity around each axis. Unit for angular velocity is degrees per second. forces <<< PROBABLY IT WILL BE BETTER TO JUST SET IT VIA EMBRYO IT DOESN'T FIT WELL IN STATE >>> It's a block used to set forces applied over body. Force is measured in kg * p / s / s. Force is the product of mass and acceleration. So, keeping the mass fixed, when force is applied acceleration will change, and consequently, velocity will gradually be changes. Force = mass * acceleration Final velocity = initial velocity + acceleration * time central [x] [y] [z] Three double values for each component of the force to be applied in the center of the body. It won't produce torque. torque [x] [y] [z] A torque will be applied over the body to change the angular acceleration of this body. It will leads to a change on angular velocity over time. Three double values for torque to be applied around each axis. Negative values will accelerate it on counter clockwise rotation. faces The "faces" block is used to list the faces that compose the body. Each face is described by a "face" block, that associates a part to a specific face of the body's shape. face [FACE] Set the face (all caps) from among the available body's shape faces. Valid faces: * BOX_MIDDLE_FRONT, * BOX_MIDDLE_BACK, * BOX_FRONT, * BOX_BACK, * BOX_LEFT, * BOX_RIGHT, * BOX_TOP, * BOX_BOTTOM, * CYLINDER_MIDDLE_FRONT, * CYLINDER_MIDDLE_BACK, * CYLINDER_FRONT, * CYLINDER_BACK, * CYLINDER_CURVED, * CLOTH_FRONT, * CLOTH_BACK, source [group's name] This sets the group that is used as the object representing the physics body face. >>> ALTERNATIVE - the same explained above for body source <<< movement_freedom The "movement_freedom" block consists of two blocks to describe all the allowed movements for a body. It's set by default to allow just 2D movement (linear moves on x and y axis and rotations on x-y plane). linear [x-axis] [y-axis] [z-axis] Block "linear" can be used to allow linear movements in the three axes. Allowed values are 0 or 1. Axes x and y are enabled by default. angular [x-axis] [y-axis] [z-axis] Block "angular" can be used to allow angular movements around the three axes. Allowed values are 0 or 1. Z axis is enabled by default. light_on [0 or 1] Set body to be affected by world's light or not. It won't be respected if world's property "all_bodies" is enabled. backface_cull [0 or 1] This enables backface culling (when the rotated part that normally faces the camera is facing away after being rotated etc.). This means that the object will be hidden when "backface culled". hardness: [hardness] The hardness is set with a double value (0.0 - 1.0), defining how the soft body is supposed to deform. Its default is set to 1.0. The soft body mass will also interfere on soft body deformation, so bare in mind that the bodies mass must also be changed to have different deformation results. Valid values vary from 0.0 to 1.0. Only works on soft bodies and cloths. anchor Anchors are used to fix one or more cloth's nodes. body ["body's name"] The body to be anchored to. side [ANCHOR_SIDE] Set the side (all caps) from among the available cloth's sides. All the nodes part of the specified side of the cloth will be anchored to body. That is, all the nodes in the informed "edge". Valid sides: * LEFT * RIGHT * TOP * BOTTOM nodes [n1] [n2] [n3] ... Instead of using sides it's possible to specify nodes by index to anchor them. <<< ALTERNATIVE nodes { node: n1; node: n2; node: n3; ... } >>> === CONSTRAINTS === >> Constraints API is going to be heavily modified in the next days, so it's just illustrative. << The "constraints" block is used to list the constraints that compose the world. Constraints can be used to limit bodies movements, between bodies or between bodies and the world. Constraints can limit movement angle, translation, or work like a motor. Each "description" block is used to set all attributes required to configure a physics constraint. ... physics { constraints { constraint { name: "name"; type: POINT_TO_POINT; description { state: "description_name" INDEX; inherit: "another_description" INDEX; anchor { p1 { body: "name"; position: x y z; } p2 { body: "name"; position: x y z; } } limit { linear { left_x: value; right_x: value; under_y: value; ... } angular { x: value; y: value; z: value; } } } } constraint {} ... } ... } ... --- name [constraint name] Define the name that refer to this constraint instance. type [TYPE] Set the type (all caps) from among the available constraint types, it's set to POINT_TO_POINT by default. Valid types: * POINT_TO_POINT * SLIDER state [a name for the description] [an index] Sets a name used to identify a description inside the constraint. All states declarations are also coupled with an index number between 0.0 and 1.0. All "constraint" block must have at least one description named "default 0.0". inherit [another description's name] [another description's index] When set, the description will inherit all the properties from the named description. The properties defined in this part will override the inherited properties, reducing the amount of necessary code for simple state changes. Note: inheritance in Edje is single level only. anchor TODO limit TODO === PROGRAMS (related to physics) === ... group { programs { program { name: "change_physics_state"; action: STATE_SET "physics_state_name" 0.0; transition: ACCEL 1; target: "world"; target: "camera"; target: "body1"; target: "body2"; target: "constraint1"; } program { name: "body_actions"; script { apply_impulse(BODY:"body1", 10, -3.2, 0.0); set_velocity(BODY:"body2", 0, 10, 0.0); apply_force(BODY:"body3", -5, 0, 0); get_geometry(PART:"button", &x, &y, &w, &h); get_cursor(&px, &py); apply_impulse(BODY:"body3", (px - x), 100, 0); } } } } scripts API: body_set_velocity body_get_velocity body_stop body_apply_impulse body_apply_central_impulse body_apply_torque_impulse body_apply_force body_apply_central_force body_apply_torque body_clear_forces <<< ALTERNATIVE Just make everything accessible via embryo. Drop states completely. >>> -- Bruno Dilly Lead Developer ProFUSION embedded systems http://profusion.mobi ------------------------------------------------------------------------------ Monitor your physical, virtual and cloud infrastructure from a single web console. Get in-depth insight into apps, servers, databases, vmware, SAP, cloud infrastructure, etc. Download 30-day Free Trial. Pricing starts from $795 for 25 servers or applications! http://p.sf.net/sfu/zoho_dev2dev_nov _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel