/src/gpac/src/scenegraph/vrml_script.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2000-2012 |
6 | | * All rights reserved |
7 | | * |
8 | | * This file is part of GPAC / Scene Graph sub-project |
9 | | * |
10 | | * GPAC is free software; you can redistribute it and/or modify |
11 | | * it under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2, or (at your option) |
13 | | * any later version. |
14 | | * |
15 | | * GPAC is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; see the file COPYING. If not, write to |
22 | | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | | * |
24 | | */ |
25 | | |
26 | | #include <gpac/internal/scenegraph_dev.h> |
27 | | /*MPEG4 & X3D tags (for node tables & script handling)*/ |
28 | | #include <gpac/nodes_mpeg4.h> |
29 | | #include <gpac/nodes_x3d.h> |
30 | | #include "qjs_common.h" |
31 | | |
32 | | #ifndef GPAC_DISABLE_VRML |
33 | | |
34 | | |
35 | | static u32 script_get_nb_static_field(GF_Node *node) |
36 | 0 | { |
37 | 0 | return (node->sgprivate->tag==TAG_MPEG4_Script) ? 3 : 4; |
38 | 0 | } |
39 | | |
40 | | void Script_PreDestroy(GF_Node *node, void *eff, Bool is_destroy) |
41 | 0 | { |
42 | 0 | GF_ScriptPriv *priv; |
43 | |
|
44 | 0 | if (!is_destroy) return; |
45 | | |
46 | 0 | priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate; |
47 | |
|
48 | 0 | if (priv->JS_PreDestroy) priv->JS_PreDestroy(node); |
49 | | |
50 | | //destroy extra fields |
51 | 0 | while (gf_list_count(priv->fields)) { |
52 | 0 | GF_ScriptField *field = (GF_ScriptField *)gf_list_get(priv->fields, 0); |
53 | 0 | gf_list_rem(priv->fields, 0); |
54 | 0 | if (field->pField) { |
55 | | //if Node unregister |
56 | 0 | switch (field->fieldType) { |
57 | | //specific case for GF_Node in script |
58 | 0 | case GF_SG_VRML_SFNODE: |
59 | 0 | gf_node_unregister((GF_Node *) field->pField, node); |
60 | 0 | break; |
61 | 0 | case GF_SG_VRML_MFNODE: |
62 | 0 | gf_node_unregister_children(node, (GF_ChildNodeItem*) field->pField); |
63 | 0 | break; |
64 | 0 | default: |
65 | 0 | gf_sg_vrml_field_pointer_del(field->pField, field->fieldType); |
66 | 0 | break; |
67 | 0 | } |
68 | 0 | } |
69 | 0 | if (field->name) gf_free(field->name); |
70 | 0 | gf_free(field); |
71 | 0 | } |
72 | 0 | gf_list_del(priv->fields); |
73 | 0 | gf_free(priv); |
74 | 0 | } |
75 | | |
76 | | u32 gf_sg_script_get_num_fields(GF_Node *node, u8 IndexMode) |
77 | 0 | { |
78 | 0 | u32 nb_static; |
79 | 0 | GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate; |
80 | 0 | switch (IndexMode) { |
81 | 0 | case GF_SG_FIELD_CODING_IN: |
82 | 0 | return priv->numIn; |
83 | 0 | case GF_SG_FIELD_CODING_OUT: |
84 | 0 | return priv->numOut; |
85 | 0 | case GF_SG_FIELD_CODING_DEF: |
86 | 0 | return priv->numDef; |
87 | 0 | case GF_SG_FIELD_CODING_DYN: |
88 | 0 | return 0; |
89 | 0 | default: |
90 | 0 | nb_static = script_get_nb_static_field(node); |
91 | 0 | return priv ? gf_list_count(priv->fields) + nb_static : nb_static; |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | GF_EXPORT |
96 | | GF_Err gf_sg_script_get_field_index(GF_Node *node, u32 inField, u8 IndexMode, u32 *allField) |
97 | 0 | { |
98 | 0 | u32 i; |
99 | 0 | GF_ScriptField *sf; |
100 | 0 | u32 nb_static = script_get_nb_static_field(node); |
101 | 0 | GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate; |
102 | 0 | i=0; |
103 | 0 | while (priv && (sf = (GF_ScriptField *)gf_list_enum(priv->fields, &i))) { |
104 | 0 | *allField = i-1+nb_static; |
105 | 0 | switch (IndexMode) { |
106 | 0 | case GF_SG_FIELD_CODING_IN: |
107 | 0 | if ((u32)sf->IN_index==inField) return GF_OK; |
108 | 0 | break; |
109 | 0 | case GF_SG_FIELD_CODING_DEF: |
110 | 0 | if ((u32)sf->DEF_index==inField) return GF_OK; |
111 | 0 | break; |
112 | 0 | case GF_SG_FIELD_CODING_OUT: |
113 | 0 | if ((u32)sf->OUT_index==inField) return GF_OK; |
114 | 0 | break; |
115 | 0 | case GF_SG_FIELD_CODING_DYN: |
116 | 0 | return GF_BAD_PARAM; |
117 | 0 | default: |
118 | 0 | if (inField==i-1+nb_static) return GF_OK; |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | } |
122 | | /*try with default*/ |
123 | | |
124 | 0 | if (gf_sg_mpeg4_node_get_field_count(node, IndexMode) <= inField) |
125 | 0 | return GF_NON_COMPLIANT_BITSTREAM; |
126 | | |
127 | 0 | return gf_sg_mpeg4_node_get_field_index(node, inField, IndexMode, allField); |
128 | 0 | } |
129 | | |
130 | | |
131 | | GF_Err gf_sg_script_get_field(GF_Node *node, GF_FieldInfo *info) |
132 | 0 | { |
133 | 0 | GF_ScriptField *field; |
134 | 0 | GF_ScriptPriv *priv; |
135 | 0 | u32 nb_static; |
136 | |
|
137 | 0 | if (!info || !node) return GF_BAD_PARAM; |
138 | | |
139 | 0 | priv = (GF_ScriptPriv *)gf_node_get_private(node); |
140 | 0 | nb_static = script_get_nb_static_field(node); |
141 | | |
142 | | //static fields |
143 | 0 | if (info->fieldIndex < nb_static) { |
144 | 0 | if (nb_static==3) return gf_sg_mpeg4_node_get_field(node, info); |
145 | 0 | #ifndef GPAC_DISABLE_X3D |
146 | 0 | return gf_sg_x3d_node_get_field(node, info); |
147 | | #else |
148 | | return GF_NOT_SUPPORTED; |
149 | | #endif |
150 | 0 | } |
151 | | |
152 | | //dyn fields |
153 | 0 | field = (GF_ScriptField *)gf_list_get(priv->fields, info->fieldIndex - nb_static); |
154 | 0 | if (!field) return GF_BAD_PARAM; |
155 | | |
156 | 0 | info->eventType = field->eventType; |
157 | 0 | info->fieldType = field->fieldType; |
158 | 0 | info->name = field->name; |
159 | | //we need the eventIn name to activate the function... |
160 | 0 | info->on_event_in = NULL; |
161 | | |
162 | | //setup pointer (special cases for nodes) |
163 | 0 | switch (field->fieldType) { |
164 | 0 | case GF_SG_VRML_SFNODE: |
165 | 0 | case GF_SG_VRML_MFNODE: |
166 | 0 | info->far_ptr = &field->pField; |
167 | 0 | info->NDTtype = NDT_SFWorldNode; |
168 | 0 | break; |
169 | 0 | default: |
170 | 0 | info->far_ptr = field->pField; |
171 | 0 | break; |
172 | 0 | } |
173 | 0 | return GF_OK; |
174 | 0 | } |
175 | | |
176 | | void gf_sg_script_init(GF_Node *node) |
177 | 0 | { |
178 | 0 | GF_ScriptPriv *priv; |
179 | | |
180 | |
|
181 | 0 | GF_SAFEALLOC(priv, GF_ScriptPriv) |
182 | 0 | if (!priv) { |
183 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create script node\n")); |
184 | 0 | return; |
185 | 0 | } |
186 | 0 | priv->fields = gf_list_new(); |
187 | |
|
188 | 0 | gf_node_set_private(node, priv); |
189 | 0 | node->sgprivate->UserCallback = Script_PreDestroy; |
190 | | |
191 | | //URL is exposedField (in, out Def) |
192 | 0 | priv->numDef = priv->numIn = priv->numOut = script_get_nb_static_field(node) - 2; |
193 | | //directOutput and mustEvaluate are fields (def) |
194 | 0 | priv->numDef += 2; |
195 | 0 | } |
196 | | |
197 | | GF_EXPORT |
198 | | GF_ScriptField *gf_sg_script_field_new(GF_Node *node, u32 eventType, u32 fieldType, const char *name) |
199 | 0 | { |
200 | 0 | GF_ScriptPriv *priv; |
201 | 0 | GF_ScriptField *field; |
202 | 0 | if (!name || ((node->sgprivate->tag != TAG_MPEG4_Script) |
203 | 0 | #ifndef GPAC_DISABLE_X3D |
204 | 0 | && (node->sgprivate->tag != TAG_X3D_Script) |
205 | 0 | #endif |
206 | 0 | )) |
207 | 0 | return NULL; |
208 | | |
209 | 0 | if (eventType > GF_SG_SCRIPT_TYPE_EVENT_OUT) return NULL; |
210 | 0 | priv = (GF_ScriptPriv *)gf_node_get_private(node); |
211 | |
|
212 | 0 | GF_SAFEALLOC(field, GF_ScriptField) |
213 | 0 | if (!field) { |
214 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create script field\n")); |
215 | 0 | return NULL; |
216 | 0 | } |
217 | 0 | field->fieldType = fieldType; |
218 | 0 | field->name = gf_strdup(name); |
219 | |
|
220 | 0 | field->DEF_index = field->IN_index = field->OUT_index = -1; |
221 | 0 | switch (eventType) { |
222 | 0 | case GF_SG_SCRIPT_TYPE_FIELD: |
223 | 0 | field->DEF_index = priv->numDef; |
224 | 0 | priv->numDef++; |
225 | 0 | field->eventType = GF_SG_EVENT_FIELD; |
226 | 0 | break; |
227 | 0 | case GF_SG_SCRIPT_TYPE_EVENT_IN: |
228 | 0 | field->IN_index = priv->numIn; |
229 | 0 | priv->numIn++; |
230 | 0 | field->eventType = GF_SG_EVENT_IN; |
231 | 0 | break; |
232 | 0 | case GF_SG_SCRIPT_TYPE_EVENT_OUT: |
233 | 0 | field->OUT_index = priv->numOut; |
234 | 0 | field->eventType = GF_SG_EVENT_OUT; |
235 | 0 | priv->numOut++; |
236 | 0 | break; |
237 | 0 | } |
238 | | //+ static fields |
239 | 0 | field->ALL_index = script_get_nb_static_field(node) + gf_list_count(priv->fields); |
240 | 0 | gf_list_add(priv->fields, field); |
241 | | |
242 | | //create field entry |
243 | 0 | if ((fieldType != GF_SG_VRML_SFNODE) && (fieldType != GF_SG_VRML_MFNODE) ) { |
244 | 0 | field->pField = gf_sg_vrml_field_pointer_new(fieldType); |
245 | 0 | } |
246 | |
|
247 | 0 | return field; |
248 | 0 | } |
249 | | |
250 | | |
251 | | GF_Err gf_sg_script_prepare_clone(GF_Node *dest, GF_Node *orig) |
252 | 0 | { |
253 | 0 | u32 i, type; |
254 | 0 | GF_ScriptField *sf; |
255 | 0 | GF_ScriptPriv *dest_priv, *orig_priv; |
256 | 0 | orig_priv = (GF_ScriptPriv *)orig->sgprivate->UserPrivate; |
257 | 0 | dest_priv = (GF_ScriptPriv *)dest->sgprivate->UserPrivate; |
258 | 0 | if (!orig_priv || !dest_priv) return GF_BAD_PARAM; |
259 | | |
260 | 0 | i=0; |
261 | 0 | while ((sf = (GF_ScriptField *)gf_list_enum(orig_priv->fields, &i))) { |
262 | 0 | switch (sf->eventType) { |
263 | 0 | case GF_SG_EVENT_IN: |
264 | 0 | type = GF_SG_SCRIPT_TYPE_EVENT_IN; |
265 | 0 | break; |
266 | 0 | case GF_SG_EVENT_OUT: |
267 | 0 | type = GF_SG_SCRIPT_TYPE_EVENT_OUT; |
268 | 0 | break; |
269 | 0 | case GF_SG_EVENT_FIELD: |
270 | 0 | type = GF_SG_SCRIPT_TYPE_FIELD; |
271 | 0 | break; |
272 | 0 | default: |
273 | 0 | return GF_BAD_PARAM; |
274 | 0 | } |
275 | 0 | gf_sg_script_field_new(dest, type, sf->fieldType, sf->name); |
276 | 0 | } |
277 | 0 | return GF_OK; |
278 | 0 | } |
279 | | |
280 | | GF_EXPORT |
281 | | GF_Err gf_sg_script_field_get_info(GF_ScriptField *field, GF_FieldInfo *info) |
282 | 0 | { |
283 | 0 | if (!field || !info) return GF_BAD_PARAM; |
284 | 0 | memset(info, 0, sizeof(GF_FieldInfo)); |
285 | |
|
286 | 0 | info->fieldIndex = field->ALL_index; |
287 | 0 | info->eventType = field->eventType; |
288 | 0 | info->fieldType = field->fieldType; |
289 | 0 | info->name = field->name; |
290 | | |
291 | | //setup pointer (special cases for nodes) |
292 | 0 | switch (field->fieldType) { |
293 | 0 | case GF_SG_VRML_SFNODE: |
294 | 0 | case GF_SG_VRML_MFNODE: |
295 | 0 | info->far_ptr = &field->pField; |
296 | 0 | info->NDTtype = NDT_SFWorldNode; |
297 | 0 | break; |
298 | 0 | default: |
299 | 0 | info->far_ptr = field->pField; |
300 | 0 | break; |
301 | 0 | } |
302 | 0 | return GF_OK; |
303 | 0 | } |
304 | | |
305 | | GF_EXPORT |
306 | | void gf_sg_script_event_in(GF_Node *node, GF_FieldInfo *in_field) |
307 | 0 | { |
308 | 0 | GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate; |
309 | 0 | if (priv->JS_EventIn) priv->JS_EventIn(node, in_field); |
310 | 0 | } |
311 | | |
312 | | |
313 | | #endif /*GPAC_DISABLE_VRML*/ |