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 :
|