LCOV - code coverage report
Current view: top level - compositor - mpeg4_grouping_3d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 173 184 94.0 %
Date: 2021-04-29 23:48:07 Functions: 13 13 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             : 
      28             : #include "nodes_stacks.h"
      29             : 
      30             : #include "mpeg4_grouping.h"
      31             : #include "visual_manager.h"
      32             : 
      33             : #ifndef GPAC_DISABLE_VRML
      34             : 
      35             : 
      36             : #ifdef GPAC_DISABLE_3D
      37             : 
      38             : static void TraverseGroup(GF_Node *node, void *rs, Bool is_destroy)
      39             : {
      40             :         GroupingNode2D *group = (GroupingNode2D *) gf_node_get_private(node);
      41             :         if (is_destroy) {
      42             :                 gf_sc_check_focus_upon_destroy(node);
      43             :                 gf_free(group);
      44             :         } else {
      45             :                 group_2d_traverse(node, group, (GF_TraverseState*)rs);
      46             :         }
      47             : }
      48             : 
      49             : void compositor_init_group(GF_Compositor *compositor, GF_Node *node)
      50             : {
      51             :         GroupingNode2D *ptr;
      52             :         GF_SAFEALLOC(ptr, GroupingNode2D);
      53             :         if (!ptr) return;
      54             :         gf_node_set_private(node, ptr);
      55             :         gf_node_set_callback_function(node, TraverseGroup);
      56             : }
      57             : 
      58             : void compositor_init_static_group(GF_Compositor *compositor, GF_Node *node)
      59             : {
      60             :         compositor_init_group(compositor, node);
      61             : }
      62             : 
      63             : #else
      64             : 
      65       21409 : static void TraverseGroup(GF_Node *node, void *rs, Bool is_destroy)
      66             : {
      67       21409 :         GroupingNode *group = (GroupingNode *) gf_node_get_private(node);
      68       21409 :         if (is_destroy) {
      69         136 :                 gf_sc_check_focus_upon_destroy(node);
      70         136 :                 group_3d_delete(node);
      71             :         } else {
      72       21273 :                 group_3d_traverse(node, group, (GF_TraverseState*)rs);
      73             :         }
      74       21409 : }
      75             : 
      76         135 : void compositor_init_group(GF_Compositor *compositor, GF_Node *node)
      77             : {
      78         135 :         group_3d_new(node);
      79         135 :         gf_node_set_callback_function(node, TraverseGroup);
      80         135 : }
      81             : 
      82             : 
      83             : /*currently static group use the same drawing as all grouping nodes, without any opts.
      84             : since we already do a lot of caching (lights, sensors) at the grouping node level, I'm not sure
      85             : we could get anything better trying to optimize the rest, since what is not cached in the base grouping
      86             : node always involves frustum culling, and caching that would require caching partial model matrix (from
      87             : the static group to each leaf)*/
      88           1 : void compositor_init_static_group(GF_Compositor *compositor, GF_Node *node)
      89             : {
      90           1 :         group_3d_new(node);
      91           1 :         gf_node_set_callback_function(node, TraverseGroup);
      92           1 : }
      93             : 
      94             : 
      95         296 : void TraverseCollision(GF_Node *node, void *rs, Bool is_destroy)
      96             : {
      97             :         u32 collide_flags;
      98             :         SFVec3f last_point;
      99             :         Fixed last_dist;
     100             :         M_Collision *col = (M_Collision *)node;
     101             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     102         296 :         GroupingNode *group = (GroupingNode *) gf_node_get_private(node);
     103             : 
     104         296 :         if (is_destroy) {
     105           8 :                 gf_sc_check_focus_upon_destroy(node);
     106           8 :                 group_3d_delete(node);
     107             :                 return;
     108             :         }
     109             : 
     110         288 :         if (tr_state->traversing_mode != TRAVERSE_COLLIDE) {
     111         154 :                 group_3d_traverse(node, group, tr_state);
     112         134 :         } else if (col->collide) {
     113             : 
     114         134 :                 collide_flags = tr_state->camera->collide_flags;
     115         134 :                 last_dist = tr_state->camera->collide_dist;
     116         134 :                 tr_state->camera->collide_flags &= 0;
     117         134 :                 tr_state->camera->collide_dist = FIX_MAX;
     118         134 :                 last_point = tr_state->camera->collide_point;
     119             : 
     120         134 :                 if (col->proxy) {
     121             :                         /*always check bounds to update any dirty node*/
     122          68 :                         tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
     123          68 :                         gf_node_traverse(col->proxy, rs);
     124             : 
     125          68 :                         tr_state->traversing_mode = TRAVERSE_COLLIDE;
     126          68 :                         gf_node_traverse(col->proxy, rs);
     127             :                 } else {
     128          66 :                         group_3d_traverse(node, group, (GF_TraverseState*)rs);
     129             :                 }
     130         134 :                 if (tr_state->camera->collide_flags & CF_COLLISION) {
     131           0 :                         col->collideTime = gf_node_get_scene_time(node);
     132           0 :                         gf_node_event_out(node, 5/*"collideTime"*/);
     133             :                         /*if not closer restore*/
     134           0 :                         if (collide_flags && (last_dist<tr_state->camera->collide_dist)) {
     135           0 :                                 tr_state->camera->collide_flags = collide_flags;
     136           0 :                                 tr_state->camera->collide_dist = last_dist;
     137           0 :                                 tr_state->camera->collide_point = last_point;
     138             :                         }
     139             :                 } else {
     140         134 :                         tr_state->camera->collide_flags = collide_flags;
     141         134 :                         tr_state->camera->collide_dist = last_dist;
     142             :                 }
     143             :         }
     144             : }
     145             : 
     146           8 : void compositor_init_collision(GF_Compositor *compositor, GF_Node *node)
     147             : {
     148           8 :         group_3d_new(node);
     149           8 :         gf_node_set_callback_function(node, TraverseCollision);
     150           8 : }
     151             : 
     152             : /*for transform, transform2D & transformMatrix2D*/
     153             : typedef struct
     154             : {
     155             :         GROUPING_NODE_STACK_3D
     156             : 
     157             :         GF_Matrix mx;
     158             :         Bool has_scale;
     159             : } TransformStack;
     160             : 
     161         187 : static void DestroyTransform(GF_Node *n)
     162             : {
     163         187 :         TransformStack *ptr = (TransformStack *)gf_node_get_private(n);
     164         187 :         gf_sc_check_focus_upon_destroy(n);
     165         187 :         gf_free(ptr);
     166         187 : }
     167             : 
     168         187 : static void NewTransformStack(GF_Compositor *compositor, GF_Node *node, GF_ChildNodeItem **children)
     169             : {
     170             :         TransformStack *st;
     171         187 :         GF_SAFEALLOC(st, TransformStack);
     172         187 :         if (!st) return;
     173             : 
     174         374 :         gf_mx_init(st->mx);
     175         187 :         gf_node_set_private(node, st);
     176             : }
     177             : 
     178       58213 : static void TraverseTransform(GF_Node *n, void *rs, Bool is_destroy)
     179             : {
     180             :         GF_Matrix gf_mx_bckup;
     181       58213 :         TransformStack *st = (TransformStack *)gf_node_get_private(n);
     182             :         M_Transform *tr = (M_Transform *)n;
     183             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     184             : 
     185       58213 :         if (is_destroy) {
     186         184 :                 DestroyTransform(n);
     187         184 :                 return;
     188             :         }
     189             : 
     190             :         /*note we don't clear dirty flag, this is done in traversing*/
     191       58029 :         if (gf_node_dirty_get(n) & GF_SG_NODE_DIRTY) {
     192             :                 Bool scale_rot, recenter;
     193        6010 :                 gf_mx_init(st->mx);
     194        3005 :                 if (tr->translation.x || tr->translation.y || tr->translation.z)
     195        1584 :                         gf_mx_add_translation(&st->mx, tr->translation.x, tr->translation.y, tr->translation.z);
     196        3005 :                 recenter = (tr->center.x || tr->center.y || tr->center.z) ? 1 : 0;
     197        3005 :                 if (recenter)
     198           0 :                         gf_mx_add_translation(&st->mx, tr->center.x, tr->center.y, tr->center.z);
     199             : 
     200        3005 :                 if (tr->rotation.q) gf_mx_add_rotation(&st->mx, tr->rotation.q, tr->rotation.x, tr->rotation.y, tr->rotation.z);
     201        3005 :                 scale_rot = (tr->scaleOrientation.q) ? 1 : 0;
     202        3005 :                 if (scale_rot)
     203           7 :                         gf_mx_add_rotation(&st->mx, tr->scaleOrientation.q, tr->scaleOrientation.x, tr->scaleOrientation.y, tr->scaleOrientation.z);
     204        3005 :                 if ((tr->scale.x != FIX_ONE) || (tr->scale.y != FIX_ONE) || (tr->scale.z != FIX_ONE))
     205         743 :                         gf_mx_add_scale(&st->mx, tr->scale.x, tr->scale.y, tr->scale.z);
     206        3005 :                 if (scale_rot)
     207           7 :                         gf_mx_add_rotation(&st->mx, -tr->scaleOrientation.q, tr->scaleOrientation.x, tr->scaleOrientation.y, tr->scaleOrientation.z);
     208        3005 :                 if (recenter)
     209           0 :                         gf_mx_add_translation(&st->mx, -tr->center.x, -tr->center.y, -tr->center.z);
     210             : 
     211        3005 :                 st->has_scale = ((tr->scale.x != FIX_ONE) || (tr->scale.y != FIX_ONE) || (tr->scale.z != FIX_ONE)) ? 1 : 0;
     212             :         }
     213             : 
     214       58029 :         gf_mx_copy(gf_mx_bckup, tr_state->model_matrix);
     215       58029 :         gf_mx_add_matrix(&tr_state->model_matrix, &st->mx);
     216             : 
     217             :         /*note we don't clear dirty flag, this is done in traversing*/
     218       58029 :         group_3d_traverse(n, (GroupingNode *) st, tr_state);
     219             : 
     220             :         gf_mx_copy(tr_state->model_matrix, gf_mx_bckup);
     221       58029 :         if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS)
     222       12865 :                 gf_mx_apply_bbox(&st->mx, &tr_state->bbox);
     223             : }
     224             : 
     225         184 : void compositor_init_transform(GF_Compositor *compositor, GF_Node *node)
     226             : {
     227         184 :         NewTransformStack(compositor, node, & ((M_Transform *)node)->children);
     228         184 :         gf_node_set_callback_function(node, TraverseTransform);
     229             : 
     230         184 : }
     231             : 
     232             : 
     233         564 : static void TraverseBillboard(GF_Node *n, void *rs, Bool is_destroy)
     234             : {
     235             :         GF_Matrix gf_mx_bckup;
     236         564 :         TransformStack *st = (TransformStack *)gf_node_get_private(n);
     237             :         M_Billboard *bb = (M_Billboard *)n;
     238             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     239             : 
     240         564 :         if (is_destroy) {
     241           3 :                 DestroyTransform(n);
     242           3 :                 return;
     243             :         }
     244         561 :         if (! tr_state->camera) return;
     245             : 
     246             :         /*can't cache the matrix here*/
     247        1116 :         gf_mx_init(st->mx);
     248         558 :         if (tr_state->camera->is_3D) {
     249             :                 SFVec3f z, axis;
     250             :                 Fixed axis_len;
     251         558 :                 SFVec3f user_pos = tr_state->camera->position;
     252             : 
     253         558 :                 gf_mx_apply_vec(&tr_state->model_matrix, &user_pos);
     254         558 :                 gf_vec_norm(&user_pos);
     255         558 :                 axis = bb->axisOfRotation;
     256         558 :                 axis_len = gf_vec_len(axis);
     257         558 :                 if (axis_len<FIX_EPSILON) {
     258             :                         SFVec3f x, y, t;
     259             :                         /*get user's right in local coord*/
     260         515 :                         gf_vec_diff(t, tr_state->camera->position, tr_state->camera->target);
     261         515 :                         gf_vec_norm(&t);
     262         515 :                         x = gf_vec_cross(tr_state->camera->up, t);
     263         515 :                         gf_vec_norm(&x);
     264         515 :                         gf_mx_rotate_vector(&tr_state->model_matrix, &x);
     265         515 :                         gf_vec_norm(&x);
     266             :                         /*get user's up in local coord*/
     267         515 :                         y = tr_state->camera->up;
     268         515 :                         gf_mx_rotate_vector(&tr_state->model_matrix, &y);
     269         515 :                         gf_vec_norm(&y);
     270         515 :                         z = gf_vec_cross(x, y);
     271         515 :                         gf_vec_norm(&z);
     272             : 
     273         515 :                         gf_mx_rotation_matrix_from_vectors(&st->mx, x, y, z);
     274         515 :                         gf_mx_inverse(&st->mx);
     275             :                 } else {
     276             :                         SFVec3f tmp;
     277             :                         Fixed d, cosw, sinw, angle;
     278          43 :                         gf_vec_norm(&axis);
     279             :                         /*map eye & z into plane with normal axis through 0.0*/
     280          43 :                         d = -gf_vec_dot(axis, user_pos);
     281          43 :                         tmp = gf_vec_scale(axis, d);
     282          43 :                         gf_vec_add(user_pos, user_pos, tmp);
     283          43 :                         gf_vec_norm(&user_pos);
     284             : 
     285          43 :                         z.x = z.y = 0;
     286          43 :                         z.z = FIX_ONE;
     287          43 :                         d = -gf_vec_dot(axis, z);
     288          43 :                         tmp = gf_vec_scale(axis, d);
     289          43 :                         gf_vec_add(z, z, tmp);
     290          43 :                         gf_vec_norm(&z);
     291             : 
     292          43 :                         cosw = gf_vec_dot(user_pos, z);
     293          43 :                         tmp = gf_vec_cross(user_pos, z);
     294          43 :                         sinw = gf_vec_len(tmp);
     295          43 :                         angle = gf_acos(cosw);
     296          43 :                         gf_vec_norm(&tmp);
     297          43 :                         if ((sinw>0) && (gf_vec_dot(axis, tmp) > 0)) gf_vec_rev(axis);
     298          43 :                         gf_mx_add_rotation(&st->mx, angle, axis.x, axis.y, axis.z);
     299             :                 }
     300             :         }
     301             : 
     302         558 :         gf_mx_copy(gf_mx_bckup, tr_state->model_matrix);
     303         558 :         gf_mx_add_matrix(&tr_state->model_matrix, &st->mx);
     304             : 
     305             :         /*note we don't clear dirty flag, this is done in traversing*/
     306         558 :         group_3d_traverse(n, (GroupingNode *) st, tr_state);
     307             : 
     308             :         gf_mx_copy(tr_state->model_matrix, gf_mx_bckup);
     309             : 
     310         558 :         if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) gf_mx_apply_bbox(&st->mx, &tr_state->bbox);
     311             : }
     312             : 
     313           3 : void compositor_init_billboard(GF_Compositor *compositor, GF_Node *node)
     314             : {
     315           3 :         NewTransformStack(compositor, node, & ((M_Billboard *)node)->children);
     316           3 :         gf_node_set_callback_function(node, TraverseBillboard);
     317             : 
     318           3 : }
     319             : 
     320          28 : static void TraverseLOD(GF_Node *node, void *rs, Bool is_destroy)
     321             : {
     322             :         GF_ChildNodeItem *children;
     323             :         MFFloat *ranges;
     324             :         SFVec3f pos, usr;
     325             :         u32 which_child, nb_children;
     326             :         Fixed dist;
     327             :         Bool do_all;
     328             :         GF_Matrix mx;
     329             :         SFVec3f center;
     330             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     331          28 :         s32 *prev_child = (s32 *)gf_node_get_private(node);
     332             : 
     333          28 :         if (is_destroy) {
     334           1 :                 gf_free(prev_child);
     335           1 :                 gf_sc_check_focus_upon_destroy(node);
     336           1 :                 return;
     337             :         }
     338             : 
     339             :         /*WARNING: X3D/MPEG4 NOT COMPATIBLE*/
     340          27 :         if (gf_node_get_tag(node) == TAG_MPEG4_LOD) {
     341          27 :                 children = ((M_LOD *) node)->level;
     342          27 :                 ranges = &((M_LOD *) node)->range;
     343          27 :                 center = ((M_LOD *) node)->center;
     344             : #ifndef GPAC_DISABLE_X3D
     345             :         } else {
     346           0 :                 children = ((X_LOD *) node)->children;
     347           0 :                 ranges = &((X_LOD *) node)->range;
     348           0 :                 center = ((X_LOD *) node)->center;
     349             : #endif
     350             :         }
     351             : 
     352          27 :         if (!children) return;
     353          27 :         nb_children = gf_node_list_get_count(children);
     354             : 
     355          27 :         if (!tr_state->camera) {
     356             :                 do_all = 1;
     357             :                 which_child = 0;
     358             :         } else {
     359             :                 /*can't cache the matrix here*/
     360          26 :                 usr = tr_state->camera->position;
     361             :                 pos = center;
     362          26 :                 gf_mx_copy(mx, tr_state->model_matrix);
     363          26 :                 gf_mx_inverse(&mx);
     364          26 :                 gf_mx_apply_vec(&mx, &usr);
     365          26 :                 gf_vec_diff(pos, pos, usr);
     366          26 :                 dist = gf_vec_len(pos);
     367          52 :                 for (which_child=0; which_child<ranges->count; which_child++) {
     368          26 :                         if (dist<ranges->vals[which_child]) break;
     369             :                 }
     370          26 :                 if (which_child>=nb_children) which_child = nb_children-1;
     371             : 
     372             :                 /*check if we're traversing the same child or not for audio rendering*/
     373             :                 do_all = 0;
     374          26 :                 if (gf_node_dirty_get(node)) {
     375           1 :                         gf_node_dirty_clear(node, 0);
     376             :                         do_all = 1;
     377          25 :                 } else if ((s32) which_child != *prev_child) {
     378           1 :                         *prev_child = which_child;
     379             :                         do_all = 1;
     380             :                 }
     381             :         }
     382             : 
     383             :         if (do_all) {
     384             :                 u32 i;
     385           3 :                 Bool prev_switch = tr_state->switched_off;
     386             :                 GF_ChildNodeItem *l = children;
     387           3 :                 tr_state->switched_off = 1;
     388             :                 i=0;
     389          12 :                 while (l) {
     390           6 :                         if (i!=which_child) gf_node_traverse(l->node, rs);
     391           6 :                         l = l->next;
     392             :                 }
     393           3 :                 tr_state->switched_off = prev_switch;
     394             :         }
     395          27 :         gf_node_traverse(gf_node_list_get_child(children, which_child), rs);
     396             : }
     397             : 
     398           1 : void compositor_init_lod(GF_Compositor *compositor, GF_Node *node)
     399             : {
     400           1 :         s32 *stack = (s32*)gf_malloc(sizeof(s32));
     401           1 :         *stack = -1;
     402           1 :         gf_node_set_callback_function(node, TraverseLOD);
     403           1 :         gf_node_set_private(node, stack);
     404           1 : }
     405             : 
     406             : #endif /*GPAC_DISABLE_3D*/
     407             : 
     408             : 
     409             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13