LCOV - code coverage report
Current view: top level - compositor - mesh_collide.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 209 303 69.0 %
Date: 2021-04-29 23:48:07 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include <gpac/internal/mesh.h>
      28             : 
      29             : #ifndef GPAC_DISABLE_3D
      30             : 
      31             : /*
      32             :         AABB tree syntax&construction code is a quick extract from OPCODE (c) Pierre Terdiman, http://www.codercorner.com/Opcode.htm
      33             : */
      34             : 
      35             : typedef struct
      36             : {
      37             :         /*max tree depth, 0 is unlimited*/
      38             :         u32 max_depth;
      39             :         /*min triangles at node to split. 0 is full split (one triangle per leaf)*/
      40             :         u32 min_tri_limit;
      41             :         /*one of the above type*/
      42             :         u32 split_type;
      43             :         u32 depth, nb_nodes;
      44             : } AABSplitParams;
      45             : 
      46             : 
      47             : 
      48      100416 : static GFINLINE void update_node_bounds(GF_Mesh *mesh, AABBNode *node)
      49             : {
      50             :         u32 i, j;
      51             :         Fixed mx, my, mz, Mx, My, Mz;
      52             :         mx = my = mz = FIX_MAX;
      53             :         Mx = My = Mz = FIX_MIN;
      54     2428300 :         for (i=0; i<node->nb_idx; i++) {
      55     2428300 :                 IDX_TYPE *idx = &mesh->indices[3*node->indices[i]];
      56     7284900 :                 for (j=0; j<3; j++) {
      57     7284900 :                         SFVec3f *v = &mesh->vertices[idx[j]].pos;
      58     7284900 :                         if (mx>v->x) mx=v->x;
      59     7284900 :                         if (Mx<v->x) Mx=v->x;
      60     7284900 :                         if (my>v->y) my=v->y;
      61     7284900 :                         if (My<v->y) My=v->y;
      62     7284900 :                         if (mz>v->z) mz=v->z;
      63     7284900 :                         if (Mz<v->z) Mz=v->z;
      64             :                 }
      65             :         }
      66      100416 :         node->min.x = mx;
      67      100416 :         node->min.y = my;
      68      100416 :         node->min.z = mz;
      69      100416 :         node->max.x = Mx;
      70      100416 :         node->max.y = My;
      71      100416 :         node->max.z = Mz;
      72      100416 : }
      73             : 
      74             : static GFINLINE u32 gf_vec_main_axis(SFVec3f v)
      75             : {
      76             :         Fixed *vals = &v.x;
      77             :         u32 m = 0;
      78       50305 :         if(vals[1] > vals[m]) m = 1;
      79       50305 :         if(vals[2] > vals[m]) m = 2;
      80             :         return m;
      81             : }
      82             : 
      83     9718236 : static GFINLINE Fixed tri_get_center(GF_Mesh *mesh, u32 tri_idx, u32 axis)
      84             : {
      85             :         SFVec3f v;
      86     9718236 :         IDX_TYPE *idx = &mesh->indices[3*tri_idx];
      87             :         /*compute center*/
      88     9718236 :         gf_vec_add(v, mesh->vertices[idx[0]].pos, mesh->vertices[idx[1]].pos);
      89     9718236 :         gf_vec_add(v, v, mesh->vertices[idx[2]].pos);
      90     9718236 :         v = gf_vec_scale(v, FIX_ONE/3);
      91     9718236 :         return ((Fixed *)&v.x)[axis];
      92             : }
      93             : 
      94      201220 : static GFINLINE u32 aabb_split(GF_Mesh *mesh, AABBNode *node, u32 axis)
      95             : {
      96             :         SFVec3f v;
      97             :         Fixed split_at;
      98             :         u32 num_pos, i;
      99             : 
     100      201220 :         gf_vec_add(v, node->max, node->min);
     101      201220 :         v = gf_vec_scale(v, FIX_ONE/2);
     102             : 
     103      201220 :         split_at = ((Fixed *)&v.x)[axis];
     104             : 
     105             :         num_pos = 0;
     106             : 
     107     9919456 :         for (i=0; i<node->nb_idx; i++) {
     108     9718236 :                 IDX_TYPE idx = node->indices[i];
     109     9718236 :                 Fixed tri_val = tri_get_center(mesh, idx, axis);
     110             : 
     111     9718236 :                 if (tri_val > split_at) {
     112             :                         /*swap*/
     113     5355095 :                         IDX_TYPE tmp_idx = node->indices[i];
     114     5355095 :                         node->indices[i] = node->indices[num_pos];
     115     5355095 :                         node->indices[num_pos] = tmp_idx;
     116     5355095 :                         num_pos++;
     117             :                 }
     118             :         }
     119      201220 :         return num_pos;
     120             : }
     121             : 
     122      100707 : static void mesh_subdivide_aabbtree(GF_Mesh *mesh, AABBNode *node, AABSplitParams *aab_par)
     123             : {
     124             :         Bool do_split;
     125             :         u32 axis, num_pos, i, j;
     126             :         SFVec3f extend;
     127             : 
     128      151206 : if (!mesh || !node) return;
     129             :         /*update mesh depth*/
     130      100707 :         aab_par->depth ++;
     131             : 
     132             :         /*done*/
     133      100707 :         if (node->nb_idx==1) return;
     134      100224 :         if (node->nb_idx <= aab_par->min_tri_limit) return;
     135       50305 :         if (aab_par->max_depth == aab_par->depth) {
     136           0 :                 aab_par->depth --;
     137           0 :                 return;
     138             :         }
     139             :         do_split = GF_TRUE;
     140             : 
     141       50305 :         gf_vec_diff(extend, node->max, node->min);
     142       50305 :         extend = gf_vec_scale(extend, FIX_ONE/2);
     143             :         axis = gf_vec_main_axis(extend);
     144             : 
     145             :         num_pos = 0;
     146       50305 :         if (aab_par->split_type==AABB_LONGEST) {
     147           0 :                 num_pos = aabb_split(mesh, node, axis);
     148             :         }
     149       50305 :         else if (aab_par->split_type==AABB_BALANCED) {
     150             :                 Fixed res[3];
     151       50305 :                 num_pos = aabb_split(mesh, node, 0);
     152       50305 :                 res[0] = gf_divfix(INT2FIX(num_pos), INT2FIX(node->nb_idx)) - FIX_ONE/2;
     153       50305 :                 res[0] = gf_mulfix(res[0], res[0]);
     154       50305 :                 num_pos = aabb_split(mesh, node, 1);
     155       50305 :                 res[1] = gf_divfix(INT2FIX(num_pos), INT2FIX(node->nb_idx)) - FIX_ONE/2;
     156       50305 :                 res[1] = gf_mulfix(res[1], res[1]);
     157       50305 :                 num_pos = aabb_split(mesh, node, 2);
     158       50305 :                 res[2] = gf_divfix(INT2FIX(num_pos), INT2FIX(node->nb_idx)) - FIX_ONE/2;
     159       50305 :                 res[2] = gf_mulfix(res[2], res[2]);
     160             : 
     161             :                 axis = 0;
     162       50305 :                 if (res[1] < res[axis])      axis = 1;
     163       50305 :                 if (res[2] < res[axis])      axis = 2;
     164       50305 :                 num_pos = aabb_split(mesh, node, axis);
     165             :         }
     166           0 :         else if (aab_par->split_type==AABB_BEST_AXIS) {
     167           0 :                 u32 sorted[] = { 0, 1, 2 };
     168             :                 Fixed *Keys = (Fixed *) &extend.x;
     169           0 :                 for (j=0; j<3; j++) {
     170           0 :                         for (i=0; i<2; i++) {
     171           0 :                                 if (Keys[sorted[i]] < Keys[sorted[i+1]]) {
     172             :                                         u32 tmp = sorted[i];
     173           0 :                                         sorted[i] = sorted[i+1];
     174           0 :                                         sorted[i+1] = tmp;
     175             :                                 }
     176             :                         }
     177             :                 }
     178             :                 axis = 0;
     179             :                 do_split = GF_FALSE;
     180           0 :                 while (!do_split && (axis!=3)) {
     181           0 :                         num_pos = aabb_split(mesh, node, sorted[axis]);
     182             :                         // Check the subdivision has been successful
     183           0 :                         if (!num_pos || (num_pos==node->nb_idx)) axis++;
     184             :                         else do_split = GF_TRUE;
     185             :                 }
     186             :         }
     187           0 :         else if (aab_par->split_type==AABB_SPLATTER) {
     188             :                 SFVec3f means, vars;
     189             :                 means.x = means.y = means.z = 0;
     190           0 :                 for (i=0; i<node->nb_idx; i++) {
     191           0 :                         IDX_TYPE idx = node->indices[i];
     192           0 :                         means.x += tri_get_center(mesh, idx, 0);
     193           0 :                         means.y += tri_get_center(mesh, idx, 1);
     194           0 :                         means.z += tri_get_center(mesh, idx, 2);
     195             :                 }
     196           0 :                 means = gf_vec_scale(means, gf_invfix(node->nb_idx));
     197             : 
     198             :                 vars.x = vars.y = vars.z = 0;
     199           0 :                 for (i=0; i<node->nb_idx; i++) {
     200           0 :                         IDX_TYPE idx = node->indices[i];
     201           0 :                         Fixed cx = tri_get_center(mesh, idx, 0);
     202           0 :                         Fixed cy = tri_get_center(mesh, idx, 1);
     203           0 :                         Fixed cz = tri_get_center(mesh, idx, 2);
     204           0 :                         vars.x += gf_mulfix(cx - means.x, cx - means.x);
     205           0 :                         vars.y += gf_mulfix(cy - means.y, cy - means.y);
     206           0 :                         vars.z += gf_mulfix(cz - means.z, cz - means.z);
     207             :                 }
     208           0 :                 vars = gf_vec_scale(vars, gf_invfix(node->nb_idx-1) );
     209             :                 axis = gf_vec_main_axis(vars);
     210           0 :                 num_pos = aabb_split(mesh, node, axis);
     211             :         }
     212             :         else if (aab_par->split_type==AABB_FIFTY) {
     213             :                 do_split = GF_FALSE;
     214             :         }
     215             : 
     216       50305 :         if (!num_pos || (num_pos==node->nb_idx)) do_split = GF_FALSE;
     217             : 
     218       50208 :         if (!do_split) {
     219          97 :                 if (aab_par->split_type==AABB_FIFTY) {
     220           0 :                         num_pos = node->nb_idx/2;
     221             :                 } else {
     222             :                         return;
     223             :                 }
     224             :         }
     225       50208 :         aab_par->nb_nodes += 2;
     226             : 
     227       50208 :         GF_SAFEALLOC(node->pos, AABBNode);
     228       50208 :         if (node->pos) {
     229       50208 :                 node->pos->indices = &node->indices[0];
     230       50208 :                 node->pos->nb_idx = num_pos;
     231       50208 :                 update_node_bounds(mesh, node->pos);
     232       50208 :                 mesh_subdivide_aabbtree(mesh, node->pos, aab_par);
     233             :         }
     234             : 
     235       50208 :         GF_SAFEALLOC(node->neg, AABBNode);
     236       50208 :         if (node->neg) {
     237       50208 :                 node->neg->indices = &node->indices[num_pos];
     238       50208 :                 node->neg->nb_idx = node->nb_idx - num_pos;
     239       50208 :                 update_node_bounds(mesh, node->neg);
     240       50208 :                 mesh_subdivide_aabbtree(mesh, node->neg, aab_par);
     241             :         }
     242       50208 :         aab_par->depth --;
     243             : }
     244             : 
     245             : 
     246         292 : void gf_mesh_build_aabbtree(GF_Mesh *mesh)
     247             : {
     248             :         u32 i, nb_idx;
     249             :         AABSplitParams pars;
     250             : 
     251             :         memset(&pars, 0, sizeof(pars));
     252         292 :         pars.min_tri_limit = 8;
     253             :         pars.max_depth = 0;
     254         292 :         pars.split_type = AABB_BALANCED;
     255             : 
     256         293 :         if (mesh->i_count <= pars.min_tri_limit) return;
     257             : 
     258         291 :         nb_idx = mesh->i_count / 3;
     259         291 :         mesh->aabb_indices = (IDX_TYPE*)gf_malloc(sizeof(IDX_TYPE) * nb_idx);
     260         291 :         for (i=0; i<nb_idx; i++) mesh->aabb_indices[i] = i;
     261             : 
     262         291 :         GF_SAFEALLOC(mesh->aabb_root, AABBNode);
     263         291 :         if (mesh->aabb_root) {
     264         291 :                 mesh->aabb_root->min = mesh->bounds.min_edge;
     265         291 :                 mesh->aabb_root->max = mesh->bounds.max_edge;
     266         291 :                 mesh->aabb_root->indices = mesh->aabb_indices;
     267         291 :                 mesh->aabb_root->nb_idx = nb_idx;
     268             :         }
     269         291 :         pars.nb_nodes = 1;
     270         291 :         pars.depth = 0;
     271         291 :         mesh_subdivide_aabbtree(mesh, mesh->aabb_root, &pars);
     272             : 
     273         291 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Mesh] AABB tree done - %d nodes depth %d - size %d bytes\n", pars.nb_nodes, pars.depth, sizeof(AABBNode)*pars.nb_nodes));
     274             : }
     275             : 
     276             : 
     277         267 : static void ray_hit_triangle_get_u_v(GF_Ray *ray, GF_Vec *v0, GF_Vec *v1, GF_Vec *v2, Fixed *u, Fixed *v)
     278             : {
     279             :         Fixed det;
     280             :         GF_Vec edge1, edge2, tvec, pvec, qvec;
     281             :         /* find vectors for two edges sharing vert0 */
     282         267 :         gf_vec_diff(edge1, *v1, *v0);
     283         267 :         gf_vec_diff(edge2, *v2, *v0);
     284             :         /* begin calculating determinant - also used to calculate U parameter */
     285         267 :         pvec = gf_vec_cross(ray->dir, edge2);
     286             :         /* if determinant is near zero, ray lies in plane of triangle */
     287         267 :         det = gf_vec_dot(edge1, pvec);
     288             :         /* calculate distance from vert0 to ray origin */
     289         267 :         gf_vec_diff(tvec, ray->orig, *v0);
     290             :         /* calculate U parameter and test bounds */
     291         267 :         (*u) = gf_divfix(gf_vec_dot(tvec, pvec), det);
     292             :         /* prepare to test V parameter */
     293         267 :         qvec = gf_vec_cross(tvec, edge1);
     294             :         /* calculate V parameter and test bounds */
     295         267 :         (*v) = gf_divfix(gf_vec_dot(ray->dir, qvec), det);
     296         267 : }
     297             : 
     298      125431 : Bool gf_mesh_aabb_ray_hit(GF_Mesh *mesh, AABBNode *n, GF_Ray *ray, Fixed *closest, SFVec3f *outPoint, SFVec3f *outNormal, SFVec2f *outTexCoords)
     299             : {
     300             :         Bool inters;
     301             :         Fixed dist;
     302             :         SFVec3f v1, v2;
     303             :         u32 i, inters_idx;
     304             : 
     305             :         /*check bbox intersection*/
     306      125431 :         inters = gf_ray_hit_box(ray, n->min, n->max, NULL);
     307      125431 :         if (!inters) return GF_FALSE;
     308             : 
     309      121158 :         if (n->pos) {
     310             :                 /*we really want to check all possible intersections to get the closest point on ray*/
     311       62262 :                 Bool res = gf_mesh_aabb_ray_hit(mesh, n->pos, ray, closest, outPoint, outNormal, outTexCoords);
     312       62262 :                 res += gf_mesh_aabb_ray_hit(mesh, n->neg, ray, closest, outPoint, outNormal, outTexCoords);
     313       62262 :                 return res;
     314             : 
     315             :         }
     316             : 
     317             : 
     318             :         inters_idx = 0;
     319             :         inters = GF_FALSE;
     320       58896 :         dist = (*closest);
     321             : 
     322             :         /*leaf, check for all faces*/
     323      409785 :         for (i=0; i<n->nb_idx; i++) {
     324             :                 Fixed res;
     325      350889 :                 IDX_TYPE *idx = &mesh->indices[3*n->indices[i]];
     326      350889 :                 if (gf_ray_hit_triangle(ray,
     327      350889 :                                         &mesh->vertices[idx[0]].pos, &mesh->vertices[idx[1]].pos, &mesh->vertices[idx[2]].pos,
     328             :                                         &res)) {
     329         467 :                         if ((res>0) && (res<dist)) {
     330             :                                 dist = res;
     331             :                                 inters_idx = i;
     332             :                                 inters = GF_TRUE;
     333             :                         }
     334             :                 }
     335             :         }
     336             : 
     337       58896 :         if (inters) {
     338         267 :                 (*closest) = dist;
     339         267 :                 if (outPoint) {
     340         267 :                         *outPoint = gf_vec_scale(ray->dir, dist);
     341         267 :                         gf_vec_add(*outPoint, ray->orig, *outPoint);
     342             :                 }
     343         267 :                 if (outNormal) {
     344         267 :                         IDX_TYPE *idx = &mesh->indices[3*n->indices[inters_idx]];
     345         267 :                         if (mesh->flags & MESH_IS_SMOOTHED) {
     346          16 :                                 gf_vec_diff(v1, mesh->vertices[idx[1]].pos, mesh->vertices[idx[0]].pos);
     347          16 :                                 gf_vec_diff(v2, mesh->vertices[idx[2]].pos, mesh->vertices[idx[0]].pos);
     348          16 :                                 *outNormal = gf_vec_cross(v1, v2);
     349          16 :                                 gf_vec_norm(outNormal);
     350             :                         } else {
     351         251 :                                 MESH_GET_NORMAL((*outNormal), mesh->vertices[idx[0]]);
     352             :                         }
     353             :                 }
     354         267 :                 if (outTexCoords) {
     355         267 :                         IDX_TYPE *idx = &mesh->indices[3*n->indices[inters_idx]];
     356         534 :                         ray_hit_triangle_get_u_v(ray,
     357         267 :                                                  &mesh->vertices[idx[0]].pos, &mesh->vertices[idx[1]].pos, &mesh->vertices[idx[2]].pos,
     358             :                                                  &outTexCoords->x, &outTexCoords->y);
     359             :                 }
     360             :         }
     361             :         return inters;
     362             : }
     363             : 
     364         907 : Bool gf_mesh_intersect_ray(GF_Mesh *mesh, GF_Ray *ray, SFVec3f *outPoint, SFVec3f *outNormal, SFVec2f *outTexCoords)
     365             : {
     366             :         Bool inters;
     367             :         u32 i, inters_idx;
     368             :         Fixed closest;
     369             :         /*no intersection on linesets/pointsets*/
     370         907 :         if (mesh->mesh_type != MESH_TRIANGLES) return GF_FALSE;
     371             : 
     372             :         /*use aabbtree*/
     373         907 :         if (mesh->aabb_root) {
     374         907 :                 closest = FIX_MAX;
     375         907 :                 return gf_mesh_aabb_ray_hit(mesh, mesh->aabb_root, ray, &closest, outPoint, outNormal, outTexCoords);
     376             :         }
     377             : 
     378             :         /*check bbox intersection*/
     379           0 :         inters = gf_ray_hit_box(ray, mesh->bounds.min_edge, mesh->bounds.max_edge, NULL);
     380           0 :         if (!inters) return GF_FALSE;
     381             : 
     382             :         inters_idx = 0;
     383             :         inters = GF_FALSE;
     384           0 :         closest = FIX_MAX;
     385           0 :         for (i=0; i<mesh->i_count; i+=3) {
     386             :                 Fixed res;
     387           0 :                 IDX_TYPE *idx = &mesh->indices[i];
     388           0 :                 if (gf_ray_hit_triangle(ray,
     389           0 :                                         &mesh->vertices[idx[0]].pos, &mesh->vertices[idx[1]].pos, &mesh->vertices[idx[2]].pos,
     390             :                                         &res)) {
     391           0 :                         if ((res>0) && (res<closest)) {
     392           0 :                                 closest = res;
     393             :                                 inters_idx = i;
     394             :                                 inters = GF_TRUE;
     395             :                         }
     396             :                 }
     397             :         }
     398             : 
     399           0 :         if (inters) {
     400           0 :                 if (outPoint) {
     401           0 :                         *outPoint = gf_vec_scale(ray->dir, closest);
     402           0 :                         gf_vec_add(*outPoint, ray->orig, *outPoint);
     403             :                 }
     404           0 :                 if (outNormal) {
     405           0 :                         IDX_TYPE *idx = &mesh->indices[inters_idx];
     406           0 :                         if (mesh->flags & MESH_IS_SMOOTHED) {
     407             :                                 SFVec3f v1, v2;
     408           0 :                                 gf_vec_diff(v1, mesh->vertices[idx[1]].pos, mesh->vertices[idx[0]].pos);
     409           0 :                                 gf_vec_diff(v2, mesh->vertices[idx[2]].pos, mesh->vertices[idx[0]].pos);
     410           0 :                                 *outNormal = gf_vec_cross(v1, v2);
     411           0 :                                 gf_vec_norm(outNormal);
     412             :                         } else {
     413           0 :                                 MESH_GET_NORMAL((*outNormal), mesh->vertices[idx[0]]);
     414             :                         }
     415             :                 }
     416           0 :                 if (outTexCoords) {
     417             :                         SFVec2f txres;
     418           0 :                         IDX_TYPE *idx = &mesh->indices[inters_idx];
     419             :                         txres.x = txres.y = 0;
     420           0 :                         txres.x += mesh->vertices[idx[0]].texcoords.x;
     421           0 :                         txres.x += mesh->vertices[idx[1]].texcoords.x;
     422           0 :                         txres.x += mesh->vertices[idx[2]].texcoords.x;
     423           0 :                         txres.y += mesh->vertices[idx[0]].texcoords.y;
     424           0 :                         txres.y += mesh->vertices[idx[1]].texcoords.y;
     425           0 :                         txres.y += mesh->vertices[idx[2]].texcoords.y;
     426           0 :                         outTexCoords->x = txres.x / 3;
     427           0 :                         outTexCoords->y = txres.y / 3;
     428             :                 }
     429             :         }
     430             :         return inters;
     431             : }
     432             : 
     433             : 
     434         712 : static GFINLINE Bool mesh_collide_triangle(GF_Ray *ray, SFVec3f *v0, SFVec3f *v1, SFVec3f *v2, Fixed *dist)
     435             : {
     436             :         Fixed u, v, det;
     437             :         SFVec3f edge1, edge2, tvec, pvec, qvec;
     438             :         /* find vectors for two edges sharing vert0 */
     439         712 :         gf_vec_diff(edge1, *v1, *v0);
     440         712 :         gf_vec_diff(edge2, *v2, *v0);
     441             :         /* begin calculating determinant - also used to calculate U parameter */
     442         712 :         pvec = gf_vec_cross(ray->dir, edge2);
     443             :         /* if determinant is near zero, ray lies in plane of triangle */
     444         712 :         det = gf_vec_dot(edge1, pvec);
     445         712 :         if (ABS(det) < FIX_EPSILON) return GF_FALSE;
     446             :         /* calculate distance from vert0 to ray origin */
     447         712 :         gf_vec_diff(tvec, ray->orig, *v0);
     448             :         /* calculate U parameter and test bounds */
     449         712 :         u = gf_divfix(gf_vec_dot(tvec, pvec), det);
     450         712 :         if ((u < 0) || (u > FIX_ONE)) return GF_FALSE;
     451             :         /* prepare to test V parameter */
     452         344 :         qvec = gf_vec_cross(tvec, edge1);
     453             :         /* calculate V parameter and test bounds */
     454         344 :         v = gf_divfix(gf_vec_dot(ray->dir, qvec), det);
     455         344 :         if ((v < 0) || (u + v > FIX_ONE)) return GF_FALSE;
     456             :         /* calculate t, ray intersects triangle */
     457         119 :         *dist = gf_divfix(gf_vec_dot(edge2, qvec), det);
     458         119 :         return GF_TRUE;
     459             : }
     460             : 
     461             : 
     462        1219 : static GFINLINE Bool sphere_box_overlap(SFVec3f sc, Fixed sq_rad, SFVec3f bmin, SFVec3f bmax)
     463             : {
     464             :         Fixed tmp, s, d, ext;
     465             :         d = 0;
     466        1219 :         tmp = sc.x  - (bmin.x + bmax.x)/2;
     467        1219 :         ext = (bmax.x-bmin.x)/2;
     468        1219 :         s = tmp + ext;
     469        1219 :         if (s<0) d += gf_mulfix(s, s);
     470             :         else {
     471        1123 :                 s = tmp - ext;
     472        1123 :                 if (s>0) d += gf_mulfix(s, s);
     473             :         }
     474        1219 :         tmp = sc.y  - (bmin.y + bmax.y)/2;
     475        1219 :         ext = (bmax.y-bmin.y)/2;
     476        1219 :         s = tmp + ext;
     477        1219 :         if (s<0) d += gf_mulfix(s, s);
     478             :         else {
     479        1100 :                 s = tmp - ext;
     480        1100 :                 if (s>0) d += gf_mulfix(s, s);
     481             :         }
     482        1219 :         tmp = sc.z  - (bmin.z + bmax.z)/2;
     483        1219 :         ext = (bmax.z-bmin.z)/2;
     484        1219 :         s = tmp + ext;
     485        1219 :         if (s<0) d += gf_mulfix(s, s);
     486             :         else {
     487        1040 :                 s = tmp - ext;
     488        1040 :                 if (s>0) d += gf_mulfix(s, s);
     489             :         }
     490        1219 :         return (d<=sq_rad) ? GF_TRUE : GF_FALSE;
     491             : }
     492             : 
     493        1219 : Bool gf_mesh_closest_face_aabb(GF_Mesh *mesh, AABBNode *node, SFVec3f pos, Fixed min_dist, Fixed min_sq_dist, Fixed *min_col_dist, SFVec3f *outPoint)
     494             : {
     495             :         GF_Ray r;
     496             :         u32 i;
     497             :         SFVec3f v1, v2, n, resn;
     498             :         Bool inters, has_inter, need_norm = GF_FALSE;
     499             :         Fixed d;
     500        1219 :         if (!sphere_box_overlap(pos, min_sq_dist, node->min, node->max)) return GF_FALSE;
     501         679 :         if (node->pos) {
     502         549 :                 if (gf_mesh_closest_face_aabb(mesh, node->pos, pos, min_dist, min_sq_dist, min_col_dist, outPoint)) return GF_TRUE;
     503         548 :                 return gf_mesh_closest_face_aabb(mesh, node->neg, pos, min_dist, min_sq_dist, min_col_dist, outPoint);
     504             :         }
     505             : 
     506         130 :         need_norm = (mesh->flags & MESH_IS_SMOOTHED) ? GF_TRUE : GF_FALSE;
     507         130 :         r.orig = pos;
     508             :         has_inter = GF_FALSE;
     509         842 :         for (i=0; i<node->nb_idx; i++) {
     510         712 :                 IDX_TYPE *idx = &mesh->indices[3*node->indices[i]];
     511         712 :                 if (need_norm) {
     512         712 :                         gf_vec_diff(v1, mesh->vertices[idx[1]].pos, mesh->vertices[idx[0]].pos);
     513         712 :                         gf_vec_diff(v2, mesh->vertices[idx[2]].pos, mesh->vertices[idx[0]].pos);
     514         712 :                         n = gf_vec_cross(v1, v2);
     515         712 :                         gf_vec_norm(&n);
     516             :                 } else {
     517           0 :                         MESH_GET_NORMAL(n, mesh->vertices[idx[0]]);
     518             :                 }
     519             : 
     520             :                 /*intersect inverse normal from position to face with face*/
     521         712 :                 r.dir = n;
     522         712 :                 gf_vec_rev(r.dir);
     523        2136 :                 inters = mesh_collide_triangle(&r,
     524        2136 :                                                &mesh->vertices[idx[0]].pos, &mesh->vertices[idx[1]].pos, &mesh->vertices[idx[2]].pos,
     525             :                                                &d);
     526             : 
     527         712 :                 if (inters) {
     528             :                         /*we're behind the face, get inverse normal*/
     529         119 :                         if (d<0) {
     530         119 :                                 d*= -1;
     531         119 :                                 n = r.dir;
     532             :                         }
     533         119 :                         if (d<=(*min_col_dist)) {
     534             :                                 has_inter = GF_TRUE;
     535           1 :                                 (*min_col_dist) = d;
     536           1 :                                 resn = n;
     537             :                         }
     538             :                 }
     539             :         }
     540         130 :         if (has_inter) {
     541           1 :                 resn = gf_vec_scale(resn, -(*min_col_dist));
     542           1 :                 gf_vec_add(*outPoint, pos, resn);
     543             :         }
     544             :         return has_inter;
     545             : }
     546             : 
     547        3933 : Bool gf_mesh_closest_face(GF_Mesh *mesh, SFVec3f pos, Fixed min_dist, SFVec3f *outPoint)
     548             : {
     549             :         GF_Ray r;
     550             :         u32 i;
     551             :         SFVec3f v1, v2, n, resn;
     552             :         Bool inters, has_inter, need_norm;
     553             :         Fixed d, dmax;
     554             : 
     555             :         /*check bounds*/
     556        3933 :         gf_vec_diff(v1, mesh->bounds.center, pos);
     557        3933 :         if (gf_vec_len(v1)>min_dist+mesh->bounds.radius) return GF_FALSE;
     558             : 
     559         122 :         if (mesh->aabb_root) {
     560         122 :                 d = min_dist * min_dist;
     561         122 :                 dmax = min_dist;
     562         122 :                 return gf_mesh_closest_face_aabb(mesh, mesh->aabb_root, pos, min_dist, d, &dmax, outPoint);
     563             :         }
     564             : 
     565           0 :         need_norm = (mesh->flags & MESH_IS_SMOOTHED) ? GF_TRUE : GF_FALSE;
     566             : 
     567           0 :         r.orig = pos;
     568             :         has_inter = GF_FALSE;
     569           0 :         dmax = min_dist;
     570           0 :         for (i=0; i<mesh->i_count; i+=3) {
     571           0 :                 IDX_TYPE *idx = &mesh->indices[i];
     572           0 :                 if (need_norm) {
     573           0 :                         gf_vec_diff(v1, mesh->vertices[idx[1]].pos, mesh->vertices[idx[0]].pos);
     574           0 :                         gf_vec_diff(v2, mesh->vertices[idx[2]].pos, mesh->vertices[idx[0]].pos);
     575           0 :                         n = gf_vec_cross(v1, v2);
     576           0 :                         gf_vec_norm(&n);
     577             :                 } else {
     578           0 :                         MESH_GET_NORMAL(n, mesh->vertices[idx[0]]);
     579           0 :                         n.x = mesh->vertices[idx[0]].normal.x;
     580           0 :                         n.y = mesh->vertices[idx[0]].normal.y;
     581           0 :                         n.z = mesh->vertices[idx[0]].normal.z;
     582             :                 }
     583             : 
     584           0 :                 d = -gf_vec_dot(mesh->vertices[idx[0]].pos, n);
     585           0 :                 d += gf_vec_dot(r.orig, n);
     586           0 :                 if (fabs(d)>min_dist) continue;
     587             : 
     588             :                 /*intersect inverse normal from position to face with face*/
     589           0 :                 r.dir = n;
     590           0 :                 gf_vec_rev(r.dir);
     591           0 :                 inters = mesh_collide_triangle(&r,
     592           0 :                                                &mesh->vertices[idx[0]].pos, &mesh->vertices[idx[1]].pos, &mesh->vertices[idx[2]].pos,
     593             :                                                &d);
     594             : 
     595           0 :                 if (inters) {
     596             :                         /*we're behind the face, get inverse normal*/
     597           0 :                         if (d<0) {
     598           0 :                                 d*= -1;
     599           0 :                                 n = r.dir;
     600             :                         }
     601           0 :                         if (d<=dmax) {
     602             :                                 has_inter = GF_TRUE;
     603           0 :                                 dmax = d;
     604           0 :                                 resn = n;
     605             :                         }
     606             :                 }
     607             :         }
     608           0 :         if (has_inter) {
     609           0 :                 resn = gf_vec_scale(resn, -dmax);
     610           0 :                 gf_vec_add(*outPoint, pos, resn);
     611             :         }
     612             :         return has_inter;
     613             : }
     614             : 
     615             : #endif  /*GPAC_DISABLE_3D*/

Generated by: LCOV version 1.13