Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Graph sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
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
35 159 : GF_Proto *gf_sg_proto_new(GF_SceneGraph *inScene, u32 ProtoID, char *name, Bool unregistered)
36 : {
37 : GF_Proto *tmp;
38 159 : if (!inScene) return NULL;
39 :
40 : /*make sure we don't define a proto already defined in this scope*/
41 159 : if (!unregistered) {
42 17 : tmp = gf_sg_find_proto(inScene, ProtoID, name);
43 17 : if (tmp) {
44 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] PROTO %s redefined - skipping loading\n", name));
45 : return NULL;
46 : }
47 : }
48 :
49 159 : GF_SAFEALLOC(tmp, GF_Proto)
50 159 : if (!tmp) return NULL;
51 :
52 159 : tmp->proto_fields = gf_list_new();
53 159 : tmp->node_code = gf_list_new();
54 159 : tmp->parent_graph = inScene;
55 159 : tmp->sub_graph = gf_sg_new_subscene(inScene);
56 159 : tmp->instances = gf_list_new();
57 :
58 159 : if (name)
59 159 : tmp->Name = gf_strdup(name);
60 : else
61 0 : tmp->Name = gf_strdup("Unnamed Proto");
62 159 : tmp->ID = ProtoID;
63 159 : if (!unregistered) {
64 17 : gf_list_add(inScene->protos, tmp);
65 : } else {
66 142 : 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
103 159 : GF_Err gf_sg_proto_del(GF_Proto *proto)
104 : {
105 : s32 i;
106 :
107 159 : if (!proto) return GF_OK;
108 159 : i = gf_list_del_item(proto->parent_graph->protos, proto);
109 159 : if (i<0) {
110 77 : gf_list_del_item(proto->parent_graph->unregistered_protos, proto);
111 : }
112 159 : if (proto->userpriv && proto->OnDelete) proto->OnDelete(proto->userpriv);
113 :
114 : /*first destroy the code*/
115 344 : while (gf_list_count(proto->node_code)) {
116 185 : GF_Node *node = (GF_Node*)gf_list_get(proto->node_code, 0);
117 185 : gf_node_unregister(node, NULL);
118 185 : gf_list_rem(proto->node_code, 0);
119 : }
120 159 : gf_list_del(proto->node_code);
121 :
122 : /*delete interface*/
123 1260 : while (gf_list_count(proto->proto_fields)) {
124 942 : GF_ProtoFieldInterface *field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, 0);
125 942 : if (field->userpriv && field->OnDelete) field->OnDelete(field->userpriv);
126 :
127 942 : if (field->FieldType==GF_SG_VRML_SFNODE) {
128 97 : if (field->def_sfnode_value)
129 0 : gf_node_unregister(field->def_sfnode_value, NULL);
130 : }
131 845 : else if (field->FieldType==GF_SG_VRML_MFNODE) {
132 15 : if (field->def_mfnode_value)
133 0 : gf_node_unregister_children(NULL, field->def_mfnode_value);
134 : }
135 830 : else if (field->def_value)
136 830 : gf_sg_vrml_field_pointer_del(field->def_value, field->FieldType);
137 :
138 942 : if (field->FieldName) gf_free(field->FieldName);
139 :
140 : /*QP fields are SF fields, we can safely gf_free() them*/
141 942 : if (field->qp_max_value) gf_free(field->qp_max_value);
142 942 : if (field->qp_min_value) gf_free(field->qp_min_value);
143 942 : gf_free(field);
144 942 : gf_list_rem(proto->proto_fields, 0);
145 : }
146 159 : gf_list_del(proto->proto_fields);
147 :
148 437 : while (gf_list_count(proto->instances)) {
149 119 : GF_ProtoInstance *p = (GF_ProtoInstance *)gf_list_get(proto->instances, 0);
150 119 : gf_list_rem(proto->instances, 0);
151 119 : p->proto_interface = NULL;
152 : }
153 :
154 : /*delete sub graph*/
155 159 : gf_sg_del(proto->sub_graph);
156 :
157 :
158 159 : if (proto->Name) gf_free(proto->Name);
159 159 : gf_sg_mfurl_del(proto->ExternProto);
160 159 : gf_list_del(proto->instances);
161 159 : gf_free(proto);
162 159 : return GF_OK;
163 : }
164 :
165 : GF_EXPORT
166 232 : GF_SceneGraph *gf_sg_proto_get_graph(GF_Proto *proto)
167 : {
168 232 : 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
188 679 : MFURL *gf_sg_proto_get_extern_url(GF_Proto *proto)
189 : {
190 679 : return proto ? &proto->ExternProto : NULL;
191 : }
192 :
193 : GF_EXPORT
194 185 : GF_Err gf_sg_proto_add_node_code(GF_Proto *proto, GF_Node *pNode)
195 : {
196 185 : if (!proto) return GF_BAD_PARAM;
197 185 : return gf_list_add(proto->node_code, pNode);
198 : }
199 :
200 : GF_EXPORT
201 1313 : GF_ProtoFieldInterface *gf_sg_proto_field_find_by_name(GF_Proto *proto, char *fieldName)
202 : {
203 : GF_ProtoFieldInterface *ptr;
204 1313 : u32 i=0;
205 7601 : while ((ptr = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
206 5346 : if (ptr->FieldName && !strcmp(ptr->FieldName, fieldName)) return ptr;
207 : }
208 : return NULL;
209 : }
210 :
211 : GF_EXPORT
212 942 : GF_ProtoFieldInterface *gf_sg_proto_field_new(GF_Proto *proto, u32 fieldType, u32 eventType, char *fieldName)
213 : {
214 : GF_ProtoFieldInterface *tmp;
215 :
216 942 : if (fieldName) {
217 942 : tmp = gf_sg_proto_field_find_by_name(proto, fieldName);
218 942 : if (tmp) return NULL;
219 : }
220 942 : GF_SAFEALLOC(tmp, GF_ProtoFieldInterface)
221 942 : if (!tmp) return NULL;
222 :
223 942 : tmp->FieldType = fieldType;
224 942 : tmp->EventType = eventType;
225 :
226 : /*create container - can be NULL if SF node*/
227 942 : if ( fieldType == GF_SG_VRML_SFNODE) {
228 97 : tmp->def_sfnode_value = NULL;
229 97 : tmp->def_value = &tmp->def_sfnode_value;
230 845 : } else if ( fieldType == GF_SG_VRML_MFNODE) {
231 15 : tmp->def_mfnode_value = NULL;
232 15 : tmp->def_value = &tmp->def_mfnode_value;
233 : } else {
234 830 : tmp->def_value = gf_sg_vrml_field_pointer_new(fieldType);
235 : }
236 :
237 942 : if (fieldName) tmp->FieldName = gf_strdup(fieldName);
238 :
239 942 : tmp->ALL_index = gf_list_count(proto->proto_fields);
240 942 : tmp->OUT_index = tmp->DEF_index = tmp->IN_index = (u32) -1;
241 :
242 942 : switch (eventType) {
243 868 : case GF_SG_EVENT_EXPOSED_FIELD:
244 868 : tmp->IN_index = proto->NumIn;
245 868 : proto->NumIn ++;
246 868 : tmp->OUT_index = proto->NumOut;
247 868 : proto->NumOut ++;
248 870 : case GF_SG_EVENT_FIELD:
249 870 : tmp->DEF_index = proto->NumDef;
250 870 : proto->NumDef ++;
251 870 : break;
252 63 : case GF_SG_EVENT_IN:
253 63 : tmp->IN_index = proto->NumIn;
254 63 : proto->NumIn ++;
255 63 : break;
256 9 : case GF_SG_EVENT_OUT:
257 9 : tmp->OUT_index = proto->NumOut;
258 9 : proto->NumOut ++;
259 9 : break;
260 : }
261 :
262 942 : gf_list_add(proto->proto_fields, tmp);
263 942 : 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
282 1981 : GF_Err gf_sg_proto_field_get_field(GF_ProtoFieldInterface *field, GF_FieldInfo *info)
283 : {
284 1981 : if (!field || !info) return GF_BAD_PARAM;
285 : memset(info, 0, sizeof(GF_FieldInfo));
286 1981 : info->fieldIndex = field->ALL_index;
287 1981 : info->fieldType = field->FieldType;
288 1981 : info->eventType = field->EventType;
289 1981 : info->far_ptr = field->def_value;
290 1981 : info->name = field->FieldName;
291 1981 : info->NDTtype = NDT_SFWorldNode;
292 1981 : return GF_OK;
293 : }
294 :
295 46686 : 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 46686 : if (!proto && !node) return GF_BAD_PARAM;
302 :
303 46686 : if (proto) {
304 651 : proto_field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, info->fieldIndex);
305 651 : if (!proto_field) return GF_BAD_PARAM;
306 :
307 651 : info->fieldType = proto_field->FieldType;
308 651 : info->eventType = proto_field->EventType;
309 651 : info->fieldIndex = proto_field->ALL_index;
310 651 : info->NDTtype = NDT_SFWorldNode;
311 651 : info->far_ptr = proto_field->def_value;
312 651 : info->name = proto_field->FieldName;
313 651 : return GF_OK;
314 : }
315 :
316 : /*otherwise this is an instantiated proto*/
317 46035 : if (node->sgprivate->tag!=TAG_ProtoNode) return GF_BAD_PARAM;
318 :
319 : inst = (GF_ProtoInstance *) node;
320 46035 : field = (GF_ProtoField*)gf_list_get(inst->fields, info->fieldIndex);
321 46035 : if (!field) return GF_BAD_PARAM;
322 :
323 46035 : info->fieldType = field->FieldType;
324 46035 : info->eventType = field->EventType;
325 46035 : info->on_event_in = field->on_event_in;
326 : /*SF/MF nodes need pointers to field object - cf gf_sg_proto_create_node*/
327 46035 : if (gf_sg_vrml_get_sf_type(field->FieldType) == GF_SG_VRML_SFNODE) {
328 4469 : info->far_ptr = &field->field_pointer;
329 : } else {
330 41566 : info->far_ptr = field->field_pointer;
331 : }
332 : /*set the name - watchout for deletion case*/
333 46035 : if (inst->proto_interface) {
334 45978 : proto_field = (GF_ProtoFieldInterface*)gf_list_get(inst->proto_interface->proto_fields, info->fieldIndex);
335 45978 : info->name = proto_field->FieldName;
336 : } else {
337 57 : info->name = "ProtoFieldDeleted";
338 : }
339 46035 : info->NDTtype = NDT_SFWorldNode;
340 46035 : return GF_OK;
341 : }
342 :
343 24847 : 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 24847 : if (!node && !proto) return -1;
349 24847 : if (node && (node->sgprivate->tag!=TAG_ProtoNode)) return -1;
350 :
351 24847 : if (proto)
352 : __proto = proto;
353 24847 : else if (node)
354 24847 : __proto = ((GF_ProtoInstance *) node)->proto_interface;
355 :
356 24847 : if (!__proto ) return -1;
357 :
358 150341 : for (i=0; i<gf_list_count(__proto->proto_fields); i++) {
359 174966 : GF_ProtoFieldInterface *proto_field = (GF_ProtoFieldInterface*)gf_list_get(__proto->proto_fields, i);
360 174966 : if (proto_field->FieldName && !strcmp(proto_field->FieldName, name)) return i;
361 : }
362 : return -1;
363 : }
364 :
365 :
366 13514 : 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 13514 : if (!orig) return NULL;
382 :
383 : /*check for DEF/USE*/
384 : szNodeName = NULL;
385 13514 : if (!inst_id_suffix) id = 0;
386 : else {
387 13514 : const char *orig_name = gf_node_get_name_and_id(orig, &id);
388 : /*generate clone IDs based on original one*/
389 13514 : if (inst_id_suffix[0] && id) {
390 0 : id = gf_sg_get_next_available_node_id(inScene);
391 0 : if (orig_name) {
392 0 : 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 13514 : else if (orig_name) szNodeName = gf_strdup(orig_name);
398 : }
399 :
400 13514 : if (id) {
401 5717 : node = szNodeName ? gf_sg_find_node_by_name(inScene, szNodeName) : gf_sg_find_node(inScene, id);
402 : /*node already created, USE*/
403 5717 : if (node) {
404 1430 : gf_node_register(node, cloned_parent);
405 1430 : if (szNodeName) gf_free(szNodeName);
406 : return node;
407 : }
408 : }
409 : /*create a node*/
410 12084 : if (orig->sgprivate->tag == TAG_ProtoNode) {
411 366 : 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 366 : node = gf_sg_proto_create_node(inScene, proto_node, (GF_ProtoInstance *) orig);
414 : } else {
415 11718 : node = gf_node_new(inScene, orig->sgprivate->tag);
416 : }
417 :
418 12084 : count = gf_node_get_field_count(orig);
419 :
420 : is_script = 0;
421 12084 : if (orig->sgprivate->tag==TAG_MPEG4_Script) is_script = 1;
422 : #ifndef GPAC_DISABLE_X3D
423 11719 : else if (orig->sgprivate->tag==TAG_X3D_Script) is_script = 1;
424 : #endif
425 :
426 365 : if (is_script) gf_sg_script_prepare_clone(node, orig);
427 :
428 :
429 : /*register node*/
430 12084 : if (id) {
431 4287 : gf_node_set_id(node, id, szNodeName);
432 4287 : if (szNodeName) gf_free(szNodeName);
433 : }
434 12084 : gf_node_register(node, cloned_parent);
435 :
436 : /*copy each field*/
437 118879 : for (i=0; i<count; i++) {
438 106795 : gf_node_get_field(orig, i, &field_orig);
439 :
440 : /*get target ptr*/
441 106795 : 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 106795 : switch (field.fieldType) {
448 10113 : case GF_SG_VRML_SFNODE:
449 10113 : child = gf_node_clone(inScene, (* ((GF_Node **) field_orig.far_ptr)), node, inst_id_suffix, 1);
450 10113 : *((GF_Node **) field.far_ptr) = child;
451 10113 : break;
452 5567 : case GF_SG_VRML_MFNODE:
453 5567 : last = NULL;
454 5567 : list = *( (GF_ChildNodeItem **) field_orig.far_ptr);
455 16550 : while (list) {
456 5416 : child = gf_node_clone(inScene, list->node, node, inst_id_suffix, 1);
457 5416 : gf_node_list_add_child_last((GF_ChildNodeItem **) field.far_ptr, child, &last);
458 5416 : list = list->next;
459 : }
460 : break;
461 5023 : case GF_SG_VRML_SFTIME:
462 5023 : gf_sg_vrml_field_copy(field.far_ptr, field_orig.far_ptr, field.fieldType);
463 5023 : if (!inScene->GetSceneTime) break;
464 : /*update SFTime that must be updated when cloning the node*/
465 5023 : if (orig->sgprivate->tag == TAG_ProtoNode) {
466 0 : if (gf_sg_proto_field_is_sftime_offset(orig, &field_orig))
467 0 : *((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
468 5023 : } else if (!stricmp(field.name, "startTime") || !stricmp(field_orig.name, "startTime") ) {
469 379 : *((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
470 : }
471 : break;
472 86092 : default:
473 86092 : gf_sg_vrml_field_clone(field.far_ptr, field_orig.far_ptr, field.fieldType, inScene);
474 86092 : break;
475 : }
476 0 : }
477 :
478 : #ifndef GPAC_DISABLE_BIFS
479 : /*init node before creating ISed routes so the eventIn handler are in place*/
480 12084 : if (node->sgprivate->tag == TAG_MPEG4_Conditional)
481 39 : BIFS_SetupConditionalClone(node, orig);
482 : else
483 : #endif
484 12045 : if (node->sgprivate->tag != TAG_ProtoNode) gf_node_init(node);
485 :
486 12084 : if (!inScene->pOwningProto) return node;
487 : proto = inScene->pOwningProto;
488 :
489 : /*create Routes for ISed fields*/
490 11903 : i=0;
491 213797 : 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 189991 : if (!r1->IS_route) continue;
495 :
496 : /*eventOut*/
497 142901 : if (r1->FromNode == orig) {
498 4248 : r2 = gf_sg_route_new(inScene, node, r1->FromField.fieldIndex, (GF_Node *) proto, r1->ToField.fieldIndex);
499 4248 : r2->IS_route = 1;
500 : }
501 : /*eventIn or exposedField*/
502 138653 : else if (r1->ToNode == orig) {
503 4258 : r2 = gf_sg_route_new(inScene, (GF_Node *) proto, r1->FromField.fieldIndex, node, r1->ToField.fieldIndex);
504 4258 : 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 4258 : gf_sg_route_activate(r2);
509 : }
510 : }
511 :
512 : /*remember scripts*/
513 11903 : if (is_script) gf_list_add(proto->scripts_to_load, node);
514 :
515 : /*this is a proto node, init our internal stuff*/
516 11903 : if (node->sgprivate->tag == TAG_ProtoNode) {
517 366 : node->sgprivate->UserCallback = NULL;
518 366 : 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 366 : gf_sg_proto_instantiate((GF_ProtoInstance *)node);
522 : }
523 : return node;
524 : }
525 :
526 2651 : GF_Err gf_sg_proto_get_field_ind_static(GF_Node *Node, u32 inField, u8 IndexMode, u32 *allField)
527 : {
528 2651 : return gf_sg_proto_get_field_index((GF_ProtoInstance *)Node, inField, IndexMode, allField);
529 : }
530 :
531 :
532 12 : 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 12 : if (gf_list_count(extern_proto->proto_fields) > gf_list_count(proto->proto_fields)) return 0;
537 12 : count = gf_list_count(extern_proto->proto_fields);
538 84 : for (i=0; i<count; i++) {
539 84 : GF_ProtoFieldInterface *pf1 = (GF_ProtoFieldInterface*)gf_list_get(extern_proto->proto_fields, i);
540 84 : GF_ProtoFieldInterface *pf2 = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
541 84 : if (pf1->EventType != pf2->EventType) return 0;
542 84 : 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 :
548 6 : 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 6 : i=0;
557 6 : while ((proto = (GF_Proto*)gf_list_enum(sg->protos, &i))) {
558 6 : if (is_same_proto(proto, extern_proto)) return proto;
559 : }
560 : /*browse all top-level unregistered in reverse order*/
561 0 : count = gf_list_count(sg->unregistered_protos);
562 0 : for (i=count; i>0; i--) {
563 0 : proto = (GF_Proto*)gf_list_get(sg->unregistered_protos, i-1);
564 0 : 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*/
570 1098 : 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 1098 : GF_Proto *proto = proto_node->proto_interface;
576 : GF_Proto *owner = proto;
577 :
578 1372 : if (!proto) return;
579 :
580 1098 : if (owner->ExternProto.count) {
581 : GF_ProtoFieldInterface *pfi;
582 : GF_SceneGraph *extern_lib;
583 280 : if (!owner->parent_graph->GetExternProtoLib) return;
584 280 : extern_lib = owner->parent_graph->GetExternProtoLib(proto->parent_graph->userpriv, &owner->ExternProto);
585 280 : if (!extern_lib) return;
586 :
587 : /*this is an hardcoded proto - all routes, node modifications and co are handled internally*/
588 100 : if (PTR_TO_U_CAST extern_lib == GF_SG_INTERNAL_PROTO) {
589 87 : proto_node->sgprivate->flags |= GF_SG_NODE_DIRTY;
590 : // take default values
591 87 : count = gf_list_count(owner->proto_fields);
592 279 : for (i=0; i<count; i++) {
593 192 : GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
594 192 : if (!pf->has_been_accessed) {
595 167 : pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
596 167 : gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
597 : }
598 : }
599 87 : owner->parent_graph->NodeCallback(owner->parent_graph->userpriv, GF_SG_CALLBACK_INIT, (GF_Node *) proto_node, NULL);
600 87 : proto_node->flags |= GF_SG_PROTO_LOADED | GF_SG_PROTO_HARDCODED;
601 87 : return;
602 : }
603 : /*not loaded yet*/
604 13 : 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 6 : if (owner->ExternProto.vals[0].url) {
610 0 : u32 ID = (u32) -1;
611 0 : char *szName = strrchr(owner->ExternProto.vals[0].url, '#');
612 0 : if (szName) {
613 0 : szName++;
614 0 : if (sscanf(szName, "%u", &ID)) ID = (u32) -1;
615 : }
616 : /*if we have the proto name, use it*/
617 0 : if (owner->Name) szName = owner->Name;
618 0 : proto = gf_sg_find_proto(extern_lib, ID, szName);
619 : }
620 0 : if (!proto) proto = gf_sg_find_proto(extern_lib, owner->ID, owner->Name);
621 6 : if (!proto) proto = find_proto_by_interface(extern_lib, owner);
622 :
623 6 : if (proto && !is_same_proto(owner, proto)) {
624 : proto = NULL;
625 0 : 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 6 : if (!proto) {
629 0 : proto_node->flags |= GF_SG_PROTO_LOADED;
630 0 : return;
631 : }
632 : /*cf VRML: once an external proto is loaded, copy back the default field values of the external proto*/
633 6 : count = gf_list_count(owner->proto_fields);
634 48 : for (i=0; i<count; i++) {
635 42 : GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
636 42 : if (!pf->has_been_accessed) {
637 18 : pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
638 18 : 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 6 : gf_list_del_item(owner->instances, proto_node);
646 6 : gf_list_add(proto->instances, proto_node);
647 : }
648 :
649 : /*OVERRIDE the proto instance (eg don't instantiate an empty externproto...)*/
650 824 : proto_node->proto_interface = proto;
651 :
652 : /*clone all nodes*/
653 824 : i=0;
654 3266 : 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 1618 : node = gf_node_clone(proto_node->sgprivate->scenegraph, orig, NULL, "", 1);
657 : assert(node);
658 :
659 : /*assign first rendering node*/
660 1618 : if (i==1) proto_node->RenderingNode = node;
661 1618 : gf_list_add(proto_node->node_code, node);
662 : }
663 :
664 : /*instantiate routes (not ISed ones)*/
665 824 : i=0;
666 13570 : while ((route = (GF_Route*)gf_list_enum(proto->sub_graph->Routes, &i))) {
667 11922 : if (route->IS_route) continue;
668 :
669 10248 : r2 = gf_sg_route_new(proto_node->sgprivate->scenegraph,
670 3416 : gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->FromNode) ),
671 : route->FromField.fieldIndex,
672 3416 : gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->ToNode) ),
673 : route->ToField.fieldIndex);
674 :
675 3416 : if (route->ID) gf_sg_route_set_id(r2, route->ID);
676 3416 : 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 824 : i=0;
680 13570 : while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
681 11922 : if (!route->IS_route) continue;
682 : /*do not activate eventIn to eventIn routes*/
683 8506 : if (route->is_setup) {
684 4258 : if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
685 : }
686 8478 : 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 1189 : while (gf_list_count(proto_node->scripts_to_load)) {
690 365 : node = (GF_Node*)gf_list_get(proto_node->scripts_to_load, 0);
691 365 : gf_list_rem(proto_node->scripts_to_load, 0);
692 365 : gf_sg_script_load(node);
693 : }
694 : /*re-activate all ISed fields pointing to scripts once scripts are loaded (eventIns)*/
695 824 : i=0;
696 13570 : while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
697 11922 : 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 8506 : if (route->is_setup) {
703 8506 : if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
704 : }
705 :
706 8478 : if (route->ToNode->sgprivate->tag==TAG_MPEG4_Script)
707 0 : gf_sg_route_activate(route);
708 : #ifndef GPAC_DISABLE_X3D
709 8478 : else if (route->ToNode->sgprivate->tag==TAG_X3D_Script)
710 0 : 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 824 : proto_node->flags |= GF_SG_PROTO_LOADED;
725 : }
726 :
727 18637 : void gf_sg_proto_mark_field_loaded(GF_Node *proto_inst, GF_FieldInfo *info)
728 : {
729 18637 : GF_ProtoInstance *inst= (proto_inst->sgprivate->tag==TAG_ProtoNode) ? (GF_ProtoInstance *)proto_inst : NULL;
730 18637 : GF_ProtoField *pf = inst ? (GF_ProtoField *)gf_list_get(inst->fields, info->fieldIndex) : NULL;
731 18637 : if (pf) pf->has_been_accessed = 1;
732 18637 : }
733 :
734 1959 : 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 1959 : if (!proto) return NULL;
741 :
742 1959 : GF_SAFEALLOC(proto_node, GF_ProtoInstance)
743 1959 : if (!proto_node) return NULL;
744 :
745 1959 : gf_node_setup((GF_Node *)proto_node, TAG_ProtoNode);
746 1959 : proto_node->node_code = gf_list_new();
747 1959 : proto_node->fields = gf_list_new();
748 1959 : proto_node->scripts_to_load = gf_list_new();
749 :
750 1959 : proto_node->proto_interface = proto;
751 1959 : gf_list_add(proto->instances, proto_node);
752 :
753 1959 : proto_node->proto_name = gf_strdup(proto->Name);
754 :
755 : /*create the namespace*/
756 1959 : proto_node->sgprivate->scenegraph = gf_sg_new_subscene(scene);
757 : /*set this proto as owner of the new graph*/
758 1959 : proto_node->sgprivate->scenegraph->pOwningProto = proto_node;
759 :
760 : /*instantiate fields*/
761 1959 : i=0;
762 15314 : while ((field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
763 11396 : GF_SAFEALLOC(inst, GF_ProtoField);
764 11396 : if (!inst) {
765 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate proto instance field\n]"));
766 0 : continue;
767 : }
768 :
769 11396 : inst->EventType = field->EventType;
770 11396 : inst->FieldType = field->FieldType;
771 :
772 : /*this is OK to call on GF_Node (returns NULL) and MFNode (returns gf_list_new() )*/
773 11396 : 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 11396 : if (gf_sg_vrml_get_sf_type(inst->FieldType) != GF_SG_VRML_SFNODE) {
778 10242 : if (from_inst) {
779 387 : from_field = (GF_ProtoField *)gf_list_get(from_inst->fields, i-1);
780 387 : gf_sg_vrml_field_copy(inst->field_pointer, from_field->field_pointer, inst->FieldType);
781 387 : inst->has_been_accessed = from_field->has_been_accessed;
782 : } else {
783 9855 : gf_sg_vrml_field_copy(inst->field_pointer, field->def_value, inst->FieldType);
784 : }
785 : }
786 : /*No default values for SFNodes as interfaces ...*/
787 11396 : gf_list_add(proto_node->fields, inst);
788 : }
789 : return (GF_Node *) proto_node;
790 : }
791 :
792 :
793 : GF_EXPORT
794 1569 : GF_Node *gf_sg_proto_create_instance(GF_SceneGraph *sg, GF_Proto *proto)
795 : {
796 1569 : return gf_sg_proto_create_node(sg, proto, NULL);
797 : }
798 :
799 : GF_EXPORT
800 541 : GF_Err gf_sg_proto_load_code(GF_Node *node)
801 : {
802 : GF_ProtoInstance *inst;
803 541 : if (node->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
804 : inst = (GF_ProtoInstance *) node;
805 541 : if (!inst->proto_interface) return GF_BAD_PARAM;
806 541 : if (inst->flags & GF_SG_PROTO_LOADED) return GF_OK;
807 541 : gf_sg_proto_instantiate(inst);
808 541 : return GF_OK;
809 : }
810 :
811 :
812 2264 : u32 gf_sg_proto_get_num_fields(GF_Node *node, u8 code_mode)
813 : {
814 : GF_ProtoInstance *proto;
815 2264 : if (!node) return 0;
816 :
817 : proto = (GF_ProtoInstance *)node;
818 : /*watchout for deletion case*/
819 2264 : switch (code_mode) {
820 153 : case GF_SG_FIELD_CODING_IN:
821 153 : return proto->proto_interface ? proto->proto_interface->NumIn : 0;
822 0 : case GF_SG_FIELD_CODING_OUT:
823 0 : return proto->proto_interface ? proto->proto_interface->NumOut : 0;
824 989 : case GF_SG_FIELD_CODING_DEF:
825 989 : return proto->proto_interface ? proto->proto_interface->NumDef : 0;
826 1122 : case GF_SG_FIELD_CODING_ALL:
827 1122 : 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 :
836 1959 : void gf_sg_proto_del_instance(GF_ProtoInstance *inst)
837 : {
838 : GF_SceneGraph *sg;
839 :
840 15314 : while (gf_list_count(inst->fields)) {
841 11396 : GF_ProtoField *field = (GF_ProtoField *)gf_list_get(inst->fields, 0);
842 11396 : gf_list_rem(inst->fields, 0);
843 :
844 : /*regular type*/
845 11396 : if ( (field->FieldType!=GF_SG_VRML_SFNODE) && (field->FieldType!=GF_SG_VRML_MFNODE)) {
846 10242 : gf_sg_vrml_field_pointer_del(field->field_pointer, field->FieldType);
847 : }
848 : /*node types: delete instances*/
849 1154 : else if (field->field_pointer) {
850 495 : if (field->FieldType == GF_SG_VRML_SFNODE) {
851 422 : gf_node_unregister((GF_Node *) field->field_pointer, (GF_Node *) inst);
852 : } else {
853 : GF_ChildNodeItem *list = (GF_ChildNodeItem *)field->field_pointer;
854 146 : while (list) {
855 : GF_ChildNodeItem *cur = list;
856 73 : gf_node_unregister(list->node, (GF_Node *) inst);
857 73 : list = list->next;
858 73 : gf_free(cur);
859 : }
860 : }
861 : }
862 :
863 11396 : gf_free(field);
864 : }
865 1959 : gf_list_del(inst->fields);
866 :
867 : /*destroy the code*/
868 5536 : while (gf_list_count(inst->node_code)) {
869 1618 : GF_Node *node = (GF_Node*)gf_list_get(inst->node_code, 0);
870 1618 : gf_node_unregister(node, (GF_Node*) inst);
871 1618 : gf_list_rem(inst->node_code, 0);
872 : }
873 :
874 1959 : 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 1959 : gf_sg_reset(sg);
880 1959 : sg->pOwningProto = NULL;
881 :
882 1959 : gf_free((char *) inst->proto_name);
883 1959 : gf_list_del(inst->node_code);
884 : assert(!gf_list_count(inst->scripts_to_load));
885 1959 : gf_list_del(inst->scripts_to_load);
886 :
887 1959 : if (inst->proto_interface && inst->proto_interface->instances) gf_list_del_item(inst->proto_interface->instances, inst);
888 :
889 1959 : gf_node_free((GF_Node *)inst);
890 1959 : gf_sg_del(sg);
891 1959 : }
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
897 552 : 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 552 : field.fieldIndex = protoFieldIndex;
903 552 : e = gf_sg_proto_get_field(proto, NULL, &field);
904 552 : if (e) return e;
905 552 : e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
906 552 : if (e) return e;
907 552 : if (field.fieldType != nodeField.fieldType) {
908 5 : 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 0 : } 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 0 : 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 552 : GF_SAFEALLOC(r, GF_Route)
919 552 : if (!r) return GF_OUT_OF_MEM;
920 552 : r->IS_route = 1;
921 :
922 552 : if (nodeField.eventType==GF_SG_EVENT_OUT) {
923 8 : r->FromField.fieldIndex = nodeFieldIndex;
924 8 : r->FromNode = node;
925 8 : r->ToField.fieldIndex = protoFieldIndex;
926 8 : r->ToNode = NULL;
927 8 : if (!node->sgprivate->interact) {
928 8 : GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
929 8 : if (!node->sgprivate->interact) {
930 : return GF_OUT_OF_MEM;
931 : }
932 : }
933 8 : if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
934 8 : gf_list_add(node->sgprivate->interact->routes, r);
935 : } else {
936 544 : switch (field.eventType) {
937 544 : case GF_SG_EVENT_FIELD:
938 : case GF_SG_EVENT_EXPOSED_FIELD:
939 : case GF_SG_EVENT_IN:
940 544 : r->FromField.fieldIndex = protoFieldIndex;
941 544 : r->FromNode = NULL;
942 544 : r->ToField.fieldIndex = nodeFieldIndex;
943 544 : r->ToNode = node;
944 : /*create an ISed route for the eventOut part of the exposedFIeld*/
945 544 : if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
946 : GF_Route *r2;
947 478 : GF_SAFEALLOC(r2, GF_Route);
948 478 : if (!r2) {
949 0 : gf_free(r);
950 0 : return GF_OUT_OF_MEM;
951 : }
952 478 : r2->IS_route = 1;
953 478 : r2->FromField.fieldIndex = nodeFieldIndex;
954 478 : r2->FromNode = node;
955 478 : r2->ToField.fieldIndex = protoFieldIndex;
956 478 : r2->ToNode = NULL;
957 478 : r2->graph = proto->sub_graph;
958 478 : if (!node->sgprivate->interact) {
959 268 : GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
960 268 : if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
961 : }
962 478 : if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
963 478 : gf_list_add(node->sgprivate->interact->routes, r2);
964 478 : gf_list_add(proto->sub_graph->Routes, r2);
965 : }
966 : break;
967 0 : case GF_SG_EVENT_OUT:
968 0 : r->FromField.fieldIndex = nodeFieldIndex;
969 0 : r->FromNode = node;
970 0 : r->ToField.fieldIndex = protoFieldIndex;
971 0 : r->ToNode = NULL;
972 0 : if (!node->sgprivate->interact) {
973 0 : GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
974 0 : if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
975 : }
976 0 : if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
977 : break;
978 0 : default:
979 0 : gf_free(r);
980 0 : return GF_BAD_PARAM;
981 : }
982 : }
983 552 : r->graph = proto->sub_graph;
984 552 : return gf_list_add(proto->sub_graph->Routes, r);
985 : }
986 :
987 : GF_EXPORT
988 0 : 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 0 : if (protoinst->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
994 :
995 0 : e = gf_node_get_field(protoinst, protoFieldIndex, &field);
996 0 : if (e) return e;
997 0 : e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
998 0 : if (e) return e;
999 0 : if (field.fieldType != nodeField.fieldType) {
1000 0 : 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 0 : } 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 0 : 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 0 : GF_SAFEALLOC(r, GF_Route)
1011 0 : if (!r) return GF_OUT_OF_MEM;
1012 0 : r->IS_route = 1;
1013 :
1014 0 : if (nodeField.eventType==GF_SG_EVENT_OUT) {
1015 0 : r->FromField.fieldIndex = nodeFieldIndex;
1016 0 : r->FromNode = node;
1017 0 : r->ToField.fieldIndex = protoFieldIndex;
1018 0 : r->ToNode = protoinst;
1019 0 : if (!node->sgprivate->interact) {
1020 0 : GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
1021 0 : if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
1022 : }
1023 0 : if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
1024 0 : gf_list_add(node->sgprivate->interact->routes, r);
1025 : } else {
1026 0 : switch (field.eventType) {
1027 0 : case GF_SG_EVENT_FIELD:
1028 : case GF_SG_EVENT_EXPOSED_FIELD:
1029 : case GF_SG_EVENT_IN:
1030 0 : r->FromField.fieldIndex = protoFieldIndex;
1031 0 : r->FromNode = protoinst;
1032 0 : r->ToField.fieldIndex = nodeFieldIndex;
1033 0 : r->ToNode = node;
1034 :
1035 : /*create an ISed route for the eventOut part of the exposedFIeld*/
1036 0 : if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
1037 : GF_Route *r2;
1038 0 : GF_SAFEALLOC(r2, GF_Route);
1039 0 : if (!r2) {
1040 0 : gf_free(r);
1041 0 : return GF_OUT_OF_MEM;
1042 : }
1043 0 : r2->IS_route = 1;
1044 0 : r2->FromField.fieldIndex = nodeFieldIndex;
1045 0 : r2->FromNode = node;
1046 0 : r2->ToField.fieldIndex = protoFieldIndex;
1047 0 : r2->ToNode = protoinst;
1048 0 : r2->graph = node->sgprivate->scenegraph;
1049 0 : if (!node->sgprivate->interact) {
1050 0 : GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
1051 0 : if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
1052 : }
1053 0 : if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
1054 0 : gf_list_add(node->sgprivate->interact->routes, r2);
1055 0 : gf_list_add(r->graph->Routes, r2);
1056 : }
1057 : break;
1058 0 : case GF_SG_EVENT_OUT:
1059 0 : r->FromField.fieldIndex = nodeFieldIndex;
1060 0 : r->FromNode = node;
1061 0 : r->ToField.fieldIndex = protoFieldIndex;
1062 0 : r->ToNode = protoinst;
1063 0 : if (!node->sgprivate->interact) {
1064 0 : GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
1065 0 : if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
1066 : }
1067 0 : if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
1068 0 : gf_list_add(node->sgprivate->interact->routes, r);
1069 0 : break;
1070 0 : default:
1071 0 : gf_free(r);
1072 0 : return GF_BAD_PARAM;
1073 : }
1074 : }
1075 0 : r->graph = node->sgprivate->scenegraph;
1076 0 : gf_sg_route_activate(r);
1077 0 : return gf_list_add(r->graph->Routes, r);
1078 : }
1079 :
1080 :
1081 4 : 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 4 : if (!field) return GF_BAD_PARAM;
1091 4 : if (!QP_Type) return GF_OK;
1092 4 : if (!gf_sg_vrml_is_sf_field(QPSFType)) return GF_BAD_PARAM;
1093 :
1094 4 : field->QP_Type = QP_Type;
1095 4 : field->hasMinMax = hasMinMax;
1096 4 : if (hasMinMax) {
1097 4 : if (qp_min_value) {
1098 4 : field->qp_min_value = gf_sg_vrml_field_pointer_new(QPSFType);
1099 4 : gf_sg_vrml_field_copy(field->qp_min_value, qp_min_value, QPSFType);
1100 : }
1101 4 : if (qp_max_value) {
1102 4 : field->qp_max_value = gf_sg_vrml_field_pointer_new(QPSFType);
1103 4 : gf_sg_vrml_field_copy(field->qp_max_value, qp_max_value, QPSFType);
1104 : }
1105 : }
1106 4 : field->NumBits = QP13_NumBits;
1107 4 : return GF_OK;
1108 : }
1109 :
1110 :
1111 2651 : 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 2651 : i=0;
1117 11508 : while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_interface->proto_fields, &i))) {
1118 : assert(proto_field);
1119 8857 : switch (code_mode) {
1120 197 : case GF_SG_FIELD_CODING_IN:
1121 197 : if (proto_field->IN_index == index) {
1122 133 : *all_index = proto_field->ALL_index;
1123 133 : return GF_OK;
1124 : }
1125 : break;
1126 0 : case GF_SG_FIELD_CODING_OUT:
1127 0 : if (proto_field->OUT_index == index) {
1128 0 : *all_index = proto_field->ALL_index;
1129 0 : return GF_OK;
1130 : }
1131 : break;
1132 8660 : case GF_SG_FIELD_CODING_DEF:
1133 8660 : if (proto_field->DEF_index == index) {
1134 2518 : *all_index = proto_field->ALL_index;
1135 2518 : return GF_OK;
1136 : }
1137 : break;
1138 0 : case GF_SG_FIELD_CODING_ALL:
1139 0 : if (proto_field->ALL_index == index) {
1140 0 : *all_index = proto_field->ALL_index;
1141 0 : 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
1154 710 : u32 gf_sg_proto_get_field_count(GF_Proto *proto)
1155 : {
1156 710 : if (!proto) return 0;
1157 710 : return gf_list_count(proto->proto_fields);
1158 : }
1159 :
1160 : GF_EXPORT
1161 326 : GF_ProtoFieldInterface *gf_sg_proto_field_find(GF_Proto *proto, u32 fieldIndex)
1162 : {
1163 326 : if (!proto) return NULL;
1164 326 : return (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, fieldIndex);
1165 : }
1166 :
1167 61686 : void gf_sg_proto_propagate_event(GF_Node *node, u32 fieldIndex, GF_Node *from_node)
1168 : {
1169 : u32 i;
1170 : GF_Route *r;
1171 106222 : if (!node) return;
1172 : /*propagation only for proto*/
1173 61686 : if (node->sgprivate->tag != TAG_ProtoNode) return;
1174 : /*with ISed fields*/
1175 21955 : 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 21056 : if (from_node->sgprivate->scenegraph == node->sgprivate->scenegraph) return;
1179 :
1180 : /*for all ISed routes*/
1181 17150 : i=0;
1182 214342 : while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
1183 180042 : 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 154378 : if ((r->FromNode == node) && (r->FromField.fieldIndex == fieldIndex) && (r->ToNode != from_node) ) {
1186 9600 : if (gf_sg_route_activate(r))
1187 2201 : gf_node_changed(r->ToNode, &r->ToField);
1188 : }
1189 : }
1190 : }
1191 :
1192 :
1193 73 : 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 73 : proto = ((GF_ProtoInstance *)Node)->proto_interface;
1200 :
1201 73 : i=0;
1202 426 : while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
1203 353 : if (proto_field->ALL_index!=FieldIndex) continue;
1204 :
1205 73 : *QType = proto_field->QP_Type;
1206 73 : *AType = proto_field->Anim_Type;
1207 73 : *b_min = FIX_MIN;
1208 73 : *b_max = FIX_MAX;
1209 :
1210 73 : if (proto_field->hasMinMax) {
1211 :
1212 : /*translate our bounds*/
1213 0 : switch (gf_sg_vrml_get_sf_type(proto_field->FieldType)) {
1214 0 : case GF_SG_VRML_SFINT32:
1215 0 : *b_min = (SFFloat) * ( (SFInt32 *) proto_field->qp_min_value);
1216 0 : *b_max = (SFFloat) * ( (SFInt32 *) proto_field->qp_max_value);
1217 0 : break;
1218 : /*TO DO EVERYWHERE: check on field translation from double to float
1219 : during quant bounds*/
1220 0 : case GF_SG_VRML_SFTIME:
1221 0 : *b_min = (SFFloat) * ( (SFTime *) proto_field->qp_min_value);
1222 0 : *b_max = (SFFloat) * ( (SFTime *) proto_field->qp_max_value);
1223 0 : break;
1224 0 : default:
1225 0 : if (proto_field->qp_min_value)
1226 0 : *b_min = (SFFloat) * ( (SFFloat *) proto_field->qp_min_value);
1227 0 : if (proto_field->qp_max_value)
1228 0 : *b_max = (SFFloat) * ( (SFFloat *) proto_field->qp_max_value);
1229 : break;
1230 : }
1231 :
1232 73 : }
1233 73 : *QT13_bits = proto_field->NumBits;
1234 73 : return 1;
1235 : }
1236 : return 0;
1237 : }
1238 :
1239 :
1240 : GF_EXPORT
1241 661 : GF_Proto *gf_node_get_proto(GF_Node *node)
1242 : {
1243 : GF_ProtoInstance *inst;
1244 661 : if (node->sgprivate->tag != TAG_ProtoNode) return NULL;
1245 : inst = (GF_ProtoInstance *) node;
1246 661 : return inst->proto_interface;
1247 : }
1248 :
1249 : /*returns the ID of the proto*/
1250 : GF_EXPORT
1251 0 : u32 gf_sg_proto_get_id(GF_Proto *proto)
1252 : {
1253 0 : return proto->ID;
1254 : }
1255 :
1256 : GF_EXPORT
1257 18 : const char *gf_sg_proto_get_class_name(GF_Proto *proto)
1258 : {
1259 18 : return (const char *) proto->Name;
1260 : }
1261 :
1262 131 : u32 gf_sg_proto_get_root_tag(GF_Proto *proto)
1263 : {
1264 : GF_Node *n;
1265 131 : if (!proto) return TAG_UndefinedNode;
1266 131 : n = (GF_Node*)gf_list_get(proto->node_code, 0);
1267 131 : if (!n) return TAG_UndefinedNode;
1268 98 : if (n->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_root_tag(((GF_ProtoInstance *)n)->proto_interface);
1269 98 : return n->sgprivate->tag;
1270 : }
1271 :
1272 : GF_EXPORT
1273 31 : 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 31 : if (node->sgprivate->tag != TAG_ProtoNode) return 0;
1280 31 : if (field->fieldType != GF_SG_VRML_SFTIME) return 0;
1281 :
1282 : inst = (GF_ProtoInstance *) node;
1283 : /*check in interface if this is ISed */
1284 31 : i=0;
1285 344 : while ((r = (GF_Route*)gf_list_enum(inst->proto_interface->sub_graph->Routes, &i))) {
1286 292 : if (!r->IS_route) continue;
1287 : /*only check eventIn/field/exposedField*/
1288 278 : if (r->FromNode || (r->FromField.fieldIndex != field->fieldIndex)) continue;
1289 :
1290 17 : gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &inf);
1291 : /*IS to another proto*/
1292 17 : 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 17 : if (!stricmp(inf.name, "startTime") || !stricmp(inf.name, "stopTime")) return 1;
1295 : }
1296 : return 0;
1297 : }
1298 :
1299 : GF_EXPORT
1300 84 : GF_Err gf_node_proto_set_grouping(GF_Node *node)
1301 : {
1302 84 : if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
1303 84 : ((GF_ProtoInstance *)node)->flags |= GF_SG_PROTO_IS_GROUPING;
1304 84 : return GF_OK;
1305 : }
1306 :
1307 : GF_EXPORT
1308 0 : Bool gf_node_proto_is_grouping(GF_Node *node)
1309 : {
1310 0 : if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return 0;
1311 0 : if ( ((GF_ProtoInstance *)node)->flags & GF_SG_PROTO_IS_GROUPING) return 1;
1312 0 : return 0;
1313 : }
1314 :
1315 : GF_EXPORT
1316 0 : GF_Node *gf_node_get_proto_root(GF_Node *node)
1317 : {
1318 0 : if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return NULL;
1319 0 : 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
1345 1 : 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 1 : if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
1350 :
1351 : inst = (GF_ProtoInstance *) node;
1352 1 : field = (GF_ProtoField*)gf_list_get(inst->fields, fieldIndex);
1353 1 : if (!field) return GF_BAD_PARAM;
1354 :
1355 1 : if (field->EventType!=GF_SG_EVENT_IN) return GF_BAD_PARAM;
1356 1 : field->on_event_in = event_in_cbk;
1357 1 : return GF_OK;
1358 : }
1359 :
1360 :
1361 :
1362 : #endif /*GPAC_DISABLE_VRML*/
|