LCOV - code coverage report
Current view: top level - compositor - hardcoded_protos.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 468 789 59.3 %
Date: 2021-04-29 23:48:07 Functions: 35 37 94.6 %

          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             : #include "nodes_stacks.h"
      27             : #include "visual_manager.h"
      28             : 
      29             : #include "offscreen_cache.h"
      30             : #include "mpeg4_grouping.h"
      31             : 
      32             : #include <gpac/modules/hardcoded_proto.h>
      33             : #include "texturing.h"
      34             : 
      35             : 
      36             : #define CHECK_FIELD(__name, __index, __type) \
      37             :         if (gf_node_get_field(node, __index, &field) != GF_OK) {\
      38             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[HardcodedProtos] Cannot get field index %d\n", __index));\
      39             :                 return GF_FALSE; \
      40             :         }\
      41             :         if (field.fieldType != __type) {\
      42             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[HardcodedProtos] %s field idx %d (%s) is not of type %s\n", __name, field.fieldIndex, field.name, gf_sg_vrml_get_field_type_name(__type) ));\
      43             :                 return GF_FALSE;\
      44             :         }
      45             : 
      46             : 
      47             : #ifndef GPAC_DISABLE_VRML
      48             : 
      49             : #ifndef GPAC_DISABLE_3D
      50             : 
      51             : 
      52             : /*PathExtrusion hardcoded proto*/
      53             : 
      54             : typedef struct
      55             : {
      56             :         GF_Node *geometry;
      57             :         MFVec3f *spine;
      58             :         Bool beginCap;
      59             :         Bool endCap;
      60             :         Fixed creaseAngle;
      61             :         MFRotation *orientation;
      62             :         MFVec2f *scale;
      63             :         Bool txAlongSpine;
      64             : } PathExtrusion;
      65             : 
      66             : 
      67          12 : static Bool PathExtrusion_GetNode(GF_Node *node, PathExtrusion *path_ext)
      68             : {
      69             :         GF_FieldInfo field;
      70             :         memset(path_ext, 0, sizeof(PathExtrusion));
      71             :         
      72          12 :         CHECK_FIELD("PathExtrusion", 0, GF_SG_VRML_SFNODE);
      73          12 :         path_ext->geometry = * (GF_Node **) field.far_ptr;
      74             :         
      75          12 :         CHECK_FIELD("PathExtrusion", 1, GF_SG_VRML_MFVEC3F);
      76          12 :         path_ext->spine = (MFVec3f *) field.far_ptr;
      77             : 
      78          12 :         CHECK_FIELD("PathExtrusion", 2, GF_SG_VRML_SFBOOL);
      79          12 :         path_ext->beginCap = *(SFBool *) field.far_ptr;
      80             :         
      81          12 :         CHECK_FIELD("PathExtrusion", 3, GF_SG_VRML_SFBOOL);
      82          12 :         path_ext->endCap = *(SFBool *) field.far_ptr;
      83             :         
      84          12 :         CHECK_FIELD("PathExtrusion", 4, GF_SG_VRML_SFFLOAT);
      85          12 :         path_ext->creaseAngle = *(SFFloat *) field.far_ptr;
      86             :         
      87          12 :         CHECK_FIELD("PathExtrusion", 5, GF_SG_VRML_MFROTATION);
      88          12 :         path_ext->orientation = (MFRotation *) field.far_ptr;
      89             :         
      90          12 :         CHECK_FIELD("PathExtrusion", 6, GF_SG_VRML_MFVEC2F);
      91          12 :         path_ext->scale = (MFVec2f *) field.far_ptr;
      92             :         
      93          12 :         CHECK_FIELD("PathExtrusion", 7, GF_SG_VRML_SFBOOL);
      94          12 :         path_ext->txAlongSpine = *(SFBool *) field.far_ptr;
      95          12 :         return GF_TRUE;
      96             : }
      97             : 
      98          13 : static void TraversePathExtrusion(GF_Node *node, void *rs, Bool is_destroy)
      99             : {
     100             :         PathExtrusion path_ext;
     101             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     102          13 :         Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);
     103             : 
     104          13 :         if (is_destroy) {
     105           1 :                 drawable_3d_del(node);
     106           1 :                 return;
     107             :         }
     108          12 :         if (!PathExtrusion_GetNode(node, &path_ext)) return;
     109          12 :         if (!path_ext.geometry) return;
     110             : 
     111             : 
     112          12 :         if (gf_node_dirty_get(node)) {
     113             :                 Drawable *stack_2d;
     114           1 :                 u32 mode = tr_state->traversing_mode;
     115           1 :                 tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
     116           1 :                 gf_node_traverse(path_ext.geometry, tr_state);
     117           1 :                 tr_state->traversing_mode = mode;
     118             : 
     119           1 :                 gf_node_dirty_clear(node, 0);
     120             : 
     121           1 :                 switch (gf_node_get_tag(path_ext.geometry) ) {
     122           0 :                 case TAG_MPEG4_Circle:
     123             :                 case TAG_MPEG4_Ellipse:
     124             :                 case TAG_MPEG4_Rectangle:
     125             :                 case TAG_MPEG4_Curve2D:
     126             :                 case TAG_MPEG4_XCurve2D:
     127             :                 case TAG_MPEG4_IndexedFaceSet2D:
     128             :                 case TAG_MPEG4_IndexedLineSet2D:
     129           0 :                         stack_2d = (Drawable*)gf_node_get_private(path_ext.geometry);
     130           0 :                         if (!stack_2d) return;
     131           0 :                         mesh_extrude_path(stack->mesh, stack_2d->path, path_ext.spine, path_ext.creaseAngle, path_ext.beginCap, path_ext.endCap, path_ext.orientation, path_ext.scale, path_ext.txAlongSpine);
     132           0 :                         break;
     133           1 :                 case TAG_MPEG4_Text:
     134           1 :                         compositor_extrude_text(path_ext.geometry, tr_state, stack->mesh, path_ext.spine, path_ext.creaseAngle, path_ext.beginCap, path_ext.endCap, path_ext.orientation, path_ext.scale, path_ext.txAlongSpine);
     135           1 :                         break;
     136             :                 }
     137             :         }
     138             : 
     139          12 :         if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
     140           9 :                 visual_3d_draw(tr_state, stack->mesh);
     141           3 :         } else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
     142           3 :                 tr_state->bbox = stack->mesh->bounds;
     143             :         }
     144             : }
     145             : 
     146             : static void compositor_init_path_extrusion(GF_Compositor *compositor, GF_Node *node)
     147             : {
     148           1 :         drawable_3d_new(node);
     149           1 :         gf_node_set_callback_function(node, TraversePathExtrusion);
     150             : }
     151             : 
     152             : 
     153             : /*PlanarExtrusion hardcoded proto*/
     154             : typedef struct
     155             : {
     156             :         GF_Node *geometry;
     157             :         GF_Node *spine;
     158             :         Bool beginCap;
     159             :         Bool endCap;
     160             :         Fixed creaseAngle;
     161             :         MFFloat *orientationKeys;
     162             :         MFRotation *orientation;
     163             :         MFFloat *scaleKeys;
     164             :         MFVec2f *scale;
     165             :         Bool txAlongSpine;
     166             : } PlanarExtrusion;
     167             : 
     168           5 : static Bool PlanarExtrusion_GetNode(GF_Node *node, PlanarExtrusion *path_ext)
     169             : {
     170             :         GF_FieldInfo field;
     171             :         memset(path_ext, 0, sizeof(PathExtrusion));
     172             : 
     173           5 :         CHECK_FIELD("PlanarExtrusion", 0, GF_SG_VRML_SFNODE);
     174           5 :         path_ext->geometry = * (GF_Node **) field.far_ptr;
     175             :         
     176           5 :         CHECK_FIELD("PlanarExtrusion", 1, GF_SG_VRML_SFNODE);
     177           5 :         path_ext->spine = * (GF_Node **) field.far_ptr;
     178             :         
     179           5 :         CHECK_FIELD("PlanarExtrusion", 2, GF_SG_VRML_SFBOOL);
     180           5 :         path_ext->beginCap = *(SFBool *) field.far_ptr;
     181             :         
     182           5 :         CHECK_FIELD("PlanarExtrusion", 3, GF_SG_VRML_SFBOOL);
     183           5 :         path_ext->endCap = *(SFBool *) field.far_ptr;
     184             :         
     185           5 :         CHECK_FIELD("PlanarExtrusion", 4, GF_SG_VRML_SFFLOAT);
     186           5 :         path_ext->creaseAngle = *(SFFloat *) field.far_ptr;
     187             :         
     188           5 :         CHECK_FIELD("PlanarExtrusion", 5, GF_SG_VRML_MFFLOAT);
     189           5 :         path_ext->orientationKeys = (MFFloat *) field.far_ptr;
     190             :         
     191           5 :         CHECK_FIELD("PlanarExtrusion", 6, GF_SG_VRML_MFROTATION);
     192           5 :         path_ext->orientation = (MFRotation *) field.far_ptr;
     193             :         
     194           5 :         CHECK_FIELD("PlanarExtrusion", 7, GF_SG_VRML_MFFLOAT);
     195           5 :         path_ext->scaleKeys = (MFFloat *) field.far_ptr;
     196             :         
     197           5 :         CHECK_FIELD("PlanarExtrusion", 8, GF_SG_VRML_MFVEC2F);
     198           5 :         path_ext->scale = (MFVec2f *) field.far_ptr;
     199             :         
     200           5 :         CHECK_FIELD("PlanarExtrusion", 9, GF_SG_VRML_SFBOOL);
     201           5 :         path_ext->txAlongSpine = *(SFBool *) field.far_ptr;
     202             : 
     203           5 :         return GF_TRUE;
     204             : }
     205             : 
     206           6 : static void TraversePlanarExtrusion(GF_Node *node, void *rs, Bool is_destroy)
     207             : {
     208             :         PlanarExtrusion plane_ext;
     209             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     210           6 :         Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);
     211             : 
     212           6 :         if (is_destroy) {
     213           1 :                 drawable_3d_del(node);
     214           1 :                 return;
     215             :         }
     216             : 
     217           5 :         if (!PlanarExtrusion_GetNode(node, &plane_ext)) return;
     218           5 :         if (!plane_ext.geometry || !plane_ext.spine) return;
     219             : 
     220             : 
     221           5 :         if (gf_node_dirty_get(node)) {
     222             :                 Drawable *stack_2d;
     223             :                 u32 i, j, k;
     224             :                 MFVec3f spine_vec;
     225             :                 SFVec3f d;
     226             :                 Fixed spine_len;
     227             :                 GF_Rect bounds;
     228             :                 u32 cur, nb_pts;
     229           1 :                 u32 mode = tr_state->traversing_mode;
     230             :                 GF_Path *geo, *spine;
     231             :                 geo = spine = NULL;
     232             : 
     233           1 :                 tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
     234           1 :                 gf_node_traverse(plane_ext.geometry, tr_state);
     235           1 :                 gf_node_traverse(plane_ext.spine, tr_state);
     236           1 :                 tr_state->traversing_mode = mode;
     237           1 :                 gf_node_dirty_clear(node, 0);
     238             : 
     239           1 :                 switch (gf_node_get_tag(plane_ext.geometry) ) {
     240           1 :                 case TAG_MPEG4_Circle:
     241             :                 case TAG_MPEG4_Ellipse:
     242             :                 case TAG_MPEG4_Rectangle:
     243             :                 case TAG_MPEG4_Curve2D:
     244             :                 case TAG_MPEG4_XCurve2D:
     245             :                 case TAG_MPEG4_IndexedFaceSet2D:
     246             :                 case TAG_MPEG4_IndexedLineSet2D:
     247           1 :                         stack_2d = (Drawable*)gf_node_get_private(plane_ext.geometry);
     248           1 :                         if (stack_2d) geo = stack_2d->path;
     249             :                         break;
     250             :                 default:
     251           0 :                         return;
     252             :                 }
     253           1 :                 switch (gf_node_get_tag(plane_ext.spine) ) {
     254           1 :                 case TAG_MPEG4_Circle:
     255             :                 case TAG_MPEG4_Ellipse:
     256             :                 case TAG_MPEG4_Rectangle:
     257             :                 case TAG_MPEG4_Curve2D:
     258             :                 case TAG_MPEG4_XCurve2D:
     259             :                 case TAG_MPEG4_IndexedFaceSet2D:
     260             :                 case TAG_MPEG4_IndexedLineSet2D:
     261           1 :                         stack_2d = (Drawable*)gf_node_get_private(plane_ext.spine);
     262           1 :                         if (stack_2d) spine = stack_2d->path;
     263             :                         break;
     264             :                 default:
     265             :                         return;
     266             :                 }
     267           1 :                 if (!geo || !spine) return;
     268             : 
     269           1 :                 mesh_reset(stack->mesh);
     270           1 :                 gf_path_flatten(spine);
     271           1 :                 gf_path_get_bounds(spine, &bounds);
     272           1 :                 gf_path_flatten(geo);
     273           1 :                 gf_path_get_bounds(geo, &bounds);
     274             : 
     275             :                 cur = 0;
     276           2 :                 for (i=0; i<spine->n_contours; i++) {
     277           1 :                         nb_pts = 1 + spine->contours[i] - cur;
     278           1 :                         spine_vec.vals = NULL;
     279           1 :                         gf_sg_vrml_mf_alloc(&spine_vec, GF_SG_VRML_MFVEC3F, nb_pts);
     280             :                         spine_len = 0;
     281          66 :                         for (j=cur; j<nb_pts; j++) {
     282          65 :                                 spine_vec.vals[j].x = spine->points[j].x;
     283          65 :                                 spine_vec.vals[j].y = spine->points[j].y;
     284          65 :                                 spine_vec.vals[j].z = 0;
     285          65 :                                 if (j) {
     286          64 :                                         gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]);
     287          64 :                                         spine_len += gf_vec_len(d);
     288             :                                 }
     289             :                         }
     290           1 :                         cur += nb_pts;
     291           1 :                         if (!plane_ext.orientation->count && !plane_ext.scale->count) {
     292           2 :                                 mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle,
     293           1 :                                                       bounds.x, bounds.y-bounds.height, bounds.width, bounds.height,
     294             :                                                       plane_ext.beginCap, plane_ext.endCap, NULL, NULL, plane_ext.txAlongSpine);
     295             :                         }
     296             :                         /*interpolate orientation and scale along subpath line*/
     297             :                         else {
     298             :                                 MFRotation ori;
     299             :                                 MFVec2f scale;
     300             :                                 Fixed cur_len, frac;
     301             : 
     302           0 :                                 ori.vals = NULL;
     303           0 :                                 gf_sg_vrml_mf_alloc(&ori, GF_SG_VRML_MFROTATION, nb_pts);
     304           0 :                                 scale.vals = NULL;
     305           0 :                                 gf_sg_vrml_mf_alloc(&scale, GF_SG_VRML_MFVEC2F, nb_pts);
     306             :                                 cur_len = 0;
     307           0 :                                 if (!plane_ext.orientation->count) ori.vals[0].y = FIX_ONE;
     308           0 :                                 if (!plane_ext.scale->count) scale.vals[0].x = scale.vals[0].y = FIX_ONE;
     309           0 :                                 for (j=0; j<nb_pts; j++) {
     310           0 :                                         if (j) {
     311           0 :                                                 gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]);
     312           0 :                                                 cur_len += gf_vec_len(d);
     313           0 :                                                 ori.vals[j] = ori.vals[j-1];
     314           0 :                                                 scale.vals[j] = scale.vals[j-1];
     315             :                                         }
     316             : 
     317           0 :                                         if (plane_ext.orientation->count && (plane_ext.orientation->count == plane_ext.orientationKeys->count)) {
     318             : 
     319           0 :                                                 frac = gf_divfix(cur_len , spine_len);
     320           0 :                                                 if (frac < plane_ext.orientationKeys->vals[0]) ori.vals[j] = plane_ext.orientation->vals[0];
     321           0 :                                                 else if (frac >= plane_ext.orientationKeys->vals[plane_ext.orientationKeys->count-1]) ori.vals[j] = plane_ext.orientation->vals[plane_ext.orientationKeys->count-1];
     322             :                                                 else {
     323           0 :                                                         for (k=1; k<plane_ext.orientationKeys->count; k++) {
     324           0 :                                                                 Fixed kDiff = plane_ext.orientationKeys->vals[k] - plane_ext.orientationKeys->vals[k-1];
     325           0 :                                                                 if (!kDiff) continue;
     326           0 :                                                                 if (frac < plane_ext.orientationKeys->vals[k-1]) continue;
     327           0 :                                                                 if (frac > plane_ext.orientationKeys->vals[k]) continue;
     328           0 :                                                                 frac = gf_divfix(frac - plane_ext.orientationKeys->vals[k-1], kDiff);
     329           0 :                                                                 break;
     330             :                                                         }
     331           0 :                                                         ori.vals[j] = gf_sg_sfrotation_interpolate(plane_ext.orientation->vals[k-1], plane_ext.orientation->vals[k], frac);
     332             :                                                 }
     333             :                                         }
     334             : 
     335           0 :                                         if (plane_ext.scale->count == plane_ext.scaleKeys->count) {
     336           0 :                                                 frac = gf_divfix(cur_len , spine_len);
     337           0 :                                                 if (frac <= plane_ext.scaleKeys->vals[0]) scale.vals[j] = plane_ext.scale->vals[0];
     338           0 :                                                 else if (frac >= plane_ext.scaleKeys->vals[plane_ext.scaleKeys->count-1]) scale.vals[j] = plane_ext.scale->vals[plane_ext.scale->count-1];
     339             :                                                 else {
     340           0 :                                                         for (k=1; k<plane_ext.scaleKeys->count; k++) {
     341           0 :                                                                 Fixed kDiff = plane_ext.scaleKeys->vals[k] - plane_ext.scaleKeys->vals[k-1];
     342           0 :                                                                 if (!kDiff) continue;
     343           0 :                                                                 if (frac < plane_ext.scaleKeys->vals[k-1]) continue;
     344           0 :                                                                 if (frac > plane_ext.scaleKeys->vals[k]) continue;
     345           0 :                                                                 frac = gf_divfix(frac - plane_ext.scaleKeys->vals[k-1], kDiff);
     346           0 :                                                                 break;
     347             :                                                         }
     348           0 :                                                         scale.vals[j].x = gf_mulfix(plane_ext.scale->vals[k].x - plane_ext.scale->vals[k-1].x, frac) + plane_ext.scale->vals[k-1].x;
     349           0 :                                                         scale.vals[j].y = gf_mulfix(plane_ext.scale->vals[k].y - plane_ext.scale->vals[k-1].y, frac) + plane_ext.scale->vals[k-1].y;
     350             :                                                 }
     351             :                                         }
     352             :                                 }
     353             : 
     354           0 :                                 mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle,
     355           0 :                                                       bounds.x, bounds.y-bounds.height, bounds.width, bounds.height,
     356             :                                                       plane_ext.beginCap, plane_ext.endCap, &ori, &scale, plane_ext.txAlongSpine);
     357             : 
     358           0 :                                 gf_sg_vrml_mf_reset(&ori, GF_SG_VRML_MFROTATION);
     359           0 :                                 gf_sg_vrml_mf_reset(&scale, GF_SG_VRML_MFVEC2F);
     360             :                         }
     361             : 
     362           1 :                         gf_sg_vrml_mf_reset(&spine_vec, GF_SG_VRML_MFVEC3F);
     363             :                 }
     364           1 :                 mesh_update_bounds(stack->mesh);
     365           1 :                 gf_mesh_build_aabbtree(stack->mesh);
     366             :         }
     367             : 
     368           5 :         if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
     369           3 :                 visual_3d_draw(tr_state, stack->mesh);
     370           2 :         } else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
     371           2 :                 tr_state->bbox = stack->mesh->bounds;
     372             :         }
     373             : }
     374             : 
     375           0 : void compositor_init_planar_extrusion(GF_Compositor *compositor, GF_Node *node)
     376             : {
     377           1 :         drawable_3d_new(node);
     378           1 :         gf_node_set_callback_function(node, TraversePlanarExtrusion);
     379           0 : }
     380             : 
     381             : /*PlaneClipper hardcoded proto*/
     382             : typedef struct
     383             : {
     384             :         BASE_NODE
     385             :         CHILDREN
     386             : 
     387             :         GF_Plane plane;
     388             : } PlaneClipper;
     389             : 
     390             : typedef struct
     391             : {
     392             :         GROUPING_NODE_STACK_3D
     393             :         PlaneClipper pc;
     394             : } PlaneClipperStack;
     395             : 
     396         349 : static Bool PlaneClipper_GetNode(GF_Node *node, PlaneClipper *pc)
     397             : {
     398             :         GF_FieldInfo field;
     399             :         memset(pc, 0, sizeof(PlaneClipper));
     400         349 :         pc->sgprivate = node->sgprivate;
     401             : 
     402         349 :         CHECK_FIELD("PlaneClipper", 0, GF_SG_VRML_SFVEC3F);
     403         349 :         pc->plane.normal = * (SFVec3f *) field.far_ptr;
     404             : 
     405         349 :         CHECK_FIELD("PlaneClipper", 1, GF_SG_VRML_SFFLOAT);
     406         349 :         pc->plane.d = * (SFFloat *) field.far_ptr;
     407             :         
     408         349 :         CHECK_FIELD("PlaneClipper", 2, GF_SG_VRML_MFNODE);
     409         349 :         pc->children = *(GF_ChildNodeItem **) field.far_ptr;
     410         349 :         return GF_TRUE;
     411             : }
     412             : 
     413             : 
     414         991 : static void TraversePlaneClipper(GF_Node *node, void *rs, Bool is_destroy)
     415             : {
     416         991 :         PlaneClipperStack *stack = (PlaneClipperStack *)gf_node_get_private(node);
     417             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     418             : 
     419         991 :         if (is_destroy) {
     420           2 :                 group_3d_delete(node);
     421           2 :                 return;
     422             :         }
     423             : 
     424         989 :         if (gf_node_dirty_get(node)) {
     425         347 :                 PlaneClipper_GetNode(node, &stack->pc);
     426         347 :                 gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     427             :         }
     428             : 
     429         989 :         if (tr_state->num_clip_planes==MAX_USER_CLIP_PLANES) {
     430           0 :                 group_3d_traverse((GF_Node*)&stack->pc, (GroupingNode*)stack, tr_state);
     431           0 :                 return;
     432             :         }
     433             : 
     434         989 :         if (tr_state->traversing_mode == TRAVERSE_SORT) {
     435             :                 GF_Matrix mx;
     436         305 :                 gf_mx_copy(mx, tr_state->model_matrix);
     437         305 :                 visual_3d_set_clip_plane(tr_state->visual, stack->pc.plane, &mx, GF_FALSE);
     438         305 :                 tr_state->num_clip_planes++;
     439             : 
     440         305 :                 group_3d_traverse((GF_Node*)&stack->pc, (GroupingNode*)stack, tr_state);
     441         305 :                 visual_3d_reset_clip_plane(tr_state->visual);
     442         305 :                 tr_state->num_clip_planes--;
     443             :         } else {
     444         684 :                 tr_state->clip_planes[tr_state->num_clip_planes] = stack->pc.plane;
     445         684 :                 gf_mx_apply_plane(&tr_state->model_matrix, &tr_state->clip_planes[tr_state->num_clip_planes]);
     446         684 :                 tr_state->num_clip_planes++;
     447             : 
     448         684 :                 group_3d_traverse((GF_Node*)&stack->pc, (GroupingNode*)stack, tr_state);
     449             : 
     450         684 :                 tr_state->num_clip_planes--;
     451             :         }
     452             : 
     453             : }
     454             : 
     455           2 : void compositor_init_plane_clipper(GF_Compositor *compositor, GF_Node *node)
     456             : {
     457             :         PlaneClipper pc;
     458           2 :         if (PlaneClipper_GetNode(node, &pc)) {
     459             :                 PlaneClipperStack *stack;
     460           2 :                 GF_SAFEALLOC(stack, PlaneClipperStack);
     461           2 :                 if (!stack) {
     462           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate plane clipper stack\n"));
     463           0 :                         return;
     464             :                 }
     465             :                 //SetupGroupingNode(stack, compositor->compositor, node, & pc.children);
     466           2 :                 gf_node_set_private(node, stack);
     467           2 :                 gf_node_set_callback_function(node, TraversePlaneClipper);
     468             :                 /*we're a grouping node, force bounds rebuild as soon as loaded*/
     469           2 :                 gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
     470             : 
     471           2 :                 stack->pc = pc;
     472           2 :                 gf_node_proto_set_grouping(node);
     473             :         }
     474             : }
     475             : 
     476             : #endif
     477             : 
     478             : 
     479             : /*OffscreenGroup hardcoded proto*/
     480             : typedef struct
     481             : {
     482             :         BASE_NODE
     483             :         CHILDREN
     484             : 
     485             :         s32 offscreen;
     486             :         Fixed opacity;
     487             : } OffscreenGroup;
     488             : 
     489             : typedef struct
     490             : {
     491             :         GROUPING_MPEG4_STACK_2D
     492             : 
     493             : #ifndef GF_SR_USE_VIDEO_CACHE
     494             :         struct _group_cache *cache;
     495             : #endif
     496             : 
     497             :         OffscreenGroup og;
     498             :         Bool detached;
     499             : } OffscreenGroupStack;
     500             : 
     501           7 : static Bool OffscreenGroup_GetNode(GF_Node *node, OffscreenGroup *og)
     502             : {
     503             :         GF_FieldInfo field;
     504             :         memset(og, 0, sizeof(OffscreenGroup));
     505           7 :         og->sgprivate = node->sgprivate;
     506             : 
     507           7 :         CHECK_FIELD("OffscreenGroup", 0, GF_SG_VRML_MFNODE);
     508           7 :         og->children = *(GF_ChildNodeItem **) field.far_ptr;
     509             : 
     510           7 :         CHECK_FIELD("OffscreenGroup", 1, GF_SG_VRML_SFINT32);
     511           7 :         og->offscreen = * (SFInt32 *) field.far_ptr;
     512             : 
     513           7 :         CHECK_FIELD("OffscreenGroup", 2, GF_SG_VRML_SFFLOAT);
     514           7 :         og->opacity = * (SFFloat *) field.far_ptr;
     515             :         
     516           7 :         return GF_TRUE;
     517             : }
     518             : 
     519             : 
     520         606 : static void TraverseOffscreenGroup(GF_Node *node, void *rs, Bool is_destroy)
     521             : {
     522         606 :         OffscreenGroupStack *stack = (OffscreenGroupStack *)gf_node_get_private(node);
     523             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     524             : 
     525         606 :         if (is_destroy) {
     526           3 :                 if (stack->cache) group_cache_del(stack->cache);
     527           3 :                 gf_free(stack);
     528           3 :                 return;
     529             :         }
     530             : 
     531         603 :         if (tr_state->traversing_mode==TRAVERSE_SORT) {
     532         363 :                 if (!stack->detached && (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY)) {
     533           4 :                         OffscreenGroup_GetNode(node, &stack->og);
     534             : 
     535           4 :                         if (stack->og.offscreen) {
     536           4 :                                 stack->flags |= GROUP_IS_CACHED | GROUP_PERMANENT_CACHE;
     537           4 :                                 if (!stack->cache) {
     538           3 :                                         stack->cache = group_cache_new(tr_state->visual->compositor, (GF_Node*)&stack->og);
     539             :                                 }
     540           4 :                                 stack->cache->opacity = stack->og.opacity;
     541           4 :                                 stack->cache->drawable->flags |= DRAWABLE_HAS_CHANGED;
     542             :                         } else {
     543           0 :                                 if (stack->cache) group_cache_del(stack->cache);
     544           0 :                                 stack->cache = NULL;
     545           0 :                                 stack->flags &= ~(GROUP_IS_CACHED|GROUP_PERMANENT_CACHE);
     546             :                         }
     547           4 :                         gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     548             :                         /*flag is not set for PROTO*/
     549           4 :                         gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
     550             :                 }
     551         363 :                 if (stack->cache) {
     552         363 :                         if (stack->detached)
     553           0 :                                 gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
     554             : 
     555         363 :                         tr_state->subscene_not_over = 0;
     556         363 :                         group_cache_traverse((GF_Node *)&stack->og, stack->cache, tr_state, stack->cache->force_recompute, GF_TRUE, stack->detached ? GF_TRUE : GF_FALSE);
     557             : 
     558         363 :                         if (gf_node_dirty_get(node)) {
     559           2 :                                 gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
     560         361 :                         } else if ((stack->og.offscreen==2) && !stack->detached && !tr_state->subscene_not_over && stack->cache->txh.width && stack->cache->txh.height) {
     561             :                                 GF_FieldInfo field;
     562           0 :                                 if (gf_node_get_field(node, 0, &field) == GF_OK) {
     563           0 :                                         gf_node_unregister_children(node, *(GF_ChildNodeItem **) field.far_ptr);
     564           0 :                                         *(GF_ChildNodeItem **) field.far_ptr = NULL;
     565           0 :                                         stack->detached = GF_TRUE;
     566             :                                 }
     567           0 :                                 if (gf_node_get_field(node, 3, &field) == GF_OK) {
     568           0 :                                         *(SFBool *) field.far_ptr = 1;
     569             :                                         //gf_node_event_out(node, 3);
     570             :                                 }
     571             :                         }
     572             :                 } else {
     573           0 :                         group_2d_traverse((GF_Node *)&stack->og, (GroupingNode2D*)stack, tr_state);
     574             :                 }
     575             :         }
     576             :         /*draw mode*/
     577         240 :         else if (stack->cache && (tr_state->traversing_mode == TRAVERSE_DRAW_2D)) {
     578             :                 /*draw it*/
     579         240 :                 group_cache_draw(stack->cache, tr_state);
     580         240 :                 gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
     581           0 :         } else if (!stack->detached) {
     582           0 :                 group_2d_traverse((GF_Node *)&stack->og, (GroupingNode2D*)stack, tr_state);
     583             :         } else {
     584           0 :                 if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
     585           0 :                         tr_state->bounds = stack->bounds;
     586             :                 }
     587           0 :                 else if (stack->cache && (tr_state->traversing_mode == TRAVERSE_PICK)) {
     588           0 :                         vrml_drawable_pick(stack->cache->drawable, tr_state);
     589             :                 }
     590             :         }
     591             : }
     592             : 
     593           3 : void compositor_init_offscreen_group(GF_Compositor *compositor, GF_Node *node)
     594             : {
     595             :         OffscreenGroup og;
     596           3 :         if (OffscreenGroup_GetNode(node, &og)) {
     597             :                 OffscreenGroupStack *stack;
     598           3 :                 GF_SAFEALLOC(stack, OffscreenGroupStack);
     599           3 :                 if (!stack) {
     600           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate offscreen group stack\n"));
     601           0 :                         return;
     602             :                 }
     603           3 :                 gf_node_set_private(node, stack);
     604           3 :                 gf_node_set_callback_function(node, TraverseOffscreenGroup);
     605           3 :                 stack->og = og;
     606           3 :                 if (og.offscreen) stack->flags |= GROUP_IS_CACHED;
     607           3 :                 gf_node_proto_set_grouping(node);
     608             :         }
     609             : }
     610             : 
     611             : 
     612             : /*DepthGroup hardcoded proto*/
     613             : typedef struct
     614             : {
     615             :         BASE_NODE
     616             :         CHILDREN
     617             : 
     618             :         Fixed depth_gain, depth_offset;
     619             : 
     620             : } DepthGroup;
     621             : 
     622             : typedef struct
     623             : {
     624             :         GROUPING_MPEG4_STACK_2D
     625             :         DepthGroup dg;
     626             : } DepthGroupStack;
     627             : 
     628           3 : static Bool DepthGroup_GetNode(GF_Node *node, DepthGroup *dg)
     629             : {
     630             :         GF_FieldInfo field;
     631             :         memset(dg, 0, sizeof(DepthGroup));
     632           3 :         dg->sgprivate = node->sgprivate;
     633             : 
     634           3 :         CHECK_FIELD("DepthGroup", 0, GF_SG_VRML_MFNODE);
     635           3 :         dg->children = *(GF_ChildNodeItem **) field.far_ptr;
     636             : 
     637           3 :         CHECK_FIELD("DepthGroup", 1, GF_SG_VRML_SFFLOAT);
     638           3 :         dg->depth_gain = * (SFFloat *) field.far_ptr;
     639             : 
     640           3 :         CHECK_FIELD("DepthGroup", 2, GF_SG_VRML_SFFLOAT);
     641           3 :         dg->depth_offset = * (SFFloat *) field.far_ptr;
     642             : 
     643           3 :         return GF_TRUE;
     644             : }
     645             : 
     646             : 
     647           3 : static void TraverseDepthGroup(GF_Node *node, void *rs, Bool is_destroy)
     648             : {
     649             : #ifdef GF_SR_USE_DEPTH
     650             :         Fixed depth_gain, depth_offset;
     651             : #endif
     652             : 
     653           3 :         DepthGroupStack *stack = (DepthGroupStack *)gf_node_get_private(node);
     654             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     655             : 
     656           3 :         if (is_destroy) {
     657           1 :                 gf_free(stack);
     658           1 :                 return;
     659             :         }
     660             : 
     661           2 :         if (tr_state->traversing_mode==TRAVERSE_SORT) {
     662           2 :                 if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
     663             : 
     664           1 :                         gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     665             :                         /*flag is not set for PROTO*/
     666           1 :                         gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
     667             :                 }
     668             :         }
     669           2 :         DepthGroup_GetNode(node, &stack->dg);
     670             : 
     671             : 
     672             : #ifdef GF_SR_USE_DEPTH
     673           2 :         depth_gain = tr_state->depth_gain;
     674           2 :         depth_offset = tr_state->depth_offset;
     675             : 
     676             :         // new offset is multiplied by parent gain and added to parent offset
     677           2 :         tr_state->depth_offset = gf_mulfix(stack->dg.depth_offset, tr_state->depth_gain) + tr_state->depth_offset;
     678             : 
     679             :         // gain is multiplied by parent gain
     680           2 :         tr_state->depth_gain = gf_mulfix(tr_state->depth_gain, stack->dg.depth_gain);
     681             : #endif
     682             : 
     683             : #ifndef GPAC_DISABLE_3D
     684           2 :         if (tr_state->visual->type_3d) {
     685             :                 GF_Matrix mx_bckup, mx;
     686             : 
     687           0 :                 gf_mx_copy(mx_bckup, tr_state->model_matrix);
     688           0 :                 gf_mx_init(mx);
     689           0 :                 mx.m[14] = gf_mulfix(stack->dg.depth_offset, tr_state->visual->compositor->depth_gl_scale);
     690           0 :                 gf_mx_add_matrix(&tr_state->model_matrix, &mx);
     691           0 :                 group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state);
     692             :                 gf_mx_copy(tr_state->model_matrix, mx_bckup);
     693             : 
     694             :         } else
     695             : #endif
     696             :         {
     697             : 
     698           2 :                 group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state);
     699             :         }
     700             : 
     701             : #ifdef GF_SR_USE_DEPTH
     702           2 :         tr_state->depth_gain = depth_gain;
     703           2 :         tr_state->depth_offset = depth_offset;
     704             : #endif
     705             : }
     706             : 
     707           1 : void compositor_init_depth_group(GF_Compositor *compositor, GF_Node *node)
     708             : {
     709             :         DepthGroup dg;
     710           1 :         if (DepthGroup_GetNode(node, &dg)) {
     711             :                 DepthGroupStack *stack;
     712           1 :                 GF_SAFEALLOC(stack, DepthGroupStack);
     713           1 :                 if (!stack) {
     714           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate depth group stack\n"));
     715           0 :                         return;
     716             :                 }
     717           1 :                 gf_node_set_private(node, stack);
     718           1 :                 gf_node_set_callback_function(node, TraverseDepthGroup);
     719           1 :                 stack->dg = dg;
     720           1 :                 gf_node_proto_set_grouping(node);
     721           0 :         } else GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Unable to initialize depth group  \n"));
     722             : 
     723             : }
     724             : 
     725             : #ifdef GF_SR_USE_DEPTH
     726           3 : static void TraverseDepthViewPoint(GF_Node *node, void *rs, Bool is_destroy)
     727             : {
     728           3 :         if (!is_destroy && gf_node_dirty_get(node)) {
     729             :                 GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     730             :                 GF_FieldInfo field;
     731           1 :                 gf_node_dirty_clear(node, 0);
     732             : 
     733           1 :                 tr_state->visual->depth_vp_position = 0;
     734           1 :                 tr_state->visual->depth_vp_range = 0;
     735             : #ifndef GPAC_DISABLE_3D
     736           2 :                 if (!tr_state->camera) return;
     737           0 :                 tr_state->camera->flags |= CAM_IS_DIRTY;
     738             : #endif
     739             : 
     740           0 :                 if (gf_node_get_field(node, 0, &field) != GF_OK) return;
     741           0 :                 if (field.fieldType != GF_SG_VRML_SFBOOL) return;
     742             : 
     743           0 :                 if ( *(SFBool *) field.far_ptr) {
     744           0 :                         if (gf_node_get_field(node, 1, &field) != GF_OK) return;
     745           0 :                         if (field.fieldType != GF_SG_VRML_SFFLOAT) return;
     746           0 :                         tr_state->visual->depth_vp_position = *(SFFloat *) field.far_ptr;
     747           0 :                         if (gf_node_get_field(node, 2, &field) != GF_OK) return;
     748           0 :                         if (field.fieldType != GF_SG_VRML_SFFLOAT) return;
     749           0 :                         tr_state->visual->depth_vp_range = *(SFFloat *) field.far_ptr;
     750             :                 }
     751             : #ifndef GPAC_DISABLE_3D
     752           0 :                 if (tr_state->layer3d) gf_node_dirty_set(tr_state->layer3d, GF_SG_NODE_DIRTY, GF_FALSE);
     753             : #endif
     754           0 :                 gf_sc_invalidate(tr_state->visual->compositor, NULL);
     755             :         }
     756             : }
     757             : #endif
     758             : 
     759             : static void compositor_init_depth_viewpoint(GF_Compositor *compositor, GF_Node *node)
     760             : {
     761             : #ifdef GF_SR_USE_DEPTH
     762           1 :         gf_node_set_callback_function(node, TraverseDepthViewPoint);
     763             : #endif
     764             : }
     765             : 
     766             : /*IndexedCurve2D hardcoded proto*/
     767             : 
     768             : typedef struct
     769             : {
     770             :         BASE_NODE
     771             : 
     772             :         GF_Node *point;
     773             :         Fixed fineness;
     774             :         MFInt32 type;
     775             :         MFInt32 index;
     776             : } IndexedCurve2D;
     777             : 
     778         263 : static Bool IndexedCurve2D_GetNode(GF_Node *node, IndexedCurve2D *ic2d)
     779             : {
     780             :         GF_FieldInfo field;
     781             :         memset(ic2d, 0, sizeof(IndexedCurve2D));
     782             : 
     783         263 :         ic2d->sgprivate = node->sgprivate;
     784             : 
     785         263 :         CHECK_FIELD("IndexedCurve2D", 0, GF_SG_VRML_SFNODE);
     786         263 :         ic2d->point = * (GF_Node **) field.far_ptr;
     787             : 
     788         263 :         CHECK_FIELD("IndexedCurve2D", 1, GF_SG_VRML_SFFLOAT);
     789         263 :         ic2d->fineness = *(SFFloat *) field.far_ptr;
     790             : 
     791         263 :         CHECK_FIELD("IndexedCurve2D", 2, GF_SG_VRML_MFINT32);
     792         263 :         ic2d->type = *(MFInt32 *) field.far_ptr;
     793             : 
     794         263 :         CHECK_FIELD("IndexedCurve2D", 3, GF_SG_VRML_MFINT32);
     795         263 :         ic2d->index = *(MFInt32 *) field.far_ptr;
     796             : 
     797         263 :         return GF_TRUE;
     798             : }
     799             : 
     800             : void curve2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state, MFInt32 *idx);
     801             : 
     802        9621 : static void TraverseIndexedCurve2D(GF_Node *node, void *rs, Bool is_destroy)
     803             : {
     804             :         DrawableContext *ctx;
     805             :         IndexedCurve2D ic2d;
     806             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     807        9621 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     808             : 
     809        9621 :         if (is_destroy) {
     810         263 :                 drawable_node_del(node);
     811         263 :                 return;
     812             :         }
     813             : 
     814        9358 :         if (gf_node_dirty_get(node)) {
     815         263 :                 if (!IndexedCurve2D_GetNode(node, &ic2d)) return;
     816             :                 //clears dirty flag
     817         263 :                 curve2d_check_changes((GF_Node*) &ic2d, stack, tr_state, &ic2d.index);
     818             :         }
     819             : 
     820        9358 :         switch (tr_state->traversing_mode) {
     821             : #ifndef GPAC_DISABLE_3D
     822           0 :         case TRAVERSE_DRAW_3D:
     823           0 :                 if (!stack->mesh) {
     824           0 :                         stack->mesh = new_mesh();
     825           0 :                         mesh_from_path(stack->mesh, stack->path);
     826             :                 }
     827           0 :                 visual_3d_draw_2d(stack, tr_state);
     828           0 :                 return;
     829             : #endif
     830           0 :         case TRAVERSE_PICK:
     831           0 :                 vrml_drawable_pick(stack, tr_state);
     832           0 :                 return;
     833           0 :         case TRAVERSE_GET_BOUNDS:
     834           0 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     835           0 :                 return;
     836        9358 :         case TRAVERSE_SORT:
     837             : #ifndef GPAC_DISABLE_3D
     838        9358 :                 if (tr_state->visual->type_3d) return;
     839             : #endif
     840        9358 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     841        9358 :                 if (!ctx) return;
     842        9358 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     843        9358 :                 return;
     844             :         }
     845             : }
     846             : 
     847             : static void compositor_init_idx_curve2d(GF_Compositor *compositor, GF_Node *node)
     848             : {
     849         263 :         drawable_stack_new(compositor, node);
     850         263 :         gf_node_set_callback_function(node, TraverseIndexedCurve2D);
     851             : }
     852             : 
     853             : 
     854             : 
     855             : 
     856             : 
     857             : /*TransformRef hardcoded proto*/
     858             : typedef struct
     859             : {
     860             :         BASE_NODE
     861             :         CHILDREN
     862             : } Untransform;
     863             : 
     864             : typedef struct
     865             : {
     866             :         GROUPING_MPEG4_STACK_2D
     867             :         Untransform untr;
     868             : } UntransformStack;
     869             : 
     870          60 : static Bool Untransform_GetNode(GF_Node *node, Untransform *tr)
     871             : {
     872             :         GF_FieldInfo field;
     873             :         memset(tr, 0, sizeof(Untransform));
     874          60 :         tr->sgprivate = node->sgprivate;
     875             : 
     876          60 :         CHECK_FIELD("Untransform", 0, GF_SG_VRML_MFNODE);
     877          60 :         tr->children = *(GF_ChildNodeItem **) field.far_ptr;
     878             : 
     879          60 :         return GF_TRUE;
     880             : }
     881             : 
     882             : 
     883         184 : static void TraverseUntransform(GF_Node *node, void *rs, Bool is_destroy)
     884             : {
     885         184 :         UntransformStack *stack = (UntransformStack *)gf_node_get_private(node);
     886             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     887             : 
     888         184 :         if (is_destroy) {
     889           3 :                 gf_free(stack);
     890           3 :                 return;
     891             :         }
     892             : 
     893         181 :         if (tr_state->traversing_mode==TRAVERSE_SORT) {
     894         181 :                 if (gf_node_dirty_get(node)) {
     895          57 :                         Untransform_GetNode(node, &stack->untr); /*lets place it below*/
     896          57 :                         gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     897             :                 }
     898             :         }
     899             : 
     900             : #ifndef GPAC_DISABLE_3D
     901         181 :         if (tr_state->visual->type_3d) {
     902             :                 GF_Matrix mx_model;
     903             :                 GF_Camera backup_cam;
     904             : 
     905           0 :                 if (!tr_state->camera) return;
     906             : 
     907           0 :                 gf_mx_copy(mx_model, tr_state->model_matrix);
     908           0 :                 gf_mx_init(tr_state->model_matrix);
     909             : 
     910             :                 memcpy(&backup_cam, tr_state->camera, sizeof(GF_Camera));
     911             : 
     912           0 :                 camera_invalidate(tr_state->camera);
     913           0 :                 tr_state->camera->is_3D = GF_FALSE;
     914           0 :                 tr_state->camera->flags |= CAM_NO_LOOKAT;
     915           0 :                 tr_state->camera->end_zoom = FIX_ONE;
     916           0 :                 camera_update(tr_state->camera, NULL, GF_TRUE);
     917             : 
     918             : 
     919           0 :                 if (tr_state->traversing_mode == TRAVERSE_SORT) {
     920           0 :                         visual_3d_set_viewport(tr_state->visual, tr_state->camera->proj_vp);
     921           0 :                         visual_3d_projection_matrix_modified(tr_state->visual);
     922             : 
     923           0 :                         gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);
     924             : 
     925             :                         gf_mx_copy(tr_state->model_matrix, mx_model);
     926           0 :                         memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
     927             : 
     928           0 :                         visual_3d_projection_matrix_modified(tr_state->visual);
     929             : 
     930           0 :                         visual_3d_set_viewport(tr_state->visual, tr_state->camera->proj_vp);
     931           0 :                 } else if (tr_state->traversing_mode == TRAVERSE_PICK) {
     932           0 :                         Fixed prev_dist = tr_state->visual->compositor->hit_square_dist;
     933           0 :                         GF_Ray r = tr_state->ray;
     934           0 :                         tr_state->ray.orig.x = INT2FIX(tr_state->pick_x);
     935           0 :                         tr_state->ray.orig.y = INT2FIX(tr_state->pick_y);
     936           0 :                         tr_state->ray.orig.z = 0;
     937           0 :                         tr_state->ray.dir.x = 0;
     938           0 :                         tr_state->ray.dir.y = 0;
     939           0 :                         tr_state->ray.dir.z = -FIX_ONE;
     940           0 :                         tr_state->visual->compositor->hit_square_dist=0;
     941             : 
     942           0 :                         gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);
     943             : 
     944             :                         gf_mx_copy(tr_state->model_matrix, mx_model);
     945           0 :                         memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
     946           0 :                         tr_state->ray = r;
     947             : 
     948             :                         /*nothing picked, restore previous pick*/
     949           0 :                         if (!tr_state->visual->compositor->hit_square_dist)
     950           0 :                                 tr_state->visual->compositor->hit_square_dist = prev_dist;
     951             : 
     952             :                 } else {
     953           0 :                         gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);
     954             : 
     955             :                         gf_mx_copy(tr_state->model_matrix, mx_model);
     956           0 :                         memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
     957             :                 }
     958             : 
     959             :         } else
     960             : #endif
     961             :         {
     962             :                 GF_Matrix2D mx2d_backup;
     963         181 :                 gf_mx2d_copy(mx2d_backup, tr_state->transform);
     964         181 :                 gf_mx2d_init(tr_state->transform);
     965             : 
     966         181 :                 group_2d_traverse((GF_Node *)&stack->untr, (GroupingNode2D *)stack, tr_state);
     967             : 
     968             :                 gf_mx2d_copy(tr_state->transform, mx2d_backup);
     969             : 
     970             : 
     971             :         }
     972             : }
     973             : 
     974           3 : void compositor_init_untransform(GF_Compositor *compositor, GF_Node *node)
     975             : {
     976             :         Untransform tr;
     977           3 :         if (Untransform_GetNode(node, &tr)) {
     978             :                 UntransformStack *stack;
     979           3 :                 GF_SAFEALLOC(stack, UntransformStack);
     980           3 :                 if (!stack) {
     981           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate untransform stack\n"));
     982           0 :                         return;
     983             :                 }
     984           3 :                 gf_node_set_private(node, stack);
     985           3 :                 gf_node_set_callback_function(node, TraverseUntransform);
     986           3 :                 stack->untr = tr;
     987           3 :                 gf_node_proto_set_grouping(node);
     988             :         }
     989             : }
     990             : 
     991             : 
     992             : 
     993             : /*StyleGroup: overrides appearance of all children*/
     994             : typedef struct
     995             : {
     996             :         BASE_NODE
     997             :         CHILDREN
     998             : 
     999             :         GF_Node *appearance;
    1000             : } StyleGroup;
    1001             : 
    1002             : typedef struct
    1003             : {
    1004             :         GROUPING_MPEG4_STACK_2D
    1005             :         StyleGroup sg;
    1006             : } StyleGroupStack;
    1007             : 
    1008         710 : static Bool StyleGroup_GetNode(GF_Node *node, StyleGroup *sg)
    1009             : {
    1010             :         GF_FieldInfo field;
    1011             :         memset(sg, 0, sizeof(StyleGroup));
    1012         710 :         sg->sgprivate = node->sgprivate;
    1013             : 
    1014         710 :         CHECK_FIELD("StyleGroup", 0, GF_SG_VRML_MFNODE);
    1015         710 :         sg->children = *(GF_ChildNodeItem **) field.far_ptr;
    1016             : 
    1017         710 :         CHECK_FIELD("StyleGroup", 1, GF_SG_VRML_SFNODE);
    1018         710 :         sg->appearance = *(GF_Node **)field.far_ptr;
    1019             : 
    1020         710 :         return GF_TRUE;
    1021             : }
    1022             : 
    1023             : 
    1024         710 : static void TraverseStyleGroup(GF_Node *node, void *rs, Bool is_destroy)
    1025             : {
    1026             :         Bool set = GF_FALSE;
    1027         710 :         StyleGroupStack *stack = (StyleGroupStack *)gf_node_get_private(node);
    1028             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
    1029             : 
    1030         710 :         if (is_destroy) {
    1031          73 :                 gf_free(stack);
    1032          73 :                 return;
    1033             :         }
    1034             : 
    1035         637 :         if (tr_state->traversing_mode==TRAVERSE_SORT) {
    1036         637 :                 if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
    1037             : 
    1038          26 :                         gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
    1039             :                         /*flag is not set for PROTO*/
    1040          26 :                         gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
    1041             :                 }
    1042             :         }
    1043         637 :         StyleGroup_GetNode(node, &stack->sg);
    1044             : 
    1045         637 :         if (!tr_state->override_appearance) {
    1046             :                 set = GF_TRUE;
    1047         637 :                 tr_state->override_appearance = stack->sg.appearance;
    1048             :         }
    1049         637 :         group_2d_traverse((GF_Node *)&stack->sg, (GroupingNode2D*)stack, tr_state);
    1050             : 
    1051         637 :         if (set) {
    1052         637 :                 tr_state->override_appearance = NULL;
    1053             :         }
    1054             : }
    1055             : 
    1056          73 : void compositor_init_style_group(GF_Compositor *compositor, GF_Node *node)
    1057             : {
    1058             :         StyleGroup sg;
    1059          73 :         if (StyleGroup_GetNode(node, &sg)) {
    1060             :                 StyleGroupStack *stack;
    1061          73 :                 GF_SAFEALLOC(stack, StyleGroupStack);
    1062          73 :                 if (!stack) {
    1063           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate style group stack\n"));
    1064           0 :                         return;
    1065             :                 }
    1066          73 :                 gf_node_set_private(node, stack);
    1067          73 :                 gf_node_set_callback_function(node, TraverseStyleGroup);
    1068          73 :                 stack->sg = sg;
    1069          73 :                 gf_node_proto_set_grouping(node);
    1070             :         } else {
    1071           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Unable to initialize style group\n"));
    1072             :         }
    1073             : }
    1074             : 
    1075             : 
    1076             : 
    1077             : /*TestSensor: tests eventIn/eventOuts for hardcoded proto*/
    1078             : typedef struct
    1079             : {
    1080             :         BASE_NODE
    1081             : 
    1082             :         Bool onTrigger;
    1083             :         Fixed value;
    1084             : } TestSensor;
    1085             : 
    1086             : typedef struct
    1087             : {
    1088             :         TestSensor ts;
    1089             : } TestSensorStack;
    1090             : 
    1091           6 : static Bool TestSensor_GetNode(GF_Node *node, TestSensor *ts)
    1092             : {
    1093             :         GF_FieldInfo field;
    1094             :         memset(ts, 0, sizeof(TestSensor));
    1095           6 :         ts->sgprivate = node->sgprivate;
    1096             : 
    1097           6 :         CHECK_FIELD("TestSensor", 0, GF_SG_VRML_SFBOOL);
    1098           6 :         if (field.eventType != GF_SG_EVENT_IN) return GF_FALSE;
    1099           6 :         ts->onTrigger = *(SFBool *)field.far_ptr;
    1100             : 
    1101           6 :         CHECK_FIELD("TestSensor", 1, GF_SG_VRML_SFFLOAT);
    1102           6 :         if (field.eventType != GF_SG_EVENT_EXPOSED_FIELD) return GF_FALSE;
    1103           6 :         ts->value = *(SFFloat *)field.far_ptr;
    1104             : 
    1105           6 :         CHECK_FIELD("TestSensor", 2, GF_SG_VRML_SFFLOAT);
    1106           6 :         if (field.eventType != GF_SG_EVENT_OUT) return GF_FALSE;
    1107             : 
    1108           6 :         return GF_TRUE;
    1109             : }
    1110             : 
    1111             : 
    1112          50 : static void TraverseTestSensor(GF_Node *node, void *rs, Bool is_destroy)
    1113             : {
    1114          50 :         TestSensorStack *stack = (TestSensorStack *)gf_node_get_private(node);
    1115             : 
    1116          50 :         if (is_destroy) {
    1117           1 :                 gf_free(stack);
    1118           1 :                 return;
    1119             :         }
    1120             : }
    1121             : 
    1122           5 : void TestSensor_OnTrigger(GF_Node *node, struct _route *route)
    1123             : {
    1124             :         GF_FieldInfo field;
    1125             :         Fixed value;
    1126           5 :         TestSensorStack *stack = (TestSensorStack *)gf_node_get_private(node);
    1127           5 :         TestSensor_GetNode(node, &stack->ts);
    1128             : 
    1129           5 :         if (stack->ts.onTrigger) {
    1130           3 :                 value = stack->ts.value;
    1131             :         } else {
    1132           2 :                 value = 1-stack->ts.value;
    1133             :         }
    1134             : 
    1135           5 :         gf_node_get_field(node, 2, &field);
    1136           5 :         *(SFFloat*)field.far_ptr = value;
    1137           5 :         gf_node_event_out(node, 2);
    1138           5 : }
    1139             : 
    1140           1 : void compositor_init_test_sensor(GF_Compositor *compositor, GF_Node *node)
    1141             : {
    1142             :         TestSensor ts;
    1143           1 :         if (TestSensor_GetNode(node, &ts)) {
    1144             :                 GF_Err e;
    1145             :                 TestSensorStack *stack;
    1146           1 :                 GF_SAFEALLOC(stack, TestSensorStack);
    1147           1 :                 if (!stack) {
    1148           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate test sensor stack\n"));
    1149           0 :                         return;
    1150             :                 }
    1151           1 :                 gf_node_set_private(node, stack);
    1152           1 :                 gf_node_set_callback_function(node, TraverseTestSensor);
    1153           1 :                 stack->ts = ts;
    1154             : 
    1155           1 :                 e = gf_node_set_proto_eventin_handler(node, 0, TestSensor_OnTrigger);
    1156           1 :                 if (e) {
    1157           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to initialize Proto TestSensor callback: %s\n", gf_error_to_string(e) ));
    1158             :                 }
    1159             :         } else {
    1160           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unable to initialize test sensor\n"));
    1161             :         }
    1162             : }
    1163             : 
    1164             : 
    1165             : /*CustomTexture: tests defining new (openGL) textures*/
    1166             : typedef struct
    1167             : {
    1168             :     BASE_NODE
    1169             :     
    1170             :     Fixed intensity;
    1171             : } CustomTexture;
    1172             : 
    1173             : typedef struct
    1174             : {
    1175             :     CustomTexture tx;
    1176             :     GF_TextureHandler txh;
    1177             :     u32 gl_id;
    1178             :     Bool disabled;
    1179             : } CustomTextureStack;
    1180             : 
    1181         152 : static Bool CustomTexture_GetNode(GF_Node *node, CustomTexture *tx)
    1182             : {
    1183             :     GF_FieldInfo field;
    1184             :     memset(tx, 0, sizeof(CustomTexture));
    1185         152 :     tx->sgprivate = node->sgprivate;
    1186             :     
    1187         152 :     CHECK_FIELD("CustomTexture", 0, GF_SG_VRML_SFFLOAT);
    1188         152 :         if (field.eventType != GF_SG_EVENT_EXPOSED_FIELD) return GF_FALSE;
    1189         152 :     tx->intensity = *(SFFloat *)field.far_ptr;
    1190             :     
    1191         152 :     return GF_TRUE;
    1192             : }
    1193             : 
    1194           1 : static void TraverseCustomTexture(GF_Node *node, void *rs, Bool is_destroy)
    1195             : {
    1196           1 :     CustomTextureStack *stack = (CustomTextureStack *)gf_node_get_private(node);
    1197             :     
    1198           1 :     if (is_destroy) {
    1199             :         //release texture object
    1200           1 :         gf_sc_texture_destroy(&stack->txh);
    1201           1 :         gf_free(stack);
    1202           1 :         return;
    1203             :     }
    1204             : }
    1205             : 
    1206             : #ifndef GPAC_DISABLE_3D
    1207             : #include "gl_inc.h"
    1208             : #endif
    1209             : 
    1210         151 : static void CustomTexture_update(GF_TextureHandler *txh)
    1211             : {
    1212             : #ifndef GPAC_DISABLE_3D
    1213             :     u8 data[16];
    1214             : #endif
    1215         151 :     CustomTextureStack *stack = gf_node_get_private(txh->owner);
    1216             :     //alloc texture
    1217         151 :     if (!txh->tx_io) {
    1218             :         //allocate texture
    1219           1 :         gf_sc_texture_allocate(txh);
    1220           1 :         if (!txh->tx_io) return;
    1221             :     }
    1222         151 :     if (stack->disabled) return;
    1223             :     
    1224             : #ifndef GPAC_DISABLE_3D
    1225             :     //texture not setup, do it
    1226         151 :     if (! gf_sc_texture_get_gl_id(txh)) {
    1227             :         
    1228             :         //setup some defaults (these two vars are used to setup internal texture format)
    1229             :         //in our case we only want to test openGL so no need to fill in the texture width/height stride
    1230             :         //since we will upload ourselves the texture
    1231           1 :         txh->transparent = 0;
    1232           1 :         txh->pixelformat = GF_PIXEL_RGB;
    1233             : 
    1234             :         //signaling we modified associated data (even if no data in our case) to mark texture as dirty
    1235           1 :         gf_sc_texture_set_data(txh);
    1236             :         
    1237             :         //trigger HW setup of the texture
    1238           1 :         gf_sc_texture_push_image(txh, GF_FALSE, GF_FALSE);
    1239             :         
    1240             :         //OK we have a valid textureID
    1241           1 :         stack->gl_id = gf_sc_texture_get_gl_id(txh);
    1242             :     }
    1243             : #endif
    1244             : 
    1245             : 
    1246             :     //get current value of node->value
    1247         151 :     CustomTexture_GetNode(txh->owner, &stack->tx);
    1248             : 
    1249             : #ifndef GPAC_DISABLE_3D
    1250             :     //setup our texture data
    1251             :     memset(data, 0, sizeof(char)*12);
    1252         151 :     data[0] = (u8) (0xFF * FIX2FLT(stack->tx.intensity)); //first pixel red modulated by intensity
    1253         151 :     data[4] = (u8) (0xFF * FIX2FLT(stack->tx.intensity)); //second pixel green
    1254         151 :     data[8] = (u8) (0xFF * FIX2FLT(stack->tx.intensity)); //third pixel blue
    1255             :     //last pixel black
    1256             :     
    1257         151 :     glBindTexture( GL_TEXTURE_2D, stack->gl_id);
    1258         151 :     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    1259             :     
    1260             : #endif
    1261             :  
    1262             : }
    1263             : 
    1264           1 : void compositor_init_custom_texture(GF_Compositor *compositor, GF_Node *node)
    1265             : {
    1266             :     CustomTexture tx;
    1267           1 :     if (CustomTexture_GetNode(node, &tx)) {
    1268             :         CustomTextureStack *stack;
    1269           1 :         GF_SAFEALLOC(stack, CustomTextureStack);
    1270           1 :                 if (!stack) {
    1271           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate custom texture group stack\n"));
    1272           0 :                         return;
    1273             :                 }
    1274           1 :         gf_node_set_private(node, stack);
    1275           1 :         gf_node_set_callback_function(node, TraverseCustomTexture);
    1276           1 :         stack->tx = tx;
    1277             : 
    1278           1 :                 if (!gf_sc_check_gl_support(compositor)) {
    1279           0 :                         stack->disabled = GF_TRUE;
    1280           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Driver disabled, cannot render custom texture test\n"));
    1281             :                         return;
    1282             :                 }
    1283             :         //register texture object
    1284           1 :         gf_sc_texture_setup(&stack->txh, compositor, node);
    1285           1 :         stack->txh.update_texture_fcnt = CustomTexture_update;
    1286             :     
    1287             :     } else {
    1288           0 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unable to initialize custom texture\n"));
    1289             :     }
    1290             : }
    1291             : 
    1292             : #ifndef GPAC_DISABLE_3D
    1293             : 
    1294           0 : static void TraverseVRGeometry(GF_Node *node, void *rs, Bool is_destroy)
    1295             : {
    1296             :         GF_TextureHandler *txh;
    1297             :         GF_MediaObjectVRInfo vrinfo;
    1298             :         GF_MeshSphereAngles sphere_angles;
    1299             :         Bool mesh_was_reset = GF_FALSE;
    1300             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
    1301           0 :         Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);
    1302             : 
    1303           0 :         if (is_destroy) {
    1304           0 :                 drawable_3d_del(node);
    1305           0 :                 return;
    1306             :         }
    1307             : 
    1308           0 :         if (!tr_state->appear || ! ((M_Appearance *)tr_state->appear)->texture)
    1309             :                 return;
    1310             :         
    1311           0 :         txh = gf_sc_texture_get_handler( ((M_Appearance *) tr_state->appear)->texture );
    1312           0 :         if (!txh->stream) return;
    1313             : 
    1314           0 :         if (gf_node_dirty_get(node) || (tr_state->traversing_mode==TRAVERSE_DRAW_3D)) {
    1315           0 :                 if (! gf_mo_get_srd_info(txh->stream, &vrinfo))
    1316             :                         return;
    1317             : 
    1318           0 :                 if (vrinfo.has_full_coverage && tr_state->disable_partial_sphere) {
    1319           0 :                         if ((vrinfo.srd_w!=vrinfo.srd_max_x) || (vrinfo.srd_h!=vrinfo.srd_max_y))
    1320             :                                 return;
    1321             :                 }
    1322             : 
    1323           0 :                 sphere_angles.min_phi = -GF_PI2 + GF_PI * vrinfo.srd_y / vrinfo.srd_max_y;
    1324           0 :                 sphere_angles.max_phi = -GF_PI2 + GF_PI * (vrinfo.srd_h +  vrinfo.srd_y) / vrinfo.srd_max_y;
    1325             : 
    1326           0 :                 sphere_angles.min_theta = GF_2PI * vrinfo.srd_x / vrinfo.srd_max_x;
    1327           0 :                 sphere_angles.max_theta = GF_2PI * ( vrinfo.srd_w + vrinfo.srd_x ) / vrinfo.srd_max_x;
    1328             : 
    1329           0 :                 if (gf_node_dirty_get(node)) {
    1330             :                         u32 radius;
    1331           0 :                         mesh_reset(stack->mesh);
    1332             : 
    1333           0 :                         radius = MAX(vrinfo.scene_width, vrinfo.scene_height) / 4;
    1334             :                         //may happen that we don't have a scene width/height, use hardcoded 100 units radius (size actually doesn't matter
    1335             :                         //since our VP/camera is at the center of the sphere
    1336           0 :                         if (!radius) {
    1337             :                                 radius = 100;
    1338             :                         }
    1339             : 
    1340             :                         if (radius) {
    1341           0 :                                 mesh_new_sphere(stack->mesh, -1 * INT2FIX(radius), GF_FALSE, &sphere_angles);
    1342             : 
    1343           0 :                                 txh->flags &= ~GF_SR_TEXTURE_REPEAT_S;
    1344           0 :                                 txh->flags &= ~GF_SR_TEXTURE_REPEAT_T;
    1345             :                         }
    1346             :                         mesh_was_reset = GF_TRUE;
    1347           0 :                         gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
    1348             :                 }
    1349             :                 
    1350             :                 
    1351           0 :                 if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
    1352             :                         Bool visible = GF_FALSE;
    1353             : #ifndef GPAC_DISABLE_LOG
    1354           0 :                         const char *pid_name = gf_filter_pid_get_name(txh->stream->odm->pid);
    1355             : #endif
    1356           0 :                         if (! tr_state->camera_was_dirty && !mesh_was_reset) {
    1357           0 :                                 visible = (stack->mesh->flags & MESH_WAS_VISIBLE) ? GF_TRUE : GF_FALSE;
    1358           0 :                         } else if ((vrinfo.srd_w==vrinfo.srd_max_x) && (vrinfo.srd_h==vrinfo.srd_max_y)) {
    1359             :                                 visible = GF_TRUE;
    1360             :                         }
    1361           0 :                         else if (txh->compositor->tvtf) {
    1362             :                                 visible = GF_TRUE;
    1363             :                         //estimate visibility asap, even if texture not yet ready (we have SRD info):
    1364             :                         //this allows sending stop commands which will free inactive decoder HW context
    1365             :                         } else {
    1366             :                                 u32 i, j;
    1367             :                                 u32 nb_visible=0;
    1368           0 :                                 u32 nb_tests = tr_state->visual->compositor->tvtn;
    1369           0 :                                 u32 min_visible_threshold = tr_state->visual->compositor->tvtt;
    1370             :                                 u32 stride;
    1371             : 
    1372             :                                 //pick nb_tests vertices spaced every stride in the mesh
    1373           0 :                                 stride = stack->mesh->v_count;
    1374           0 :                                 stride /= nb_tests;
    1375           0 :                                 for (i=0; i<nb_tests; i++) {
    1376             :                                         Bool vis = GF_TRUE;
    1377           0 :                                         GF_Vec pt = stack->mesh->vertices[i*stride].pos;
    1378             :                                         //check the point is in our frustum - don't test far plane
    1379           0 :                                         for (j=1; j<6; j++) {
    1380           0 :                                                 Fixed d = gf_plane_get_distance(&tr_state->camera->planes[j], &pt);
    1381           0 :                                                 if (d<0) {
    1382             :                                                         vis = GF_FALSE;
    1383             :                                                         break;
    1384             :                                                 }
    1385             :                                         }
    1386           0 :                                         if (vis) {
    1387           0 :                                                 nb_visible++;
    1388             :                                                 //abort test if more visible points than our threshold
    1389           0 :                                                 if (nb_visible > min_visible_threshold)
    1390             :                                                         break;
    1391             :                                         }
    1392             :                                 }
    1393           0 :                                 if (nb_visible > min_visible_threshold) 
    1394             :                                         visible = GF_TRUE;
    1395           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %s Partial sphere is %s - %d sample points visible out of %d\n", pid_name, visible ? "visible" : "hidden",  nb_visible, i));
    1396             :                         }
    1397             : 
    1398           0 :                         if (visible) {
    1399           0 :                                 stack->mesh->flags |= MESH_WAS_VISIBLE;
    1400             :                         } else {
    1401           0 :                                 stack->mesh->flags &= ~MESH_WAS_VISIBLE;
    1402             :                         }
    1403             : 
    1404           0 :                         if (visible && (vrinfo.srd_w != vrinfo.srd_max_x) && tr_state->visual->compositor->gazer_enabled) {
    1405             :                                 s32 gx, gy;
    1406           0 :                                 tr_state->visual->compositor->hit_node = NULL;
    1407           0 :                                 tr_state->visual->compositor->hit_square_dist = 0;
    1408             : 
    1409             :                                 //gaze coords are 0,0 in top-left
    1410           0 :                                 gx = (s32)( tr_state->visual->compositor->gaze_x - tr_state->camera->width/2 );
    1411           0 :                                 gy = (s32)( tr_state->camera->height/2 - tr_state->visual->compositor->gaze_y );
    1412             : 
    1413           0 :                                 visual_3d_setup_ray(tr_state->visual, tr_state, gx, gy);
    1414           0 :                                 visual_3d_vrml_drawable_pick(node, tr_state, stack->mesh, NULL);
    1415           0 :                                 if (tr_state->visual->compositor->hit_node) {
    1416           0 :                                         GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %s Partial sphere is under gaze coord %d %d\n", pid_name, tr_state->visual->compositor->gaze_x, tr_state->visual->compositor->gaze_y));
    1417             : 
    1418           0 :                                         tr_state->visual->compositor->hit_node = NULL;
    1419             :                                 } else {
    1420             :                                         visible = GF_FALSE;
    1421             :                                 }
    1422             : 
    1423             :                         }
    1424             : 
    1425           0 :                         if (vrinfo.has_full_coverage) {
    1426           0 :                                 if (visible) {
    1427           0 :                                         if (!txh->is_open) {
    1428           0 :                                                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %s stoped on visible partial sphere - starting it\n", pid_name));
    1429             :                                                 assert(txh->stream && txh->stream->odm);
    1430           0 :                                                 txh->stream->odm->disable_buffer_at_next_play = GF_TRUE;
    1431           0 :                                                 txh->stream->odm->flags |= GF_ODM_TILED_SHARED_CLOCK;
    1432           0 :                                                 gf_sc_texture_play_from_to(txh, NULL, -1, -1, 1, 0);
    1433             :                                         }
    1434             : 
    1435           0 :                                         if (txh->data) {
    1436             :                                                 Bool do_show = GF_TRUE;
    1437           0 :                                                 Bool is_full_cover =  (vrinfo.srd_w == vrinfo.srd_max_x) ? GF_TRUE : GF_FALSE;
    1438           0 :                                                 visual_3d_enable_depth_buffer(tr_state->visual, GF_FALSE);
    1439           0 :                                                 visual_3d_enable_antialias(tr_state->visual, GF_FALSE);
    1440           0 :                                                 if ((tr_state->visual->compositor->tvtd == TILE_DEBUG_FULL) && !is_full_cover) do_show = GF_FALSE;
    1441           0 :                                                 else if ((tr_state->visual->compositor->tvtd == TILE_DEBUG_PARTIAL) && is_full_cover) do_show = GF_FALSE;
    1442             : 
    1443             :                                                 if (do_show) {
    1444           0 :                                                         visual_3d_draw(tr_state, stack->mesh);
    1445             :                                                 }
    1446           0 :                                                 visual_3d_enable_depth_buffer(tr_state->visual, GF_TRUE);
    1447             :                                         }
    1448             :                                 } else {
    1449           0 :                                         if (txh->is_open) {
    1450           0 :                                                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %s playing on hidden partial sphere - stopping it\n", pid_name));
    1451           0 :                                                 gf_sc_texture_stop_no_unregister(txh);
    1452             :                                         }
    1453             :                                 }
    1454             :                         } else {
    1455           0 :                                 if (txh->data) {
    1456           0 :                                         visual_3d_enable_depth_buffer(tr_state->visual, GF_FALSE);
    1457           0 :                                         visual_3d_enable_antialias(tr_state->visual, GF_FALSE);
    1458           0 :                                         visual_3d_draw(tr_state, stack->mesh);
    1459           0 :                                         visual_3d_enable_depth_buffer(tr_state->visual, GF_TRUE);
    1460             :                                 }
    1461           0 :                                 if (!tr_state->disable_partial_sphere) {
    1462           0 :                                         if (visible) {
    1463           0 :                                                 gf_mo_hint_quality_degradation(txh->stream, 0);
    1464             :                                         } else {
    1465           0 :                                                 gf_mo_hint_quality_degradation(txh->stream, 100);
    1466             :                                         }
    1467             :                                 }
    1468             :                         }
    1469             :                 }
    1470             :         }
    1471           0 :         if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
    1472           0 :                 tr_state->bbox = stack->mesh->bounds;
    1473             :         }
    1474             : }
    1475             : 
    1476             : 
    1477             : static void compositor_init_vr_geometry(GF_Compositor *compositor, GF_Node *node)
    1478             : {
    1479           0 :         drawable_3d_new(node);
    1480           0 :         gf_node_set_callback_function(node, TraverseVRGeometry);
    1481             : }
    1482             : 
    1483             : #define VRHUD_SCALE     6
    1484         154 : static void TraverseVRHUD(GF_Node *node, void *rs, Bool is_destroy)
    1485             : {
    1486             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
    1487             :         GF_Matrix mv_bck, proj_bck, cam_bck;
    1488             :         /*SFVec3f target;*/
    1489             :         GF_Rect vp, orig_vp;
    1490             :         u32 mode, i, cull_bck;
    1491             :         Fixed angle_yaw/*, angle_pitch*/;
    1492             :         SFVec3f axis;
    1493         154 :         GF_Node *subtree = gf_node_get_private(node);
    1494         308 :         if (is_destroy) return;
    1495             : 
    1496         152 :         if (!tr_state->camera) return;
    1497         150 :         mode = tr_state->visual->compositor->vrhud_mode;
    1498         150 :         if (!mode) return;
    1499             : 
    1500           0 :         gf_mx_copy(mv_bck, tr_state->model_matrix);
    1501           0 :         gf_mx_copy(cam_bck, tr_state->camera->modelview);
    1502             : 
    1503           0 :         tr_state->disable_partial_sphere = GF_TRUE;
    1504             :         /*target = tr_state->camera->target;*/
    1505           0 :         orig_vp = tr_state->camera->proj_vp;
    1506             : 
    1507             : /*
    1508             :         //compute pitch (elevation)
    1509             :         dlen = tr_state->camera->target.x*tr_state->camera->target.x + tr_state->camera->target.z*tr_state->camera->target.z;
    1510             :         dlen = gf_sqrt(dlen);
    1511             : */
    1512             : 
    1513             :         /*angle_pitch = gf_atan2(tr_state->camera->target.y, dlen);*/
    1514             : 
    1515             :         //compute yaw (rotation Y)
    1516           0 :         angle_yaw = gf_atan2(tr_state->camera->target.z, tr_state->camera->target.x);
    1517             : 
    1518             :         //compute axis for the pitch
    1519           0 :         axis = tr_state->camera->target;
    1520           0 :         axis.y=0;
    1521           0 :         gf_vec_norm(&axis);
    1522             : 
    1523           0 :         visual_3d_enable_depth_buffer(tr_state->visual, GF_FALSE);
    1524             : 
    1525           0 :         if (mode==2) {
    1526             :                 //rear mirror, reverse x-axis on projection
    1527           0 :                 tr_state->camera->projection.m[0] *= -1;
    1528           0 :                 visual_3d_projection_matrix_modified(tr_state->visual);
    1529             :                 //inverse backface culling
    1530           0 :                 tr_state->reverse_backface = GF_TRUE;
    1531             :                 vp = orig_vp;
    1532           0 :                 vp.width/=VRHUD_SCALE;
    1533           0 :                 vp.height/=VRHUD_SCALE;
    1534           0 :                 vp.x = orig_vp.x + (orig_vp.width-vp.width)/2;
    1535           0 :                 vp.y = orig_vp.y + orig_vp.height-vp.height;
    1536             : 
    1537           0 :                 visual_3d_set_viewport(tr_state->visual, vp);
    1538             : 
    1539           0 :                 gf_mx_add_rotation(&tr_state->model_matrix, GF_PI, tr_state->camera->up.x, tr_state->camera->up.y, tr_state->camera->up.z);
    1540           0 :                 gf_node_traverse(subtree, rs);
    1541           0 :                 tr_state->camera->projection.m[0] *= -1;
    1542           0 :                 visual_3d_projection_matrix_modified(tr_state->visual);
    1543           0 :         } else if (mode==1) {
    1544           0 :                 gf_mx_copy(proj_bck, tr_state->camera->projection);
    1545           0 :                 gf_mx_init(tr_state->camera->modelview);
    1546             : 
    1547             :                 //force projection with PI/2 fov and AR 1:1
    1548           0 :                 tr_state->camera->projection.m[0] = -1;
    1549           0 :                 tr_state->camera->projection.m[5] = 1;
    1550           0 :                 visual_3d_projection_matrix_modified(tr_state->visual);
    1551             :                 //force cull inside
    1552           0 :                 cull_bck = tr_state->cull_flag;
    1553           0 :                 tr_state->cull_flag = CULL_INSIDE;
    1554             :                 //inverse backface culling
    1555           0 :                 tr_state->reverse_backface = GF_TRUE;
    1556             : 
    1557             :                 //draw 3 viewports, each separated by PI/2 rotation
    1558           0 :                 for (i=0; i<3; i++) {
    1559             :                         vp = orig_vp;
    1560           0 :                         vp.height/=VRHUD_SCALE;
    1561             :                         vp.width=vp.height;
    1562             :                         //we reverse X in the projection, so reverse the viewports
    1563           0 :                         vp.x = orig_vp.x + orig_vp.width/2 - 3*vp.width/2 + (3-i-1)*vp.width;
    1564           0 :                         vp.y = orig_vp.y + orig_vp.height - vp.height;
    1565           0 :                         visual_3d_set_viewport(tr_state->visual, vp);
    1566           0 :                         tr_state->disable_cull = GF_TRUE;
    1567             : 
    1568           0 :                         gf_mx_init(tr_state->model_matrix);
    1569           0 :                         gf_mx_add_rotation(&tr_state->model_matrix, angle_yaw-GF_PI, 0, 1, 0);
    1570           0 :                         gf_mx_add_rotation(&tr_state->model_matrix, i*GF_PI2, 0, 1, 0);
    1571             : 
    1572           0 :                         gf_node_traverse(subtree, rs);
    1573             :                 }
    1574           0 :                 gf_mx_copy(tr_state->camera->projection, proj_bck);
    1575           0 :                 visual_3d_projection_matrix_modified(tr_state->visual);
    1576           0 :                 tr_state->cull_flag = cull_bck;
    1577           0 :                 gf_mx_copy(tr_state->camera->modelview, cam_bck);
    1578             :         }
    1579           0 :         else if ((mode==4) || (mode==3)) {
    1580             :                 // mirror, reverse x-axis on projection
    1581           0 :                 tr_state->camera->projection.m[0] *= -1;
    1582           0 :                 visual_3d_projection_matrix_modified(tr_state->visual);
    1583             :                 //inverse backface culling
    1584           0 :                 tr_state->reverse_backface = GF_TRUE;
    1585             : 
    1586             :                 //side left view
    1587           0 :                 vp = orig_vp;
    1588           0 :                 vp.width/=VRHUD_SCALE;
    1589           0 :                 vp.height/=VRHUD_SCALE;
    1590           0 :                 if (mode==3) {
    1591             :                         vp.x = orig_vp.x;
    1592             :                 } else {
    1593           0 :                         vp.x = orig_vp.x + orig_vp.width/2 - 2*vp.width;
    1594             :                 }
    1595           0 :                 vp.y = orig_vp.y + orig_vp.height - vp.height;
    1596           0 :                 visual_3d_set_viewport(tr_state->visual, vp);
    1597             : 
    1598           0 :                 gf_mx_add_rotation(&tr_state->model_matrix, -2*GF_PI/3, 0, 1, 0);
    1599             : 
    1600           0 :                 gf_node_traverse(subtree, rs);
    1601             : 
    1602             :                 //side right view
    1603           0 :                 if (mode==3) {
    1604           0 :                         vp.x = orig_vp.x + orig_vp.width - vp.width;
    1605             :                 } else {
    1606           0 :                         vp.x = orig_vp.x + orig_vp.width/2+vp.width;
    1607             :                 }
    1608           0 :                 visual_3d_set_viewport(tr_state->visual, vp);
    1609             : 
    1610             :                 gf_mx_copy(tr_state->model_matrix, mv_bck);
    1611           0 :                 gf_mx_add_rotation(&tr_state->model_matrix, 2*GF_PI/3, 0, 1, 0);
    1612             : 
    1613           0 :                 gf_node_traverse(subtree, rs);
    1614             : 
    1615           0 :                 if (mode==4) {
    1616             :                         //upper view
    1617           0 :                         vp.x = orig_vp.x + orig_vp.width/2 - vp.width;
    1618           0 :                         visual_3d_set_viewport(tr_state->visual, vp);
    1619             : 
    1620             :                         gf_mx_copy(tr_state->model_matrix, mv_bck);
    1621           0 :                         gf_mx_add_rotation(&tr_state->model_matrix, - GF_PI2, -axis.z, 0, axis.x);
    1622           0 :                         gf_node_traverse(subtree, rs);
    1623             : 
    1624             :                         //down view
    1625           0 :                         vp.x = orig_vp.x + orig_vp.width/2;
    1626           0 :                         visual_3d_set_viewport(tr_state->visual, vp);
    1627             : 
    1628             :                         gf_mx_copy(tr_state->model_matrix, mv_bck);
    1629           0 :                         gf_mx_add_rotation(&tr_state->model_matrix, GF_PI2, -axis.z, 0, axis.x);
    1630             : 
    1631           0 :                         gf_node_traverse(subtree, rs);
    1632             :                 }
    1633             : 
    1634           0 :                 tr_state->camera->projection.m[0] *= -1;
    1635           0 :                 visual_3d_projection_matrix_modified(tr_state->visual);
    1636             :         }
    1637             : 
    1638             :         //restore camera and VP
    1639             :         gf_mx_copy(tr_state->model_matrix, mv_bck);
    1640           0 :         visual_3d_set_viewport(tr_state->visual, orig_vp);
    1641           0 :         visual_3d_enable_depth_buffer(tr_state->visual, GF_TRUE);
    1642           0 :         tr_state->disable_partial_sphere = GF_FALSE;
    1643           0 :         tr_state->reverse_backface = GF_FALSE;
    1644             : }
    1645             : 
    1646           2 : void compositor_init_vrhud(GF_Compositor *compositor, GF_Node *node)
    1647             : {
    1648             :         GF_Node *n;
    1649           2 :         GF_SceneGraph *sg = gf_node_get_graph(node);
    1650           2 :         sg = gf_sg_get_parent(sg);
    1651             : 
    1652           2 :         n = gf_sg_find_node_by_name(sg, "DYN_TRANS");
    1653           2 :         if (!n) {
    1654           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Unable to initialize VRHUD group, no main scene\n"));
    1655             :         } else {
    1656           2 :                 gf_node_set_callback_function(node, TraverseVRHUD);
    1657           2 :                 gf_node_proto_set_grouping(node);
    1658           2 :                 gf_node_set_private(node, n);
    1659             :         }
    1660           2 : }
    1661             : 
    1662             : 
    1663             : #endif //GPAC_DISABLE_3D
    1664             : 
    1665             : /*hardcoded proto loading - this is mainly used for module development and testing...*/
    1666         359 : void gf_sc_init_hardcoded_proto(GF_Compositor *compositor, GF_Node *node)
    1667             : {
    1668             :         MFURL *proto_url;
    1669             :         GF_Proto *proto;
    1670             :         u32 i, j;
    1671             :         GF_HardcodedProto *ifce;
    1672             : 
    1673         359 :         proto = gf_node_get_proto(node);
    1674         711 :         if (!proto) return;
    1675         359 :         proto_url = gf_sg_proto_get_extern_url(proto);
    1676             : 
    1677         363 :         for (i=0; i<proto_url->count; i++) {
    1678         356 :                 const char *url = proto_url->vals[0].url;
    1679         356 :         if (!url) continue;
    1680             :         
    1681             : #ifndef GPAC_DISABLE_3D
    1682         356 :                 if (!strcmp(url, "urn:inet:gpac:builtin:PathExtrusion")) {
    1683             :                         compositor_init_path_extrusion(compositor, node);
    1684             :                         return;
    1685             :                 }
    1686         355 :                 if (!strcmp(url, "urn:inet:gpac:builtin:PlanarExtrusion")) {
    1687             :                         compositor_init_planar_extrusion(compositor, node);
    1688             :                         return;
    1689             :                 }
    1690         354 :                 if (!strcmp(url, "urn:inet:gpac:builtin:PlaneClipper")) {
    1691           2 :                         compositor_init_plane_clipper(compositor, node);
    1692           2 :                         return;
    1693             :                 }
    1694         352 :         if (!strcmp(url, "urn:inet:gpac:builtin:VRGeometry")) {
    1695             :             compositor_init_vr_geometry(compositor, node);
    1696             :             return;
    1697             :         }
    1698         352 :         if (!strcmp(url, "urn:inet:gpac:builtin:VRHUD")) {
    1699           2 :             compositor_init_vrhud(compositor, node);
    1700           2 :             return;
    1701             :         }
    1702             : #endif
    1703         350 :                 if (!strcmp(url, "urn:inet:gpac:builtin:OffscreenGroup")) {
    1704           3 :                         compositor_init_offscreen_group(compositor, node);
    1705           3 :                         return;
    1706             :                 }
    1707         347 :                 if (!strcmp(url, "urn:inet:gpac:builtin:DepthGroup")) {
    1708           1 :                         compositor_init_depth_group(compositor, node);
    1709           1 :                         return;
    1710             :                 }
    1711         346 :                 if (!strcmp(url, "urn:inet:gpac:builtin:DepthViewPoint")) {
    1712             :                         compositor_init_depth_viewpoint(compositor, node);
    1713             :                         return;
    1714             :                 }
    1715         345 :                 if (!strcmp(url, "urn:inet:gpac:builtin:IndexedCurve2D")) {
    1716             :                         compositor_init_idx_curve2d(compositor, node);
    1717             :                         return;
    1718             :                 }
    1719          82 :                 if (!strcmp(url, "urn:inet:gpac:builtin:Untransform")) {
    1720           3 :                         compositor_init_untransform(compositor, node);
    1721           3 :                         return;
    1722             :                 }
    1723          79 :                 if (!strcmp(url, "urn:inet:gpac:builtin:FlashShape")) {
    1724             : #ifdef GPAC_ENABLE_FLASHSHAPE
    1725             :                         compositor_init_hc_flashshape(compositor, node);
    1726             : #endif
    1727             :                         return;
    1728             :                 }
    1729          79 :                 if (!strcmp(url, "urn:inet:gpac:builtin:StyleGroup")) {
    1730          73 :                         compositor_init_style_group(compositor, node);
    1731          73 :                         return;
    1732             :                 }
    1733           6 :                 if (!strcmp(url, "urn:inet:gpac:builtin:TestSensor")) {
    1734           1 :                         compositor_init_test_sensor(compositor, node);
    1735           1 :                         return;
    1736             :                 }
    1737           5 :         if (!strcmp(url, "urn:inet:gpac:builtin:CustomTexture")) {
    1738           1 :             compositor_init_custom_texture(compositor, node);
    1739           1 :             return;
    1740             :         }
    1741             : 
    1742             : 
    1743             :                 /*check proto modules*/
    1744           4 :                 if (compositor->proto_modules) {
    1745           4 :                         j = 0;
    1746           8 :                         while ( (ifce = (GF_HardcodedProto *)gf_list_enum(compositor->proto_modules, &j) )) {
    1747           0 :                                 if ( ifce->can_load_proto(url) && ifce->init(ifce, compositor, node, url) ) {
    1748             :                                         return;
    1749             :                                 }
    1750             :                         }
    1751             :                 }
    1752             :         }
    1753             : 
    1754             : }
    1755             : 
    1756         306 : Bool gf_sc_uri_is_hardcoded_proto(GF_Compositor *compositor, const char *uri)
    1757             : {
    1758             :         /*check proto modules*/
    1759         306 :         if (compositor && compositor->proto_modules ) {
    1760         306 :                 u32 j = 0;
    1761             :                 GF_HardcodedProto *ifce;
    1762         612 :                 while ( (ifce = (GF_HardcodedProto *)gf_list_enum(compositor->proto_modules, &j) )) {
    1763           0 :                         if ( ifce->can_load_proto(uri)) {
    1764           0 :                                 return GF_TRUE;
    1765             :                         }
    1766             :                 }
    1767             :         }
    1768             :         return GF_FALSE;
    1769             : }
    1770             : 
    1771         302 : GF_TextureHandler *gf_sc_hardcoded_proto_get_texture_handler(GF_Node *n)
    1772             : {
    1773             :     
    1774             :     MFURL *proto_url;
    1775             :     GF_Proto *proto;
    1776             :     u32 i;
    1777             :     
    1778         302 :     proto = gf_node_get_proto(n);
    1779         302 :     if (!proto) return NULL;
    1780         302 :     proto_url = gf_sg_proto_get_extern_url(proto);
    1781             :     
    1782         302 :     for (i=0; i<proto_url->count; i++) {
    1783         302 :         const char *url = proto_url->vals[0].url;
    1784         302 :         if (!strcmp(url, "urn:inet:gpac:builtin:CustomTexture")) {
    1785         302 :             CustomTextureStack *stack = gf_node_get_private(n);
    1786         302 :             if (stack) return &stack->txh;
    1787             :         }
    1788             :     }
    1789             :     return NULL;
    1790             : }
    1791             : 
    1792             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13