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
gf_sg_route_new(GF_SceneGraph * sg,GF_Node * fromNode,u32 fromField,GF_Node * toNode,u32 toField)36 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 	if (!sg || !toNode || !fromNode) return NULL;
40 
41 	if ( (r = gf_sg_route_exists(sg, fromNode, fromField, toNode, toField)) )
42 		return r;
43 
44 	GF_SAFEALLOC(r, GF_Route)
45 	if (!r) return NULL;
46 	r->FromNode = fromNode;
47 	r->FromField.fieldIndex = fromField;
48 	r->ToNode = toNode;
49 	r->ToField.fieldIndex = toField;
50 	r->graph = sg;
51 
52 	if (!fromNode->sgprivate->interact) {
53 		GF_SAFEALLOC(fromNode->sgprivate->interact, struct _node_interactive_ext);
54 		if (!fromNode->sgprivate->interact) {
55 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create interact storage\n"));
56 			gf_free(r);
57 			return NULL;
58 		}
59 	}
60 	if (!fromNode->sgprivate->interact->routes) fromNode->sgprivate->interact->routes = gf_list_new();
61 	gf_list_add(fromNode->sgprivate->interact->routes, r);
62 	gf_list_add(sg->Routes, r);
63 	return r;
64 }
65 
gf_sg_route_exists(GF_SceneGraph * sg,GF_Node * fromNode,u32 fromField,GF_Node * toNode,u32 toField)66 GF_Route* gf_sg_route_exists(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, GF_Node *toNode, u32 toField)
67 {
68 	u32 i = 0;
69 	GF_Route* rt;
70 	if ( !fromNode->sgprivate->interact || !fromNode->sgprivate->interact->routes )
71 		return NULL;
72 
73 	while ( (rt = (GF_Route*)gf_list_enum(fromNode->sgprivate->interact->routes, &i) )) {
74 		if ( rt->FromField.fieldIndex == fromField && rt->ToNode == toNode && rt->ToField.fieldIndex == toField )
75 			return rt;
76 	}
77 	return NULL;
78 }
79 
80 GF_EXPORT
gf_sg_route_del(GF_Route * r)81 void gf_sg_route_del(GF_Route *r)
82 {
83 	GF_SceneGraph *sg;
84 
85 	/*remove declared routes*/
86 	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 	if (r->FromNode && r->FromNode->sgprivate->interact && r->FromNode->sgprivate->interact->routes) {
89 		gf_list_del_item(r->FromNode->sgprivate->interact->routes, r);
90 		if (!gf_list_count(r->FromNode->sgprivate->interact->routes)) {
91 			gf_list_del(r->FromNode->sgprivate->interact->routes);
92 			r->FromNode->sgprivate->interact->routes = NULL;
93 		}
94 	}
95 	/*special case for script events: notify desdctruction*/
96 	if (r->ToNode && (r->ToField.fieldType==GF_SG_VRML_SCRIPT_FUNCTION) && r->ToField.on_event_in) {
97 		r->is_setup = 0;
98 		r->FromNode = NULL;
99 		if (!r->graph->pOwningProto) r->ToField.on_event_in(r->ToNode, r);
100 	}
101 
102 	r->is_setup = 0;
103 	sg = r->graph;
104 	while (sg->parent_scene) sg = sg->parent_scene;
105 	gf_list_add(sg->routes_to_destroy, r);
106 	gf_list_del_item(sg->routes_to_activate, r);
107 }
108 
109 GF_EXPORT
gf_sg_route_del_by_id(GF_SceneGraph * sg,u32 routeID)110 GF_Err gf_sg_route_del_by_id(GF_SceneGraph *sg,u32 routeID)
111 {
112 	GF_Route *r;
113 	if(!sg) return GF_BAD_PARAM;
114 	r = gf_sg_route_find(sg, routeID);
115 	if (!r) return GF_BAD_PARAM;
116 	gf_sg_route_del(r);
117 	return GF_OK;
118 }
119 
gf_sg_destroy_routes(GF_SceneGraph * sg)120 void gf_sg_destroy_routes(GF_SceneGraph *sg)
121 {
122 	while (gf_list_count(sg->routes_to_destroy) ) {
123 		GF_Route *r = (GF_Route *)gf_list_get(sg->routes_to_destroy, 0);
124 		gf_list_rem(sg->routes_to_destroy, 0);
125 		gf_sg_route_unqueue(sg, r);
126 		if (r->name) gf_free(r->name);
127 		gf_free(r);
128 	}
129 }
130 
131 
gf_sg_route_queue(GF_SceneGraph * sg,GF_Route * r)132 void gf_sg_route_queue(GF_SceneGraph *sg, GF_Route *r)
133 {
134 	u32 now;
135 	if (!sg) return;
136 
137 	/*get the top level scene (that's the only reliable one regarding simulatioin tick)*/
138 	while (sg->parent_scene) sg = sg->parent_scene;
139 	/*a single route may not be activated more than once in a simulation tick*/
140 	now = 1 + sg->simulation_tick;
141 	if (r->lastActivateTime >= now) return;
142 	r->lastActivateTime = now;
143 	gf_list_add(sg->routes_to_activate, r);
144 }
145 
146 /*activate all routes in the order they where triggered*/
147 GF_EXPORT
gf_sg_activate_routes(GF_SceneGraph * sg)148 void gf_sg_activate_routes(GF_SceneGraph *sg)
149 {
150 	GF_Route *r;
151 	GF_Node *targ;
152 	if (!sg) return;
153 
154 	sg->simulation_tick++;
155 	gf_sg_destroy_routes(sg);
156 
157 	while (gf_list_count(sg->routes_to_activate)) {
158 		r = (GF_Route *)gf_list_get(sg->routes_to_activate, 0);
159 		gf_list_rem(sg->routes_to_activate, 0);
160 		if (r) {
161 			targ = r->ToNode;
162 			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 				if (r->is_setup) gf_node_changed(targ, &r->ToField);
170 			}
171 		}
172 	}
173 }
174 
gf_sg_route_unqueue(GF_SceneGraph * sg,GF_Route * r)175 void gf_sg_route_unqueue(GF_SceneGraph *sg, GF_Route *r)
176 {
177 	/*get the top level scene*/
178 	while (sg->parent_scene) sg = sg->parent_scene;
179 	/*remove route from queue list*/
180 	gf_list_del_item(sg->routes_to_activate, r);
181 }
182 
183 GF_EXPORT
gf_sg_route_find(GF_SceneGraph * sg,u32 RouteID)184 GF_Route *gf_sg_route_find(GF_SceneGraph *sg, u32 RouteID)
185 {
186 	GF_Route *r;
187 	u32 i=0;
188 	while ((r = (GF_Route*)gf_list_enum(sg->Routes, &i))) {
189 		if (r->ID == RouteID) return r;
190 	}
191 	return NULL;
192 }
193 
194 GF_EXPORT
gf_sg_route_find_by_name(GF_SceneGraph * sg,char * name)195 GF_Route *gf_sg_route_find_by_name(GF_SceneGraph *sg, char *name)
196 {
197 	GF_Route *r;
198 	u32 i;
199 	if (!sg || !name) return NULL;
200 
201 	i=0;
202 	while ((r = (GF_Route*)gf_list_enum(sg->Routes, &i))) {
203 		if (r->name && !strcmp(r->name, name)) return r;
204 	}
205 	return NULL;
206 }
207 
208 GF_EXPORT
gf_sg_route_set_id(GF_Route * route,u32 ID)209 GF_Err gf_sg_route_set_id(GF_Route *route, u32 ID)
210 {
211 	GF_Route *ptr;
212 	if (!route || !ID) return GF_BAD_PARAM;
213 
214 	ptr = gf_sg_route_find(route->graph, ID);
215 	if (ptr) return GF_BAD_PARAM;
216 	route->ID = ID;
217 	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
gf_sg_route_set_name(GF_Route * route,char * name)228 GF_Err gf_sg_route_set_name(GF_Route *route, char *name)
229 {
230 	GF_Route *ptr;
231 	if (!name || !route) return GF_BAD_PARAM;
232 	ptr = gf_sg_route_find_by_name(route->graph, name);
233 	if (ptr) return GF_BAD_PARAM;
234 	if (route->name) gf_free(route->name);
235 	route->name = gf_strdup(name);
236 	return GF_OK;
237 }
238 
239 GF_EXPORT
gf_sg_route_get_name(GF_Route * route)240 char *gf_sg_route_get_name(GF_Route *route)
241 {
242 	return route->name;
243 }
244 
gf_sg_route_setup(GF_Route * r)245 void gf_sg_route_setup(GF_Route *r)
246 {
247 	gf_node_get_field(r->FromNode, r->FromField.fieldIndex, &r->FromField);
248 	gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &r->ToField);
249 	switch (r->FromField.fieldType) {
250 	case GF_SG_VRML_MFNODE:
251 		if (r->ToField.fieldType != GF_SG_VRML_MFNODE) return;
252 		break;
253 	case GF_SG_VRML_SFNODE:
254 		if (r->ToField.fieldType != GF_SG_VRML_SFNODE) return;
255 		break;
256 	}
257 	r->is_setup = 1;
258 }
259 
260 /*send event out of proto - all ISed fields are ignored*/
gf_node_event_out_proto(GF_Node * node,u32 FieldIndex)261 void gf_node_event_out_proto(GF_Node *node, u32 FieldIndex)
262 {
263 	u32 i;
264 	GF_Route *r;
265 	if (!node) return;
266 
267 	if (!node->sgprivate->interact) return;
268 
269 	//search for routes to activate in the order they where declared
270 	i=0;
271 	while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
272 		if (r->IS_route) continue;
273 		if (r->FromNode != node) continue;
274 		if (r->FromField.fieldIndex != FieldIndex) continue;
275 		gf_sg_route_queue(node->sgprivate->scenegraph, r);
276 	}
277 }
278 
gf_sg_route_activate(GF_Route * r)279 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 	if (!r->is_setup) {
286 		gf_sg_route_setup(r);
287 		if (!r->is_setup) return 0;
288 		/*special case when initing ISed routes on eventOuts: skip*/
289 		if (r->IS_route) {
290 			if (r->FromField.eventType == GF_SG_EVENT_OUT) return 0;
291 			if (r->ToField.eventType == GF_SG_EVENT_OUT) return 0;
292 		}
293 		if (r->IS_route && ((r->ToNode->sgprivate->tag==TAG_MPEG4_Script)
294 #ifndef GPAC_DISABLE_X3D
295 		                    || (r->ToNode->sgprivate->tag==TAG_X3D_Script)
296 #endif
297 		                   ) && ((r->ToField.eventType==GF_SG_EVENT_IN) /*|| (r->ToField.eventType==GF_SG_EVENT_FIELD)*/)
298 		        && r->FromField.eventType==GF_SG_EVENT_IN) {
299 			return 0;
300 		}
301 	}
302 #ifndef GPAC_DISABLE_LOG
303 	if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) {
304 		if (r->IS_route) {
305 			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 			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 		if (r->FromField.fieldType==GF_SG_VRML_SFBOOL) {
310 			GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("\tBOOL VAL: %d\n", *((SFBool*)r->FromField.far_ptr)));
311 		} else if (r->FromField.fieldType==GF_SG_VRML_SFINT32) {
312 			GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("\tINT VAL: %d\n", *((SFInt32*)r->FromField.far_ptr)));
313 		} else {
314 			GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("\n"));
315 		}
316 	}
317 #endif
318 
319 	ret = 1;
320 	switch (r->FromField.fieldType) {
321 	case GF_SG_VRML_SFNODE:
322 		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 			if (n) gf_node_unregister(n, r->ToNode);
326 			/*and use the node*/
327 			* (GF_Node **) r->ToField.far_ptr = * (GF_Node **) r->FromField.far_ptr;
328 			n = * (GF_Node **) r->FromField.far_ptr;
329 			gf_node_register(n, r->ToNode);
330 		}
331 		break;
332 
333 	/*move all pointers to dest*/
334 	case GF_SG_VRML_MFNODE:
335 	{
336 		GF_ChildNodeItem *last = NULL;
337 		GF_ChildNodeItem *orig = *(GF_ChildNodeItem **)r->FromField.far_ptr;
338 
339 		/*empty list*/
340 		gf_node_unregister_children(r->ToNode, *(GF_ChildNodeItem **)r->ToField.far_ptr );
341 		*(GF_ChildNodeItem **)r->ToField.far_ptr = NULL;
342 
343 		while (orig) {
344 			gf_node_list_add_child_last( (GF_ChildNodeItem **)r->ToField.far_ptr, orig->node, &last);
345 			gf_node_register(orig->node, r->ToNode);
346 			orig = orig->next;
347 		}
348 	}
349 	break;
350 
351 	default:
352 		if (r->ToField.fieldType==r->FromField.fieldType) {
353 			/*if unchanged don't invalidate dst node*/
354 			if (gf_sg_vrml_field_equal(r->ToField.far_ptr, r->FromField.far_ptr, r->FromField.fieldType)) {
355 				ret = 0;
356 			} else {
357 				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 			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 	if (r->ToField.fieldType==GF_SG_VRML_GENERIC_FUNCTION) {
369 		ret = 0;
370 	}
371 
372 #ifndef GPAC_DISABLE_LOG
373 	if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) {
374 		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 	if (r->ToField.on_event_in) {
380 		r->ToField.on_event_in(r->ToNode, r);
381 	}
382 	//if this is a script eventIn call directly script
383 	else if (((r->ToNode->sgprivate->tag==TAG_MPEG4_Script)
384 #ifndef GPAC_DISABLE_X3D
385 	          || (r->ToNode->sgprivate->tag==TAG_X3D_Script)
386 #endif
387 	         ) && ((r->ToField.eventType==GF_SG_EVENT_IN) /*|| (r->ToField.eventType==GF_SG_EVENT_FIELD)*/) ) {
388 		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 		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 		if (r->ToField.eventType != GF_SG_EVENT_EXPOSED_FIELD)
395 			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 		if (r->IS_route && r->ToField.eventType==GF_SG_EVENT_OUT)
398 			gf_node_event_out(r->ToNode, r->ToField.fieldIndex);
399 	}
400 
401 	/*and signal routes on exposed fields if field changed*/
402 	if (r->ToField.eventType == GF_SG_EVENT_EXPOSED_FIELD) {
403 		if (r->IS_route)
404 			gf_node_event_out_proto(r->ToNode, r->ToField.fieldIndex);
405 		else
406 			gf_node_event_out(r->ToNode, r->ToField.fieldIndex);
407 	}
408 
409 #ifndef GPAC_DISABLE_LOG
410 	if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) {
411 		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
gf_node_event_out(GF_Node * node,u32 FieldIndex)420 void gf_node_event_out(GF_Node *node, u32 FieldIndex)
421 {
422 	u32 i;
423 	GF_Route *r;
424 	if (!node) return;
425 
426 	/*node has no routes*/
427 	if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
428 
429 	//search for routes to activate in the order they where declared
430 	i=0;
431 	while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
432 		if (r->FromNode != node) continue;
433 		if (r->FromField.fieldIndex != FieldIndex) continue;
434 
435 		/*no postpone for IS routes*/
436 		if (r->IS_route) {
437 			if (gf_sg_route_activate(r))
438 				gf_node_changed(r->ToNode, &r->ToField);
439 		}
440 		//queue
441 		else {
442 			gf_sg_route_queue(node->sgprivate->scenegraph, r);
443 		}
444 	}
445 }
446 
447 GF_EXPORT
gf_node_event_out_str(GF_Node * node,const char * eventName)448 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 	if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
455 
456 	//search for routes to activate in the order they where declared
457 	i=0;
458 	while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
459 		if (!r->is_setup) gf_sg_route_setup(r);
460 		if (stricmp(r->FromField.name, eventName)) continue;
461 
462 		//no postpone
463 		if (r->IS_route) {
464 			gf_sg_route_activate(r);
465 		}
466 		//queue
467 		else {
468 			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 
on_route_to_function(GF_Node * node,GF_Route * r)479 static void on_route_to_function(GF_Node *node, GF_Route *r)
480 {
481 	GF_RouteToFunction *rf = (GF_RouteToFunction *)r;
482 	rf->route_callback(r->ToNode, &r->FromField);
483 }
484 
485 GF_EXPORT
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))486 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 	GF_SAFEALLOC(rf, GF_RouteToFunction);
491 	if (!rf) return;
492 	rf->route_callback = route_callback;
493 
494 	r = (GF_Route *)rf;
495 	r->FromNode = fromNode;
496 	r->FromField.fieldIndex = fromField;
497 	gf_node_get_field(r->FromNode, fromField, &r->FromField);
498 
499 	r->ToNode = (GF_Node *) cbk;
500 	r->ToField.fieldType = GF_SG_VRML_GENERIC_FUNCTION;
501 	r->ToField.on_event_in = on_route_to_function;
502 	r->ToField.eventType = GF_SG_EVENT_IN;
503 	r->ToField.far_ptr = NULL;
504 
505 	r->is_setup = 1;
506 	r->graph = sg;
507 
508 	if (!fromNode->sgprivate->interact) {
509 		GF_SAFEALLOC(fromNode->sgprivate->interact, struct _node_interactive_ext);
510 		if (!fromNode->sgprivate->interact) {
511 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create interact storage\n"));
512 			gf_free(r);
513 			return;
514 		}
515 	}
516 	if (!fromNode->sgprivate->interact->routes) fromNode->sgprivate->interact->routes = gf_list_new();
517 	gf_list_add(fromNode->sgprivate->interact->routes, r);
518 	gf_list_add(fromNode->sgprivate->scenegraph->Routes, r);
519 }
520 
521 
522 #endif	/*GPAC_DISABLE_VRML*/
523 
524