From 08643f3112c2b1494734aae07a34927275655fac Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Thu, 18 Oct 2012 23:27:26 +0000 Subject: [PATCH] ephysics: add perspective support SVN revision: 78205 --- legacy/ephysics/src/bin/test_bouncing_3d.c | 1 + legacy/ephysics/src/lib/EPhysics.h | 94 ++++++++++++++++++++++ legacy/ephysics/src/lib/ephysics_body.cpp | 7 ++ legacy/ephysics/src/lib/ephysics_world.cpp | 72 +++++++++++++++++ 4 files changed, 174 insertions(+) diff --git a/legacy/ephysics/src/bin/test_bouncing_3d.c b/legacy/ephysics/src/bin/test_bouncing_3d.c index 248f1ec45e..bc1440e91c 100644 --- a/legacy/ephysics/src/bin/test_bouncing_3d.c +++ b/legacy/ephysics/src/bin/test_bouncing_3d.c @@ -127,6 +127,7 @@ test_bouncing_3d(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event ephysics_world_gravity_set(world, 0, 0, 0); ephysics_world_render_geometry_set(world, 50, 40, -50, WIDTH - 100, FLOOR_Y - 40, DEPTH); + ephysics_world_perspective_enabled_set(world, EINA_TRUE); test_data->world = world; boundary = ephysics_body_bottom_boundary_add(test_data->world); diff --git a/legacy/ephysics/src/lib/EPhysics.h b/legacy/ephysics/src/lib/EPhysics.h index f81c3d76e2..fb13874718 100644 --- a/legacy/ephysics/src/lib/EPhysics.h +++ b/legacy/ephysics/src/lib/EPhysics.h @@ -1422,6 +1422,100 @@ EAPI void ephysics_world_light_all_bodies_set(EPhysics_World *world, Eina_Bool e */ EAPI Eina_Bool ephysics_world_light_all_bodies_get(const EPhysics_World *world); +/** + * @brief + * Set perspective to be applied on the scene. + * + * This applies a given perspective (3D) to the world rendering. + * It will be used when the scene is rendered, after each simulation step, + * by @ref ephysics_body_evas_object_update(). + * + * The @p px and @p py points specify the "infinite distance" point in the 3D + * conversion (where all lines converge to like when artists draw 3D by hand). + * The @p z0 value specifies the z value at which there is a 1:1 mapping between + * spatial coordinates and screen coordinates. Any points on this z value will + * not have their X and Y values modified in the transform. + * Those further away (Z value higher) will shrink into the distance, and those + * less than this value will expand and become bigger. The foc value determines + * the "focal length" of the camera. This is in reality the distance between + * the camera lens plane itself (at or closer than this rendering results are + * undefined) and the @p z0 z value. This allows for some "depth" control and + * @p foc must be greater than 0. + * + * Considering the world geometry, by default, perspective is set to + * px = x + w / 2, py = y + h / 2, z0 = z + d / 2 and foc = 10 * (z + d). + * This means the conversion point is centered on render area, and @p z0 + * is on the center of render area z axis. It is set when + * @ref ephysics_world_render_geometry_set() is called. + * + * @note The unit used for all parameters is Evas coordinates. + * + * @note To be used, perspective need to be enabled with + * @ref ephysics_world_perspective_enabled_set(). + * + * @param world The physics world + * @param px The perspective distance X coordinate + * @param py The perspective distance Y coordinate + * @param z0 The "0" z plane value + * @param foc The focal distance + * + * @see ephysics_world_perspective_get(). + * @see ephysics_world_perspective_enabled_set(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_perspective_set(EPhysics_World *world, Evas_Coord px, Evas_Coord py, Evas_Coord z0, Evas_Coord foc); + +/** + * @brief + * Get perspective applied on the scene. + * + * @param world The physics world + * @param px The perspective distance X coordinate + * @param py The perspective distance Y coordinate + * @param z0 The "0" z plane value + * @param foc The focal distance + * + * @see ephysics_world_perspective_set() for more details. + * @see ephysics_world_perspective_enabled_get(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_perspective_get(const EPhysics_World *world, Evas_Coord *px, Evas_Coord *py, Evas_Coord *z0, Evas_Coord *foc); + +/** + * @brief + * Set if perspective should be applied. + * + * The applied perspective can be set with + * @ref ephysics_world_perspective_set(). + * + * @param world The physics world. + * @param enabled @c EINA_TRUE if perspective should be used, or @c EINA_FALSE + * if it shouldn't. + * + * @see ephysics_world_perspective_set() for more details. + * @see ephysics_world_perspective_enabled_get(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_perspective_enabled_set(EPhysics_World *world, Eina_Bool enabled); + +/** + * @brief + * Return if perspective is enabled or not. + * + * @param world The physics world. + * @return @c EINA_TRUE if perspective is enabled, or @c EINA_FALSE if it + * isn't, or on error. + * + * @see ephysics_world_perspective_set() for more details. + * @see ephysics_world_perspective_enabled_set(). + * + * @ingroup EPhysics_World + */ +EAPI Eina_Bool ephysics_world_perspective_enabled_get(const EPhysics_World *world); + /** * @} */ diff --git a/legacy/ephysics/src/lib/ephysics_body.cpp b/legacy/ephysics/src/lib/ephysics_body.cpp index d50558eaf1..88c6034352 100644 --- a/legacy/ephysics/src/lib/ephysics_body.cpp +++ b/legacy/ephysics/src/lib/ephysics_body.cpp @@ -1061,6 +1061,13 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body) evas_map_util_quat_rotate(map, quat.x(), quat.y(), quat.z(), -quat.w(), x + (w * body->cm.x), y + (h * body->cm.y), z); + if (ephysics_world_perspective_enabled_get(body->world)) + { + int px, py, z0, foc; + ephysics_world_perspective_get(body->world, &px, &py, &z0, &foc); + evas_map_util_3d_perspective(map, px, py, z0, foc); + } + if ((body->light_apply) || (ephysics_world_light_all_bodies_get(body->world))) { diff --git a/legacy/ephysics/src/lib/ephysics_world.cpp b/legacy/ephysics/src/lib/ephysics_world.cpp index 8c5c77fdce..8b0104fbc2 100644 --- a/legacy/ephysics/src/lib/ephysics_world.cpp +++ b/legacy/ephysics/src/lib/ephysics_world.cpp @@ -88,6 +88,15 @@ struct _EPhysics_World { double max_sleeping_time; Eina_Lock mutex; Eina_Condition condition; + + struct { + Evas_Coord px; + Evas_Coord py; + Evas_Coord z0; + Evas_Coord foc; + Eina_Bool enabled:1; + } perspective; + Eina_Bool running:1; Eina_Bool ticked:1; Eina_Bool active:1; @@ -1234,6 +1243,9 @@ ephysics_world_render_geometry_set(EPhysics_World *world, Evas_Coord x, Evas_Coo world->geometry.h = h; world->geometry.d = d; + ephysics_world_perspective_set(world, x + w / 2, y + h / 2, z + d / 2, + 10 * (z + d)); + ephysics_body_world_boundaries_resize(world); ephysics_camera_position_set(world->camera, x, y); } @@ -1623,6 +1635,66 @@ ephysics_world_light_all_bodies_get(const EPhysics_World *world) return world->light->all_bodies; } +EAPI void +ephysics_world_perspective_set(EPhysics_World *world, Evas_Coord px, Evas_Coord py, Evas_Coord z0, Evas_Coord foc) +{ + if (!world) + { + ERR("No world, can't set perspective."); + return; + } + + if (foc <= 0) + { + ERR("Focal distance need to be greater than 0."); + return; + } + + world->perspective.px = px; + world->perspective.py = py; + world->perspective.z0 = z0; + world->perspective.foc = foc; +} + +EAPI void +ephysics_world_perspective_get(const EPhysics_World *world, Evas_Coord *px, Evas_Coord *py, Evas_Coord *z0, Evas_Coord *foc) +{ + if (!world) + { + ERR("No world, can't get perspective."); + return; + } + + if (px) *px = world->perspective.px; + if (py) *py = world->perspective.py; + if (z0) *z0 = world->perspective.z0; + if (foc) *foc = world->perspective.foc; +} + +EAPI void +ephysics_world_perspective_enabled_set(EPhysics_World *world, Eina_Bool enabled) +{ + if (!world) + { + ERR("No world, can't enable / disable perspective."); + return; + } + + world->perspective.enabled = !!enabled; +} + +EAPI Eina_Bool +ephysics_world_perspective_enabled_get(const EPhysics_World *world) +{ + if (!world) + { + ERR("No world, can't get perspective behavior."); + return EINA_FALSE; + } + + return world->perspective.enabled; +} + #ifdef __cplusplus } #endif