LCOV - code coverage report
Current view: top level - scenegraph - vrml_route.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 199 227 87.7 %
Date: 2021-04-29 23:48:07 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Graph 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 <gpac/internal/scenegraph_dev.h>
      27             : /*MPEG4 & X3D tags (for node tables & script handling)*/
      28             : #include <gpac/nodes_mpeg4.h>
      29             : #include <gpac/nodes_x3d.h>
      30             : 
      31             : #ifndef GPAC_DISABLE_VRML
      32             : 
      33             : GF_Route* gf_sg_route_exists(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, GF_Node *toNode, u32 toField);
      34             : 
      35             : GF_EXPORT
      36       14227 : GF_Route *gf_sg_route_new(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, GF_Node *toNode, u32 toField)
      37             : {
      38             :         GF_Route *r;
      39       14227 :         if (!sg || !toNode || !fromNode) return NULL;
      40             : 
      41       14227 :         if ( (r = gf_sg_route_exists(sg, fromNode, fromField, toNode, toField)) )
      42             :                 return r;
      43             : 
      44       14222 :         GF_SAFEALLOC(r, GF_Route)
      45       14222 :         if (!r) return NULL;
      46       14222 :         r->FromNode = fromNode;
      47       14222 :         r->FromField.fieldIndex = fromField;
      48       14222 :         r->ToNode = toNode;
      49       14222 :         r->ToField.fieldIndex = toField;
      50       14222 :         r->graph = sg;
      51             : 
      52       14222 :         if (!fromNode->sgprivate->interact) {
      53        7038 :                 GF_SAFEALLOC(fromNode->sgprivate->interact, struct _node_interactive_ext);
      54        7038 :                 if (!fromNode->sgprivate->interact) {
      55           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create interact storage\n"));
      56           0 :                         gf_free(r);
      57           0 :                         return NULL;
      58             :                 }
      59             :         }
      60       14222 :         if (!fromNode->sgprivate->interact->routes) fromNode->sgprivate->interact->routes = gf_list_new();
      61       14222 :         gf_list_add(fromNode->sgprivate->interact->routes, r);
      62       14222 :         gf_list_add(sg->Routes, r);
      63       14222 :         return r;
      64             : }
      65             : 
      66       14227 : GF_Route* gf_sg_route_exists(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, GF_Node *toNode, u32 toField)
      67             : {
      68       14227 :         u32 i = 0;
      69             :         GF_Route* rt;
      70       14227 :         if ( !fromNode->sgprivate->interact || !fromNode->sgprivate->interact->routes )
      71             :                 return NULL;
      72             : 
      73       33678 :         while ( (rt = (GF_Route*)gf_list_enum(fromNode->sgprivate->interact->routes, &i) )) {
      74       26504 :                 if ( rt->FromField.fieldIndex == fromField && rt->ToNode == toNode && rt->ToField.fieldIndex == toField )
      75             :                         return rt;
      76             :         }
      77             :         return NULL;
      78             : }
      79             : 
      80             : GF_EXPORT
      81       15697 : void gf_sg_route_del(GF_Route *r)
      82             : {
      83             :         GF_SceneGraph *sg;
      84             : 
      85             :         /*remove declared routes*/
      86       15697 :         gf_list_del_item(r->graph->Routes, r);
      87             :         /*remove route from node - do this regardless of setup state since the route is registered upon creation*/
      88       15697 :         if (r->FromNode && r->FromNode->sgprivate->interact && r->FromNode->sgprivate->interact->routes) {
      89       15153 :                 gf_list_del_item(r->FromNode->sgprivate->interact->routes, r);
      90       15153 :                 if (!gf_list_count(r->FromNode->sgprivate->interact->routes)) {
      91        7642 :                         gf_list_del(r->FromNode->sgprivate->interact->routes);
      92        7642 :                         r->FromNode->sgprivate->interact->routes = NULL;
      93             :                 }
      94             :         }
      95             :         /*special case for script events: notify desdctruction*/
      96       15697 :         if (r->ToNode && (r->ToField.fieldType==GF_SG_VRML_SCRIPT_FUNCTION) && r->ToField.on_event_in) {
      97         236 :                 r->is_setup = 0;
      98         236 :                 r->FromNode = NULL;
      99         236 :                 if (!r->graph->pOwningProto) r->ToField.on_event_in(r->ToNode, r);
     100             :         }
     101             : 
     102       15697 :         r->is_setup = 0;
     103       15697 :         sg = r->graph;
     104       15697 :         while (sg->parent_scene) sg = sg->parent_scene;
     105       15697 :         gf_list_add(sg->routes_to_destroy, r);
     106       15697 :         gf_list_del_item(sg->routes_to_activate, r);
     107       15697 : }
     108             : 
     109             : GF_EXPORT
     110          38 : GF_Err gf_sg_route_del_by_id(GF_SceneGraph *sg,u32 routeID)
     111             : {
     112             :         GF_Route *r;
     113          38 :         if(!sg) return GF_BAD_PARAM;
     114          38 :         r = gf_sg_route_find(sg, routeID);
     115          38 :         if (!r) return GF_BAD_PARAM;
     116          37 :         gf_sg_route_del(r);
     117          37 :         return GF_OK;
     118             : }
     119             : 
     120       51988 : void gf_sg_destroy_routes(GF_SceneGraph *sg)
     121             : {
     122      119673 :         while (gf_list_count(sg->routes_to_destroy) ) {
     123       15697 :                 GF_Route *r = (GF_Route *)gf_list_get(sg->routes_to_destroy, 0);
     124       15697 :                 gf_list_rem(sg->routes_to_destroy, 0);
     125             :                 gf_sg_route_unqueue(sg, r);
     126       15697 :                 if (r->name) gf_free(r->name);
     127       15697 :                 gf_free(r);
     128             :         }
     129       51988 : }
     130             : 
     131             : 
     132       49960 : void gf_sg_route_queue(GF_SceneGraph *sg, GF_Route *r)
     133             : {
     134             :         u32 now;
     135       49960 :         if (!sg) return;
     136             : 
     137             :         /*get the top level scene (that's the only reliable one regarding simulatioin tick)*/
     138       59865 :         while (sg->parent_scene) sg = sg->parent_scene;
     139             :         /*a single route may not be activated more than once in a simulation tick*/
     140       49960 :         now = 1 + sg->simulation_tick;
     141       49960 :         if (r->lastActivateTime >= now) return;
     142       48440 :         r->lastActivateTime = now;
     143       48440 :         gf_list_add(sg->routes_to_activate, r);
     144             : }
     145             : 
     146             : /*activate all routes in the order they where triggered*/
     147             : GF_EXPORT
     148       46389 : void gf_sg_activate_routes(GF_SceneGraph *sg)
     149             : {
     150             :         GF_Route *r;
     151             :         GF_Node *targ;
     152       46389 :         if (!sg) return;
     153             : 
     154       46389 :         sg->simulation_tick++;
     155       46389 :         gf_sg_destroy_routes(sg);
     156             : 
     157      141200 :         while (gf_list_count(sg->routes_to_activate)) {
     158       48422 :                 r = (GF_Route *)gf_list_get(sg->routes_to_activate, 0);
     159       48422 :                 gf_list_rem(sg->routes_to_activate, 0);
     160       48422 :                 if (r) {
     161       48422 :                         targ = r->ToNode;
     162       48422 :                         if (gf_sg_route_activate(r)) {
     163             : #ifdef GF_SELF_REPLACE_ENABLE
     164             :                                 if (sg->graph_has_been_reset) {
     165             :                                         sg->graph_has_been_reset = 0;
     166             :                                         return;
     167             :                                 }
     168             : #endif
     169       46736 :                                 if (r->is_setup) gf_node_changed(targ, &r->ToField);
     170             :                         }
     171             :                 }
     172             :         }
     173             : }
     174             : 
     175           0 : void gf_sg_route_unqueue(GF_SceneGraph *sg, GF_Route *r)
     176             : {
     177             :         /*get the top level scene*/
     178       15697 :         while (sg->parent_scene) sg = sg->parent_scene;
     179             :         /*remove route from queue list*/
     180       15697 :         gf_list_del_item(sg->routes_to_activate, r);
     181           0 : }
     182             : 
     183             : GF_EXPORT
     184         182 : GF_Route *gf_sg_route_find(GF_SceneGraph *sg, u32 RouteID)
     185             : {
     186             :         GF_Route *r;
     187         182 :         u32 i=0;
     188         834 :         while ((r = (GF_Route*)gf_list_enum(sg->Routes, &i))) {
     189         527 :                 if (r->ID == RouteID) return r;
     190             :         }
     191             :         return NULL;
     192             : }
     193             : 
     194             : GF_EXPORT
     195         208 : GF_Route *gf_sg_route_find_by_name(GF_SceneGraph *sg, char *name)
     196             : {
     197             :         GF_Route *r;
     198             :         u32 i;
     199         208 :         if (!sg || !name) return NULL;
     200             : 
     201         208 :         i=0;
     202         873 :         while ((r = (GF_Route*)gf_list_enum(sg->Routes, &i))) {
     203         462 :                 if (r->name && !strcmp(r->name, name)) return r;
     204             :         }
     205             :         return NULL;
     206             : }
     207             : 
     208             : GF_EXPORT
     209          84 : GF_Err gf_sg_route_set_id(GF_Route *route, u32 ID)
     210             : {
     211             :         GF_Route *ptr;
     212          84 :         if (!route || !ID) return GF_BAD_PARAM;
     213             : 
     214          84 :         ptr = gf_sg_route_find(route->graph, ID);
     215          84 :         if (ptr) return GF_BAD_PARAM;
     216          84 :         route->ID = ID;
     217          84 :         return GF_OK;
     218             : }
     219             : 
     220             : #if 0 //unused
     221             : u32 gf_sg_route_get_id(GF_Route *route)
     222             : {
     223             :         return route->ID;
     224             : }
     225             : #endif
     226             : 
     227             : GF_EXPORT
     228          69 : GF_Err gf_sg_route_set_name(GF_Route *route, char *name)
     229             : {
     230             :         GF_Route *ptr;
     231          69 :         if (!name || !route) return GF_BAD_PARAM;
     232          69 :         ptr = gf_sg_route_find_by_name(route->graph, name);
     233          69 :         if (ptr) return GF_BAD_PARAM;
     234          69 :         if (route->name) gf_free(route->name);
     235          69 :         route->name = gf_strdup(name);
     236          69 :         return GF_OK;
     237             : }
     238             : 
     239             : GF_EXPORT
     240           3 : char *gf_sg_route_get_name(GF_Route *route)
     241             : {
     242           3 :         return route->name;
     243             : }
     244             : 
     245       10162 : void gf_sg_route_setup(GF_Route *r)
     246             : {
     247       10162 :         gf_node_get_field(r->FromNode, r->FromField.fieldIndex, &r->FromField);
     248       10162 :         gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &r->ToField);
     249       10162 :         switch (r->FromField.fieldType) {
     250          12 :         case GF_SG_VRML_MFNODE:
     251          12 :                 if (r->ToField.fieldType != GF_SG_VRML_MFNODE) return;
     252             :                 break;
     253          52 :         case GF_SG_VRML_SFNODE:
     254          52 :                 if (r->ToField.fieldType != GF_SG_VRML_SFNODE) return;
     255             :                 break;
     256             :         }
     257       10162 :         r->is_setup = 1;
     258             : }
     259             : 
     260             : /*send event out of proto - all ISed fields are ignored*/
     261       37835 : void gf_node_event_out_proto(GF_Node *node, u32 FieldIndex)
     262             : {
     263             :         u32 i;
     264             :         GF_Route *r;
     265       38595 :         if (!node) return;
     266             : 
     267       37835 :         if (!node->sgprivate->interact) return;
     268             : 
     269             :         //search for routes to activate in the order they where declared
     270       37075 :         i=0;
     271      318017 :         while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
     272      243867 :                 if (r->IS_route) continue;
     273       25690 :                 if (r->FromNode != node) continue;
     274       25690 :                 if (r->FromField.fieldIndex != FieldIndex) continue;
     275           0 :                 gf_sg_route_queue(node->sgprivate->scenegraph, r);
     276             :         }
     277             : }
     278             : 
     279       71110 : Bool gf_sg_route_activate(GF_Route *r)
     280             : {
     281             :         Bool ret;
     282             :         /*URL/String conversion clone*/
     283             :         void VRML_FieldCopyCast(void *dest, u32 dst_field_type, void *orig, u32 ori_field_type);
     284             :         assert(r->FromNode);
     285       71110 :         if (!r->is_setup) {
     286        9298 :                 gf_sg_route_setup(r);
     287        9298 :                 if (!r->is_setup) return 0;
     288             :                 /*special case when initing ISed routes on eventOuts: skip*/
     289        9298 :                 if (r->IS_route) {
     290        8506 :                         if (r->FromField.eventType == GF_SG_EVENT_OUT) return 0;
     291        7714 :                         if (r->ToField.eventType == GF_SG_EVENT_OUT) return 0;
     292             :                 }
     293       16220 :                 if (r->IS_route && ((r->ToNode->sgprivate->tag==TAG_MPEG4_Script)
     294             : #ifndef GPAC_DISABLE_X3D
     295        7714 :                                     || (r->ToNode->sgprivate->tag==TAG_X3D_Script)
     296             : #endif
     297           0 :                                    ) && ((r->ToField.eventType==GF_SG_EVENT_IN) /*|| (r->ToField.eventType==GF_SG_EVENT_FIELD)*/)
     298           0 :                         && r->FromField.eventType==GF_SG_EVENT_IN) {
     299             :                         return 0;
     300             :                 }
     301             :         }
     302             : #ifndef GPAC_DISABLE_LOG
     303       70318 :         if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) {
     304           0 :                 if (r->IS_route) {
     305           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[VRML Event] executing %s.%s IS %s.%s", gf_node_get_name(r->FromNode), r->FromField.name, gf_node_get_name(r->ToNode), r->ToField.name));
     306             :                 } else {
     307           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[VRML Event] executing ROUTE %s.%s TO %s.%s", gf_node_get_name(r->FromNode), r->FromField.name, gf_node_get_name(r->ToNode), r->ToField.name));
     308             :                 }
     309           0 :                 if (r->FromField.fieldType==GF_SG_VRML_SFBOOL) {
     310           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("\tBOOL VAL: %d\n", *((SFBool*)r->FromField.far_ptr)));
     311           0 :                 } else if (r->FromField.fieldType==GF_SG_VRML_SFINT32) {
     312           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("\tINT VAL: %d\n", *((SFInt32*)r->FromField.far_ptr)));
     313             :                 } else {
     314           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("\n"));
     315             :                 }
     316             :         }
     317             : #endif
     318             : 
     319             :         ret = 1;
     320       70318 :         switch (r->FromField.fieldType) {
     321          78 :         case GF_SG_VRML_SFNODE:
     322          78 :                 if (* (GF_Node **) r->ToField.far_ptr != * (GF_Node **) r->FromField.far_ptr) {
     323             :                         GF_Node *n = * (GF_Node **) r->ToField.far_ptr;
     324             :                         /*delete instance*/
     325          24 :                         if (n) gf_node_unregister(n, r->ToNode);
     326             :                         /*and use the node*/
     327          24 :                         * (GF_Node **) r->ToField.far_ptr = * (GF_Node **) r->FromField.far_ptr;
     328          24 :                         n = * (GF_Node **) r->FromField.far_ptr;
     329          24 :                         gf_node_register(n, r->ToNode);
     330             :                 }
     331             :                 break;
     332             : 
     333             :         /*move all pointers to dest*/
     334          18 :         case GF_SG_VRML_MFNODE:
     335             :         {
     336          18 :                 GF_ChildNodeItem *last = NULL;
     337          18 :                 GF_ChildNodeItem *orig = *(GF_ChildNodeItem **)r->FromField.far_ptr;
     338             : 
     339             :                 /*empty list*/
     340          18 :                 gf_node_unregister_children(r->ToNode, *(GF_ChildNodeItem **)r->ToField.far_ptr );
     341          18 :                 *(GF_ChildNodeItem **)r->ToField.far_ptr = NULL;
     342             : 
     343          42 :                 while (orig) {
     344           6 :                         gf_node_list_add_child_last( (GF_ChildNodeItem **)r->ToField.far_ptr, orig->node, &last);
     345           6 :                         gf_node_register(orig->node, r->ToNode);
     346           6 :                         orig = orig->next;
     347             :                 }
     348             :         }
     349          18 :         break;
     350             : 
     351       70222 :         default:
     352       70222 :                 if (r->ToField.fieldType==r->FromField.fieldType) {
     353             :                         /*if unchanged don't invalidate dst node*/
     354       69950 :                         if (gf_sg_vrml_field_equal(r->ToField.far_ptr, r->FromField.far_ptr, r->FromField.fieldType)) {
     355             :                                 ret = 0;
     356             :                         } else {
     357       51155 :                                 gf_sg_vrml_field_copy(r->ToField.far_ptr, r->FromField.far_ptr, r->FromField.fieldType);
     358             :                         }
     359             :                 }
     360             :                 /*typecast URL <-> string if needed*/
     361             :                 else {
     362         272 :                         VRML_FieldCopyCast(r->ToField.far_ptr, r->ToField.fieldType, r->FromField.far_ptr, r->FromField.fieldType);
     363             :                 }
     364             :                 break;
     365             :         }
     366             : 
     367             :         //don't notify dest change for generic function since the dest is not a node
     368       70318 :         if (r->ToField.fieldType==GF_SG_VRML_GENERIC_FUNCTION) {
     369             :                 ret = 0;
     370             :         }
     371             : 
     372             : #ifndef GPAC_DISABLE_LOG
     373       70318 :         if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) {
     374           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[VRML Route] field copy/casted\n"));
     375             :         }
     376             : #endif
     377             : 
     378             :         //if this is a supported eventIn call watcher
     379       70318 :         if (r->ToField.on_event_in) {
     380       24264 :                 r->ToField.on_event_in(r->ToNode, r);
     381             :         }
     382             :         //if this is a script eventIn call directly script
     383       92108 :         else if (((r->ToNode->sgprivate->tag==TAG_MPEG4_Script)
     384             : #ifndef GPAC_DISABLE_X3D
     385       46054 :                   || (r->ToNode->sgprivate->tag==TAG_X3D_Script)
     386             : #endif
     387        1759 :                  ) && ((r->ToField.eventType==GF_SG_EVENT_IN) /*|| (r->ToField.eventType==GF_SG_EVENT_FIELD)*/) ) {
     388        1759 :                 gf_sg_script_event_in(r->ToNode, &r->ToField);
     389             :         }
     390             :         //check if ISed or not - this will notify the node of any changes
     391             :         else {
     392       44295 :                 gf_sg_proto_propagate_event(r->ToNode, r->ToField.fieldIndex, r->FromNode);
     393             :                 /*if not an ISed field, propagate (otherwise ROUTE is executed just below)*/
     394       44295 :                 if (r->ToField.eventType != GF_SG_EVENT_EXPOSED_FIELD)
     395         120 :                         gf_sg_proto_propagate_event(r->ToNode, r->ToField.fieldIndex, r->FromNode);
     396             :                 /*only happen on proto, an eventOut may route to an eventOut*/
     397       44295 :                 if (r->IS_route && r->ToField.eventType==GF_SG_EVENT_OUT)
     398          98 :                         gf_node_event_out(r->ToNode, r->ToField.fieldIndex);
     399             :         }
     400             : 
     401             :         /*and signal routes on exposed fields if field changed*/
     402       70318 :         if (r->ToField.eventType == GF_SG_EVENT_EXPOSED_FIELD) {
     403       44175 :                 if (r->IS_route)
     404       20564 :                         gf_node_event_out_proto(r->ToNode, r->ToField.fieldIndex);
     405             :                 else
     406       23611 :                         gf_node_event_out(r->ToNode, r->ToField.fieldIndex);
     407             :         }
     408             : 
     409             : #ifndef GPAC_DISABLE_LOG
     410       70318 :         if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) {
     411           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[VRML Route] done executing (res %d)\n", ret));
     412             :         }
     413             : #endif
     414             : 
     415             :         return ret;
     416             : }
     417             : 
     418             : 
     419             : GF_EXPORT
     420      125467 : void gf_node_event_out(GF_Node *node, u32 FieldIndex)
     421             : {
     422             :         u32 i;
     423             :         GF_Route *r;
     424      183981 :         if (!node) return;
     425             : 
     426             :         /*node has no routes*/
     427      125467 :         if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
     428             : 
     429             :         //search for routes to activate in the order they where declared
     430       66953 :         i=0;
     431      226540 :         while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
     432       92634 :                 if (r->FromNode != node) continue;
     433       92634 :                 if (r->FromField.fieldIndex != FieldIndex) continue;
     434             : 
     435             :                 /*no postpone for IS routes*/
     436       46671 :                 if (r->IS_route) {
     437         278 :                         if (gf_sg_route_activate(r))
     438         277 :                                 gf_node_changed(r->ToNode, &r->ToField);
     439             :                 }
     440             :                 //queue
     441             :                 else {
     442       46393 :                         gf_sg_route_queue(node->sgprivate->scenegraph, r);
     443             :                 }
     444             :         }
     445             : }
     446             : 
     447             : GF_EXPORT
     448        1746 : void gf_node_event_out_str(GF_Node *node, const char *eventName)
     449             : {
     450             :         u32 i;
     451             :         GF_Route *r;
     452             : 
     453             :         /*node has no routes*/
     454        3492 :         if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
     455             : 
     456             :         //search for routes to activate in the order they where declared
     457           0 :         i=0;
     458           0 :         while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
     459           0 :                 if (!r->is_setup) gf_sg_route_setup(r);
     460           0 :                 if (stricmp(r->FromField.name, eventName)) continue;
     461             : 
     462             :                 //no postpone
     463           0 :                 if (r->IS_route) {
     464           0 :                         gf_sg_route_activate(r);
     465             :                 }
     466             :                 //queue
     467             :                 else {
     468           0 :                         gf_sg_route_queue(node->sgprivate->scenegraph, r);
     469             :                 }
     470             :         }
     471             : }
     472             : 
     473             : typedef struct
     474             : {
     475             :         GF_Route r;
     476             :         void ( *route_callback) (void *param, GF_FieldInfo *from_field);
     477             : } GF_RouteToFunction;
     478             : 
     479           1 : static void on_route_to_function(GF_Node *node, GF_Route *r)
     480             : {
     481             :         GF_RouteToFunction *rf = (GF_RouteToFunction *)r;
     482           1 :         rf->route_callback(r->ToNode, &r->FromField);
     483           1 : }
     484             : 
     485             : GF_EXPORT
     486         209 : void gf_sg_route_new_to_callback(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, void *cbk, void ( *route_callback) (void *param, GF_FieldInfo *from_field) )
     487             : {
     488             :         GF_Route *r;
     489             :         GF_RouteToFunction *rf;
     490         209 :         GF_SAFEALLOC(rf, GF_RouteToFunction);
     491         209 :         if (!rf) return;
     492         209 :         rf->route_callback = route_callback;
     493             : 
     494             :         r = (GF_Route *)rf;
     495         209 :         r->FromNode = fromNode;
     496         209 :         r->FromField.fieldIndex = fromField;
     497         209 :         gf_node_get_field(r->FromNode, fromField, &r->FromField);
     498             : 
     499         209 :         r->ToNode = (GF_Node *) cbk;
     500         209 :         r->ToField.fieldType = GF_SG_VRML_GENERIC_FUNCTION;
     501         209 :         r->ToField.on_event_in = on_route_to_function;
     502         209 :         r->ToField.eventType = GF_SG_EVENT_IN;
     503         209 :         r->ToField.far_ptr = NULL;
     504             : 
     505         209 :         r->is_setup = 1;
     506         209 :         r->graph = sg;
     507             : 
     508         209 :         if (!fromNode->sgprivate->interact) {
     509         209 :                 GF_SAFEALLOC(fromNode->sgprivate->interact, struct _node_interactive_ext);
     510         209 :                 if (!fromNode->sgprivate->interact) {
     511           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create interact storage\n"));
     512           0 :                         gf_free(r);
     513           0 :                         return;
     514             :                 }
     515             :         }
     516         209 :         if (!fromNode->sgprivate->interact->routes) fromNode->sgprivate->interact->routes = gf_list_new();
     517         209 :         gf_list_add(fromNode->sgprivate->interact->routes, r);
     518         209 :         gf_list_add(fromNode->sgprivate->scenegraph->Routes, r);
     519             : }
     520             : 
     521             : 
     522             : #endif  /*GPAC_DISABLE_VRML*/
     523             : 

Generated by: LCOV version 1.13