EPhysics: improve convex shapes
authorBruno Dilly <bdilly@profusion.mobi>
Wed, 22 Aug 2012 20:05:25 +0000 (20:05 +0000)
committerBruno Dilly <bdilly@profusion.mobi>
Wed, 22 Aug 2012 20:05:25 +0000 (20:05 +0000)
Center of these shapes were wrong, now it's much better.
But collision still seems a bit inaccurate.

SVN revision: 75572

legacy/ephysics/src/bin/test_shapes.c
legacy/ephysics/src/lib/EPhysics.h
legacy/ephysics/src/lib/ephysics_body.cpp
legacy/ephysics/src/lib/ephysics_private.h
legacy/ephysics/src/lib/ephysics_shape.cpp

index 4e00b5a..3547dbb 100644 (file)
@@ -9,68 +9,51 @@ _world_populate(Test_Data *test_data)
 {
    EPhysics_Shape *pentagon_shape, *hexagon_shape;
    EPhysics_Body *pentagon_body, *hexagon_body;
-   EPhysics_Constraint *constraint;
    Evas_Object *pentagon, *hexagon;
 
    pentagon = elm_image_add(test_data->win);
    elm_image_file_set(
       pentagon, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "pentagon");
    evas_object_move(pentagon, WIDTH / 3, HEIGHT / 2 - 30);
-   evas_object_resize(pentagon, 70, 66);
+   evas_object_resize(pentagon, 70, 68);
    evas_object_show(pentagon);
    test_data->evas_objs = eina_list_append(test_data->evas_objs, pentagon);
 
    pentagon_shape = ephysics_shape_new();
-   ephysics_shape_point_add(pentagon_shape, 0/70., 24/66.);
-   ephysics_shape_point_add(pentagon_shape, 35/70., 0/66.);
-   ephysics_shape_point_add(pentagon_shape, 70/70., 24/66.);
-   ephysics_shape_point_add(pentagon_shape, 56/70., 66/66.);
-   ephysics_shape_point_add(pentagon_shape, 14/70., 66/66.);
+   ephysics_shape_point_add(pentagon_shape, -1, -9/33.);
+   ephysics_shape_point_add(pentagon_shape, 0, -1);
+   ephysics_shape_point_add(pentagon_shape, 1, -9/33.);
+   ephysics_shape_point_add(pentagon_shape, -21/35., 1);
+   ephysics_shape_point_add(pentagon_shape, 21/35., 1);
 
    pentagon_body = ephysics_body_shape_add(test_data->world, pentagon_shape);
    ephysics_body_evas_object_set(pentagon_body, pentagon, EINA_TRUE);
    ephysics_body_restitution_set(pentagon_body, 1);
-   ephysics_body_friction_set(pentagon_body, 0);
    test_data->bodies = eina_list_append(test_data->bodies, pentagon_body);
 
    hexagon = elm_image_add(test_data->win);
    elm_image_file_set(
       hexagon, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "hexagon");
-   evas_object_move(hexagon, WIDTH / 3 + 80, HEIGHT / 2 - 30 + 35);
+   evas_object_move(hexagon, WIDTH / 3 + 80, HEIGHT / 2 - 30);
    evas_object_resize(hexagon, 70, 60);
    evas_object_show(hexagon);
    test_data->evas_objs = eina_list_append(test_data->evas_objs, hexagon);
 
    hexagon_shape = ephysics_shape_new();
-   ephysics_shape_point_add(hexagon_shape, 0, 0.5);
-   ephysics_shape_point_add(hexagon_shape, 18/70., 0);
-   ephysics_shape_point_add(hexagon_shape, 52/70., 0);
-   ephysics_shape_point_add(hexagon_shape, 1, 0.5);
-   ephysics_shape_point_add(hexagon_shape, 52/70., 1);
-   ephysics_shape_point_add(hexagon_shape, 18/70., 1);
+   ephysics_shape_point_add(hexagon_shape, 0, 30);
+   ephysics_shape_point_add(hexagon_shape, 18, 0);
+   ephysics_shape_point_add(hexagon_shape, 52, 0);
+   ephysics_shape_point_add(hexagon_shape, 70, 30);
+   ephysics_shape_point_add(hexagon_shape, 52, 60);
+   ephysics_shape_point_add(hexagon_shape, 18, 60);
 
    hexagon_body = ephysics_body_shape_add(test_data->world, hexagon_shape);
-   ephysics_body_mass_set(hexagon_body, 5);
    ephysics_body_evas_object_set(hexagon_body, hexagon, EINA_TRUE);
    ephysics_body_restitution_set(hexagon_body, 1);
-   ephysics_body_friction_set(hexagon_body, 0);
    test_data->bodies = eina_list_append(test_data->bodies, hexagon_body);
 
-   constraint = ephysics_constraint_p2p_add(pentagon_body, NULL, 8, 0,
-                                            0, 0);
-   test_data->constraints = eina_list_append(test_data->constraints,
-                                             constraint);
-
-   constraint = ephysics_constraint_p2p_add(hexagon_body, NULL, 0, 0, 0, 0);
-   test_data->constraints = eina_list_append(test_data->constraints,
-                                             constraint);
-
-   ephysics_body_torque_impulse_apply(pentagon_body, 2);
-
    ephysics_shape_del(pentagon_shape);
    ephysics_shape_del(hexagon_shape);
-
-   ephysics_world_serialize(test_data->world, "/tmp/test.bullet");
 }
 
 static void
@@ -86,6 +69,7 @@ _restart(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED_
 void
 test_shapes(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 {
+   EPhysics_Body *boundary;
    EPhysics_World *world;
    Test_Data *test_data;
 
@@ -102,5 +86,12 @@ test_shapes(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    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_top_boundary_add(test_data->world);
+   ephysics_body_left_boundary_add(test_data->world);
+   ephysics_body_right_boundary_add(test_data->world);
+
    _world_populate(test_data);
 }
index 3372c1c..babe3b5 100644 (file)
@@ -205,6 +205,9 @@ EAPI void ephysics_shape_del(EPhysics_Shape *shape);
  * geometric shapes. The final shape will be constructed in such a way
  * it will have all the added points and will be convex.
  *
+ * The center of mass will be the centroid, or geometric center of the
+ * shape.
+ *
  * The order of points doesn't matter.
  *
  * For example, to create a pentagon:
@@ -212,11 +215,11 @@ EAPI void ephysics_shape_del(EPhysics_Shape *shape);
  * @code
  * EPhysics_Shape *shape = ephysics_shape_new();
  *
- * ephysics_shape_point_add(shape, 0/70., 24/66.);
- * ephysics_shape_point_add(shape, 35/70., 0/66.);
- * ephysics_shape_point_add(shape, 70/70., 24/66.);
- * ephysics_shape_point_add(shape, 56/70., 66/66.);
- * ephysics_shape_point_add(shape, 14/70., 66/66.);
+ * ephysics_shape_point_add(shape, 0, 24);
+ * ephysics_shape_point_add(shape, 35, 0);
+ * ephysics_shape_point_add(shape, 70, 24);
+ * ephysics_shape_point_add(shape, 56, 66);
+ * ephysics_shape_point_add(shape, 14, 66);
  *
  * ephysics_body_shape_add(world, shape);
  *
@@ -224,8 +227,8 @@ EAPI void ephysics_shape_del(EPhysics_Shape *shape);
  * @endcode
  *
  * @param shape The shape to be modified.
- * @param x Point position at x axis. Should be a value between 0 and 1.
- * @param y Point position at y axis. Should be a value between 0 and 1.
+ * @param x Point position at x axis.
+ * @param y Point position at y axis.
  * @return @c EINA_TRUE on success or EINA_FALSE on error.
  *
  * @see ephysics_shape_new().
index b390108..1231927 100644 (file)
@@ -193,7 +193,7 @@ 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)
+_ephysics_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;
@@ -244,6 +244,8 @@ _ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape, con
    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));
@@ -353,8 +355,8 @@ _ephysics_body_move(EPhysics_Body *body, Evas_Coord x, Evas_Coord y)
    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, &height);
    height += wy;
 
-   mx = (x + body->w / 2) / rate;
-   my = (height - (y + body->h / 2)) / rate;
+   mx = (x + body->w * body->cm.x) / rate;
+   my = (height - (y + body->h * body->cm.y)) / rate;
 
    body->rigid_body->getMotionState()->getWorldTransform(trans);
    trans.setOrigin(btVector3(mx, my, 0));
@@ -377,8 +379,8 @@ _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Eva
    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, &height);
    height += wy;
 
-   mx = (x + w / 2) / rate;
-   my = (height - (y + h / 2)) / rate;
+   mx = (x + w * body->cm.x) / rate;
+   my = (height - (y + h * body->cm.y)) / rate;
    sx = w / rate;
    sy = h / rate;
 
@@ -513,8 +515,8 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
 
    evas_object_geometry_get(body->evas_obj, NULL, NULL, &w, &h);
    rate = ephysics_world_rate_get(body->world);
-   x = (int) (trans.getOrigin().getX() * rate) - w / 2 - cx;
-   y = wh + wy - (int) (trans.getOrigin().getY() * rate) - h / 2 - cy;
+   x = (int) (trans.getOrigin().getX() * rate) - w * body->cm.x - cx;
+   y = wh + wy - (int) (trans.getOrigin().getY() * rate) - h * body->cm.y - cy;
 
    evas_object_move(body->evas_obj, x, y);
 
@@ -534,7 +536,8 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
    if (body->soft_body)
      _ephysics_body_soft_body_deform(body, rate, map);
 
-   evas_map_util_rotate(map, rot, x + (w / 2), y + (h / 2));
+   evas_map_util_rotate(map, rot, x + (w * body->cm.x), y +
+                        (h * body->cm.y));
    evas_object_map_set(body->evas_obj, map);
    evas_object_map_enable_set(body->evas_obj, EINA_TRUE);
    evas_map_free(map);
@@ -690,7 +693,7 @@ _ephysics_body_soft_add(EPhysics_World *world, btCollisionShape *collision_shape
    btSoftBody::AJoint::Specs angular_joint;
    btSoftBody::LJoint::Specs linear_joint;
 
-   body = _ephysics_body_add(world, collision_shape, "soft box");
+   body = _ephysics_body_add(world, collision_shape, "soft box", 0.5, 0.5);
    if (!body)
      {
         ephysics_body_del(body);
@@ -702,7 +705,7 @@ _ephysics_body_soft_add(EPhysics_World *world, btCollisionShape *collision_shape
 
    body->soft_body->getCollisionShape()->setMargin(0.22);
 
-   soft_body->m_materials[0]->m_kLST = 0.35;
+   soft_body->m_materials[0]->m_kLST = 0.35;
    soft_body->setPose(true, false);
 
    body->soft_body->m_cfg.collisions += btSoftBody::fCollision::SDF_RS;
@@ -806,7 +809,7 @@ ephysics_body_circle_add(EPhysics_World *world)
         return NULL;
      }
 
-   return _ephysics_body_add(world, collision_shape, "circle");
+   return _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
 }
 
 EAPI EPhysics_Body *
@@ -883,13 +886,14 @@ ephysics_body_box_add(EPhysics_World *world)
 
    collision_shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
 
-   return _ephysics_body_add(world, collision_shape, "box");
+   return _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
 }
 
 EAPI EPhysics_Body *
 ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
 {
    btConvexHullShape *full_shape, *simplified_shape;
+   double max_x, max_y, min_x, min_y, cm_x, cm_y, range_x, range_y;
    const Eina_Inlist *points;
    EPhysics_Point *point;
    btShapeHull *hull;
@@ -908,6 +912,13 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
         return NULL;
      }
 
+   points = ephysics_shape_points_get(shape);
+   if (eina_inlist_count(points) < 3)
+     {
+        ERR("At least 3 points are required to add a shape");
+        return NULL;
+     }
+
    full_shape = new btConvexHullShape();
    if (!full_shape)
      {
@@ -915,24 +926,65 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
         return NULL;
      }
 
-   points = ephysics_shape_points_get(shape);
+   point = EINA_INLIST_CONTAINER_GET(points, EPhysics_Point);
+   max_x = min_x = point->x;
+   max_y = min_y = point->y;
+   cm_x = cm_y = 0;
+
+   /* FIXME : only vertices should be used to calculate the center of mass */
+   EINA_INLIST_FOREACH(points, point)
+     {
+        if (point->x > max_x) max_x = point->x;
+        if (point->x < min_x) min_x = point->x;
+        if (point->y > max_y) max_y = point->y;
+        if (point->y < min_y) min_y = point->y;
+
+        cm_x += point->x;
+        cm_y += point->y;
+     }
+
+   cm_x /= eina_inlist_count(points);
+   cm_y /= eina_inlist_count(points);
+   range_x = max_x - min_x;
+   range_y = max_y - min_y;
 
    EINA_INLIST_FOREACH(points, point)
      {
-        point3d = btVector3(point->x, point->y, 0);
+        double x, y;
+
+        x = (point->x - cm_x) / range_x;
+        y = - (point->y - cm_y) / range_y;
+
+        point3d = btVector3(x, y, -0.5);
         full_shape->addPoint(point3d);
-        point3d = btVector3(point->x, point->y, 0.5);
+
+        point3d = btVector3(x, y, 0.5);
         full_shape->addPoint(point3d);
      }
 
    hull = new btShapeHull(full_shape);
+   if (!hull)
+     {
+        delete full_shape;
+        ERR("Couldn't create a shape hull.");
+        return NULL;
+     }
+
    margin = full_shape->getMargin();
    hull->buildHull(margin);
    simplified_shape = new btConvexHullShape(&(hull->getVertexPointer()->getX()),
                                             hull->numVertices());
+   delete hull;
+   delete full_shape;
+   if (!simplified_shape)
+     {
+        ERR("Couldn't create a simplified shape.");
+        return NULL;
+     }
 
    return _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
-                             "generic");
+                             "generic", (cm_x - min_x) / range_x,
+                             1 - (cm_y - min_y) / range_y);
 }
 
 void
index 1cd491e..a9d29b1 100644 (file)
@@ -85,6 +85,10 @@ struct _EPhysics_Body {
           double y;
           double torque;
      } force;
+     struct {
+          double x;
+          double y;
+     } cm;
      Eina_Bool active:1;
      Eina_Bool deleted:1;
      double distances[4][3];
index 7970b09..f75a4e6 100644 (file)
@@ -80,12 +80,6 @@ ephysics_shape_point_add(EPhysics_Shape *shape, double x, double y)
         return EINA_FALSE;;
      }
 
-   if ((x < 0) || (x > 1) || (y < 0) || (y > 1))
-     {
-        ERR("Points should be between 0 and 1.");
-        return EINA_FALSE;
-     }
-
    point = _ephysics_shape_point_new();
    if (!point)
      return EINA_FALSE;;