EPhysics: implement camera position handling
authorBruno Dilly <bdilly@profusion.mobi>
Fri, 27 Jul 2012 14:50:03 +0000 (14:50 +0000)
committerBruno Dilly <bdilly@profusion.mobi>
Fri, 27 Jul 2012 14:50:03 +0000 (14:50 +0000)
Now it's possibly to keep default updates of evas objects
and has scenes larger than render areas.

SVN revision: 74502

legacy/ephysics/src/bin/Makefile.am
legacy/ephysics/src/bin/test.c
legacy/ephysics/src/bin/test_camera.c [new file with mode: 0644]
legacy/ephysics/src/lib/EPhysics.h
legacy/ephysics/src/lib/ephysics_body.cpp
legacy/ephysics/src/lib/ephysics_camera.cpp
legacy/ephysics/src/lib/ephysics_world.cpp

index 7d6b212..fd93bdb 100644 (file)
@@ -18,6 +18,7 @@ ephysics_test_SOURCES = \
 test.c \
 test_bouncing_ball.c \
 test_bouncing_text.c \
+test_camera.c \
 test_colliding_balls.c \
 test_collision_detection.c \
 test_collision_speed.c \
index b9c8b24..5302da2 100644 (file)
@@ -11,6 +11,7 @@ int _ephysics_test_log_dom = -1;
 /* examples prototypes */
 void test_bouncing_ball(void *data, Evas_Object *obj, void *event_info);
 void test_bouncing_text(void *data, Evas_Object *obj, void *event_info);
+void test_camera(void *data, Evas_Object *obj, void *event_info);
 void test_colliding_balls(void *data, Evas_Object *obj, void *event_info);
 void test_collision(void *data, Evas_Object *obj, void *event_info);
 void test_collision_speed(void *data, Evas_Object *obj, void *event_info);
@@ -151,6 +152,7 @@ _main_win_add(char *autorun __UNUSED__, Eina_Bool test_win_only __UNUSED__)
 
    ADD_TEST("BOUNCING BALL", test_bouncing_ball);
    ADD_TEST("BOUNCING TEXT", test_bouncing_text);
+   ADD_TEST("CAMERA", test_camera);
    ADD_TEST("COLLIDING BALLS", test_colliding_balls);
    ADD_TEST("COLLISION DETECTION", test_collision);
    ADD_TEST("COLLISION HIGH SPEED", test_collision_speed);
diff --git a/legacy/ephysics/src/bin/test_camera.c b/legacy/ephysics/src/bin/test_camera.c
new file mode 100644 (file)
index 0000000..1020050
--- /dev/null
@@ -0,0 +1,147 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ephysics_test.h"
+
+static Eina_Bool
+_camera_move_cb(void *data)
+{
+   Test_Data *test_data = data;
+   EPhysics_Camera *camera;
+   int x, y, w;
+
+   ephysics_world_render_geometry_get(test_data->world, NULL, NULL, &w, NULL);
+
+   camera = ephysics_world_camera_get(test_data->world);
+   ephysics_camera_position_get(camera, &x, &y);
+
+   if (x + w > WIDTH * 2)
+     {
+        test_data->data = NULL;
+        return EINA_FALSE;
+     }
+
+   ephysics_camera_position_set(camera, x + 2, y);
+   return EINA_TRUE;
+}
+
+static void
+_world_populate(Test_Data *test_data)
+{
+   Evas_Object *sphere, *shadow;
+   EPhysics_Body *fall_body;
+
+   shadow = elm_layout_add(test_data->win);
+   elm_layout_file_set(
+      shadow, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "shadow-ball");
+   evas_object_move(shadow, WIDTH / 3, FLOOR_Y);
+   evas_object_resize(shadow, 70, 3);
+   evas_object_show(shadow);
+   test_data->evas_objs = eina_list_append(test_data->evas_objs, shadow);
+
+   sphere = elm_image_add(test_data->win);
+   elm_image_file_set(
+      sphere, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "big-blue-ball");
+   evas_object_move(sphere, WIDTH / 3, FLOOR_Y - 70);
+   evas_object_resize(sphere, 70, 70);
+   evas_object_show(sphere);
+   test_data->evas_objs = eina_list_append(test_data->evas_objs, sphere);
+
+   fall_body = ephysics_body_circle_add(test_data->world);
+   ephysics_body_evas_object_set(fall_body, sphere, EINA_TRUE);
+   ephysics_body_restitution_set(fall_body, 0.2);
+   ephysics_body_friction_set(fall_body, 0.5);
+   ephysics_body_event_callback_add(fall_body, EPHYSICS_CALLBACK_BODY_UPDATE,
+                                    update_object_cb, shadow);
+   test_data->bodies = eina_list_append(test_data->bodies, fall_body);
+   ephysics_body_central_impulse_apply(fall_body, 10, 0);
+
+   shadow = elm_layout_add(test_data->win);
+   elm_layout_file_set(
+      shadow, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "shadow-ball");
+   evas_object_move(shadow, WIDTH * 4 / 3, FLOOR_Y);
+   evas_object_resize(shadow, 70, 3);
+   evas_object_show(shadow);
+   test_data->evas_objs = eina_list_append(test_data->evas_objs, shadow);
+
+   sphere = elm_image_add(test_data->win);
+   elm_image_file_set(
+      sphere, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "big-red-ball");
+   evas_object_move(sphere, WIDTH * 4 / 3, FLOOR_Y - 70);
+   evas_object_resize(sphere, 70, 70);
+   evas_object_show(sphere);
+   test_data->evas_objs = eina_list_append(test_data->evas_objs, sphere);
+
+   fall_body = ephysics_body_circle_add(test_data->world);
+   ephysics_body_mass_set(fall_body, 3.2);
+   ephysics_body_evas_object_set(fall_body, sphere, EINA_TRUE);
+   ephysics_body_restitution_set(fall_body, 0.2);
+   ephysics_body_friction_set(fall_body, 1);
+   ephysics_body_event_callback_add(fall_body, EPHYSICS_CALLBACK_BODY_UPDATE,
+                                    update_object_cb, shadow);
+   test_data->bodies = eina_list_append(test_data->bodies, fall_body);
+
+   test_data->data = ecore_animator_add(_camera_move_cb, test_data);
+}
+
+static void
+_win_del(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Test_Data *test_data = data;
+
+   if (test_data->data)
+     ecore_animator_del(test_data->data);
+
+   test_data_del(test_data);
+   ephysics_shutdown();
+}
+
+static void
+_restart(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
+{
+   Test_Data *test_data = data;
+   EPhysics_Camera *camera;
+
+   DBG("Restart pressed");
+
+   if (test_data->data)
+     ecore_animator_del(test_data->data);
+
+   camera = ephysics_world_camera_get(test_data->world);
+   ephysics_camera_position_set(camera, 50, 40);
+
+   test_clean(test_data);
+   _world_populate(test_data);
+}
+
+void
+test_camera(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, "Camera", EINA_FALSE);
+   evas_object_smart_callback_add(test_data->win, "delete,request",
+                                  _win_del, test_data);
+
+   elm_layout_signal_callback_add(test_data->layout, "restart", "test-theme",
+                                  _restart, test_data);
+
+   world = ephysics_world_new();
+   ephysics_world_render_geometry_set(world, 50, 40, WIDTH - 100, FLOOR_Y - 40);
+   test_data->world = world;
+
+   boundary = ephysics_body_box_add(test_data->world);
+   ephysics_body_mass_set(boundary, 0);
+   ephysics_body_geometry_set(boundary, 0, FLOOR_Y, WIDTH * 2, 10);
+   ephysics_body_restitution_set(boundary, 0.65);
+   ephysics_body_friction_set(boundary, 4);
+
+   _world_populate(test_data);
+}
index 8448c88..78d9908 100644 (file)
@@ -133,7 +133,7 @@ EAPI int ephysics_shutdown(void);
  * Its position can be set with @ref ephysics_camera_position_set() and zoom
  * in / zoom out can be done with @ref ephysics_camera_zoom_set().
  *
- * @note WIP: IT'S NOT WORKING YET!!
+ * @note WIP: ZOOM API ISN'T WORKING YET!!
  */
 
 typedef struct _EPhysics_Camera EPhysics_Camera; /**< Camera handle, used to zoom in / out a scene, or change the frame position to be rendered. Every world have a camera that can be get with @ref ephysics_world_camera_get(). */
@@ -147,10 +147,16 @@ typedef struct _EPhysics_Camera EPhysics_Camera; /**< Camera handle, used to zoo
  *
  * By default a camera is created to map the first quadrant of physics
  * world from the point (0, 0) to
- * (canvas width / world rate, canvas height / world rate).
+ * (render area width / world rate, render area height / world rate).
  *
- * It can be modified passing another top-left point position, so another
- * region of the physics world will be rendered on the canvas.
+ * When render area is set with @ref ephysics_world_render_geometry_set(),
+ * the camera geometry is updated to match it. So, for most cases, camera
+ * won't need to be handled by the user.
+ *
+ * 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.
  *
  * @note This change will be noticed on the next physics tick, so evas objects
  * will be updated taking the camera's new position in account.
@@ -165,7 +171,7 @@ typedef struct _EPhysics_Camera EPhysics_Camera; /**< Camera handle, used to zoo
  *
  * @ingroup EPhysics_Camera
  */
-EAPI void ephysics_camera_position_set(EPhysics_Camera *camera, double x, double y);
+EAPI void ephysics_camera_position_set(EPhysics_Camera *camera, Evas_Coord x, Evas_Coord y);
 
 /**
  * @brief
@@ -179,7 +185,7 @@ EAPI void ephysics_camera_position_set(EPhysics_Camera *camera, double x, double
  *
  * @ingroup EPhysics_Camera
  */
-EAPI void ephysics_camera_position_get(const EPhysics_Camera *camera, double *x, double *y);
+EAPI void ephysics_camera_position_get(const EPhysics_Camera *camera, Evas_Coord *x, Evas_Coord *y);
 
 /**
  * @brief
index 133c36a..063edc6 100644 (file)
@@ -247,8 +247,9 @@ _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Eva
 static void
 _ephysics_body_evas_object_default_update(EPhysics_Body *body)
 {
+   int x, y, w, h, wx, wy, wh, cx, cy;
+   EPhysics_Camera *camera;
    btTransform trans;
-   int wy, height, x, y, w, h;
    double rate, rot;
    Evas_Map *map;
 
@@ -256,13 +257,17 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body)
      return;
 
    body->rigid_body->getMotionState()->getWorldTransform(trans);
-   ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, &height);
-   height += wy;
+   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;
+   cy -= wy;
 
    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;
-   y = height - (int) (trans.getOrigin().getY() * rate) - h / 2;
+   x = (int) (trans.getOrigin().getX() * rate) - w / 2 - cx;
+   y = wh + wy - (int) (trans.getOrigin().getY() * rate) - h / 2 - cy;
 
    evas_object_move(body->evas_obj, x, y);
 
index ef03f4f..01f62a4 100644 (file)
@@ -12,7 +12,8 @@ extern "C" {
 
 struct _EPhysics_Camera {
      EPhysics_World *world;
-     double x, y, zoom;
+     double zoom;
+     int x, y;
 };
 
 EPhysics_Camera *
@@ -47,7 +48,7 @@ ephysics_camera_del(EPhysics_Camera *camera)
 }
 
 EAPI void
-ephysics_camera_position_set(EPhysics_Camera *camera, double x, double y)
+ephysics_camera_position_set(EPhysics_Camera *camera, Evas_Coord x, Evas_Coord y)
 {
    if (!camera)
      {
@@ -60,7 +61,7 @@ ephysics_camera_position_set(EPhysics_Camera *camera, double x, double y)
 }
 
 EAPI void
-ephysics_camera_position_get(const EPhysics_Camera *camera, double *x, double *y)
+ephysics_camera_position_get(const EPhysics_Camera *camera, Evas_Coord *x, Evas_Coord *y)
 {
    if (!camera)
      {
index 2b1e04a..64c4c6e 100644 (file)
@@ -762,6 +762,7 @@ ephysics_world_render_geometry_set(EPhysics_World *world, Evas_Coord x, Evas_Coo
    world->h = h;
 
    ephysics_body_world_boundaries_resize(world);
+   ephysics_camera_position_set(world->camera, x, y);
 }
 
 EAPI void