EPhysics: add cloth support

This patch introduces the cloth support. Auxiliary API's for setting
full anchors, cloth nodes anchors and so on is also introduced. Few
other issues concerning soft body and cloth transform, has been worked
to fit the cloth support needs.


Patch by: Leandro Dorileo <dorileo@profusion.mobi>



SVN revision: 77467
This commit is contained in:
Leandro Dorileo 2012-10-04 22:40:16 +00:00 committed by Bruno Dilly
parent 1cb8f6fc0c
commit 252643a33b
13 changed files with 681 additions and 87 deletions

View File

@ -55,7 +55,9 @@ EXTRA_DIST = \
images/spinner_bt_left_pressed.png \
images/spinner_bt_right.png \
images/spinner_bt_right_pressed.png \
images/star.png
images/star.png \
images/green-flag.png \
images/brown-pole.png
ephysics_test.edj: Makefile $(EXTRA_DIST)
$(EDJE_CC) $(EDJE_FLAGS) \

View File

@ -12,4 +12,5 @@ collections {
#include "shadows.edc"
#include "shapes.edc"
#include "spinner.edc"
#include "others.edc"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,42 @@
images {
image: "green-flag.png" COMP;
image: "brown-pole.png" COMP;
}
group {
name: "green-flag";
parts {
part {
name: "flag";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
image.normal: "green-flag.png";
}
}
}
}
group {
name: "brown-pole";
parts {
part {
name: "pole";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
image.normal: "brown-pole.png";
}
}
}
}

View File

@ -39,7 +39,8 @@ test_shapes.c \
test_sleeping_threshold.c \
test_slider.c \
test_soft_body.c \
test_win_resize.c
test_win_resize.c \
test_flag.c
ephysics_logo_SOURCES = \
ephysics_logo.c

View File

@ -26,6 +26,7 @@ void test_collision_speed(void *data, Evas_Object *obj, void *event_info);
void test_constraint(void *data, Evas_Object *obj, void *event_info);
void test_delete(void *data, Evas_Object *obj, void *event_info);
void test_falling_letters(void *data, Evas_Object *obj, void *event_info);
void test_flag(void *data, Evas_Object *obj, void *event_info);
void test_forces(void *data, Evas_Object *obj, void *event_info);
void test_growing_balls(void *data, Evas_Object *obj, void *event_info);
void test_jumping_balls(void *data, Evas_Object *obj, void *event_info);
@ -52,6 +53,7 @@ static const EPhysics_Test tests[] = {
{"Constraint", test_constraint},
{"Delete Body", test_delete},
{"Falling Letters", test_falling_letters},
{"Flag - Cloth", test_flag},
{"Forces", test_forces},
{"Growing Balls", test_growing_balls},
{"Jumping Balls", test_jumping_balls},

View File

@ -0,0 +1,94 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ephysics_test.h"
static void
_world_populate(Test_Data *test_data)
{
Evas_Object *evas_obj;
EPhysics_Body *flag_body, *pole_body;
evas_obj = elm_image_add(test_data->win);
elm_image_file_set(
evas_obj, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "brown-pole");
evas_object_move(evas_obj, 150, FLOOR_Y - 280);
evas_object_resize(evas_obj, 17, 280);
evas_object_show(evas_obj);
test_data->evas_objs = eina_list_append(test_data->evas_objs, evas_obj);
pole_body = ephysics_body_box_add(test_data->world);
ephysics_body_mass_set(pole_body, 0);
ephysics_body_evas_object_set(pole_body, evas_obj, EINA_TRUE);
ephysics_body_restitution_set(pole_body, 0.5);
ephysics_body_friction_set(pole_body, 0.1);
test_data->bodies = eina_list_append(test_data->bodies, pole_body);
evas_obj = elm_image_add(test_data->win);
elm_image_file_set(
evas_obj, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "green-flag");
evas_object_move(evas_obj, 150 + 17, FLOOR_Y - 280 + 14);
evas_object_resize(evas_obj, 180, 126);
evas_object_show(evas_obj);
test_data->evas_objs = eina_list_append(test_data->evas_objs, evas_obj);
flag_body = ephysics_body_cloth_add(test_data->world, 0);
ephysics_body_mass_set(flag_body, 10);
ephysics_body_soft_body_hardness_set(flag_body, 1);
evas_obj = ephysics_body_evas_object_set(flag_body, evas_obj, EINA_TRUE);
ephysics_body_restitution_set(flag_body, 0.5);
ephysics_body_friction_set(flag_body, 0.1);
test_data->evas_objs = eina_list_append(test_data->evas_objs, evas_obj);
test_data->bodies = eina_list_append(test_data->bodies, flag_body);
ephysics_body_cloth_anchor_full_add(flag_body, pole_body,
EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_LEFT);
}
static void
_restart(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
{
Test_Data *test_data = data;
DBG("Restart pressed");
test_clean(test_data);
_world_populate(test_data);
}
void
test_flag(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
{
EPhysics_Body *boundary;
EPhysics_World *world;
Test_Data *test_data;
if (!ephysics_init())
return;
test_data = test_data_new();
test_win_add(test_data, "Flag", EINA_TRUE);
elm_layout_signal_callback_add(test_data->layout, "restart", "test-theme",
_restart, test_data);
elm_object_signal_emit(test_data->layout, "borders,show", "ephysics_test");
world = ephysics_world_new();
ephysics_world_simulation_set(world, 1/160.f, 10);
ephysics_world_render_geometry_set(world, 50, 40, WIDTH - 100, FLOOR_Y - 40);
test_data->world = world;
boundary = ephysics_body_bottom_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.65);
ephysics_body_friction_set(boundary, 4);
boundary = ephysics_body_right_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.4);
ephysics_body_friction_set(boundary, 3);
boundary = ephysics_body_left_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.4);
ephysics_body_friction_set(boundary, 3);
ephysics_body_top_boundary_add(test_data->world);
_world_populate(test_data);
}

View File

@ -1426,6 +1426,24 @@ EAPI void ephysics_world_simulation_get(const EPhysics_World *world, double *fix
*/
#define EPHYSICS_BODY_RESTITUTION_PLASTIC (0.6)
/**
* @enum _EPhysics_Body_Cloth_Anchor_Side
* @typedef EPhysics_Body_Cloth_Anchor_Side
*
* Identifier of cloth anchor sides.
*
* @see ephysics_body_cloth_anchor_full_add()
*
* @ingroup EPhysics_Body
*/
typedef enum _EPhysics_Body_Cloth_Anchor_Side
{
EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_LEFT,
EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_RIGHT,
EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_TOP,
EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_BOTTOM,
} EPhysics_Body_Cloth_Anchor_Side;
/**
* @typedef EPhysics_Body_Collision
*
@ -1628,8 +1646,8 @@ EAPI EPhysics_Body *ephysics_body_box_add(EPhysics_World *world);
*
* For a rigid circle, check @ref ephysics_body_circle_add().
*
* @param world The world this body will belongs to.
* @return a new body or @c NULL, on errors.
* @param world The world this body will belong to.
* @return a new body or @c NULL on errors.
*
* @see ephysics_body_del().
* @see ephysics_body_evas_object_set().
@ -1639,6 +1657,102 @@ EAPI EPhysics_Body *ephysics_body_box_add(EPhysics_World *world);
*/
EAPI EPhysics_Body *ephysics_body_soft_box_add(EPhysics_World *world);
/**
* @brief
* Create a new deformable cloth physics body.
*
* A cloth has its points of deformation conceptually split into rows and columns
* where every square is also split into two triangles - afore named nodes. To
* fine tune the deformation one can increase this granularity by increasing the
* @p granularity parameter.
*
* The number of rows is always proportional to the number of columns, for
* example passing @p granularity of 20 will create a cloth with 20 rows and 20
* columns.
*
* By default EPhysics creates a cloth with 10 rows and 10 columns, these default
* values will generally fit the most common scenarios.
*
* If the informed @p granularity is of 0 then the default value - of 10 - is
* assumed.
*
* @param world The world this body will belong to.
* @granularity Define - proportionally - the number of rows and columns, if 0
* the default value - of 10 - is assumed.
* @return a bew body or @c NULL on erros.
*
* @see ephysics_body_del().
* @see ephysics_body_evas_object_set().
* @see ephysics_world_simulation_set().
* @see ephysics_body_cloth_anchor_add().
* @see ephysics_body_cloth_anchor_full_add().
*
* @ingroup EPhysics_Body
*/
EAPI EPhysics_Body *ephysics_body_cloth_add(EPhysics_World *world, unsigned short granularity);
/**
* @brief
* Anchors a cloth with a rigid body.
*
* All the informed @p side of @p body1 will be anchored to @p body1 wherever
* it's in time of anchoring. That is, all the nodes in the informed "edge".
*
* An anchor assumes the @p body1 positions, if it's 20px far from @p body2 then
* this distance is always kept, moving @p body1 or @p body2 will respect a 20px
* difference.
*
* @param body1 The cloth body to be anchored.
* @param body2 The body to be anchored to.
* @param side The side to be anchored.
*
* @see ephysics_body_cloth_anchor_add().
* @see ephysics_body_cloth_anchor_del().
* @see ephysics_body_cloth_add() to know more about the cloth physics
* representation.
* @ingroup EPhysics_Body
*/
EAPI void ephysics_body_cloth_anchor_full_add(EPhysics_Body *body1, EPhysics_Body *body2, EPhysics_Body_Cloth_Anchor_Side side);
/**
* @brief
* Anchors an arbitrary cloth's node with a rigid body.
*
* The informed @p node of @p body1 will be anchored to @p body2 wherever it's
* in time of anchoring.
*
* @see ephysics_body_cloth_add() to know more about the cloth physics
* representation, nodes and so on.
*
* An anchor assumes the @p body1 positions, if it's 20px far from @p body2 then
* this distance is always kept, moving @p body1 or @p body2 will respect a 20px
* difference.
*
* @param body1 The cloth body to be anchored.
* @param body2 The body to be anchored to.
* @param node The node index to be anchored.
*
* @see ephysics_body_cloth_anchor_full_add().
* @see ephysics_body_cloth_anchor_del().
*
* @ingroup EPhysics_Body
*/
EAPI void ephysics_body_cloth_anchor_add(EPhysics_Body *body1, EPhysics_Body *body2, int node);
/**
* @brief
* Removes the anchors in a cloth body.
*
* @param body The body to delete anchors from.
*
* @see ephysics_body_cloth_anchor_full_add().
* @see ephysics_body_cloth_anchor_add().
*
* @ingroup EPhysics_Body
*/
EAPI void ephysics_body_cloth_anchor_del(EPhysics_Body *body);
/**
* @brief
* Create a new physics body using a custom shape.

View File

@ -68,13 +68,14 @@ _ephysics_body_soft_body_slices_apply(Evas_Object *obj)
double rate;
void *data;
Eina_List *l;
Evas_Coord x, y, h, wy, wh, y0, y1, y2, x0, x1, x2;
Evas_Coord x, y, h, wy, wh, y0, y1, y2, x0, x1, x2, z0, z1, z2;
Evas_Map *map;
btVector3 p0, p1, p2;
btSoftBody::tFaceArray faces;
EPhysics_Body_Soft_Body_Slice *slice;
EPhysics_Body_Soft_Body_Smart_Data *smart_data;
EPhysics_Body *body;
short z_factor;
EPHYSICS_BODY_SOFT_BODY_SMART_DATA_GET(obj, smart_data);
body = smart_data->body;
@ -98,19 +99,28 @@ _ephysics_body_soft_body_slices_apply(Evas_Object *obj)
x1 = p1.x() * rate;
x2 = p2.x() * rate;
z0 = p0.z() * rate;
z1 = p1.z() * rate;
z2 = p2.z() * rate;
z_factor = p0.z() + p1.z() + p2.z();
z_factor = (z_factor < 0) ? -z_factor : z_factor;
evas_object_layer_set(slice->evas_obj, z_factor);
evas_object_map_enable_set(slice->evas_obj, EINA_FALSE);
map = (Evas_Map *)evas_object_map_get((const Evas_Object *)
slice->evas_obj);
evas_object_image_smooth_scale_set(slice->evas_obj, EINA_TRUE);
evas_map_point_coord_set(map, 0, x0, y0, 0);
evas_map_point_coord_set(map, 1, x1, y1, 0);
evas_map_point_coord_set(map, 2, x2, y2, 0);
evas_map_point_coord_set(map, 3, x2, y2, 0);
evas_map_point_coord_set(map, 0, x0, y0, z0);
evas_map_point_coord_set(map, 1, x1, y1, z1);
evas_map_point_coord_set(map, 2, x2, y2, z2);
evas_map_point_coord_set(map, 3, x2, y2, z2);
evas_object_map_set(slice->evas_obj, map);
evas_object_map_enable_set(slice->evas_obj, EINA_TRUE);
evas_object_show(slice->evas_obj);
}
}
@ -136,7 +146,7 @@ static Eina_Bool
_ephysics_body_soft_body_slices_init(EPhysics_Body *body, Evas_Object *obj)
{
double rate;
Evas_Coord x, y, w, h, wy, wh, y0, y1, y2, x0, x1, x2;
Evas_Coord x, y, w, h, wy, wh, y0, y1, y2, x0, x1, x2, z0, z1, z2;
Evas_Map *map;
Evas *evas;
EPhysics_Body_Soft_Body_Smart_Data *smart_data;
@ -177,6 +187,10 @@ _ephysics_body_soft_body_slices_init(EPhysics_Body *body, Evas_Object *obj)
x1 = p1.x() * rate;
x2 = p2.x() * rate;
z0 = p0.z() * rate;
z1 = p1.z() * rate;
z2 = p2.z() * rate;
map = evas_map_new(4);
evas_map_util_points_populate_from_object(map, slice->evas_obj);
@ -185,17 +199,16 @@ _ephysics_body_soft_body_slices_init(EPhysics_Body *body, Evas_Object *obj)
evas_map_point_image_uv_set(map, 2, x2 - x, y2 - y);
evas_map_point_image_uv_set(map, 3, x2 - x, y2 - y);
evas_map_point_coord_set(map, 0, x0, y0, 0);
evas_map_point_coord_set(map, 1, x1, y1, 0);
evas_map_point_coord_set(map, 2, x2, y2, 0);
evas_map_point_coord_set(map, 3, x2, y2, 0);
evas_map_point_coord_set(map, 0, x0, y0, z0);
evas_map_point_coord_set(map, 1, x1, y1, z1);
evas_map_point_coord_set(map, 2, x2, y2, z2);
evas_map_point_coord_set(map, 3, x2, y2, z2);
evas_object_map_set(slice->evas_obj, map);
evas_object_map_enable_set(slice->evas_obj, EINA_TRUE);
evas_map_free(map);
smart_data->slices = eina_list_append(smart_data->slices, slice);
evas_object_smart_member_add(slice->evas_obj, obj);
}
return EINA_TRUE;
@ -349,6 +362,63 @@ _ephysics_body_soft_body_evas_add(EPhysics_Body *body)
return obj;
}
static btTransform
_ephysics_body_transform_get(const EPhysics_Body *body)
{
btTransform trans;
btVector3 center;
btScalar radius;
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
{
body->rigid_body->getMotionState()->getWorldTransform(trans);
return trans;
}
body->soft_body->getCollisionShape()->getBoundingSphere(center, radius);
trans.setIdentity();
trans.setOrigin(center);
return trans;
}
static void
_ephysics_body_transform_set(EPhysics_Body *body, btTransform trans)
{
btTransform origin;
btTransform dest;
if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
{
origin = _ephysics_body_transform_get(body);
dest.setIdentity();
dest.setOrigin(trans.getOrigin() / origin.getOrigin());
body->soft_body->translate(trans.getOrigin() - origin.getOrigin());
return;
}
body->rigid_body->getMotionState()->setWorldTransform(trans);
}
static btVector3
_ephysics_body_scale_get(const EPhysics_Body *body)
{
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
return body->collision_shape->getLocalScaling();
return body->soft_body->getCollisionShape()->getLocalScaling();
}
void
ephysics_body_activate(const EPhysics_Body *body, Eina_Bool activate)
{
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
{
body->rigid_body->activate(activate);
return;
}
body->soft_body->activate(activate);
}
static void
_ephysics_body_forces_update(EPhysics_Body *body)
{
@ -515,7 +585,27 @@ ephysics_body_collision_group_list_get(const EPhysics_Body *body)
}
static EPhysics_Body *
_ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, const char *type, double cm_x, double cm_y)
_ephysics_body_new(EPhysics_World *world, btScalar mass, double cm_x, double cm_y)
{
EPhysics_Body *body;
body = (EPhysics_Body *) calloc(1, sizeof(EPhysics_Body));
if (!body)
{
ERR("Couldn't create a new body instance.");
return NULL;
}
body->mass = mass;
body->world = world;
body->cm.x = cm_x;
body->cm.y = cm_y;
return body;
}
static EPhysics_Body *
_ephysics_body_rigid_body_add(EPhysics_World *world, btCollisionShape *collision_shape, const char *type, double cm_x, double cm_y)
{
btRigidBody::btRigidBodyConstructionInfo *rigid_body_ci;
btDefaultMotionState *motion_state;
@ -530,7 +620,7 @@ _ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, con
return NULL;
}
body = (EPhysics_Body *) calloc(1, sizeof(EPhysics_Body));
body = _ephysics_body_new(world, mass, cm_x, cm_y);
if (!body)
{
ERR("Couldn't create a new body instance.");
@ -562,12 +652,9 @@ _ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, con
goto err_rigid_body;
}
body->type = EPHYSICS_BODY_TYPE_RIGID;
body->collision_shape = collision_shape;
body->rigid_body = rigid_body;
body->mass = mass;
body->world = world;
body->cm.x = cm_x;
body->cm.y = cm_y;
body->rigid_body->setUserPointer(body);
body->rigid_body->setLinearFactor(btVector3(1, 1, 0));
body->rigid_body->setAngularFactor(btVector3(0, 0, 1));
@ -617,6 +704,37 @@ _ephysics_body_soft_body_anchors_rebuild(int node, btRigidBody *rigid_body, btSo
}
}
static void
_ephysics_body_cloth_constraints_rebuild(EPhysics_Body *body)
{
btRigidBody *rigid_body;
btSoftBody *soft_body;
btSoftBody::Node *node;
btSoftBody::Anchor anchor;
int anchors_size = body->soft_body->m_anchors.size();
soft_body = body->soft_body;
if (anchors_size)
{
rigid_body = soft_body->m_anchors[0].m_body;
for (int m = 0; m < anchors_size; m++)
{
anchor = soft_body->m_anchors[m];
node = anchor.m_node;
for (int n = 0; n < soft_body->m_nodes.size(); n++)
{
if (node == &soft_body->m_nodes[n])
_ephysics_body_soft_body_anchors_rebuild(n, rigid_body,
soft_body);
}
}
}
soft_body->generateClusters(0);
soft_body->generateBendingConstraints(2, soft_body->m_materials[0]);
}
static void
_ephysics_body_soft_body_constraints_rebuild(EPhysics_Body *body)
{
@ -691,7 +809,7 @@ _ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h)
body->w = w;
body->h = h;
body->rigid_body->activate(1);
ephysics_body_activate(body, EINA_TRUE);
DBG("Body %p scale changed to %lf, %lf.", body, sx, sy);
}
@ -711,12 +829,12 @@ _ephysics_body_move(EPhysics_Body *body, Evas_Coord x, Evas_Coord y)
mx = (x + body->w * body->cm.x) / rate;
my = (height - (y + body->h * body->cm.y)) / rate;
body->rigid_body->getMotionState()->getWorldTransform(trans);
trans = _ephysics_body_transform_get(body);
trans.setOrigin(btVector3(mx, my, 0));
body->rigid_body->proceedToTransform(trans);
body->rigid_body->getMotionState()->setWorldTransform(trans);
body->rigid_body->activate(1);
ephysics_body_activate(body, EINA_TRUE);
DBG("Body %p position changed to %lf, %lf.", body, mx, my);
}
@ -737,17 +855,23 @@ _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Eva
sx = w / rate;
sy = h / rate;
body->rigid_body->getMotionState()->getWorldTransform(trans);
trans.setOrigin(btVector3(mx, my, 0));
trans = _ephysics_body_transform_get(body);
trans.setOrigin(btVector3(mx, my, trans.getOrigin().z()));
body_scale = btVector3(sx, sy, 1);
if (body->soft_body)
if (body->type == EPHYSICS_BODY_TYPE_SOFT)
{
body->soft_body->scale(btVector3(sx, sy, 1));
body->soft_body->scale(body_scale);
body->rigid_body->proceedToTransform(trans);
body->soft_body->transform(trans);
_ephysics_body_soft_body_constraints_rebuild(body);
}
else if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
{
body->soft_body->scale(body_scale);
_ephysics_body_transform_set(body, trans);
_ephysics_body_cloth_constraints_rebuild(body);
}
else
{
body->collision_shape->setLocalScaling(body_scale);
@ -757,13 +881,12 @@ _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Eva
_ephysics_body_mass_set(body, ephysics_body_mass_get(body));
}
body->rigid_body->getMotionState()->setWorldTransform(trans);
_ephysics_body_transform_set(body, trans);
ephysics_body_activate(body, EINA_TRUE);
body->w = w;
body->h = h;
body->rigid_body->activate(1);
DBG("Body %p position changed to %lf, %lf.", body, mx, my);
DBG("Body %p scale changed to %lf, %lf.", body, sx, sy);
}
@ -811,9 +934,13 @@ _ephysics_body_del(EPhysics_Body *body)
free(body->points_deform);
delete body->rigid_body->getMotionState();
delete body->collision_shape;
delete body->rigid_body;
if (body->rigid_body)
{
delete body->rigid_body->getMotionState();
delete body->collision_shape;
delete body->rigid_body;
}
delete body->soft_body;
free(body);
@ -831,9 +958,8 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
if (!body->evas_obj)
return;
body->rigid_body->getMotionState()->getWorldTransform(trans);
trans = _ephysics_body_transform_get(body);
ephysics_world_render_geometry_get(body->world, &wx, &wy, NULL, &wh);
camera = ephysics_world_camera_get(body->world);
ephysics_camera_position_get(camera, &cx, &cy);
cx -= wx;
@ -853,7 +979,7 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
return;
}
if (body->soft_body)
if (body->type != EPHYSICS_BODY_TYPE_RIGID)
return;
rot = - trans.getRotation().getAngle() * RAD_TO_DEG *
@ -901,7 +1027,7 @@ ephysics_body_forces_apply(EPhysics_Body *body)
return;
rate = ephysics_world_rate_get(body->world);
body->rigid_body->activate(1);
ephysics_body_activate(body, EINA_TRUE);
body->rigid_body->applyCentralForce(btVector3(body->force.x / rate,
body->force.y / rate, 0));
body->rigid_body->applyTorque(btVector3(0, 0, body->force.torque));
@ -1015,7 +1141,7 @@ static void
_ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
{
btSoftBody *soft_body = body->soft_body;
soft_body->m_cfg.kAHR = (hardness / 1000) * 0.6;
soft_body->m_cfg.kAHR = (hardness / body->anchor_prop) * 0.6;
soft_body->m_materials[0]->m_kVST = (hardness / 1000);
soft_body->m_materials[0]->m_kLST = (hardness / 1000);
soft_body->m_materials[0]->m_kAST = (hardness / 1000);
@ -1066,21 +1192,10 @@ ephysics_body_soft_body_hardness_get(const EPhysics_Body *body)
return (body->soft_body->m_materials[0]->m_kVST * 100);
}
static EPhysics_Body *
_ephysics_body_soft_body_add(EPhysics_World *world, btCollisionShape *collision_shape, btSoftBody *soft_body)
static void
_ephysics_body_soft_body_default_config(EPhysics_Body *body, btSoftBody *soft_body)
{
EPhysics_Body *body;
body = _ephysics_body_add(world, collision_shape, "soft box", 0.5, 0.5);
if (!body)
{
if (body->deleted) return NULL;
body->deleted = EINA_TRUE;
ephysics_world_body_del(body->world, body);
return NULL;
}
body->soft_body = soft_body;
body->soft_body->getCollisionShape()->setMargin(btScalar(0.02));
body->soft_body->setUserPointer(body);
body->soft_body->setTotalMass(body->mass);
@ -1089,6 +1204,27 @@ _ephysics_body_soft_body_add(EPhysics_World *world, btCollisionShape *collision_
body->soft_body->m_cfg.collisions += btSoftBody::fCollision::VF_SS;
_ephysics_body_soft_body_hardness_set(body, 100);
}
static EPhysics_Body *
_ephysics_body_soft_body_add(EPhysics_World *world, btCollisionShape *collision_shape, btSoftBody *soft_body)
{
EPhysics_Body *body;
body = _ephysics_body_rigid_body_add(world, collision_shape, "soft box", 0.5,
0.5);
if (!body)
{
if (body->deleted) return NULL;
body->deleted = EINA_TRUE;
ephysics_world_body_del(body->world, body);
return NULL;
}
body->anchor_prop = 1000;
body->type = EPHYSICS_BODY_TYPE_SOFT;
_ephysics_body_soft_body_default_config(body, soft_body);
body->rigid_body->setCollisionFlags(
btCollisionObject::CF_NO_CONTACT_RESPONSE);
@ -1097,6 +1233,157 @@ _ephysics_body_soft_body_add(EPhysics_World *world, btCollisionShape *collision_
return body;
}
EAPI void
ephysics_body_cloth_anchor_full_add(EPhysics_Body *body1, EPhysics_Body *body2, EPhysics_Body_Cloth_Anchor_Side side)
{
int rows;
int columns;
if (!body1 || !body2)
{
ERR("Could not add anchors, body1 or body2 is null");
return;
}
if (body1->type != EPHYSICS_BODY_TYPE_CLOTH ||
body2->type != EPHYSICS_BODY_TYPE_RIGID)
{
ERR("Cloth anchors are allowed only between cloth and rigid body.");
return;
}
rows = body1->cloth_rows;
columns = body1->cloth_columns;
if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_LEFT)
{
for (int i = 0; i < rows; i++)
body1->soft_body->appendAnchor(i, body2->rigid_body);
return;
}
if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_RIGHT)
{
for (int i = 1; i <= rows; i++)
body1->soft_body->appendAnchor((rows * columns) - i,
body2->rigid_body);
return;
}
if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_TOP)
{
for (int i = 0; i <= rows; i++)
body1->soft_body->appendAnchor(i * rows, body2->rigid_body);
return;
}
if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_BOTTOM)
{
for (int i = 0; i < columns; i++)
body1->soft_body->appendAnchor((rows - 1) + rows * i,
body2->rigid_body);
}
}
EAPI void
ephysics_body_cloth_anchor_add(EPhysics_Body *body1, EPhysics_Body *body2, int node)
{
if (!body1 || !body2)
{
ERR("Could not add anchors, body1 or body2 is null");
return;
}
if (body1->type != EPHYSICS_BODY_TYPE_CLOTH ||
body2->type != EPHYSICS_BODY_TYPE_RIGID)
{
ERR("Cloth anchors are allowed only between cloth and rigid body.");
return;
}
body1->soft_body->appendAnchor(node, body2->rigid_body);
}
EAPI void
ephysics_body_cloth_anchor_del(EPhysics_Body *body)
{
if (!body)
{
ERR("Could not delete anchor, body is null.");
return;
}
if (body->type != EPHYSICS_BODY_TYPE_CLOTH)
{
ERR("Could not delete anchors, body is not a cloth.");
return;
}
body->soft_body->m_anchors.resize(0);
}
EAPI EPhysics_Body *
ephysics_body_cloth_add(EPhysics_World *world, unsigned short granularity)
{
EPhysics_Body *body;
btSoftBodyWorldInfo *world_info;
btSoftBody *soft_body;
const int rows = (!granularity) ? 10 : granularity;
const int columns = (!granularity) ? 10 : granularity;
if (!world)
{
ERR("Can't add circle, world is null.");
return NULL;
}
world_info = ephysics_world_info_get(world);
soft_body = btSoftBodyHelpers::CreatePatch(*world_info,
btVector3(1, 2, 0.5),
btVector3(1, 1, 0.5),
btVector3(2, 2, 0.5),
btVector3(2, 1, 0.5),
rows, columns, 0, false);
if (!soft_body)
{
ERR("Couldn't create a new soft body.");
return NULL;
}
body = _ephysics_body_new(world, 1, 0.5, 0.5);
if (!body)
goto no_body;
_ephysics_body_soft_body_default_config(body, soft_body);
soft_body->m_cfg.piterations = 10;
_ephysics_body_cloth_constraints_rebuild(body);
body->slices = soft_body->m_faces.size();
body->points_deform = (int *)malloc(body->slices * sizeof(int));
if (!body->points_deform)
{
ERR("Couldn't create points of deformation.");
goto no_deform;
}
for (int i = 0; i < body->slices; i++)
body->points_deform[i] = i;
body->cloth_columns = columns;
body->cloth_rows = rows;
body->anchor_prop = 100;
body->type = EPHYSICS_BODY_TYPE_CLOTH;
ephysics_world_soft_body_add(world, body);
return body;
no_deform:
free(body);
no_body:
delete soft_body;
return NULL;
}
EAPI EPhysics_Body *
ephysics_body_soft_circle_add(EPhysics_World *world)
{
@ -1181,7 +1468,8 @@ ephysics_body_circle_add(EPhysics_World *world)
}
ephysics_world_lock_take(world);
body = _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
body = _ephysics_body_rigid_body_add(world, collision_shape, "circle", 0.5,
0.5);
ephysics_world_lock_release(world);
return body;
}
@ -1265,7 +1553,7 @@ ephysics_body_box_add(EPhysics_World *world)
collision_shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
ephysics_world_lock_take(world);
body = _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
body = _ephysics_body_rigid_body_add(world, collision_shape, "box", 0.5, 0.5);
ephysics_world_lock_release(world);
return body;
}
@ -1380,9 +1668,10 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
}
ephysics_world_lock_take(world);
body = _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
"generic", (cm_x - min_x) / range_x,
1 - (cm_y - min_y) / range_y);
body = _ephysics_body_rigid_body_add(world,
(btCollisionShape *)simplified_shape,
"generic", (cm_x - min_x) / range_x,
1 - (cm_y - min_y) / range_y);
ephysics_world_lock_release(world);
return body;
}
@ -1552,9 +1841,12 @@ ephysics_body_evas_object_set(EPhysics_Body *body, Evas_Object *evas_obj, Eina_B
if (body->soft_body)
{
body->evas_obj = _ephysics_body_soft_body_evas_add(body);
evas_object_event_callback_del(evas_obj, EVAS_CALLBACK_DEL,
_ephysics_body_evas_obj_del_cb);
evas_obj = _ephysics_body_soft_body_evas_add(body);
body->evas_obj = evas_obj;
evas_object_event_callback_add(body->evas_obj, EVAS_CALLBACK_DEL,
_ephysics_body_evas_obj_del_cb, body);
}
@ -1661,7 +1953,7 @@ EAPI void
ephysics_body_geometry_get(const EPhysics_Body *body, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
{
btTransform trans;
btVector3 vector;
btVector3 scale;
double rate;
int wy, height;
@ -1671,15 +1963,15 @@ ephysics_body_geometry_get(const EPhysics_Body *body, Evas_Coord *x, Evas_Coord
return;
}
body->rigid_body->getMotionState()->getWorldTransform(trans);
vector = body->collision_shape->getLocalScaling();
trans = _ephysics_body_transform_get(body);
scale = _ephysics_body_scale_get(body);
rate = ephysics_world_rate_get(body->world);
ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, &height);
height += wy;
if (x) *x = round((trans.getOrigin().getX() - vector.x() / 2) * rate);
if (y) *y = height - round((trans.getOrigin().getY() + vector.y() / 2)
if (x) *x = round((trans.getOrigin().getX() - scale.x() / 2) * rate);
if (y) *y = height - round((trans.getOrigin().getY() + scale.y() / 2)
* rate);
if (w) *w = body->w;
if (h) *h = body->h;
@ -1960,7 +2252,13 @@ ephysics_body_event_callback_del_full(EPhysics_Body *body, EPhysics_Callback_Bod
static void
_ephysics_body_restitution_set(EPhysics_Body *body, double restitution)
{
body->rigid_body->setRestitution(btScalar(restitution));
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
{
body->rigid_body->setRestitution(btScalar(restitution));
return;
}
body->soft_body->setRestitution(btScalar(restitution));
DBG("Body %p restitution set to %lf", body, restitution);
}
@ -1988,13 +2286,22 @@ ephysics_body_restitution_get(const EPhysics_Body *body)
return 0;
}
return body->rigid_body->getRestitution();
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
return body->rigid_body->getRestitution();
return body->soft_body->getRestitution();
}
static void
_ephysics_body_friction_set(EPhysics_Body *body, double friction)
{
body->rigid_body->setFriction(btScalar(friction));
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
{
body->rigid_body->setFriction(btScalar(friction));
return;
}
body->soft_body->setFriction(btScalar(friction));
DBG("Body %p friction set to %lf", body, friction);
}
@ -2022,7 +2329,10 @@ ephysics_body_friction_get(const EPhysics_Body *body)
return 0;
}
return body->rigid_body->getFriction();
if (body->type == EPHYSICS_BODY_TYPE_RIGID)
return body->rigid_body->getFriction();
return body->soft_body->getFriction();
}
EAPI EPhysics_World *
@ -2051,7 +2361,7 @@ ephysics_body_central_impulse_apply(EPhysics_Body *body, double x, double y)
rate = ephysics_world_rate_get(body->world);
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
ephysics_body_activate(body, EINA_TRUE);
body->rigid_body->applyCentralImpulse(btVector3(x / rate, - y / rate, 0));
ephysics_world_lock_release(body->world);
}
@ -2070,7 +2380,7 @@ ephysics_body_impulse_apply(EPhysics_Body *body, double x, double y, Evas_Coord
rate = ephysics_world_rate_get(body->world);
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
ephysics_body_activate(body, EINA_TRUE);
body->rigid_body->applyImpulse(btVector3(x / rate, - y / rate, 0),
btVector3((double) pos_x / rate,
(double) pos_y / rate, 0));
@ -2114,7 +2424,7 @@ ephysics_body_torque_impulse_apply(EPhysics_Body *body, double roll)
}
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
ephysics_body_activate(body, EINA_TRUE);
body->rigid_body->applyTorqueImpulse(btVector3(0, 0, -roll));
ephysics_world_lock_release(body->world);
}
@ -2160,7 +2470,7 @@ ephysics_body_rotation_get(const EPhysics_Body *body)
return 0;
}
body->rigid_body->getMotionState()->getWorldTransform(trans);
trans = _ephysics_body_transform_get(body);
rot = - trans.getRotation().getAngle() * RAD_TO_DEG *
trans.getRotation().getAxis().getZ();
@ -2180,8 +2490,9 @@ ephysics_body_rotation_set(EPhysics_Body *body, double rotation)
}
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->getMotionState()->getWorldTransform(trans);
ephysics_body_activate(body, EINA_TRUE);
trans = _ephysics_body_transform_get(body);
quat.setEuler(0, 0, -rotation / RAD_TO_DEG);
trans.setRotation(quat);

View File

@ -119,6 +119,13 @@ ephysics_constraint_slider_add(EPhysics_Body *body)
return NULL;
}
if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
{
ERR("Constraints are allowed only between rigid -> rigid bodies or "
"rigid -> soft bodies");
return NULL;
}
constraint = (EPhysics_Constraint *) calloc(1, sizeof(EPhysics_Constraint));
if (!constraint)
{
@ -277,11 +284,19 @@ ephysics_constraint_p2p_add(EPhysics_Body *body1, EPhysics_Body *body2, Evas_Coo
if ((body2) &&
(ephysics_body_world_get(body1) != ephysics_body_world_get(body2)))
{
ERR("To create a constraint both bodies must to belong to the same"
ERR("To create a constraint both bodies must belong to the same"
"world.");
return NULL;
}
if (body1->type == EPHYSICS_BODY_TYPE_CLOTH ||
body2->type == EPHYSICS_BODY_TYPE_CLOTH)
{
ERR("Constraints are allowed only between rigid -> rigid bodies or"
"rigid -> soft bodies");
return NULL;
}
constraint = (EPhysics_Constraint *) calloc(1, sizeof(EPhysics_Constraint));
if (!constraint)
{

View File

@ -65,6 +65,13 @@ struct _EPhysics_Point {
double y;
};
typedef enum _EPhysics_Body_Type
{
EPHYSICS_BODY_TYPE_RIGID,
EPHYSICS_BODY_TYPE_SOFT,
EPHYSICS_BODY_TYPE_CLOTH,
} EPhysics_Body_Type;
struct _EPhysics_Body {
EINA_INLIST;
btCollisionShape *collision_shape;
@ -95,6 +102,10 @@ struct _EPhysics_Body {
Eina_Bool deleted:1;
int slices;
int *points_deform;
EPhysics_Body_Type type;
int cloth_columns;
int cloth_rows;
int anchor_prop;
};
extern int _ephysics_log_dom;
@ -116,6 +127,8 @@ void ephysics_world_boundary_set(EPhysics_World *world, EPhysics_World_Boundary
EPhysics_Body *ephysics_world_boundary_get(const EPhysics_World *world, EPhysics_World_Boundary boundary);
Eina_Bool ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world);
btSoftBodyWorldInfo *ephysics_world_info_get(const EPhysics_World *world);
void ephysics_world_lock_take(EPhysics_World *world);
void ephysics_world_lock_release(EPhysics_World *world);
/* Body */
Eina_Bool ephysics_body_filter_collision(EPhysics_Body *body0, EPhysics_Body *body1);
@ -127,8 +140,7 @@ btSoftBody *ephysics_body_soft_body_get(const EPhysics_Body *body);
void ephysics_body_active_set(EPhysics_Body *body, Eina_Bool active);
void ephysics_body_recalc(EPhysics_Body *body, double rate);
void ephysics_body_forces_apply(EPhysics_Body *body);
void ephysics_world_lock_take(EPhysics_World *world);
void ephysics_world_lock_release(EPhysics_World *world);
void ephysics_body_activate(const EPhysics_Body *body, Eina_Bool activate);
/* Camera */
EPhysics_Camera *ephysics_camera_add(EPhysics_World *world);

View File

@ -171,9 +171,10 @@ _ephysics_world_tick(btDynamicsWorld *dynamics_world)
{
Eina_Bool world_active, camera_moved, tx, ty;
btCollisionObjectArray objects;
btRigidBody *rigid_body;
btCollisionObject *collision;
EPhysics_World *world;
EPhysics_Body *body;
btRigidBody *rigid_body;
world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
@ -192,12 +193,13 @@ _ephysics_world_tick(btDynamicsWorld *dynamics_world)
objects = dynamics_world->getCollisionObjectArray();
for (int i = 0; i < objects.size(); i++)
{
btRigidBody *rigid_body = btRigidBody::upcast(objects[i]);
if (!rigid_body)
collision = objects[i];
if (!collision)
continue;
body = (EPhysics_Body *) rigid_body->getUserPointer();
if (rigid_body->isActive())
body = (EPhysics_Body *) collision->getUserPointer();
if (collision->isActive())
{
ephysics_body_active_set(body, EINA_TRUE);
ephysics_body_evas_object_update_select(body);
@ -260,7 +262,8 @@ _ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
{
btSoftBody *soft_body;
world->dynamics_world->removeRigidBody(ephysics_body_rigid_body_get(body));
if (ephysics_body_rigid_body_get(body))
world->dynamics_world->removeRigidBody(ephysics_body_rigid_body_get(body));
soft_body = ephysics_body_soft_body_get(body);
if (soft_body)
@ -291,10 +294,7 @@ ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
and body 2 will stay freezed in the air. Gravity won't start to
act over it until it's activated again. */
EINA_INLIST_FOREACH(world->bodies, bd)
{
btRigidBody *rigid_body = ephysics_body_rigid_body_get(bd);
rigid_body->activate(1);
}
ephysics_body_activate(bd, EINA_TRUE);
return EINA_TRUE;
}