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 
27 #include <gpac/internal/scenegraph_dev.h>
28 /*MPEG4 & X3D tags (for node tables & script handling)*/
29 #include <gpac/nodes_mpeg4.h>
30 #include <gpac/nodes_x3d.h>
31 
32 #ifndef GPAC_DISABLE_VRML
33 
34 GF_EXPORT
gf_sg_proto_new(GF_SceneGraph * inScene,u32 ProtoID,char * name,Bool unregistered)35 GF_Proto *gf_sg_proto_new(GF_SceneGraph *inScene, u32 ProtoID, char *name, Bool unregistered)
36 {
37 	GF_Proto *tmp;
38 	if (!inScene) return NULL;
39 
40 	/*make sure we don't define a proto already defined in this scope*/
41 	if (!unregistered) {
42 		tmp = gf_sg_find_proto(inScene, ProtoID, name);
43 		if (tmp) {
44 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] PROTO %s redefined - skipping loading\n", name));
45 			return NULL;
46 		}
47 	}
48 
49 	GF_SAFEALLOC(tmp, GF_Proto)
50 	if (!tmp) return NULL;
51 
52 	tmp->proto_fields = gf_list_new();
53 	tmp->node_code = gf_list_new();
54 	tmp->parent_graph = inScene;
55 	tmp->sub_graph = gf_sg_new_subscene(inScene);
56 	tmp->instances = gf_list_new();
57 
58 	if (name)
59 		tmp->Name = gf_strdup(name);
60 	else
61 		tmp->Name = gf_strdup("Unnamed Proto");
62 	tmp->ID = ProtoID;
63 	if (!unregistered) {
64 		gf_list_add(inScene->protos, tmp);
65 	} else {
66 		gf_list_add(inScene->unregistered_protos, tmp);
67 	}
68 	return tmp;
69 }
70 
71 #if 0
72 /*used for memory handling of scene graph only. move proto from off-graph to in-graph or reverse*/
73 GF_Err gf_sg_proto_set_in_graph(GF_Proto *proto, GF_SceneGraph *inScene, Bool set_in)
74 {
75 	u32 i;
76 	GF_Proto *tmp;
77 	GF_List *removeFrom;
78 	GF_List *insertIn;
79 
80 	if (set_in) {
81 		removeFrom = proto->parent_graph->unregistered_protos;
82 		insertIn = proto->parent_graph->protos;
83 	} else {
84 		insertIn = proto->parent_graph->unregistered_protos;
85 		removeFrom = proto->parent_graph->protos;
86 	}
87 
88 	gf_list_del_item(removeFrom, proto);
89 
90 	i=0;
91 	while ((tmp = (GF_Proto*)gf_list_enum(insertIn, &i))) {
92 		if (tmp==proto) return GF_OK;
93 		if (!set_in) continue;
94 		/*if registering, make sure no other proto has the same ID/name*/
95 		if (tmp->ID==proto->ID) return GF_BAD_PARAM;
96 		if (!stricmp(tmp->Name, proto->Name)) return GF_BAD_PARAM;
97 	}
98 	return gf_list_add(insertIn, proto);
99 }
100 #endif
101 
102 GF_EXPORT
gf_sg_proto_del(GF_Proto * proto)103 GF_Err gf_sg_proto_del(GF_Proto *proto)
104 {
105 	s32 i;
106 
107 	if (!proto) return GF_OK;
108 	i = gf_list_del_item(proto->parent_graph->protos, proto);
109 	if (i<0) {
110 		gf_list_del_item(proto->parent_graph->unregistered_protos, proto);
111 	}
112 	if (proto->userpriv && proto->OnDelete) proto->OnDelete(proto->userpriv);
113 
114 	/*first destroy the code*/
115 	while (gf_list_count(proto->node_code)) {
116 		GF_Node *node = (GF_Node*)gf_list_get(proto->node_code, 0);
117 		gf_node_unregister(node, NULL);
118 		gf_list_rem(proto->node_code, 0);
119 	}
120 	gf_list_del(proto->node_code);
121 
122 	/*delete interface*/
123 	while (gf_list_count(proto->proto_fields)) {
124 		GF_ProtoFieldInterface *field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, 0);
125 		if (field->userpriv && field->OnDelete) field->OnDelete(field->userpriv);
126 
127 		if (field->FieldType==GF_SG_VRML_SFNODE) {
128 			if (field->def_sfnode_value)
129 				gf_node_unregister(field->def_sfnode_value, NULL);
130 		}
131 		else if (field->FieldType==GF_SG_VRML_MFNODE) {
132 			if (field->def_mfnode_value)
133 				gf_node_unregister_children(NULL, field->def_mfnode_value);
134 		}
135 		else if (field->def_value)
136 			gf_sg_vrml_field_pointer_del(field->def_value, field->FieldType);
137 
138 		if (field->FieldName) gf_free(field->FieldName);
139 
140 		/*QP fields are SF fields, we can safely gf_free() them*/
141 		if (field->qp_max_value) gf_free(field->qp_max_value);
142 		if (field->qp_min_value) gf_free(field->qp_min_value);
143 		gf_free(field);
144 		gf_list_rem(proto->proto_fields, 0);
145 	}
146 	gf_list_del(proto->proto_fields);
147 
148 	while (gf_list_count(proto->instances)) {
149 		GF_ProtoInstance *p = (GF_ProtoInstance *)gf_list_get(proto->instances, 0);
150 		gf_list_rem(proto->instances, 0);
151 		p->proto_interface = NULL;
152 	}
153 
154 	/*delete sub graph*/
155 	gf_sg_del(proto->sub_graph);
156 
157 
158 	if (proto->Name) gf_free(proto->Name);
159 	gf_sg_mfurl_del(proto->ExternProto);
160 	gf_list_del(proto->instances);
161 	gf_free(proto);
162 	return GF_OK;
163 }
164 
165 GF_EXPORT
gf_sg_proto_get_graph(GF_Proto * proto)166 GF_SceneGraph *gf_sg_proto_get_graph(GF_Proto *proto)
167 {
168 	return proto ? proto->sub_graph : NULL;
169 }
170 
171 
172 #if 0
173 void gf_sg_proto_set_private(GF_Proto *p, void *ptr, void (*OnDelete)(void *ptr) )
174 {
175 	if (p) {
176 		p->userpriv = ptr;
177 		p->OnDelete = OnDelete;
178 	}
179 }
180 
181 void *gf_sg_proto_get_private(GF_Proto *p)
182 {
183 	return p ? p->userpriv : NULL;
184 }
185 #endif
186 
187 GF_EXPORT
gf_sg_proto_get_extern_url(GF_Proto * proto)188 MFURL *gf_sg_proto_get_extern_url(GF_Proto *proto)
189 {
190 	return proto ? &proto->ExternProto : NULL;
191 }
192 
193 GF_EXPORT
gf_sg_proto_add_node_code(GF_Proto * proto,GF_Node * pNode)194 GF_Err gf_sg_proto_add_node_code(GF_Proto *proto, GF_Node *pNode)
195 {
196 	if (!proto) return GF_BAD_PARAM;
197 	return gf_list_add(proto->node_code, pNode);
198 }
199 
200 GF_EXPORT
gf_sg_proto_field_find_by_name(GF_Proto * proto,char * fieldName)201 GF_ProtoFieldInterface *gf_sg_proto_field_find_by_name(GF_Proto *proto, char *fieldName)
202 {
203 	GF_ProtoFieldInterface *ptr;
204 	u32 i=0;
205 	while ((ptr = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
206 		if (ptr->FieldName && !strcmp(ptr->FieldName, fieldName)) return ptr;
207 	}
208 	return NULL;
209 }
210 
211 GF_EXPORT
gf_sg_proto_field_new(GF_Proto * proto,u32 fieldType,u32 eventType,char * fieldName)212 GF_ProtoFieldInterface *gf_sg_proto_field_new(GF_Proto *proto, u32 fieldType, u32 eventType, char *fieldName)
213 {
214 	GF_ProtoFieldInterface *tmp;
215 
216 	if (fieldName) {
217 		tmp = gf_sg_proto_field_find_by_name(proto, fieldName);
218 		if (tmp) return NULL;
219 	}
220 	GF_SAFEALLOC(tmp, GF_ProtoFieldInterface)
221 	if (!tmp) return NULL;
222 
223 	tmp->FieldType = fieldType;
224 	tmp->EventType = eventType;
225 
226 	/*create container - can be NULL if SF node*/
227 	if ( fieldType == GF_SG_VRML_SFNODE) {
228 		tmp->def_sfnode_value = NULL;
229 		tmp->def_value = &tmp->def_sfnode_value;
230 	} else if ( fieldType == GF_SG_VRML_MFNODE) {
231 		tmp->def_mfnode_value = NULL;
232 		tmp->def_value = &tmp->def_mfnode_value;
233 	} else {
234 		tmp->def_value = gf_sg_vrml_field_pointer_new(fieldType);
235 	}
236 
237 	if (fieldName) tmp->FieldName = gf_strdup(fieldName);
238 
239 	tmp->ALL_index = gf_list_count(proto->proto_fields);
240 	tmp->OUT_index = tmp->DEF_index = tmp->IN_index = (u32) -1;
241 
242 	switch (eventType) {
243 	case GF_SG_EVENT_EXPOSED_FIELD:
244 		tmp->IN_index = proto->NumIn;
245 		proto->NumIn ++;
246 		tmp->OUT_index = proto->NumOut;
247 		proto->NumOut ++;
248 	case GF_SG_EVENT_FIELD:
249 		tmp->DEF_index = proto->NumDef;
250 		proto->NumDef ++;
251 		break;
252 	case GF_SG_EVENT_IN:
253 		tmp->IN_index = proto->NumIn;
254 		proto->NumIn ++;
255 		break;
256 	case GF_SG_EVENT_OUT:
257 		tmp->OUT_index = proto->NumOut;
258 		proto->NumOut ++;
259 		break;
260 	}
261 
262 	gf_list_add(proto->proto_fields, tmp);
263 	return tmp;
264 }
265 
266 #if 0 //unused
267 void gf_sg_proto_field_set_private(GF_ProtoFieldInterface *field, void *ptr, void (*OnDelete)(void *ptr))
268 {
269 	if (field) {
270 		field->userpriv = ptr;
271 		field->OnDelete = OnDelete;
272 	}
273 }
274 
275 void *gf_sg_proto_field_get_private(GF_ProtoFieldInterface *field)
276 {
277 	return field ? field->userpriv : NULL;
278 }
279 #endif
280 
281 GF_EXPORT
gf_sg_proto_field_get_field(GF_ProtoFieldInterface * field,GF_FieldInfo * info)282 GF_Err gf_sg_proto_field_get_field(GF_ProtoFieldInterface *field, GF_FieldInfo *info)
283 {
284 	if (!field || !info) return GF_BAD_PARAM;
285 	memset(info, 0, sizeof(GF_FieldInfo));
286 	info->fieldIndex = field->ALL_index;
287 	info->fieldType = field->FieldType;
288 	info->eventType = field->EventType;
289 	info->far_ptr = field->def_value;
290 	info->name = field->FieldName;
291 	info->NDTtype = NDT_SFWorldNode;
292 	return GF_OK;
293 }
294 
gf_sg_proto_get_field(GF_Proto * proto,GF_Node * node,GF_FieldInfo * info)295 GF_Err gf_sg_proto_get_field(GF_Proto *proto, GF_Node *node, GF_FieldInfo *info)
296 {
297 	GF_ProtoFieldInterface *proto_field;
298 	GF_ProtoInstance *inst;
299 	GF_ProtoField *field;
300 
301 	if (!proto && !node) return GF_BAD_PARAM;
302 
303 	if (proto) {
304 		proto_field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, info->fieldIndex);
305 		if (!proto_field) return GF_BAD_PARAM;
306 
307 		info->fieldType = proto_field->FieldType;
308 		info->eventType = proto_field->EventType;
309 		info->fieldIndex = proto_field->ALL_index;
310 		info->NDTtype = NDT_SFWorldNode;
311 		info->far_ptr = proto_field->def_value;
312 		info->name = proto_field->FieldName;
313 		return GF_OK;
314 	}
315 
316 	/*otherwise this is an instantiated proto*/
317 	if (node->sgprivate->tag!=TAG_ProtoNode) return GF_BAD_PARAM;
318 
319 	inst = (GF_ProtoInstance *) node;
320 	field = (GF_ProtoField*)gf_list_get(inst->fields, info->fieldIndex);
321 	if (!field) return GF_BAD_PARAM;
322 
323 	info->fieldType = field->FieldType;
324 	info->eventType = field->EventType;
325 	info->on_event_in = field->on_event_in;
326 	/*SF/MF nodes need pointers to field object - cf gf_sg_proto_create_node*/
327 	if (gf_sg_vrml_get_sf_type(field->FieldType) == GF_SG_VRML_SFNODE) {
328 		info->far_ptr = &field->field_pointer;
329 	} else {
330 		info->far_ptr = field->field_pointer;
331 	}
332 	/*set the name - watchout for deletion case*/
333 	if (inst->proto_interface) {
334 		proto_field = (GF_ProtoFieldInterface*)gf_list_get(inst->proto_interface->proto_fields, info->fieldIndex);
335 		info->name = proto_field->FieldName;
336 	} else {
337 		info->name = "ProtoFieldDeleted";
338 	}
339 	info->NDTtype = NDT_SFWorldNode;
340 	return GF_OK;
341 }
342 
gf_sg_proto_get_field_index_by_name(GF_Proto * proto,GF_Node * node,char * name)343 s32 gf_sg_proto_get_field_index_by_name(GF_Proto *proto, GF_Node *node, char *name)
344 {
345 	u32 i;
346 	GF_Proto *__proto=NULL;
347 
348 	if (!node && !proto) return -1;
349 	if (node && (node->sgprivate->tag!=TAG_ProtoNode)) return -1;
350 
351 	if (proto)
352 		__proto = proto;
353 	else if (node)
354 		__proto = ((GF_ProtoInstance *) node)->proto_interface;
355 
356 	if (!__proto ) return -1;
357 
358 	for (i=0; i<gf_list_count(__proto->proto_fields); i++) {
359 		GF_ProtoFieldInterface *proto_field = (GF_ProtoFieldInterface*)gf_list_get(__proto->proto_fields, i);
360 		if (proto_field->FieldName && !strcmp(proto_field->FieldName, name)) return i;
361 	}
362 	return -1;
363 }
364 
365 
gf_vrml_node_clone(GF_SceneGraph * inScene,GF_Node * orig,GF_Node * cloned_parent,char * inst_id_suffix)366 GF_Node *gf_vrml_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *cloned_parent, char *inst_id_suffix)
367 {
368 	u32 i, count, id;
369 	char *szNodeName;
370 	Bool is_script;
371 	GF_Node *node, *child;
372 	GF_ChildNodeItem *list, *last;
373 	GF_Route *r1;
374 #ifndef GPAC_DISABLE_BIFS
375 	void BIFS_SetupConditionalClone(GF_Node *node, GF_Node *orig);
376 #endif
377 	GF_ProtoInstance *proto;
378 	GF_FieldInfo field_orig, field;
379 
380 	/*this is not a mistake*/
381 	if (!orig) return NULL;
382 
383 	/*check for DEF/USE*/
384 	szNodeName = NULL;
385 	if (!inst_id_suffix) id = 0;
386 	else {
387 		const char *orig_name = gf_node_get_name_and_id(orig, &id);
388 		/*generate clone IDs based on original one*/
389 		if (inst_id_suffix[0] && id) {
390 			id = gf_sg_get_next_available_node_id(inScene);
391 			if (orig_name) {
392 				szNodeName = gf_malloc(sizeof(char)*(strlen(orig_name)+strlen(inst_id_suffix)+1));
393 				strcpy(szNodeName, orig_name);
394 				strcat(szNodeName, inst_id_suffix);
395 			}
396 		}
397 		else if (orig_name) szNodeName = gf_strdup(orig_name);
398 	}
399 
400 	if (id) {
401 		node = szNodeName ? gf_sg_find_node_by_name(inScene, szNodeName) : gf_sg_find_node(inScene, id);
402 		/*node already created, USE*/
403 		if (node) {
404 			gf_node_register(node, cloned_parent);
405 			if (szNodeName) gf_free(szNodeName);
406 			return node;
407 		}
408 	}
409 	/*create a node*/
410 	if (orig->sgprivate->tag == TAG_ProtoNode) {
411 		GF_Proto *proto_node = ((GF_ProtoInstance *)orig)->proto_interface;
412 		/*create the instance but don't load the code -c we MUST wait for ISed routes to be cloned before*/
413 		node = gf_sg_proto_create_node(inScene, proto_node, (GF_ProtoInstance *) orig);
414 	} else {
415 		node = gf_node_new(inScene, orig->sgprivate->tag);
416 	}
417 
418 	count = gf_node_get_field_count(orig);
419 
420 	is_script = 0;
421 	if (orig->sgprivate->tag==TAG_MPEG4_Script) is_script = 1;
422 #ifndef GPAC_DISABLE_X3D
423 	else if (orig->sgprivate->tag==TAG_X3D_Script) is_script = 1;
424 #endif
425 
426 	if (is_script) gf_sg_script_prepare_clone(node, orig);
427 
428 
429 	/*register node*/
430 	if (id) {
431 		gf_node_set_id(node, id, szNodeName);
432 		if (szNodeName) gf_free(szNodeName);
433 	}
434 	gf_node_register(node, cloned_parent);
435 
436 	/*copy each field*/
437 	for (i=0; i<count; i++) {
438 		gf_node_get_field(orig, i, &field_orig);
439 
440 		/*get target ptr*/
441 		gf_node_get_field(node, i, &field);
442 
443 		assert(field.eventType==field_orig.eventType);
444 		assert(field.fieldType==field_orig.fieldType);
445 
446 		/*duplicate it*/
447 		switch (field.fieldType) {
448 		case GF_SG_VRML_SFNODE:
449 			child = gf_node_clone(inScene, (* ((GF_Node **) field_orig.far_ptr)), node, inst_id_suffix, 1);
450 			*((GF_Node **) field.far_ptr) = child;
451 			break;
452 		case GF_SG_VRML_MFNODE:
453 			last = NULL;
454 			list = *( (GF_ChildNodeItem **) field_orig.far_ptr);
455 			while (list) {
456 				child = gf_node_clone(inScene, list->node, node, inst_id_suffix, 1);
457 				gf_node_list_add_child_last((GF_ChildNodeItem **) field.far_ptr, child, &last);
458 				list = list->next;
459 			}
460 			break;
461 		case GF_SG_VRML_SFTIME:
462 			gf_sg_vrml_field_copy(field.far_ptr, field_orig.far_ptr, field.fieldType);
463 			if (!inScene->GetSceneTime) break;
464 			/*update SFTime that must be updated when cloning the node*/
465 			if (orig->sgprivate->tag == TAG_ProtoNode) {
466 				if (gf_sg_proto_field_is_sftime_offset(orig, &field_orig))
467 					*((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
468 			} else if (!stricmp(field.name, "startTime") || !stricmp(field_orig.name, "startTime") ) {
469 				*((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
470 			}
471 			break;
472 		default:
473 			gf_sg_vrml_field_clone(field.far_ptr, field_orig.far_ptr, field.fieldType, inScene);
474 			break;
475 		}
476 	}
477 
478 #ifndef GPAC_DISABLE_BIFS
479 	/*init node before creating ISed routes so the eventIn handler are in place*/
480 	if (node->sgprivate->tag == TAG_MPEG4_Conditional)
481 		BIFS_SetupConditionalClone(node, orig);
482 	else
483 #endif
484 		if (node->sgprivate->tag != TAG_ProtoNode) gf_node_init(node);
485 
486 	if (!inScene->pOwningProto) return node;
487 	proto = inScene->pOwningProto;
488 
489 	/*create Routes for ISed fields*/
490 	i=0;
491 	while ((r1 = (GF_Route*)gf_list_enum(proto->proto_interface->sub_graph->Routes, &i))) {
492 		GF_Route *r2 = NULL;
493 		/*locate only ISed routes*/
494 		if (!r1->IS_route) continue;
495 
496 		/*eventOut*/
497 		if (r1->FromNode == orig) {
498 			r2 = gf_sg_route_new(inScene, node, r1->FromField.fieldIndex, (GF_Node *) proto, r1->ToField.fieldIndex);
499 			r2->IS_route = 1;
500 		}
501 		/*eventIn or exposedField*/
502 		else if (r1->ToNode == orig) {
503 			r2 = gf_sg_route_new(inScene, (GF_Node *) proto, r1->FromField.fieldIndex, node, r1->ToField.fieldIndex);
504 			r2->IS_route = 1;
505 
506 			/*activate the route now so that proto instanciation works properly, otherwise we may load scripts with wrong field values
507 			Note: we don't activate eventOut routes upon instanciation since no event has been triggered yet*/
508 			gf_sg_route_activate(r2);
509 		}
510 	}
511 
512 	/*remember scripts*/
513 	if (is_script) gf_list_add(proto->scripts_to_load, node);
514 
515 	/*this is a proto node, init our internal stuff*/
516 	if (node->sgprivate->tag == TAG_ProtoNode) {
517 		node->sgprivate->UserCallback = NULL;
518 		node->sgprivate->UserPrivate = NULL;
519 		/*NO RENDER, this is filtered at the generic gf_node_traverse to cope with instanciations and externProto*/
520 		/*load code*/
521 		gf_sg_proto_instantiate((GF_ProtoInstance *)node);
522 	}
523 	return node;
524 }
525 
gf_sg_proto_get_field_ind_static(GF_Node * Node,u32 inField,u8 IndexMode,u32 * allField)526 GF_Err gf_sg_proto_get_field_ind_static(GF_Node *Node, u32 inField, u8 IndexMode, u32 *allField)
527 {
528 	return gf_sg_proto_get_field_index((GF_ProtoInstance *)Node, inField, IndexMode, allField);
529 }
530 
531 
is_same_proto(GF_Proto * extern_proto,GF_Proto * proto)532 static Bool is_same_proto(GF_Proto *extern_proto, GF_Proto *proto)
533 {
534 	u32 i, count;
535 	/*VRML allows external protos to have more fields defined that the externProto referencing them*/
536 	if (gf_list_count(extern_proto->proto_fields) > gf_list_count(proto->proto_fields)) return 0;
537 	count = gf_list_count(extern_proto->proto_fields);
538 	for (i=0; i<count; i++) {
539 		GF_ProtoFieldInterface *pf1 = (GF_ProtoFieldInterface*)gf_list_get(extern_proto->proto_fields, i);
540 		GF_ProtoFieldInterface *pf2 = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
541 		if (pf1->EventType != pf2->EventType) return 0;
542 		if (pf1->FieldType != pf2->FieldType) return 0;
543 		/*note we don't check names since we're not sure both protos use name coding (MPEG4 only)*/
544 	}
545 	return 1;
546 }
547 
find_proto_by_interface(GF_SceneGraph * sg,GF_Proto * extern_proto)548 static GF_Proto *find_proto_by_interface(GF_SceneGraph *sg, GF_Proto *extern_proto)
549 {
550 	GF_Proto *proto;
551 	u32 i, count;
552 
553 	assert(sg);
554 
555 	/*browse all top-level */
556 	i=0;
557 	while ((proto = (GF_Proto*)gf_list_enum(sg->protos, &i))) {
558 		if (is_same_proto(proto, extern_proto)) return proto;
559 	}
560 	/*browse all top-level unregistered in reverse order*/
561 	count = gf_list_count(sg->unregistered_protos);
562 	for (i=count; i>0; i--) {
563 		proto = (GF_Proto*)gf_list_get(sg->unregistered_protos, i-1);
564 		if (is_same_proto(proto, extern_proto)) return proto;
565 	}
566 	return NULL;
567 }
568 
569 /*performs common initialization of routes ISed fields and protos once everything is loaded*/
gf_sg_proto_instantiate(GF_ProtoInstance * proto_node)570 void gf_sg_proto_instantiate(GF_ProtoInstance *proto_node)
571 {
572 	GF_Node *node, *orig;
573 	GF_Route *route, *r2;
574 	u32 i, count;
575 	GF_Proto *proto = proto_node->proto_interface;
576 	GF_Proto *owner = proto;
577 
578 	if (!proto) return;
579 
580 	if (owner->ExternProto.count) {
581 		GF_ProtoFieldInterface *pfi;
582 		GF_SceneGraph *extern_lib;
583 		if (!owner->parent_graph->GetExternProtoLib) return;
584 		extern_lib = owner->parent_graph->GetExternProtoLib(proto->parent_graph->userpriv, &owner->ExternProto);
585 		if (!extern_lib) return;
586 
587 		/*this is an hardcoded proto - all routes, node modifications and co are handled internally*/
588 		if (PTR_TO_U_CAST extern_lib == GF_SG_INTERNAL_PROTO) {
589 			proto_node->sgprivate->flags |= GF_SG_NODE_DIRTY;
590 			// take default values
591 			count = gf_list_count(owner->proto_fields);
592 			for (i=0; i<count; i++) {
593 				GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
594 				if (!pf->has_been_accessed) {
595 					pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
596 					gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
597 				}
598 			}
599 			owner->parent_graph->NodeCallback(owner->parent_graph->userpriv, GF_SG_CALLBACK_INIT, (GF_Node *) proto_node, NULL);
600 			proto_node->flags |= GF_SG_PROTO_LOADED | GF_SG_PROTO_HARDCODED;
601 			return;
602 		}
603 		/*not loaded yet*/
604 		if (!gf_list_count(extern_lib->protos)) return;
605 
606 		/*overwrite this proto by external one*/
607 		proto = NULL;
608 		/*start with proto v2 addressing*/
609 		if (owner->ExternProto.vals[0].url) {
610 			u32 ID = (u32) -1;
611 			char *szName = strrchr(owner->ExternProto.vals[0].url, '#');
612 			if (szName) {
613 				szName++;
614 				if (sscanf(szName, "%u", &ID)) ID = (u32) -1;
615 			}
616 			/*if we have the proto name, use it*/
617 			if (owner->Name) szName = owner->Name;
618 			proto = gf_sg_find_proto(extern_lib, ID, szName);
619 		}
620 		if (!proto) proto = gf_sg_find_proto(extern_lib, owner->ID, owner->Name);
621 		if (!proto) proto = find_proto_by_interface(extern_lib, owner);
622 
623 		if (proto && !is_same_proto(owner, proto)) {
624 			proto = NULL;
625 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] fields/types mismatch for PROTO %s - skipping instantiation\n", owner->Name));
626 		}
627 		/*couldn't find proto in the given lib, consider the proto as loaded (give up)*/
628 		if (!proto) {
629 			proto_node->flags |= GF_SG_PROTO_LOADED;
630 			return;
631 		}
632 		/*cf VRML: once an external proto is loaded, copy back the default field values of the external proto*/
633 		count = gf_list_count(owner->proto_fields);
634 		for (i=0; i<count; i++) {
635 			GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
636 			if (!pf->has_been_accessed) {
637 				pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
638 				gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
639 			} else {
640 				//pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
641 			}
642 		}
643 
644 		/*unregister from prev and reg with real proto*/
645 		gf_list_del_item(owner->instances, proto_node);
646 		gf_list_add(proto->instances, proto_node);
647 	}
648 
649 	/*OVERRIDE the proto instance (eg don't instantiate an empty externproto...)*/
650 	proto_node->proto_interface = proto;
651 
652 	/*clone all nodes*/
653 	i=0;
654 	while ((orig = (GF_Node*)gf_list_enum(proto->node_code, &i))) {
655 		/*node is cloned in the new scenegraph and its parent is NULL */
656 		node = gf_node_clone(proto_node->sgprivate->scenegraph, orig, NULL, "", 1);
657 		assert(node);
658 
659 		/*assign first rendering node*/
660 		if (i==1) proto_node->RenderingNode = node;
661 		gf_list_add(proto_node->node_code, node);
662 	}
663 
664 	/*instantiate routes (not ISed ones)*/
665 	i=0;
666 	while ((route = (GF_Route*)gf_list_enum(proto->sub_graph->Routes, &i))) {
667 		if (route->IS_route) continue;
668 
669 		r2 = gf_sg_route_new(proto_node->sgprivate->scenegraph,
670 		                     gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->FromNode) ),
671 		                     route->FromField.fieldIndex,
672 		                     gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->ToNode) ),
673 		                     route->ToField.fieldIndex);
674 
675 		if (route->ID) gf_sg_route_set_id(r2, route->ID);
676 		if (route->name) gf_sg_route_set_name(r2, route->name);
677 	}
678 	/*activate all ISed fields so that inits on events is properly done*/
679 	i=0;
680 	while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
681 		if (!route->IS_route) continue;
682 		/*do not activate eventIn to eventIn routes*/
683 		if (route->is_setup) {
684 			if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
685 		}
686 		gf_sg_route_activate(route);
687 	}
688 	/*and load all scripts (this must be done once all fields are routed for the "initialize" method)*/
689 	while (gf_list_count(proto_node->scripts_to_load)) {
690 		node = (GF_Node*)gf_list_get(proto_node->scripts_to_load, 0);
691 		gf_list_rem(proto_node->scripts_to_load, 0);
692 		gf_sg_script_load(node);
693 	}
694 	/*re-activate all ISed fields pointing to scripts once scripts are loaded (eventIns)*/
695 	i=0;
696 	while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
697 		if (!route->IS_route || !route->ToNode) continue;
698 		/*		assert(route->is_setup);
699 				if ((route->FromField.eventType == GF_SG_EVENT_OUT) || (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
700 		*/
701 
702 		if (route->is_setup) {
703 			if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
704 		}
705 
706 		if (route->ToNode->sgprivate->tag==TAG_MPEG4_Script)
707 			gf_sg_route_activate(route);
708 #ifndef GPAC_DISABLE_X3D
709 		else if (route->ToNode->sgprivate->tag==TAG_X3D_Script)
710 			gf_sg_route_activate(route);
711 #endif
712 	}
713 
714 #if 0
715 	/*reset all regular route activation times - if we don't do so, creating a proto by script and then manipulating one of its
716 	ISed field may not trigger the proper routes*/
717 	i=0;
718 	while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
719 		if (!route->IS_route) {
720 			route->lastActivateTime = 0;
721 		}
722 	}
723 #endif
724 	proto_node->flags |= GF_SG_PROTO_LOADED;
725 }
726 
gf_sg_proto_mark_field_loaded(GF_Node * proto_inst,GF_FieldInfo * info)727 void gf_sg_proto_mark_field_loaded(GF_Node *proto_inst, GF_FieldInfo *info)
728 {
729 	GF_ProtoInstance *inst= (proto_inst->sgprivate->tag==TAG_ProtoNode) ? (GF_ProtoInstance *)proto_inst : NULL;
730 	GF_ProtoField *pf = inst ? (GF_ProtoField *)gf_list_get(inst->fields, info->fieldIndex) : NULL;
731 	if (pf) pf->has_been_accessed = 1;
732 }
733 
gf_sg_proto_create_node(GF_SceneGraph * scene,GF_Proto * proto,GF_ProtoInstance * from_inst)734 GF_Node *gf_sg_proto_create_node(GF_SceneGraph *scene, GF_Proto *proto, GF_ProtoInstance *from_inst)
735 {
736 	u32 i;
737 	GF_ProtoField *inst, *from_field;
738 	GF_ProtoFieldInterface *field;
739 	GF_ProtoInstance *proto_node;
740 	if (!proto) return NULL;
741 
742 	GF_SAFEALLOC(proto_node, GF_ProtoInstance)
743 	if (!proto_node) return NULL;
744 
745 	gf_node_setup((GF_Node *)proto_node, TAG_ProtoNode);
746 	proto_node->node_code = gf_list_new();
747 	proto_node->fields = gf_list_new();
748 	proto_node->scripts_to_load = gf_list_new();
749 
750 	proto_node->proto_interface = proto;
751 	gf_list_add(proto->instances, proto_node);
752 
753 	proto_node->proto_name = gf_strdup(proto->Name);
754 
755 	/*create the namespace*/
756 	proto_node->sgprivate->scenegraph = gf_sg_new_subscene(scene);
757 	/*set this proto as owner of the new graph*/
758 	proto_node->sgprivate->scenegraph->pOwningProto = proto_node;
759 
760 	/*instantiate fields*/
761 	i=0;
762 	while ((field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
763 		GF_SAFEALLOC(inst, GF_ProtoField);
764 		if (!inst) {
765 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate proto instance field\n]"));
766 			continue;
767 		}
768 
769 		inst->EventType = field->EventType;
770 		inst->FieldType = field->FieldType;
771 
772 		/*this is OK to call on GF_Node (returns NULL) and MFNode (returns gf_list_new() )*/
773 		inst->field_pointer = gf_sg_vrml_field_pointer_new(inst->FieldType);
774 
775 		/*regular field, duplicate from default value or instantiated one if specified (since
776 		a proto may be partially instantiated when used in another proto)*/
777 		if (gf_sg_vrml_get_sf_type(inst->FieldType) != GF_SG_VRML_SFNODE) {
778 			if (from_inst) {
779 				from_field = (GF_ProtoField *)gf_list_get(from_inst->fields, i-1);
780 				gf_sg_vrml_field_copy(inst->field_pointer, from_field->field_pointer, inst->FieldType);
781 				inst->has_been_accessed = from_field->has_been_accessed;
782 			} else {
783 				gf_sg_vrml_field_copy(inst->field_pointer, field->def_value, inst->FieldType);
784 			}
785 		}
786 		/*No default values for SFNodes as interfaces ...*/
787 		gf_list_add(proto_node->fields, inst);
788 	}
789 	return (GF_Node *) proto_node;
790 }
791 
792 
793 GF_EXPORT
gf_sg_proto_create_instance(GF_SceneGraph * sg,GF_Proto * proto)794 GF_Node *gf_sg_proto_create_instance(GF_SceneGraph *sg, GF_Proto *proto)
795 {
796 	return gf_sg_proto_create_node(sg, proto, NULL);
797 }
798 
799 GF_EXPORT
gf_sg_proto_load_code(GF_Node * node)800 GF_Err gf_sg_proto_load_code(GF_Node *node)
801 {
802 	GF_ProtoInstance *inst;
803 	if (node->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
804 	inst = (GF_ProtoInstance *) node;
805 	if (!inst->proto_interface) return GF_BAD_PARAM;
806 	if (inst->flags & GF_SG_PROTO_LOADED) return GF_OK;
807 	gf_sg_proto_instantiate(inst);
808 	return GF_OK;
809 }
810 
811 
gf_sg_proto_get_num_fields(GF_Node * node,u8 code_mode)812 u32 gf_sg_proto_get_num_fields(GF_Node *node, u8 code_mode)
813 {
814 	GF_ProtoInstance *proto;
815 	if (!node) return 0;
816 
817 	proto = (GF_ProtoInstance *)node;
818 	/*watchout for deletion case*/
819 	switch (code_mode) {
820 	case GF_SG_FIELD_CODING_IN:
821 		return proto->proto_interface ? proto->proto_interface->NumIn : 0;
822 	case GF_SG_FIELD_CODING_OUT:
823 		return proto->proto_interface ? proto->proto_interface->NumOut : 0;
824 	case GF_SG_FIELD_CODING_DEF:
825 		return proto->proto_interface ? proto->proto_interface->NumDef : 0;
826 	case GF_SG_FIELD_CODING_ALL:
827 		return gf_list_count(proto->proto_interface ? proto->proto_interface->proto_fields : proto->fields);
828 	/*BIFS-ANIM not supported*/
829 	case GF_SG_FIELD_CODING_DYN:
830 	default:
831 		return 0;
832 	}
833 }
834 
835 
gf_sg_proto_del_instance(GF_ProtoInstance * inst)836 void gf_sg_proto_del_instance(GF_ProtoInstance *inst)
837 {
838 	GF_SceneGraph *sg;
839 
840 	while (gf_list_count(inst->fields)) {
841 		GF_ProtoField *field = (GF_ProtoField *)gf_list_get(inst->fields, 0);
842 		gf_list_rem(inst->fields, 0);
843 
844 		/*regular type*/
845 		if ( (field->FieldType!=GF_SG_VRML_SFNODE) && (field->FieldType!=GF_SG_VRML_MFNODE)) {
846 			gf_sg_vrml_field_pointer_del(field->field_pointer, field->FieldType);
847 		}
848 		/*node types: delete instances*/
849 		else if (field->field_pointer) {
850 			if (field->FieldType == GF_SG_VRML_SFNODE) {
851 				gf_node_unregister((GF_Node *) field->field_pointer, (GF_Node *) inst);
852 			} else {
853 				GF_ChildNodeItem *list = (GF_ChildNodeItem *)field->field_pointer;
854 				while (list) {
855 					GF_ChildNodeItem *cur = list;
856 					gf_node_unregister(list->node, (GF_Node *) inst);
857 					list = list->next;
858 					gf_free(cur);
859 				}
860 			}
861 		}
862 
863 		gf_free(field);
864 	}
865 	gf_list_del(inst->fields);
866 
867 	/*destroy the code*/
868 	while (gf_list_count(inst->node_code)) {
869 		GF_Node *node = (GF_Node*)gf_list_get(inst->node_code, 0);
870 		gf_node_unregister(node, (GF_Node*) inst);
871 		gf_list_rem(inst->node_code, 0);
872 	}
873 
874 	sg = inst->sgprivate->scenegraph;
875 
876 	/*reset the scene graph before destroying the node code list, as unregistering nodes
877 	not destroyed in the previous phase (eg, cyclic references such as script and co) will
878 	refer to the node-code list*/
879 	gf_sg_reset(sg);
880 	sg->pOwningProto = NULL;
881 
882 	gf_free((char *) inst->proto_name);
883 	gf_list_del(inst->node_code);
884 	assert(!gf_list_count(inst->scripts_to_load));
885 	gf_list_del(inst->scripts_to_load);
886 
887 	if (inst->proto_interface && inst->proto_interface->instances) gf_list_del_item(inst->proto_interface->instances, inst);
888 
889 	gf_node_free((GF_Node *)inst);
890 	gf_sg_del(sg);
891 }
892 
893 /*Note on ISed fields: we cannot support fan-in on proto, eg we assume only one eventIn field can receive events
894 thus situations where a proto receives eventIn from outside and the node with ISed eventIn receives event
895 from inside the proto are undefined*/
896 GF_EXPORT
gf_sg_proto_field_set_ised(GF_Proto * proto,u32 protoFieldIndex,GF_Node * node,u32 nodeFieldIndex)897 GF_Err gf_sg_proto_field_set_ised(GF_Proto *proto, u32 protoFieldIndex, GF_Node *node, u32 nodeFieldIndex)
898 {
899 	GF_Err e;
900 	GF_Route *r;
901 	GF_FieldInfo field, nodeField;
902 	field.fieldIndex = protoFieldIndex;
903 	e = gf_sg_proto_get_field(proto, NULL, &field);
904 	if (e) return e;
905 	e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
906 	if (e) return e;
907 	if (field.fieldType != nodeField.fieldType) {
908 		if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFSTRING) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFURL)) {
909 //			e = GF_OK;
910 		} else if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFURL) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFSTRING)) {
911 //			e = GF_OK;
912 		} else {
913 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] error in IS - node field %s.%s - inType %s - outType %s\n", gf_node_get_class_name(node) , nodeField.name, gf_sg_vrml_get_field_type_name(field.fieldType), gf_sg_vrml_get_field_type_name(nodeField.fieldType)));
914 			return GF_SG_INVALID_PROTO;
915 		}
916 	}
917 
918 	GF_SAFEALLOC(r, GF_Route)
919 	if (!r) return GF_OUT_OF_MEM;
920 	r->IS_route = 1;
921 
922 	if (nodeField.eventType==GF_SG_EVENT_OUT) {
923 		r->FromField.fieldIndex = nodeFieldIndex;
924 		r->FromNode = node;
925 		r->ToField.fieldIndex = protoFieldIndex;
926 		r->ToNode = NULL;
927 		if (!node->sgprivate->interact) {
928 			GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
929 			if (!node->sgprivate->interact) {
930 				return GF_OUT_OF_MEM;
931 			}
932 		}
933 		if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
934 		gf_list_add(node->sgprivate->interact->routes, r);
935 	} else {
936 		switch (field.eventType) {
937 		case GF_SG_EVENT_FIELD:
938 		case GF_SG_EVENT_EXPOSED_FIELD:
939 		case GF_SG_EVENT_IN:
940 			r->FromField.fieldIndex = protoFieldIndex;
941 			r->FromNode = NULL;
942 			r->ToField.fieldIndex = nodeFieldIndex;
943 			r->ToNode = node;
944 			/*create an ISed route for the eventOut part of the exposedFIeld*/
945 			if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
946 				GF_Route *r2;
947 				GF_SAFEALLOC(r2, GF_Route);
948 				if (!r2) {
949 					gf_free(r);
950 					return GF_OUT_OF_MEM;
951 				}
952 				r2->IS_route = 1;
953 				r2->FromField.fieldIndex = nodeFieldIndex;
954 				r2->FromNode = node;
955 				r2->ToField.fieldIndex = protoFieldIndex;
956 				r2->ToNode = NULL;
957 				r2->graph =  proto->sub_graph;
958 				if (!node->sgprivate->interact) {
959 					GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
960 					if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
961 				}
962 				if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
963 				gf_list_add(node->sgprivate->interact->routes, r2);
964 				gf_list_add(proto->sub_graph->Routes, r2);
965 			}
966 			break;
967 		case GF_SG_EVENT_OUT:
968 			r->FromField.fieldIndex = nodeFieldIndex;
969 			r->FromNode = node;
970 			r->ToField.fieldIndex = protoFieldIndex;
971 			r->ToNode = NULL;
972 			if (!node->sgprivate->interact) {
973 				GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
974 				if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
975 			}
976 			if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
977 			break;
978 		default:
979 			gf_free(r);
980 			return GF_BAD_PARAM;
981 		}
982 	}
983 	r->graph = proto->sub_graph;
984 	return gf_list_add(proto->sub_graph->Routes, r);
985 }
986 
987 GF_EXPORT
gf_sg_proto_instance_set_ised(GF_Node * protoinst,u32 protoFieldIndex,GF_Node * node,u32 nodeFieldIndex)988 GF_Err gf_sg_proto_instance_set_ised(GF_Node *protoinst, u32 protoFieldIndex, GF_Node *node, u32 nodeFieldIndex)
989 {
990 	GF_Err e;
991 	GF_Route *r;
992 	GF_FieldInfo field, nodeField;
993 	if (protoinst->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
994 
995 	e = gf_node_get_field(protoinst, protoFieldIndex, &field);
996 	if (e) return e;
997 	e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
998 	if (e) return e;
999 	if (field.fieldType != nodeField.fieldType) {
1000 		if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFSTRING) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFURL)) {
1001 //			e = GF_OK;
1002 		} else if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFURL) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFSTRING)) {
1003 //			e = GF_OK;
1004 		} else {
1005 			GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] error in IS - node field %s.%s - inType %s - outType %s\n", gf_node_get_class_name(node) , nodeField.name, gf_sg_vrml_get_field_type_name(field.fieldType), gf_sg_vrml_get_field_type_name(nodeField.fieldType)));
1006 			return GF_SG_INVALID_PROTO;
1007 		}
1008 	}
1009 
1010 	GF_SAFEALLOC(r, GF_Route)
1011 	if (!r) return GF_OUT_OF_MEM;
1012 	r->IS_route = 1;
1013 
1014 	if (nodeField.eventType==GF_SG_EVENT_OUT) {
1015 		r->FromField.fieldIndex = nodeFieldIndex;
1016 		r->FromNode = node;
1017 		r->ToField.fieldIndex = protoFieldIndex;
1018 		r->ToNode = protoinst;
1019 		if (!node->sgprivate->interact) {
1020 			GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
1021 			if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
1022 		}
1023 		if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
1024 		gf_list_add(node->sgprivate->interact->routes, r);
1025 	} else {
1026 		switch (field.eventType) {
1027 		case GF_SG_EVENT_FIELD:
1028 		case GF_SG_EVENT_EXPOSED_FIELD:
1029 		case GF_SG_EVENT_IN:
1030 			r->FromField.fieldIndex = protoFieldIndex;
1031 			r->FromNode = protoinst;
1032 			r->ToField.fieldIndex = nodeFieldIndex;
1033 			r->ToNode = node;
1034 
1035 			/*create an ISed route for the eventOut part of the exposedFIeld*/
1036 			if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
1037 				GF_Route *r2;
1038 				GF_SAFEALLOC(r2, GF_Route);
1039 				if (!r2) {
1040 					gf_free(r);
1041 					return GF_OUT_OF_MEM;
1042 				}
1043 				r2->IS_route = 1;
1044 				r2->FromField.fieldIndex = nodeFieldIndex;
1045 				r2->FromNode = node;
1046 				r2->ToField.fieldIndex = protoFieldIndex;
1047 				r2->ToNode = protoinst;
1048 				r2->graph =  node->sgprivate->scenegraph;
1049 				if (!node->sgprivate->interact) {
1050 					GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
1051 					if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
1052 				}
1053 				if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
1054 				gf_list_add(node->sgprivate->interact->routes, r2);
1055 				gf_list_add(r->graph->Routes, r2);
1056 			}
1057 			break;
1058 		case GF_SG_EVENT_OUT:
1059 			r->FromField.fieldIndex = nodeFieldIndex;
1060 			r->FromNode = node;
1061 			r->ToField.fieldIndex = protoFieldIndex;
1062 			r->ToNode = protoinst;
1063 			if (!node->sgprivate->interact) {
1064 				GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
1065 				if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
1066 			}
1067 			if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
1068 			gf_list_add(node->sgprivate->interact->routes, r);
1069 			break;
1070 		default:
1071 			gf_free(r);
1072 			return GF_BAD_PARAM;
1073 		}
1074 	}
1075 	r->graph = node->sgprivate->scenegraph;
1076 	gf_sg_route_activate(r);
1077 	return gf_list_add(r->graph->Routes, r);
1078 }
1079 
1080 
gf_bifs_proto_field_set_aq_info(GF_ProtoFieldInterface * field,u32 QP_Type,u32 hasMinMax,u32 QPSFType,void * qp_min_value,void * qp_max_value,u32 QP13_NumBits)1081 GF_Err gf_bifs_proto_field_set_aq_info(GF_ProtoFieldInterface *field,
1082                                        u32 QP_Type,
1083                                        u32 hasMinMax,
1084                                        u32 QPSFType,
1085                                        void *qp_min_value,
1086                                        void *qp_max_value,
1087                                        u32 QP13_NumBits)
1088 {
1089 
1090 	if (!field) return GF_BAD_PARAM;
1091 	if (!QP_Type) return GF_OK;
1092 	if (!gf_sg_vrml_is_sf_field(QPSFType)) return GF_BAD_PARAM;
1093 
1094 	field->QP_Type = QP_Type;
1095 	field->hasMinMax = hasMinMax;
1096 	if (hasMinMax) {
1097 		if (qp_min_value) {
1098 			field->qp_min_value = gf_sg_vrml_field_pointer_new(QPSFType);
1099 			gf_sg_vrml_field_copy(field->qp_min_value, qp_min_value, QPSFType);
1100 		}
1101 		if (qp_max_value) {
1102 			field->qp_max_value = gf_sg_vrml_field_pointer_new(QPSFType);
1103 			gf_sg_vrml_field_copy(field->qp_max_value, qp_max_value, QPSFType);
1104 		}
1105 	}
1106 	field->NumBits = QP13_NumBits;
1107 	return GF_OK;
1108 }
1109 
1110 
gf_sg_proto_get_field_index(GF_ProtoInstance * proto,u32 index,u32 code_mode,u32 * all_index)1111 GF_Err gf_sg_proto_get_field_index(GF_ProtoInstance *proto, u32 index, u32 code_mode, u32 *all_index)
1112 {
1113 	u32 i;
1114 	GF_ProtoFieldInterface *proto_field;
1115 
1116 	i=0;
1117 	while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_interface->proto_fields, &i))) {
1118 		assert(proto_field);
1119 		switch (code_mode) {
1120 		case GF_SG_FIELD_CODING_IN:
1121 			if (proto_field->IN_index == index) {
1122 				*all_index = proto_field->ALL_index;
1123 				return GF_OK;
1124 			}
1125 			break;
1126 		case GF_SG_FIELD_CODING_OUT:
1127 			if (proto_field->OUT_index == index) {
1128 				*all_index = proto_field->ALL_index;
1129 				return GF_OK;
1130 			}
1131 			break;
1132 		case GF_SG_FIELD_CODING_DEF:
1133 			if (proto_field->DEF_index == index) {
1134 				*all_index = proto_field->ALL_index;
1135 				return GF_OK;
1136 			}
1137 			break;
1138 		case GF_SG_FIELD_CODING_ALL:
1139 			if (proto_field->ALL_index == index) {
1140 				*all_index = proto_field->ALL_index;
1141 				return GF_OK;
1142 			}
1143 			break;
1144 		/*BIFS-ANIM not supported*/
1145 		case GF_SG_FIELD_CODING_DYN:
1146 		default:
1147 			return GF_BAD_PARAM;
1148 		}
1149 	}
1150 	return GF_BAD_PARAM;
1151 }
1152 
1153 GF_EXPORT
gf_sg_proto_get_field_count(GF_Proto * proto)1154 u32 gf_sg_proto_get_field_count(GF_Proto *proto)
1155 {
1156 	if (!proto) return 0;
1157 	return gf_list_count(proto->proto_fields);
1158 }
1159 
1160 GF_EXPORT
gf_sg_proto_field_find(GF_Proto * proto,u32 fieldIndex)1161 GF_ProtoFieldInterface *gf_sg_proto_field_find(GF_Proto *proto, u32 fieldIndex)
1162 {
1163 	if (!proto) return NULL;
1164 	return (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, fieldIndex);
1165 }
1166 
gf_sg_proto_propagate_event(GF_Node * node,u32 fieldIndex,GF_Node * from_node)1167 void gf_sg_proto_propagate_event(GF_Node *node, u32 fieldIndex, GF_Node *from_node)
1168 {
1169 	u32 i;
1170 	GF_Route *r;
1171 	if (!node) return;
1172 	/*propagation only for proto*/
1173 	if (node->sgprivate->tag != TAG_ProtoNode) return;
1174 	/*with ISed fields*/
1175 	if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
1176 	/*we only need to propagate ISed for eventIn/exposedField. This means that if the event comes from
1177 	the same scene graph as the proto (eg from the proto code) we don't propagate the event*/
1178 	if (from_node->sgprivate->scenegraph == node->sgprivate->scenegraph) return;
1179 
1180 	/*for all ISed routes*/
1181 	i=0;
1182 	while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
1183 		if (!r->IS_route) continue;
1184 		/*connecting from this node && field to a destination node other than the event source (this will break loops due to exposedFields)*/
1185 		if ((r->FromNode == node) && (r->FromField.fieldIndex == fieldIndex) && (r->ToNode != from_node) ) {
1186 			if (gf_sg_route_activate(r))
1187 				gf_node_changed(r->ToNode, &r->ToField);
1188 		}
1189 	}
1190 }
1191 
1192 
gf_sg_proto_get_aq_info(GF_Node * Node,u32 FieldIndex,u8 * QType,u8 * AType,Fixed * b_min,Fixed * b_max,u32 * QT13_bits)1193 Bool gf_sg_proto_get_aq_info(GF_Node *Node, u32 FieldIndex, u8 *QType, u8 *AType, Fixed *b_min, Fixed *b_max, u32 *QT13_bits)
1194 {
1195 	GF_Proto *proto;
1196 	u32 i;
1197 	GF_ProtoFieldInterface *proto_field;
1198 
1199 	proto = ((GF_ProtoInstance *)Node)->proto_interface;
1200 
1201 	i=0;
1202 	while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
1203 		if (proto_field->ALL_index!=FieldIndex) continue;
1204 
1205 		*QType = proto_field->QP_Type;
1206 		*AType = proto_field->Anim_Type;
1207 		*b_min = FIX_MIN;
1208 		*b_max = FIX_MAX;
1209 
1210 		if (proto_field->hasMinMax) {
1211 
1212 			/*translate our bounds*/
1213 			switch (gf_sg_vrml_get_sf_type(proto_field->FieldType)) {
1214 			case GF_SG_VRML_SFINT32:
1215 				*b_min = (SFFloat) * ( (SFInt32 *) proto_field->qp_min_value);
1216 				*b_max = (SFFloat) * ( (SFInt32 *) proto_field->qp_max_value);
1217 				break;
1218 			/*TO DO EVERYWHERE: check on field translation from double to float
1219 			during quant bounds*/
1220 			case GF_SG_VRML_SFTIME:
1221 				*b_min = (SFFloat) * ( (SFTime *) proto_field->qp_min_value);
1222 				*b_max = (SFFloat) * ( (SFTime *) proto_field->qp_max_value);
1223 				break;
1224 			default:
1225 				if (proto_field->qp_min_value)
1226 					*b_min = (SFFloat) * ( (SFFloat *) proto_field->qp_min_value);
1227 				if (proto_field->qp_max_value)
1228 					*b_max = (SFFloat) * ( (SFFloat *) proto_field->qp_max_value);
1229 				break;
1230 			}
1231 
1232 		}
1233 		*QT13_bits = proto_field->NumBits;
1234 		return 1;
1235 	}
1236 	return 0;
1237 }
1238 
1239 
1240 GF_EXPORT
gf_node_get_proto(GF_Node * node)1241 GF_Proto *gf_node_get_proto(GF_Node *node)
1242 {
1243 	GF_ProtoInstance *inst;
1244 	if (node->sgprivate->tag != TAG_ProtoNode) return NULL;
1245 	inst = (GF_ProtoInstance *) node;
1246 	return inst->proto_interface;
1247 }
1248 
1249 /*returns the ID of the proto*/
1250 GF_EXPORT
gf_sg_proto_get_id(GF_Proto * proto)1251 u32 gf_sg_proto_get_id(GF_Proto *proto)
1252 {
1253 	return proto->ID;
1254 }
1255 
1256 GF_EXPORT
gf_sg_proto_get_class_name(GF_Proto * proto)1257 const char *gf_sg_proto_get_class_name(GF_Proto *proto)
1258 {
1259 	return (const char *) proto->Name;
1260 }
1261 
gf_sg_proto_get_root_tag(GF_Proto * proto)1262 u32 gf_sg_proto_get_root_tag(GF_Proto *proto)
1263 {
1264 	GF_Node *n;
1265 	if (!proto) return TAG_UndefinedNode;
1266 	n = (GF_Node*)gf_list_get(proto->node_code, 0);
1267 	if (!n) return TAG_UndefinedNode;
1268 	if (n->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_root_tag(((GF_ProtoInstance *)n)->proto_interface);
1269 	return n->sgprivate->tag;
1270 }
1271 
1272 GF_EXPORT
gf_sg_proto_field_is_sftime_offset(GF_Node * node,GF_FieldInfo * field)1273 Bool gf_sg_proto_field_is_sftime_offset(GF_Node *node, GF_FieldInfo *field)
1274 {
1275 	u32 i;
1276 	GF_Route *r;
1277 	GF_ProtoInstance *inst;
1278 	GF_FieldInfo inf;
1279 	if (node->sgprivate->tag != TAG_ProtoNode) return 0;
1280 	if (field->fieldType != GF_SG_VRML_SFTIME) return 0;
1281 
1282 	inst = (GF_ProtoInstance *) node;
1283 	/*check in interface if this is ISed */
1284 	i=0;
1285 	while ((r = (GF_Route*)gf_list_enum(inst->proto_interface->sub_graph->Routes, &i))) {
1286 		if (!r->IS_route) continue;
1287 		/*only check eventIn/field/exposedField*/
1288 		if (r->FromNode || (r->FromField.fieldIndex != field->fieldIndex)) continue;
1289 
1290 		gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &inf);
1291 		/*IS to another proto*/
1292 		if (r->ToNode->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_field_is_sftime_offset(r->ToNode, &inf);
1293 		/*IS to a startTime/stopTime field*/
1294 		if (!stricmp(inf.name, "startTime") || !stricmp(inf.name, "stopTime")) return 1;
1295 	}
1296 	return 0;
1297 }
1298 
1299 GF_EXPORT
gf_node_proto_set_grouping(GF_Node * node)1300 GF_Err gf_node_proto_set_grouping(GF_Node *node)
1301 {
1302 	if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
1303 	((GF_ProtoInstance *)node)->flags |= GF_SG_PROTO_IS_GROUPING;
1304 	return GF_OK;
1305 }
1306 
1307 GF_EXPORT
gf_node_proto_is_grouping(GF_Node * node)1308 Bool gf_node_proto_is_grouping(GF_Node *node)
1309 {
1310 	if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return 0;
1311 	if ( ((GF_ProtoInstance *)node)->flags & GF_SG_PROTO_IS_GROUPING) return 1;
1312 	return 0;
1313 }
1314 
1315 GF_EXPORT
gf_node_get_proto_root(GF_Node * node)1316 GF_Node *gf_node_get_proto_root(GF_Node *node)
1317 {
1318 	if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return NULL;
1319 	return ((GF_ProtoInstance *)node)->RenderingNode;
1320 }
1321 
1322 #if 0 //unused
1323 GF_Node *gf_node_get_proto_parent(GF_Node *node)
1324 {
1325 	if (!node) return NULL;
1326 	if (node->sgprivate->scenegraph->pOwningProto) {
1327 		GF_Node *the_node = (GF_Node *) node->sgprivate->scenegraph->pOwningProto;
1328 		if (the_node != node) return the_node;
1329 	}
1330 	return NULL;
1331 }
1332 
1333 Bool gf_node_is_proto_root(GF_Node *node)
1334 {
1335 	if (!node) return 0;
1336 	if (!node->sgprivate->scenegraph->pOwningProto) return 0;
1337 
1338 	if (gf_list_find(node->sgprivate->scenegraph->pOwningProto->node_code, node)>=0) return 1;
1339 	return 0;
1340 }
1341 #endif
1342 
1343 
1344 GF_EXPORT
gf_node_set_proto_eventin_handler(GF_Node * node,u32 fieldIndex,void (* event_in_cbk)(GF_Node * pThis,struct _route * route))1345 GF_Err gf_node_set_proto_eventin_handler(GF_Node *node, u32 fieldIndex, void (*event_in_cbk)(GF_Node *pThis, struct _route *route) )
1346 {
1347 	GF_ProtoInstance *inst;
1348 	GF_ProtoField *field;
1349 	if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
1350 
1351 	inst = (GF_ProtoInstance *) node;
1352 	field = (GF_ProtoField*)gf_list_get(inst->fields, fieldIndex);
1353 	if (!field) return GF_BAD_PARAM;
1354 
1355 	if (field->EventType!=GF_SG_EVENT_IN) return GF_BAD_PARAM;
1356 	field->on_event_in = event_in_cbk;
1357 	return GF_OK;
1358 }
1359 
1360 
1361 
1362 #endif	/*GPAC_DISABLE_VRML*/
1363