evas: Evas_3D - add bounding sphere, revision frustum culling
authorOleksandr Shcherbina <o.shcherbina@samsung.com>
Mon, 1 Dec 2014 05:26:28 +0000 (06:26 +0100)
committerCedric BAIL <cedric@osg.samsung.com>
Mon, 1 Dec 2014 05:26:32 +0000 (06:26 +0100)
Summary:
Move check visibility of node from evas_3d_node to evas_3d_camera
Move functionality (normalize, check distance, calculate frustum)
in evas_3d_utils.h (we are planing use evas_is_sphere_in_frustum in evas_gl_3d.c -
don't render mesh if it non visible)
Add possibility check frustum by box, aabb, central point
Refactor example frustum culling

@feature

Reviewers: Hermet, raster, cedric

Subscribers: cedric

Differential Revision: https://phab.enlightenment.org/D1420

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/lib/evas/Evas_Eo.h
src/lib/evas/canvas/evas_3d_camera.c
src/lib/evas/canvas/evas_3d_camera.eo
src/lib/evas/canvas/evas_3d_node.c
src/lib/evas/canvas/evas_3d_node.eo
src/lib/evas/include/evas_3d_utils.h
src/lib/evas/include/evas_private.h

index fd48f74..9d8e93f 100644 (file)
@@ -566,6 +566,20 @@ typedef enum _Evas_3D_Index_Format
 } Evas_3D_Index_Format;
 
 /**
+ * Frustum modes
+ *
+ * @since 1.12
+ * @ingroup Evas_3D_Types
+ */
+typedef enum _Evas_3D_Frustum_Mode
+{
+   EVAS_3D_FRUSTUM_MODE_BSPHERE,
+   EVAS_3D_FRUSTUM_MODE_AABB,
+   EVAS_3D_FRUSTUM_MODE_CENTRAL_POINT
+} Evas_3D_Frustum_Mode;
+
+
+/**
  * Vertex assembly modes
  *
  * Vertex assembly represents how the vertices are organized into geometric
index d8a7d24..c6da2d3 100644 (file)
@@ -140,5 +140,49 @@ _evas_3d_camera_projection_ortho_set(Eo *obj, Evas_3D_Camera_Data *pd,
    eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_CAMERA_PROJECTION, NULL));
 }
 
+EOLIAN static Eina_Bool
+_evas_3d_camera_node_visible_get(Eo *obj EINA_UNUSED, Evas_3D_Camera_Data *pd, Evas_3D_Node *camera_node, Evas_3D_Node *node, Evas_3D_Frustum_Mode key)
+{
+   Evas_Mat4 matrix_vp;
+   Evas_Vec4 planes[6];
+   Evas_3D_Node_Data *pd_node = eo_data_scope_get(node, EVAS_3D_NODE_CLASS);
+   Evas_3D_Node_Data *pd_camera = eo_data_scope_get(camera_node, EVAS_3D_NODE_CLASS);
+   Evas_Vec3 central_point;
+
+   if (!node || pd_node->type != EVAS_3D_NODE_TYPE_MESH)
+     {
+        ERR("Mesh node %p type mismatch.", node);
+        return EINA_FALSE;
+     }
+
+   if (!camera_node || pd_camera->type != EVAS_3D_NODE_TYPE_CAMERA)
+     {
+        ERR("Camera node %p type mismatch.", camera_node);
+        return EINA_FALSE;
+     }
+
+   /*get need matrix like multiply projection matrix with view matrix*/
+   evas_mat4_multiply(&matrix_vp, &pd->projection, &pd_camera->data.camera.matrix_world_to_eye);
+
+   evas_frustum_calculate(planes, &matrix_vp);
+
+   if (key == EVAS_3D_FRUSTUM_MODE_BSPHERE)
+     return evas_is_sphere_in_frustum(&pd_node->bsphere, planes);
+   else if (key == EVAS_3D_FRUSTUM_MODE_AABB)
+     return evas_is_box_in_frustum(&pd_node->aabb, planes);
+   else if (key == EVAS_3D_FRUSTUM_MODE_CENTRAL_POINT)
+     {
+        central_point.x = (pd_node->aabb.p0.x + pd_node->aabb.p1.x) / 2;
+        central_point.y = (pd_node->aabb.p0.y + pd_node->aabb.p1.y) / 2;
+        central_point.z = (pd_node->aabb.p0.z + pd_node->aabb.p1.z) / 2;
+        return evas_is_point_in_frustum(&central_point, planes);
+     }
+   else
+     {
+        ERR("Unknown frustun mode.");
+        return EINA_TRUE;
+     }
+}
+
 #include "canvas/evas_3d_camera.eo.c"
 
index 4b4d95e..45e9e9a 100644 (file)
@@ -96,6 +96,25 @@ class Evas_3D_Camera (Evas_3D_Object, Evas.Common_Interface)
             Evas_Real dfar; /*@ Distance to far clipping plane. */
          }
       }
+      node_visible_get {
+         /*@
+            Check is bounding sphere of given node inside frustum of camera node.
+          *
+          * @param camera          The given camera node.
+          * @param node            The given node.
+          * @return                @c EINA_TRUE in frustum, @c EINA_FALSE otherwise
+
+          * If the nodes are @ NULL or nodes type mismatch error wrong type of nodes will be generated and returned @ EINA_FALSE.
+
+          * @ingroup Evas_3D_Camera
+          */
+         return: bool;
+         params {
+            @in Evas_3D_Node *camera_node;
+            @in Evas_3D_Node *node;
+            @in Evas_3D_Frustum_Mode key;
+         }
+      }
    }
 
    implements {
index 7b30486..bcbb1db 100644 (file)
@@ -204,6 +204,7 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED)
    Eina_Bool transform_dirty = EINA_FALSE, mesh_geom_dirty = EINA_FALSE;
    Eina_Bool mesh_frame_dirty = EINA_FALSE, member_dirty = EINA_FALSE;
    Eina_Bool frame_found = EINA_FALSE, is_change_orientation = EINA_FALSE;
+   Eina_Bool parent_dirty = EINA_FALSE;
    const Eina_List *m, *l;
    Evas_3D_Mesh *mesh;
    int frame, count, size, i, j;
@@ -217,19 +218,21 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED)
          transform_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_TRANSFORM),
          mesh_geom_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_MESH_GEOMETRY),
          mesh_frame_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_MESH_FRAME),
+         parent_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_PARENT),
          member_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_MEMBER));
 
-   if (transform_dirty ||
+     if (transform_dirty ||
        mesh_geom_dirty ||
        mesh_frame_dirty ||
-       member_dirty)
+       member_dirty ||
+       parent_dirty)
      {
         if (pd->type == EVAS_3D_NODE_TYPE_MESH)
           {
 
-             if (pd->orientation.x || pd->orientation.y || pd->orientation.z)
+             if (pd->orientation_world.x || pd->orientation_world.y || pd->orientation_world.z)
                {
-                  evas_vec4_set(&orientation, pd->orientation.x, pd->orientation.y, pd->orientation.z, pd->orientation.w);
+                  evas_vec4_set(&orientation, pd->orientation_world.x, pd->orientation_world.y, pd->orientation_world.z, pd->orientation_world.w);
                   is_change_orientation = EINA_TRUE;
                }
 
@@ -347,19 +350,19 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED)
                        evas_vec3_quaternion_rotate(&pd->obb.p0, &pd->obb.p0, &orientation);
                        evas_vec3_quaternion_rotate(&pd->obb.p1, &pd->obb.p1, &orientation);
                     }
-                  if ((pd->scale.x != 1 || pd->scale.y != 1 || pd->scale.z != 1))
+                  if ((pd->scale_world.x != 1 || pd->scale_world.y != 1 || pd->scale_world.z != 1))
                     {
                        Evas_Vec3 scale;
-                       evas_vec3_set(&scale, pd->scale.x, pd->scale.y, pd->scale.z);
+                       evas_vec3_set(&scale, pd->scale_world.x, pd->scale_world.y, pd->scale_world.z);
                        evas_vec3_multiply(&pd->obb.p0, &scale, &pd->obb.p0);
                        evas_vec3_multiply(&pd->obb.p1, &scale, &pd->obb.p1);
                        evas_vec3_multiply(&pd->aabb.p0, &scale, &pd->aabb.p0);
                        evas_vec3_multiply(&pd->aabb.p1, &scale, &pd->aabb.p1);
                     }
-                  if ((pd->position.x || pd->position.y || pd->position.z))
+                  if ((pd->position_world.x || pd->position_world.y || pd->position_world.z))
                     {
                        Evas_Vec3 position;
-                       evas_vec3_set(&position, pd->position.x, pd->position.y, pd->position.z);
+                       evas_vec3_set(&position, pd->position_world.x, pd->position_world.y, pd->position_world.z);
                        evas_vec3_add(&pd->obb.p0, &position, &pd->obb.p0);
                        evas_vec3_add(&pd->obb.p1, &position, &pd->obb.p1);
                        evas_vec3_add(&pd->aabb.p0, &position, &pd->aabb.p0);
@@ -372,7 +375,7 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED)
              Eina_List *current;
              Evas_3D_Node *datanode;
 
-             /* Update AABB and OBB of this node. */
+             /* Update AABB, OBB, bounding sphere of this node. */
              evas_box3_empty_set(&pd->aabb);
              evas_box3_empty_set(&pd->obb);
 
@@ -383,6 +386,7 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED)
                   evas_box3_union(&pd->aabb, &pd->aabb, &datapd->aabb);
                }
           }
+          evas_build_sphere(&pd->obb, &pd->bsphere);
      }
 
    return EINA_TRUE;
@@ -1362,99 +1366,13 @@ _evas_3d_node_bounding_box_get(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_
    if (z2) *z2 = pd->aabb.p1.z;
 }
 
-EOLIAN static int
-_evas_3d_node_obb_frustum_check(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_3D_Node *camera_node)
+EOLIAN static void
+_evas_3d_node_bounding_sphere_get(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *r)
 {
-   Evas_Mat4  matrix_eye = { { 0 } };
-   Evas_Mat4  matrix_local_to_world;
-   Evas_Mat4  matrix_mv;
-   Evas_Mat4  matrix_mvp;
-   Evas_Vec4 plane_right, plane_left, plane_bottom, plane_top, plane_far, plane_near, tmp;
-   int frustum = 0;
-   Evas_3D_Node_Data *camera_pd = eo_data_scope_get(camera_node, EVAS_3D_CAMERA_CLASS);
-   Evas_3D_Camera_Data *camera = eo_data_scope_get(camera_pd->data.camera.camera, EVAS_3D_CAMERA_CLASS);
-
-
-   if (camera_pd->type != EVAS_3D_NODE_TYPE_CAMERA)
-     {
-        ERR("Nodes type mismatch.");
-        return -1;
-     }
-
-#define CHECK_IN_FRUSTUM_MIN(name) \
-   (((plane_##name.x * pd->obb.p0.x + plane_##name.y * pd->obb.p0.y + plane_##name.z * pd->obb.p0.z + plane_##name.w) >= 0) ? EINA_TRUE : EINA_FALSE)
-
-#define CHECK_IN_FRUSTUM_MAX(name) \
-   (((plane_##name.x * pd->obb.p1.x + plane_##name.y * pd->obb.p1.y + plane_##name.z * pd->obb.p1.z + plane_##name.w) >= 0) ? EINA_TRUE : EINA_FALSE)
-
-#define NORMALIZE(name) \
-   evas_vec4_copy(&tmp, &plane_##name); \
-   plane_##name.x = plane_##name.x / sqrtf(evas_vec4_length_square_get(&tmp)); \
-   plane_##name.y = plane_##name.y / sqrtf(evas_vec4_length_square_get(&tmp)); \
-   plane_##name.z = plane_##name.z / sqrtf(evas_vec4_length_square_get(&tmp)); \
-   plane_##name.w = plane_##name.w / sqrtf(evas_vec4_length_square_get(&tmp));
-
-   /*get need matrix like multiply view matrix with projection matrix*/
-   evas_mat4_inverse_build(&matrix_eye, &camera_pd->position_world, &camera_pd->orientation_world, &camera_pd->scale_world);
-   evas_mat4_build(&matrix_local_to_world, &pd->position_world, &pd->orientation_world, &pd->scale_world);
-   evas_mat4_multiply(&matrix_mv, &matrix_eye, &matrix_local_to_world);
-   evas_mat4_multiply(&matrix_mvp, &camera->projection, &matrix_mv);
-
-   /*get planes and normilize results*/
-   evas_vec4_set(&plane_right, matrix_mvp.m[3] - matrix_mvp.m[0],
-                               matrix_mvp.m[7] - matrix_mvp.m[4],
-                               matrix_mvp.m[11] - matrix_mvp.m[8],
-                               matrix_mvp.m[15] - matrix_mvp.m[12]);
-   NORMALIZE(right)
-
-   evas_vec4_set(&plane_left, matrix_mvp.m[3] + matrix_mvp.m[0],
-                              matrix_mvp.m[7] + matrix_mvp.m[4],
-                              matrix_mvp.m[11] + matrix_mvp.m[8],
-                              matrix_mvp.m[15] + matrix_mvp.m[12]);
-   NORMALIZE(left)
-
-   evas_vec4_set(&plane_bottom, matrix_mvp.m[3] + matrix_mvp.m[1],
-                                matrix_mvp.m[7] + matrix_mvp.m[5],
-                                matrix_mvp.m[11] + matrix_mvp.m[9],
-                                matrix_mvp.m[15] + matrix_mvp.m[13]);
-   NORMALIZE(bottom)
-
-   evas_vec4_set(&plane_top, matrix_mvp.m[3] - matrix_mvp.m[1],
-                             matrix_mvp.m[7] - matrix_mvp.m[5],
-                             matrix_mvp.m[11] - matrix_mvp.m[9],
-                             matrix_mvp.m[15] - matrix_mvp.m[13]);
-   NORMALIZE(top)
-
-   evas_vec4_set(&plane_far, matrix_mvp.m[3] - matrix_mvp.m[2],
-                             matrix_mvp.m[7] - matrix_mvp.m[6],
-                             matrix_mvp.m[11] - matrix_mvp.m[10],
-                             matrix_mvp.m[15] - matrix_mvp.m[14]);
-   NORMALIZE(far)
-
-   evas_vec4_set(&plane_near, matrix_mvp.m[3] + matrix_mvp.m[2],
-                              matrix_mvp.m[7] + matrix_mvp.m[6],
-                              matrix_mvp.m[11] + matrix_mvp.m[10],
-                              matrix_mvp.m[15] + matrix_mvp.m[14]);
-   NORMALIZE(near)
-
-#undef NORMALIZE
-
-   /*check OBB points in frustum (Ax + By + Cz + D >= 0)*/
-   if (CHECK_IN_FRUSTUM_MIN(right) && CHECK_IN_FRUSTUM_MIN(left)
-       && CHECK_IN_FRUSTUM_MIN(bottom) && CHECK_IN_FRUSTUM_MIN(top)
-       && CHECK_IN_FRUSTUM_MIN(far) && CHECK_IN_FRUSTUM_MIN(near))
-     frustum |= 1;
-
-   if (CHECK_IN_FRUSTUM_MAX(right) && CHECK_IN_FRUSTUM_MAX(left)
-       && CHECK_IN_FRUSTUM_MAX(bottom) && CHECK_IN_FRUSTUM_MAX(top)
-       && CHECK_IN_FRUSTUM_MAX(far) && CHECK_IN_FRUSTUM_MAX(near))
-     frustum |= 2;
-
-#undef CHECK_IN_FRUSTUM_MIN
-#undef CHECK_IN_FRUSTUM_MAX
-
-   return frustum;
+   if (x) *x = pd->bsphere.center.x;
+   if (y) *y = pd->bsphere.center.y;
+   if (z) *z = pd->bsphere.center.z;
+   if (r) *r = pd->bsphere.radius;
 }
 
-
 #include "canvas/evas_3d_node.eo.c"
index 5046f44..b82b90e 100644 (file)
@@ -324,13 +324,12 @@ class Evas_3D_Node (Evas_3D_Object, Evas.Common_Interface)
 
       bounding_box_get{
          /*
-
-          * Get axis-aligned bounding box (AABB) of the given node.
+           Get axis-aligned bounding box (AABB) of the given node.
           *
           * @param node     The given node.
-          * @param x       Pointer to receive X coordinate of the first point of AABB.
-          * @param y       Pointer to receive Y coordinate of the first point of AABB.
-          * @param z       Pointer to receive Z coordinate of the first point of AABB.
+          * @param x        Pointer to receive X coordinate of the first point of AABB.
+          * @param y        Pointer to receive Y coordinate of the first point of AABB.
+          * @param z        Pointer to receive Z coordinate of the first point of AABB.
           * @param x2       Pointer to receive X coordinate of the second point of AABB.
           * @param y2       Pointer to receive Y coordinate of the second point of AABB.
           * @param z2       Pointer to receive Z coordinate of the second point of AABB.
@@ -347,23 +346,25 @@ class Evas_3D_Node (Evas_3D_Object, Evas.Common_Interface)
          }
       }
 
-      obb_frustum_check {
+      bounding_sphere_get {
          /*
-
-          * Check is the obb of node in frustum of camera node.
+          Get bounding sphere of the given node.
           *
-          * @param camera_node     The given node of camera.
-          * @param node            The given node.
-          * @return                @c 0 if the obb is not in frustum, @c 1 if only min coordinate of obb is in frustum,
-          *                        @c 2 if only max coordinate of obb is in frustum, @c 3 if both coordinates of obb is in frustum.
+          * @param node     The given node.
 
-          * If the camera_node is not of type EVAS_3D_NODE_TYPE_CAMERA error wrong type of node will be generated and returned @ -1.
+          * @param x       Pointer to receive X coordinate of the center of sphere.
+          * @param y       Pointer to receive Y coordinate of the center of sphere.
+          * @param z       Pointer to receive Z coordinate of center of sphere.
+          * @param r       Pointer to receive radius of center of sphere.
 
-          * @ingroup Evas_3D_Node
+           @ingroup Evas_3D_Node
           */
-         return: int;
          params {
-            @in Evas_3D_Node *camera_node;
+
+            @in Evas_Real *x;      /*@ Coordinates of vector.*/
+            @in Evas_Real *y;
+            @in Evas_Real *z;
+            @in Evas_Real *r;
          }
       }
    }
index 8e02a07..139351d 100644 (file)
@@ -17,8 +17,10 @@ typedef struct _Evas_Mat3 Evas_Mat3;
 typedef struct _Evas_Mat4 Evas_Mat4;
 typedef struct _Evas_Box2 Evas_Box2;
 typedef struct _Evas_Box3 Evas_Box3;
+typedef struct _Evas_Line3 Evas_Line3;
 typedef struct _Evas_Triangle3 Evas_Triangle3;
 typedef struct _Evas_Ray3 Evas_Ray3;
+typedef struct _Evas_Sphere Evas_Sphere;
 
 struct _Evas_Color
 {
@@ -79,6 +81,12 @@ struct _Evas_Box3
    Evas_Vec3   p1;
 };
 
+struct _Evas_Line3
+{
+   Evas_Vec3   point;
+   Evas_Vec3   direction;
+};
+
 struct _Evas_Triangle3
 {
    Evas_Vec3   p0;
@@ -92,6 +100,12 @@ struct _Evas_Ray3
    Evas_Vec3   dir;
 };
 
+struct _Evas_Sphere
+{
+   Evas_Vec3 center;
+   Evas_Real radius;
+};
+
 /* 2D vector */
 static inline void
 evas_vec2_set(Evas_Vec2 *dst, Evas_Real x, Evas_Real y)
@@ -1594,6 +1608,17 @@ evas_box2_intersect_2d(const Evas_Box2 *box, const Evas_Vec2 *org, const Evas_Ve
    return EINA_TRUE;
 }
 
+static inline Evas_Real
+evas_determinant_3D(Evas_Real matrix[3][3])
+{
+   return (matrix[0][0] * matrix[1][1] * matrix[2][2]) +
+          (matrix[0][1] * matrix[1][2] * matrix[2][0]) +
+          (matrix[0][2] * matrix[1][0] * matrix[2][1]) -
+          (matrix[0][2] * matrix[1][1] * matrix[2][0]) -
+          (matrix[0][1] * matrix[1][0] * matrix[2][2]) -
+          (matrix[0][0] * matrix[1][2] * matrix[2][1]);
+}
+
 static inline Eina_Bool
 evas_box3_ray3_intersect(const Evas_Box3 *box, const Evas_Ray3 *ray)
 {
@@ -1722,3 +1747,242 @@ evas_reciprocal_sqrt(Evas_Real x)
    u.i = 0x5f3759df - (u.i >> 1);
    return u.f * (1.5f - u.f * u.f * x * 0.5f);
 }
+
+static inline void
+evas_build_sphere(const Evas_Box3 *box, Evas_Sphere *sphere)
+{
+   Evas_Vec3 tmp;
+
+   evas_vec3_set(&sphere->center, (0.5 * (box->p0.x + box->p1.x)), (0.5 * (box->p0.y + box->p1.y)), (0.5 * (box->p0.z + box->p1.z)));
+   evas_vec3_set(&tmp, sphere->center.x - box->p0.x, sphere->center.y - box->p0.y, sphere->center.z - box->p0.z);
+
+   sphere->radius = sqrtf(evas_vec3_dot_product(&tmp, &tmp));
+}
+
+static inline void
+evas_plane_normalize(Evas_Vec4 *plane)
+{
+   Evas_Vec3 tmp;
+   Evas_Real length;
+   evas_vec3_set(&tmp, plane->x, plane->y, plane->z);
+   length = evas_vec3_length_get(&tmp);
+   plane->x = plane->x / length;
+   plane->y = plane->y / length;
+   plane->z = plane->z / length;
+   plane->w = plane->w / length;
+}
+
+static inline Eina_Bool
+evas_intersection_line_of_two_planes(Evas_Line3 *line, Evas_Vec4 *plane1, Evas_Vec4 *plane2)
+{
+   //TODO:parallel case
+   Evas_Vec3 planes3D[2];
+
+   evas_vec3_set(&planes3D[0], plane1->x, plane1->y, plane1->z);
+   evas_vec3_set(&planes3D[1], plane2->x, plane2->y, plane2->z);
+
+   evas_vec3_cross_product(&line->direction, &planes3D[0], &planes3D[1]);
+
+#define SOLVE_EQUATION(x, y, z) \
+   line->point.x = 0; \
+   line->point.y = (plane2->w * plane1->z - plane1->w * plane2->z) / line->direction.x; \
+   line->point.z = (plane2->y * plane1->w - plane1->y * plane2->w) / line->direction.x;
+
+   if (line->direction.x && plane1->z)
+     {
+        SOLVE_EQUATION(x, y, z)
+     }
+   else if (line->direction.y && plane1->x)
+     {
+        SOLVE_EQUATION(y, z, x)
+     }
+   else
+     {
+        SOLVE_EQUATION(z, x, y)
+     }
+#undef SOLVE_EQUATION
+
+   return EINA_TRUE;
+}
+
+static inline Eina_Bool
+evas_intersection_point_of_three_planes(Evas_Vec3 *point, Evas_Vec4 *plane1, Evas_Vec4 *plane2, Evas_Vec4 *plane3)
+{
+   //TODO:parallel case
+   int i;
+   Evas_Real delta, deltax, deltay, deltaz;
+   Evas_Real matrix_to_det[3][3];
+   Evas_Vec4 planes[3];
+
+   planes[0] = *plane1;
+   planes[1] = *plane2;
+   planes[2] = *plane3;
+
+   for (i = 0; i < 3; i++)
+     {
+        matrix_to_det[0][i] = planes[i].x;
+        matrix_to_det[1][i] = planes[i].y;
+        matrix_to_det[2][i] = planes[i].z;
+     }
+   delta = evas_determinant_3D(matrix_to_det);
+
+   for (i = 0; i < 3; i++)
+     matrix_to_det[0][i] = planes[i].w;
+   deltax = evas_determinant_3D(matrix_to_det);
+
+   for (i = 0; i < 3; i++)
+     {
+        matrix_to_det[0][i] = planes[i].x;
+        matrix_to_det[1][i] = planes[i].w;
+     }
+   deltay = evas_determinant_3D(matrix_to_det);
+
+   for (i = 0; i < 3; i++)
+     {
+        matrix_to_det[1][i] = planes[i].y;
+        matrix_to_det[2][i] = planes[i].w;
+     }
+   deltaz = evas_determinant_3D(matrix_to_det);
+
+   evas_vec3_set(point, -deltax/delta, -deltay/delta, -deltaz/delta);
+
+   return EINA_TRUE;
+}
+
+static inline Evas_Real
+evas_point_plane_distance(Evas_Vec3 *point, Evas_Vec4 *plane)
+{
+   return plane->x * point->x + plane->y * point->y + plane->z * point->z + plane->w;
+}
+
+static inline Evas_Real
+evas_point_line_distance(Evas_Vec3 *point, Evas_Line3 *line)
+{
+   Evas_Vec3 temp, sub;
+
+   evas_vec3_subtract(&sub, point, &line->point);
+   evas_vec3_cross_product(&temp, &sub, &line->direction);
+
+   return evas_vec3_length_get(&temp) / evas_vec3_length_get(&line->direction);
+}
+
+static inline Eina_Bool
+evas_is_sphere_in_frustum(Evas_Sphere *bsphere, Evas_Vec4 *planes)
+{
+   int i;
+   Evas_Line3 line;
+   Evas_Vec3 point, sub;
+   Evas_Real distances[6] = {0};
+   int intersected_planes[3];
+   int intersected_planes_count = 0;
+
+   for (i = 0; i < 6; i++)
+     {
+        distances[i] = evas_point_plane_distance(&bsphere->center, &planes[i]);
+     }
+
+   for (i = 0; i < 6; i++)
+     {
+        if (distances[i] <= -bsphere->radius)
+          {
+             return EINA_FALSE;
+          }
+        else if (distances[i] <= 0)
+          {
+             intersected_planes[intersected_planes_count] = i;
+             intersected_planes_count++;
+          }
+      }
+
+   if ((intersected_planes_count == 0) || (intersected_planes_count == 1))
+     return EINA_TRUE;
+   else if (intersected_planes_count == 2)
+     {
+        evas_intersection_line_of_two_planes(&line, &planes[intersected_planes[0]], &planes[intersected_planes[1]]);
+        return (evas_point_line_distance(&bsphere->center, &line) < bsphere->radius) ? EINA_TRUE : EINA_FALSE;
+     }
+   else if (intersected_planes_count == 3)
+     {
+        evas_intersection_point_of_three_planes(&point, &planes[intersected_planes[0]], &planes[intersected_planes[1]], &planes[intersected_planes[2]]);
+        evas_vec3_subtract(&sub, &point, &bsphere->center);
+        return (evas_vec3_length_get(&sub) < bsphere->radius) ? EINA_TRUE : EINA_FALSE;
+     }
+
+   return EINA_FALSE;
+}
+
+static inline Eina_Bool
+evas_is_point_in_frustum(Evas_Vec3 *point, Evas_Vec4 *planes)
+{
+   int i;
+   for (i = 0; i < 6; i++)
+     if (evas_point_plane_distance(point, &planes[i]) <= 0) return EINA_FALSE;
+   return EINA_TRUE;
+}
+
+static inline Eina_Bool
+evas_is_box_in_frustum(Evas_Box3 *box, Evas_Vec4 *planes)
+{
+   int i;
+   for (i = 0; i < 6; i++)
+     {
+        if (planes[i].x * box->p0.x + planes[i].y * box->p0.y + planes[i].z * box->p0.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p1.x + planes[i].y * box->p0.y + planes[i].z * box->p0.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p1.x + planes[i].y * box->p1.y + planes[i].z * box->p0.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p0.x + planes[i].y * box->p1.y + planes[i].z * box->p0.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p0.x + planes[i].y * box->p0.y + planes[i].z * box->p1.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p1.x + planes[i].y * box->p0.y + planes[i].z * box->p1.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p1.x + planes[i].y * box->p1.y + planes[i].z * box->p1.z + planes[i].w > 0)
+          continue;
+        if (planes[i].x * box->p0.x + planes[i].y * box->p1.y + planes[i].z * box->p1.z + planes[i].w > 0)
+          continue;
+       return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static inline void
+evas_frustum_calculate(Evas_Vec4 *planes, Evas_Mat4 *matrix_vp)
+{
+   int i;
+   evas_vec4_set(&planes[0], matrix_vp->m[3] - matrix_vp->m[0],
+                             matrix_vp->m[7] - matrix_vp->m[4],
+                             matrix_vp->m[11] - matrix_vp->m[8],
+                             matrix_vp->m[15] - matrix_vp->m[12]);
+
+   evas_vec4_set(&planes[1], matrix_vp->m[3] + matrix_vp->m[0],
+                             matrix_vp->m[7] + matrix_vp->m[4],
+                             matrix_vp->m[11] + matrix_vp->m[8],
+                             matrix_vp->m[15] + matrix_vp->m[12]);
+
+   evas_vec4_set(&planes[2], matrix_vp->m[3] + matrix_vp->m[1],
+                             matrix_vp->m[7] + matrix_vp->m[5],
+                             matrix_vp->m[11] + matrix_vp->m[9],
+                             matrix_vp->m[15] + matrix_vp->m[13]);
+
+   evas_vec4_set(&planes[3], matrix_vp->m[3] - matrix_vp->m[1],
+                             matrix_vp->m[7] - matrix_vp->m[5],
+                             matrix_vp->m[11] - matrix_vp->m[9],
+                             matrix_vp->m[15] - matrix_vp->m[13]);
+
+   evas_vec4_set(&planes[4], matrix_vp->m[3] - matrix_vp->m[2],
+                             matrix_vp->m[7] - matrix_vp->m[6],
+                             matrix_vp->m[11] - matrix_vp->m[10],
+                             matrix_vp->m[15] - matrix_vp->m[14]);
+
+   evas_vec4_set(&planes[5], matrix_vp->m[3] + matrix_vp->m[2],
+                             matrix_vp->m[7] + matrix_vp->m[6],
+                             matrix_vp->m[11] + matrix_vp->m[10],
+                             matrix_vp->m[15] + matrix_vp->m[14]);
+   for (i = 0; i < 6; i++)
+     {
+       evas_plane_normalize(&planes[i]);
+     }
+}
index 50f9fa5..6cf5c06 100644 (file)
@@ -219,6 +219,7 @@ struct _Evas_3D_Node
 
    Evas_Box3         aabb;
    Evas_Box3         obb;
+   Evas_Sphere       bsphere;
 
    Evas_3D_Node_Type type;