From fc6cdaaa9d9d1af66ee931aa249faff4a2a81543 Mon Sep 17 00:00:00 2001 From: Taekyun Kim Date: Mon, 6 Jan 2014 15:10:59 +0900 Subject: [PATCH] Evas: 3D: evas_3d_node_look_at_set() bug fix --- src/lib/evas/canvas/evas_3d_node.c | 49 ++++++++++++++++++++++++---- src/lib/evas/include/evas_3d_utils.h | 14 ++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/lib/evas/canvas/evas_3d_node.c b/src/lib/evas/canvas/evas_3d_node.c index acbab4a6ab..90843ae216 100644 --- a/src/lib/evas/canvas/evas_3d_node.c +++ b/src/lib/evas/canvas/evas_3d_node.c @@ -965,16 +965,51 @@ evas_3d_node_look_at_set(Evas_3D_Node *node, evas_vec3_cross_product(&y, &z, &x); evas_vec3_normalize(&y, &y); - Evas_Real w = sqrt(1.0 + x.x + y.y + z.z); + /* Below matrix to quaternion conversion code taken from + * http://fabiensanglard.net/doom3_documentation/37726-293748.pdf + * When any license issue occurs, use ken shoemake's algorithm instead. + */ - node->orientation.w = 0.5 * w; + if (x.x + y.y + z.z > 0.0) + { + Evas_Real t = x.x + y.y + z.z + 1.0; + Evas_Real s = evas_reciprocal_sqrt(t) * 0.5; - w = 0.5 / w; + node->orientation.w = s * t; + node->orientation.z = (x.y - y.x) * s; + node->orientation.y = (z.x - x.z) * s; + node->orientation.x = (y.z - z.y) * s; + } + else if (x.x > y.y && x.x > z.z) + { + Evas_Real t = x.x - y.y - z.z + 1.0; + Evas_Real s = evas_reciprocal_sqrt(t) * 0.5; - /* Inverse the axis. */ - node->orientation.x = (y.z - z.y) * w; - node->orientation.y = (z.x - x.z) * w; - node->orientation.z = (x.y - y.x) * w; + node->orientation.x = s * t; + node->orientation.y = (x.y + y.x) * s; + node->orientation.z = (z.x + x.z) * s; + node->orientation.w = (y.z - z.y) * s; + } + else if (y.y > z.z) + { + Evas_Real t = -x.x + y.y - z.z + 1.0; + Evas_Real s = evas_reciprocal_sqrt(t) * 0.5; + + node->orientation.y = s * t; + node->orientation.x = (x.y + y.x) * s; + node->orientation.w = (z.x - x.z) * s; + node->orientation.z = (y.z + z.y) * s; + } + else + { + Evas_Real t = -x.x - y.y + z.z + 1.0; + Evas_Real s = evas_reciprocal_sqrt(t) * 0.5; + + node->orientation.z = s * t; + node->orientation.w = (x.y - y.x) * s; + node->orientation.x = (z.x + x.z) * s; + node->orientation.y = (y.z + z.y) * s; + } evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL); } diff --git a/src/lib/evas/include/evas_3d_utils.h b/src/lib/evas/include/evas_3d_utils.h index 196d3df5f5..92ae65a564 100644 --- a/src/lib/evas/include/evas_3d_utils.h +++ b/src/lib/evas/include/evas_3d_utils.h @@ -1524,3 +1524,17 @@ evas_box3_ray3_intersect(const Evas_Box3 *box EINA_UNUSED, const Evas_Ray3 *ray /* TODO: */ return EINA_TRUE; } + +static inline Evas_Real +evas_reciprocal_sqrt(Evas_Real x) +{ + long i; + float y, r; + + y = x * 0.5f; + i = *(long *)(&x); + i = 0x5f3759df - (i >> 1); + r = *(float *)(&i); + r = r * (1.5f - r * r * y); + return r; +}