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