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