EPhysics: add forces API
authorBruno Dilly <bdilly@profusion.mobi>
Mon, 20 Aug 2012 22:15:52 +0000 (22:15 +0000)
committerBruno Dilly <bdilly@profusion.mobi>
Mon, 20 Aug 2012 22:15:52 +0000 (22:15 +0000)
Implement functions to make it possible to control forces acting
over a body.

SVN revision: 75476

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_world.cpp

index dec2024..4809864 100644 (file)
@@ -2185,7 +2185,7 @@ EAPI void ephysics_body_torque_impulse_apply(EPhysics_Body *body, double roll);
  * or can be used to lead to both behaviors with
  * @ref ephysics_body_impulse_apply().
  *
- * It will resulte in a central impulse with impulse (@p x, @p y) and a
+ * It will result in a central impulse with impulse (@p x, @p y) and a
  * torque impulse that will be calculated as a cross product on impulse
  * and relative position.
  *
@@ -2300,7 +2300,7 @@ EAPI double ephysics_body_rotation_get(const EPhysics_Body *body);
  * @note The unit used for rotation is degrees.
  *
  * @param body The physics body.
- * @param The amount of degrees @p body should be rotated.
+ * @param rotation The amount of degrees @p body should be rotated.
  *
  * @see ephysics_body_rotation_get()
  *
@@ -2347,6 +2347,143 @@ EAPI void ephysics_body_data_set(EPhysics_Body *body, void *data);
 EAPI void *ephysics_body_data_get(const EPhysics_Body *body);
 
 /**
+ * @brief
+ * Apply a force on the center of a body.
+ *
+ * Applying a force to a body will lead it to change its velocity.
+ *
+ * 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
+ *
+ * While a force is applied, it will be acting over a body. It can be canceled
+ * by applying an inverse force, or just calling
+ * @ref ephysics_body_forces_clear().
+ *
+ * This force will be applied on body's center, so it won't implies in
+ * changing angular acceleration. For that, it is possible to apply a torque
+ * with @ref ephysics_body_torque_apply().
+ *
+ * If the force shouldn't be applied on body's center, it can be applied on
+ * a relative point with @ref ephysics_body_force_apply().
+ *
+ * @note Force is measured in kg * p / s / s.
+ *
+ * @param body The physics body which over the force will be applied.
+ * @param x The axis x component of force.
+ * @param y The axis y component of force.
+ *
+ * @see ephysics_body_torque_apply().
+ * @see ephysics_body_force_apply().
+ * @see ephysics_body_forces_get().
+ *
+ * @ingroup EPhysics_Body
+ */
+EAPI void ephysics_body_central_force_apply(EPhysics_Body *body, double x, double y);
+
+/**
+ * @brief
+ * Apply a torque over a body.
+ *
+ * A torque will be applied over the @p body to change the angular acceleration
+ * of this body. It will leads to a change on angular velocity over time.
+ * And the body will rotate around Z axis considering this angular velocity.
+ *
+ * @param body The physics body that will receive the torque.
+ * @param torque Torque to change angular acceleration of the body around Z
+ * axis (rotate on x - y plane).
+ * Negative values will accelerate it on anti clock rotation.
+ *
+ * @see ephysics_body_central_force_apply().
+ * @see ephysics_body_force_apply().
+ * @see ephysics_body_forces_get().
+ *
+ * @ingroup EPhysics_Body
+ */
+EAPI void ephysics_body_torque_apply(EPhysics_Body *body, double torque);
+
+/**
+ * @brief
+ * Apply a force over a body.
+ *
+ * A force will be applied over the body to change it's linear and angular
+ * accelerations.
+ *
+ * It can be applied in the center of the body, avoiding affecting angular
+ * acceleration, with @ref ephysics_body_central_force_apply(),
+ * it can be applied only to change angular acceleration, with
+ * @ref ephysics_body_torque_apply(), or can be used to lead to both
+ * behaviors with @ref ephysics_body_force_apply().
+ *
+ * It will result in a central force with force (@p x, @p y) and a
+ * torque that will be calculated as a cross product on force
+ * and relative position.
+ *
+ * @param body The physics body that will receive the impulse.
+ * @param x The axis x component of force.
+ * @param y The axis y component of force.
+ * @param pos_x The axis x component of the relative position to apply force.
+ * @param pos_y The axis y component of the relative position to apply force.
+ *
+ * @note Force is measured in kg * p / s / s and position in p (pixels, or
+ * Evas coordinates).
+ *
+ * @see ephysics_body_central_force_apply().
+ * @see ephysics_body_torque_apply().
+ * @see ephysics_body_forces_get().
+ *
+ * @ingroup EPhysics_Body
+ */
+EAPI void ephysics_body_force_apply(EPhysics_Body *body, double x, double y, Evas_Coord pos_x, Evas_Coord pos_y);
+
+/**
+ * @brief
+ * Get physics body forces.
+ *
+ * Get all the forces applied over a body.
+ *
+ * @param body The physics body.
+ * @param x The axis x component of total force.
+ * @param y The axis y component of total force.
+ * @param torque The torque.
+ *
+ * @see ephysics_body_force_apply() for more details.
+ * @see ephysics_body_central_force_apply().
+ * @see ephysics_body_torque_apply().
+ * @see ephysics_body_forces_clear().
+ *
+ * @ingroup EPhysics_Body
+ */
+EAPI void ephysics_body_forces_get(const EPhysics_Body *body, double *x, double *y, double *torque);
+
+/**
+ * @brief
+ * Clear all the forces applied to a body.
+ *
+ * It will remove all the forces previously applied. So linear acceleration
+ * and angular acceleration will be set to 0.
+ *
+ * It won't interfere with world's gravity, the body will continue to be
+ * accelerated considering gravity.
+ *
+ * It won't affect damping.
+ *
+ * @param body The physics body that will have applied forces set to 0.
+ *
+ * @see ephysics_body_central_force_apply().
+ * @see ephysics_body_torque_apply().
+ * @see ephysics_body_force_apply().
+ * @see ephysics_body_forces_get().
+ *
+ * @ingroup EPhysics_Body
+ */
+EAPI void ephysics_body_forces_clear(EPhysics_Body *body);
+
+/**
  * @}
  */
 
index a907008..c495bcb 100644 (file)
@@ -26,6 +26,15 @@ struct _EPhysics_Body_Collision {
      Evas_Coord y;
 };
 
+static void
+_ephysics_body_forces_update(EPhysics_Body *body)
+{
+   body->force.x = body->rigid_body->getTotalForce().getX();
+   body->force.y = body->rigid_body->getTotalForce().getY();
+   body->force.torque = body->rigid_body->getTotalTorque().getZ();
+   body->rigid_body->clearForces();
+}
+
 static inline void
 _ephysics_body_sleeping_threshold_set(EPhysics_Body *body, double linear_threshold, double angular_threshold, double rate)
 {
@@ -464,6 +473,16 @@ _ephysics_body_outside_render_area_check(EPhysics_Body *body)
 }
 
 void
+ephysics_body_forces_apply(EPhysics_Body *body)
+{
+   double rate = ephysics_world_rate_get(body->world);
+   body->rigid_body->activate(1);
+   body->rigid_body->applyCentralForce(btVector3(body->force.x / rate,
+                                                 body->force.y / rate, 0));
+   body->rigid_body->applyTorque(btVector3(0, 0, body->force.torque));
+}
+
+void
 ephysics_body_recalc(EPhysics_Body *body, double rate)
 {
    Evas_Coord x, y, w, h;
@@ -1386,6 +1405,91 @@ ephysics_body_data_get(const EPhysics_Body *body)
    return body->data;
 }
 
+EAPI void
+ephysics_body_central_force_apply(EPhysics_Body *body, double x, double y)
+{
+   double rate;
+
+   if (!body)
+     {
+        ERR("Can't apply force to a null body.");
+        return;
+     }
+
+   rate = ephysics_world_rate_get(body->world);
+   ephysics_body_forces_apply(body);
+   body->rigid_body->applyCentralForce(btVector3(x / rate, y / rate, 0));
+   _ephysics_body_forces_update(body);
+}
+
+EAPI void
+ephysics_body_force_apply(EPhysics_Body *body, double x, double y, Evas_Coord pos_x, Evas_Coord pos_y)
+{
+   double rate;
+
+   if (!body)
+     {
+        ERR("Can't apply force to a null body.");
+        return;
+     }
+
+   rate = ephysics_world_rate_get(body->world);
+   ephysics_body_forces_apply(body);
+   body->rigid_body->applyForce(btVector3(x / rate, y / rate, 0),
+                                btVector3((double) pos_x / rate,
+                                          (double) pos_y / rate, 0));
+   _ephysics_body_forces_update(body);
+}
+
+EAPI void
+ephysics_body_torque_apply(EPhysics_Body *body, double torque)
+{
+   double rate;
+
+   if (!body)
+     {
+        ERR("Can't apply force to a null body.");
+        return;
+     }
+
+   rate = ephysics_world_rate_get(body->world);
+   ephysics_body_forces_apply(body);
+   body->rigid_body->applyTorque(btVector3(0, 0, -torque));
+   _ephysics_body_forces_update(body);
+}
+
+EAPI void
+ephysics_body_forces_get(const EPhysics_Body *body, double *x, double *y, double *torque)
+{
+   double rate;
+
+   if (!body)
+     {
+        ERR("Can't get forces from a null body.");
+        return;
+     }
+
+   rate = ephysics_world_rate_get(body->world);
+
+   if (x) *x = body->force.x * rate;
+   if (y) *y = body->force.y * rate;
+   if (torque) *torque = -body->force.torque;
+}
+
+EAPI void
+ephysics_body_forces_clear(EPhysics_Body *body)
+{
+   if (!body)
+     {
+        ERR("Can't clear forces of a null body.");
+        return;
+     }
+
+   body->force.x = 0;
+   body->force.y = 0;
+   body->force.torque = 0;
+}
+
 #ifdef  __cplusplus
 }
 #endif
index eb7669f..3a3dad4 100644 (file)
@@ -75,6 +75,11 @@ struct _EPhysics_Body {
      Eina_List *collision_groups;
      Eina_List *to_delete;
      double mass;
+     struct {
+          double x;
+          double y;
+          double torque;
+     } force;
      Eina_Bool active:1;
      Eina_Bool deleted:1;
 };
@@ -101,6 +106,7 @@ void ephysics_body_contact_processed(EPhysics_Body *body, EPhysics_Body *contact
 btRigidBody *ephysics_body_rigid_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);
 
 /* Camera */
 EPhysics_Camera *ephysics_camera_add(EPhysics_World *world);
index 292a42c..a0a4c5e 100644 (file)
@@ -245,12 +245,16 @@ _simulate_worlds(void *data)
    EINA_INLIST_FOREACH(lworlds, world)
      {
         double time_now, delta;
+        EPhysics_Body *body;
 
         if (!world->running)
           continue;
 
         world->walking++;
 
+        EINA_INLIST_FOREACH(world->bodies, body)
+           ephysics_body_forces_apply(body);
+
         time_now = ecore_time_get();
         delta = time_now - world->last_update;
         world->last_update = time_now;