Evas: 3D: evas_3d_node_look_at_set() bug fix
authorTaekyun Kim <tkq.kim@samsung.com>
Mon, 6 Jan 2014 06:10:59 +0000 (15:10 +0900)
committerChunEon Park <hermet@hermet.pe.kr>
Fri, 25 Apr 2014 07:19:18 +0000 (16:19 +0900)
src/lib/evas/canvas/evas_3d_node.c
src/lib/evas/include/evas_3d_utils.h

index acbab4a..90843ae 100644 (file)
@@ -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;
+
+        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;
 
-   w = 0.5 / 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;
 
-   /* 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.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);
 }
index 196d3df..92ae65a 100644 (file)
@@ -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;
+}