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 
script_get_nb_static_field(GF_Node * node)35 static u32 script_get_nb_static_field(GF_Node *node)
36 {
37 	return (node->sgprivate->tag==TAG_MPEG4_Script) ? 3 : 4;
38 }
39 
Script_PreDestroy(GF_Node * node,void * eff,Bool is_destroy)40 void Script_PreDestroy(GF_Node *node, void *eff, Bool is_destroy)
41 {
42 	GF_ScriptPriv *priv;
43 
44 	if (!is_destroy) return;
45 
46 	priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
47 
48 	if (priv->JS_PreDestroy) priv->JS_PreDestroy(node);
49 
50 	//destroy extra fields
51 	while (gf_list_count(priv->fields)) {
52 		GF_ScriptField *field = (GF_ScriptField *)gf_list_get(priv->fields, 0);
53 		gf_list_rem(priv->fields, 0);
54 		if (field->pField) {
55 			//if Node unregister
56 			switch (field->fieldType) {
57 			//specific case for GF_Node in script
58 			case GF_SG_VRML_SFNODE:
59 				gf_node_unregister((GF_Node *) field->pField, node);
60 				break;
61 			case GF_SG_VRML_MFNODE:
62 				gf_node_unregister_children(node, (GF_ChildNodeItem*) field->pField);
63 				break;
64 			default:
65 				gf_sg_vrml_field_pointer_del(field->pField, field->fieldType);
66 				break;
67 			}
68 		}
69 		if (field->name) gf_free(field->name);
70 		gf_free(field);
71 	}
72 	gf_list_del(priv->fields);
73 	gf_free(priv);
74 }
75 
gf_sg_script_get_num_fields(GF_Node * node,u8 IndexMode)76 u32 gf_sg_script_get_num_fields(GF_Node *node, u8 IndexMode)
77 {
78 	u32 nb_static;
79 	GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
80 	switch (IndexMode) {
81 	case GF_SG_FIELD_CODING_IN:
82 		return priv->numIn;
83 	case GF_SG_FIELD_CODING_OUT:
84 		return priv->numOut;
85 	case GF_SG_FIELD_CODING_DEF:
86 		return priv->numDef;
87 	case GF_SG_FIELD_CODING_DYN:
88 		return 0;
89 	default:
90 		nb_static = script_get_nb_static_field(node);
91 		return priv ? gf_list_count(priv->fields) + nb_static : nb_static;
92 	}
93 }
94 
95 GF_EXPORT
gf_sg_script_get_field_index(GF_Node * node,u32 inField,u8 IndexMode,u32 * allField)96 GF_Err gf_sg_script_get_field_index(GF_Node *node, u32 inField, u8 IndexMode, u32 *allField)
97 {
98 	u32 i;
99 	GF_ScriptField *sf;
100 	u32 nb_static = script_get_nb_static_field(node);
101 	GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
102 	i=0;
103 	while (priv && (sf = (GF_ScriptField *)gf_list_enum(priv->fields, &i))) {
104 		*allField = i-1+nb_static;
105 		switch (IndexMode) {
106 		case GF_SG_FIELD_CODING_IN:
107 			if ((u32)sf->IN_index==inField) return GF_OK;
108 			break;
109 		case GF_SG_FIELD_CODING_DEF:
110 			if ((u32)sf->DEF_index==inField) return GF_OK;
111 			break;
112 		case GF_SG_FIELD_CODING_OUT:
113 			if ((u32)sf->OUT_index==inField) return GF_OK;
114 			break;
115 		case GF_SG_FIELD_CODING_DYN:
116 			return GF_BAD_PARAM;
117 		default:
118 			if (inField==i-1+nb_static) return GF_OK;
119 			break;
120 		}
121 	}
122 	/*try with default*/
123 	return gf_sg_mpeg4_node_get_field_index(node, inField, IndexMode, allField);
124 }
125 
126 
gf_sg_script_get_field(GF_Node * node,GF_FieldInfo * info)127 GF_Err gf_sg_script_get_field(GF_Node *node, GF_FieldInfo *info)
128 {
129 	GF_ScriptField *field;
130 	GF_ScriptPriv *priv;
131 	u32 nb_static;
132 
133 	if (!info || !node) return GF_BAD_PARAM;
134 
135 	priv = (GF_ScriptPriv *)gf_node_get_private(node);
136 	nb_static = script_get_nb_static_field(node);
137 
138 	//static fields
139 	if (info->fieldIndex < nb_static) {
140 		if (nb_static==3) return gf_sg_mpeg4_node_get_field(node, info);
141 #ifndef GPAC_DISABLE_X3D
142 		return gf_sg_x3d_node_get_field(node, info);
143 #else
144 		return GF_NOT_SUPPORTED;
145 #endif
146 	}
147 
148 	//dyn fields
149 	field = (GF_ScriptField *)gf_list_get(priv->fields, info->fieldIndex - nb_static);
150 	if (!field) return GF_BAD_PARAM;
151 
152 	info->eventType = field->eventType;
153 	info->fieldType = field->fieldType;
154 	info->name = field->name;
155 	//we need the eventIn name to activate the function...
156 	info->on_event_in = NULL;
157 
158 	//setup pointer (special cases for nodes)
159 	switch (field->fieldType) {
160 	case GF_SG_VRML_SFNODE:
161 	case GF_SG_VRML_MFNODE:
162 		info->far_ptr = &field->pField;
163 		info->NDTtype = NDT_SFWorldNode;
164 		break;
165 	default:
166 		info->far_ptr = field->pField;
167 		break;
168 	}
169 	return GF_OK;
170 }
171 
gf_sg_script_init(GF_Node * node)172 void gf_sg_script_init(GF_Node *node)
173 {
174 	GF_ScriptPriv *priv;
175 
176 
177 	GF_SAFEALLOC(priv, GF_ScriptPriv)
178 	if (!priv) {
179 		GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create script node\n"));
180 		return;
181 	}
182 	priv->fields = gf_list_new();
183 
184 	gf_node_set_private(node, priv);
185 	node->sgprivate->UserCallback = Script_PreDestroy;
186 
187 	//URL is exposedField (in, out Def)
188 	priv->numDef = priv->numIn = priv->numOut = script_get_nb_static_field(node) - 2;
189 	//directOutput and mustEvaluate are fields (def)
190 	priv->numDef += 2;
191 }
192 
193 GF_EXPORT
gf_sg_script_field_new(GF_Node * node,u32 eventType,u32 fieldType,const char * name)194 GF_ScriptField *gf_sg_script_field_new(GF_Node *node, u32 eventType, u32 fieldType, const char *name)
195 {
196 	GF_ScriptPriv *priv;
197 	GF_ScriptField *field;
198 	if (!name || ((node->sgprivate->tag != TAG_MPEG4_Script)
199 #ifndef GPAC_DISABLE_X3D
200 	              && (node->sgprivate->tag != TAG_X3D_Script)
201 #endif
202 	             ))
203 		return NULL;
204 
205 	if (eventType > GF_SG_SCRIPT_TYPE_EVENT_OUT) return NULL;
206 	priv = (GF_ScriptPriv *)gf_node_get_private(node);
207 
208 	GF_SAFEALLOC(field, GF_ScriptField)
209 	if (!field) {
210 		GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to create script field\n"));
211 		return NULL;
212 	}
213 	field->fieldType = fieldType;
214 	field->name = gf_strdup(name);
215 
216 	field->DEF_index = field->IN_index = field->OUT_index = -1;
217 	switch (eventType) {
218 	case GF_SG_SCRIPT_TYPE_FIELD:
219 		field->DEF_index = priv->numDef;
220 		priv->numDef++;
221 		field->eventType = GF_SG_EVENT_FIELD;
222 		break;
223 	case GF_SG_SCRIPT_TYPE_EVENT_IN:
224 		field->IN_index = priv->numIn;
225 		priv->numIn++;
226 		field->eventType = GF_SG_EVENT_IN;
227 		break;
228 	case GF_SG_SCRIPT_TYPE_EVENT_OUT:
229 		field->OUT_index = priv->numOut;
230 		field->eventType = GF_SG_EVENT_OUT;
231 		priv->numOut++;
232 		break;
233 	}
234 	//+ static fields
235 	field->ALL_index = script_get_nb_static_field(node) + gf_list_count(priv->fields);
236 	gf_list_add(priv->fields, field);
237 
238 	//create field entry
239 	if ((fieldType != GF_SG_VRML_SFNODE) && (fieldType != GF_SG_VRML_MFNODE) ) {
240 		field->pField = gf_sg_vrml_field_pointer_new(fieldType);
241 	}
242 
243 	return field;
244 }
245 
246 
gf_sg_script_prepare_clone(GF_Node * dest,GF_Node * orig)247 GF_Err gf_sg_script_prepare_clone(GF_Node *dest, GF_Node *orig)
248 {
249 	u32 i, type;
250 	GF_ScriptField *sf;
251 	GF_ScriptPriv *dest_priv, *orig_priv;
252 	orig_priv = (GF_ScriptPriv *)orig->sgprivate->UserPrivate;
253 	dest_priv = (GF_ScriptPriv *)dest->sgprivate->UserPrivate;
254 	if (!orig_priv || !dest_priv) return GF_BAD_PARAM;
255 
256 	i=0;
257 	while ((sf = (GF_ScriptField *)gf_list_enum(orig_priv->fields, &i))) {
258 		switch (sf->eventType) {
259 		case GF_SG_EVENT_IN:
260 			type = GF_SG_SCRIPT_TYPE_EVENT_IN;
261 			break;
262 		case GF_SG_EVENT_OUT:
263 			type = GF_SG_SCRIPT_TYPE_EVENT_OUT;
264 			break;
265 		case GF_SG_EVENT_FIELD:
266 			type = GF_SG_SCRIPT_TYPE_FIELD;
267 			break;
268 		default:
269 			return GF_BAD_PARAM;
270 		}
271 		gf_sg_script_field_new(dest, type, sf->fieldType, sf->name);
272 	}
273 	return GF_OK;
274 }
275 
276 GF_EXPORT
gf_sg_script_field_get_info(GF_ScriptField * field,GF_FieldInfo * info)277 GF_Err gf_sg_script_field_get_info(GF_ScriptField *field, GF_FieldInfo *info)
278 {
279 	if (!field || !info) return GF_BAD_PARAM;
280 	memset(info, 0, sizeof(GF_FieldInfo));
281 
282 	info->fieldIndex = field->ALL_index;
283 	info->eventType = field->eventType;
284 	info->fieldType = field->fieldType;
285 	info->name = field->name;
286 
287 	//setup pointer (special cases for nodes)
288 	switch (field->fieldType) {
289 	case GF_SG_VRML_SFNODE:
290 	case GF_SG_VRML_MFNODE:
291 		info->far_ptr = &field->pField;
292 		info->NDTtype = NDT_SFWorldNode;
293 		break;
294 	default:
295 		info->far_ptr = field->pField;
296 		break;
297 	}
298 	return GF_OK;
299 }
300 
301 GF_EXPORT
gf_sg_script_event_in(GF_Node * node,GF_FieldInfo * in_field)302 void gf_sg_script_event_in(GF_Node *node, GF_FieldInfo *in_field)
303 {
304 	GF_ScriptPriv *priv = (GF_ScriptPriv *)node->sgprivate->UserPrivate;
305 	if (priv->JS_EventIn) priv->JS_EventIn(node, in_field);
306 }
307 
308 
309 #endif /*GPAC_DISABLE_VRML*/
310