FreeWRL / FreeX3D 4.3.0
CScripts.c
1/*
2
3
4???
5
6*/
7
8/****************************************************************************
9 This file is part of the FreeWRL/FreeX3D Distribution.
10
11 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12
13 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Lesser Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25****************************************************************************/
26
27
28
29#include <config.h>
30#include <system.h>
31#include <display.h>
32#include <internal.h>
33
34#include <libFreeWRL.h>
35#include <list.h>
36#include <io_files.h>
37
38#include "../vrml_parser/Structs.h"
39#include "../main/headers.h"
40#include "../vrml_parser/CParseGeneral.h"
41#include "../vrml_parser/CFieldDecls.h"
42#include "../vrml_parser/CParseLexer.h"
43#include "../main/Snapshot.h"
44#include "../scenegraph/Vector.h"
45#include "../scenegraph/Collision.h"
46#include "../scenegraph/quaternion.h"
47#include "../scenegraph/Viewer.h"
48#include "../input/SensInterps.h"
49#include "../input/InputFunctions.h"
50#include "../x3d_parser/Bindable.h"
51#include "../opengl/OpenGL_Utils.h"
52#include "../opengl/Textures.h"
53
54#include "JScript.h"
55#include "CScripts.h"
56
57
58#include <limits.h>
59
60
61/* JavaScript-"protocols" */
62const char* JS_PROTOCOLS[]={
63 "x-shader", //https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context
64 "text/plain",
65 "glsl",
66 "shader",
67 "javascript",
68 "ecmascript",
69 "vrmlscript",
70 "data:text/plain"};
71
72typedef struct pCScripts{
73 /* Next handle to be assinged */
74 int handleCnt;//=0;
75 //JAS - gives threading collision errors char *buffer;// = NULL;
76
77}* ppCScripts;
78void *CScripts_constructor(){
79 void *v = MALLOCV(sizeof(struct pCScripts));
80 memset(v,0,sizeof(struct pCScripts));
81 return v;
82}
83void CScripts_init(struct tCScripts *t){
84 //public
85 //private
86 t->prv = CScripts_constructor();
87 {
88 ppCScripts p = (ppCScripts)t->prv;
89 /* Next handle to be assinged */
90 p->handleCnt=0;
91 }
92}
93// ppCScripts p = (ppCScripts)gglobal()->CScripts.prv;
94
95
96/* ************************************************************************** */
97/* ****************************** ScriptFieldDecl *************************** */
98/* ************************************************************************** */
99
100/* Constructor and destructor */
101/* ************************** */
102
103struct ScriptFieldDecl* newScriptFieldDecl(struct VRMLLexer* me, indexT mod, indexT type, indexT name)
104{
105 struct ScriptFieldDecl* ret=MALLOC(struct ScriptFieldDecl *, sizeof(struct ScriptFieldDecl));
106 ASSERT(ret);
107 bzero(ret,sizeof(struct ScriptFieldDecl));
108
109 ASSERT(mod!=PKW_inputOutput);
110
111 /* shaderID will get set when shader is activiated */
112 ret->fieldDecl=newFieldDecl(mod, type, name,
113 JSparamIndex(lexer_stringUser_fieldName(me,name,mod),FIELDTYPES[type],mod)
114 , -1);
115 ASSERT(ret->fieldDecl);
116
117 /* Stringify */
118 ret->ASCIIvalue=NULL; /* used only for XML PROTO ProtoInterface fields */
119
120 /* printf ("newScript, asciiType %s,\n",stringFieldtypeType(
121 fieldDecl_getType(ret->fieldDecl)));
122 printf ("newScriptFieldDecl, name :%s:, getIndexName %d, ShaderScriptIndex %d\n",
123 fieldDecl_getShaderScriptName(ret->fieldDecl),
124 fieldDecl_getIndexName(ret->fieldDecl), fieldDecl_getShaderScriptIndex(ret->fieldDecl)); */
125
126 /* Field's value not yet initialized! */
127 ret->valueSet=(mod!=PKW_initializeOnly);
128 ret->eventInSet = FALSE; //flag used for directOutput
129 /* value is set later on */
130
131 #ifdef CPARSERVERBOSE
132 printf ("newScriptFieldDecl, returning name %s, type %s, mode %s\n",fieldDecl_getShaderScriptName(ret->fieldDecl),
133 stringFieldtypeType( fieldDecl_getType(ret->fieldDecl))
134,PROTOKEYWORDS[ret->fieldDecl->mode]);
135 #endif
136
137 return ret;
138}
139
140/* Create a new ScriptFieldInstanceInfo structure to hold information about script fields that are destinations for IS statements in PROTOs */
141struct ScriptFieldInstanceInfo* newScriptFieldInstanceInfo(struct ScriptFieldDecl* dec, struct Shader_Script* script) {
142 struct ScriptFieldInstanceInfo* ret = MALLOC(struct ScriptFieldInstanceInfo *, sizeof(struct ScriptFieldInstanceInfo));
143
144 ASSERT(ret);
145
146 ret->decl = dec;
147 ret->script = script;
148
149 #ifdef CPARSERVERBOSE
150 printf("creating new scriptfieldinstanceinfo with decl %p script %p\n", dec, script);
151 #endif
152
153 return(ret);
154}
155
156/* Copy a ScriptFieldInstanceInfo structure to a new structure */
157struct ScriptFieldInstanceInfo* scriptFieldInstanceInfo_copy(struct ScriptFieldInstanceInfo* me) {
158 struct ScriptFieldInstanceInfo* ret = MALLOC(struct ScriptFieldInstanceInfo *, sizeof(struct ScriptFieldInstanceInfo));
159
160 #ifdef CPARSERVERBOSE
161 printf("copying instanceinfo %p (%p %p) to %p\n", me, me->decl, me->script, ret);
162 #endif
163
164
165 ASSERT(ret);
166
167 ret->decl = me->decl;
168 ret->script = me->script;
169
170 return ret;
171}
172
173struct ScriptFieldDecl* scriptFieldDecl_copy(struct VRMLLexer* lex, struct ScriptFieldDecl* me)
174{
175 struct ScriptFieldDecl* ret = MALLOC(struct ScriptFieldDecl *, sizeof (struct ScriptFieldDecl));
176 ASSERT(ret);
177
178 #ifdef CPARSERVERBOSE
179 printf("copying script field decl %p to %p\n", me, ret);
180 #endif
181
182
183 ret->fieldDecl = fieldDecl_copy(me->fieldDecl);
184 ASSERT(ret->fieldDecl);
185
186 ret->ASCIIvalue = me->ASCIIvalue;
187
188 ret->valueSet=(fieldDecl_getAccessType(ret->fieldDecl)!=PKW_initializeOnly);
189 return ret;
190}
191
192void deleteScriptFieldDecl(struct ScriptFieldDecl* me)
193{
194 deleteFieldDecl(me->fieldDecl);
195 FREE_IF_NZ (me);
196}
197
198/* Other members */
199/* ************* */
200
201/* Sets script field value */
202void scriptFieldDecl_setFieldValue(struct ScriptFieldDecl* me, union anyVrml v)
203{
204 //ASSERT(me->fieldDecl->PKWmode==PKW_initializeOnly);
205 //dug9 2014 in june or july I changed scripts to allow inputOutput/exposedFields, to match X3D v3.3 specs (vrml specs said no)
206 ASSERT(me->fieldDecl->PKWmode==PKW_initializeOnly || me->fieldDecl->PKWmode==PKW_inputOutput)
207 me->value=v;
208 me->valueSet=TRUE;
209}
210
211void scriptFieldDecl_setFieldASCIIValue(struct ScriptFieldDecl *me, const char *val)
212{
213 me->ASCIIvalue=(char *)val;
214}
215
216/* dug9_2014 abstract away a few ugly details with functional wrappers,
217so JScript_duk/duktape can use Shader_Script->fields ScriptFieldDecls instead of jsNative*/
218int ScriptFieldDecl_getMode(struct ScriptFieldDecl* sfd)
219{
220 return fieldDecl_getAccessType(sfd->fieldDecl);
221}
222int ScriptFieldDecl_getType(struct ScriptFieldDecl* sfd){
223 return fieldDecl_getType(sfd->fieldDecl);
224}
225const char* ScriptFieldDecl_getName(struct ScriptFieldDecl* sfd){
226 struct CRjsnameStruct *JSparamnames = getJSparamnames();
227 return fieldDecl_getShaderScriptName(sfd->fieldDecl);
228}
229
230struct ScriptFieldDecl* Shader_Script_getScriptField(struct Shader_Script* script, int ifield)
231{
232 return vector_get(struct ScriptFieldDecl*,script->fields,ifield);
233
234}
235int Shader_Script_getScriptFieldCount(struct Shader_Script* script)
236{
237 return script->fields->n;
238}
239
240
241/* Get "offset" data for routing. Return an error if we are passed an invalid pointer. */
242/* this is the field used for Scripts and Shaders; each number identifies a name AND data
243 type; eg, 0="Var1","SFInt32", 1="Var1","MFFloat" while the lexerNameIndex would be the
244 same */
245
246int scriptFieldDecl_getRoutingOffset(struct ScriptFieldDecl* me)
247{
248 if (me == NULL) {
249 ConsoleMessage ("call to scriptFieldDecl_getRoutingOffset made with NULL input");
250 return INT_ID_UNDEFINED;
251 }
252 return fieldDecl_getShaderScriptIndex(me->fieldDecl);
253}
254
255
256
257
258/* Initialize JSField */
259void scriptFieldDecl_jsFieldInit(struct ScriptFieldDecl* me, int num) {
260 struct CRjsnameStruct *JSparamnames = getJSparamnames();
261
262 #ifdef CPARSERVERBOSE
263 printf ("scriptFieldDecl_jsFieldInit mode %d\n",me->fieldDecl->mode);
264 #endif
265
266 ASSERT(me->valueSet);
267 SaveScriptField(num, fieldDecl_getAccessType(me->fieldDecl),
268 fieldDecl_getType(me->fieldDecl), fieldDecl_getShaderScriptName(me->fieldDecl), me->value);
269}
270
271
272
273/* ************************************************************************** */
274/* ********************************** Script ******************************** */
275/* ************************************************************************** */
276
277/* Constructor and destructor */
278/* ************************** */
279
281//static int handleCnt=0;
282int nextScriptHandle (void) {
283 int retval;
284 ppCScripts p = (ppCScripts)gglobal()->CScripts.prv;
285
286 retval = p->handleCnt;
287 p->handleCnt++;
288 return retval;
289}
290
291/* copy a Script node in a proto. */
292struct X3D_Script * protoScript_copy (struct X3D_Script *me) {
293 struct X3D_Script* ret;
294
295 ret = createNewX3DNode(NODE_Script);
296 ret->_parentResource = me->_parentResource;
297 ret->directOutput = me->directOutput;
298 ret->mustEvaluate = me->mustEvaluate;
299 ret->url = me->url;
300 ret->__scriptObj = me->__scriptObj;
301 return ret;
302
303}
304
305/* on a reload, zero script counts */
306void zeroScriptHandles (void) {
307 ppCScripts p = (ppCScripts)gglobal()->CScripts.prv;
308 p->handleCnt = 0;
309}
310
311/* this can be a script, or a shader, take your pick
312 like new_Shader_Script below except no script registration here - used in 2-stage Broto parsing.
313*/
314struct Shader_Script* new_Shader_ScriptB(struct X3D_Node *node) {
315 struct Shader_Script* ret=MALLOC(struct Shader_Script *, sizeof(struct Shader_Script));
316
317 ASSERT(ret);
318
319 ret->loaded=FALSE;
320 ret->fields=newVector(struct ScriptFieldDecl*, 4);
321 ret->ShaderScriptNode = node; /* pointer back to the node that this is associated with */
322 ret->num = -1;
323 return ret;
324}
325struct Shader_Script* new_Shader_Script(struct X3D_Node *node) {
326 // struct Shader_Script* ret=MALLOC(struct Shader_Script *, sizeof(struct Shader_Script));
327
328 // ASSERT(ret);
329
330 //ret->loaded=FALSE;
331 //ret->fields=newVector(struct ScriptFieldDecl*, 4);
332 //ret->ShaderScriptNode = node; /* pointer back to the node that this is associated with */
333 //ret->num = -1;
334 struct Shader_Script* ret;
335 ret = new_Shader_ScriptB(node);
336
337 /* X3D XML protos do not have a node defined when parsed, Shaders and Scripts do */
338 if (node!=NULL) {
339 /* printf ("new_Shader_Script, node %s\n",stringNodeType(node->_nodeType)); */
340 if (node->_nodeType == NODE_Script) {
341 ret->num=nextScriptHandle();
342 #ifdef CPARSERVERBOSE
343 printf("newScript: created new script nodePtr %u with num %d\n", node, ret->num);
344 #endif
345
346 JSInit(ret); //->num);
347 }
348 }
349
350
351 /* printf ("new_Shader_Script - num %d, Shader_Script is %u\n",ret->num,ret); */
352
353 return ret;
354}
355
356void deleteScript(struct Shader_Script* me)
357{
358 size_t i;
359 for(i=0; i!=vectorSize(me->fields); ++i)
360 deleteScriptFieldDecl(vector_get(struct ScriptFieldDecl*, me->fields, i));
361 deleteVector(struct ScriptFieldDecl*, me->fields);
362
363 FREE_IF_NZ (me);
364 /* FIXME: JS-handle is not freed! */
365}
366
367/* Other members */
368/* ************* */
369
370/* look for the field, via the ASCII name. Slower than script_getField, though... */
371struct ScriptFieldDecl* script_getField_viaCharName (struct Shader_Script* me, const char *name)
372{
373
374 size_t i;
375 struct CRjsnameStruct *JSparamnames = getJSparamnames();
376
377 if (me!=NULL) {
378
379 for(i=0; i!=vectorSize(me->fields); ++i) {
380 struct ScriptFieldDecl* curField= vector_get(struct ScriptFieldDecl*, me->fields, i);
381 if(strcmp(name,fieldDecl_getShaderScriptName(curField->fieldDecl)) == 0)
382 return curField;
383 }
384 }
385
386 return NULL;
387}
388
389struct ScriptFieldDecl* script_getField(struct Shader_Script* me, indexT n, indexT mod)
390{
391
392 size_t i;
393 if (me!=NULL) {
394 for(i=0; i!=vectorSize(me->fields); ++i) {
395 struct ScriptFieldDecl* curField= vector_get(struct ScriptFieldDecl*, me->fields, i);
396 if(scriptFieldDecl_isField(curField, n, mod))
397 return curField;
398 }
399 }
400
401 return NULL;
402}
403
404void script_addField(struct Shader_Script* me, struct ScriptFieldDecl* field)
405{
406
407 #ifdef CPARSERVERBOSE
408 printf ("script_addField: adding field %u to script %d (pointer %u)\n",field,me->num,me);
409 #endif
410
411 vector_pushBack(struct ScriptFieldDecl*, me->fields, field);
412 field->script = me; //added for duktape proxy - so in handler we can find the field from private pointer, and from field we can find Script and any info we need about script
413#ifdef CPARSERVERBOSE
414 {
415 size_t i;
416 for(i=0; i!=vectorSize(me->fields); ++i) {
417 struct ScriptFieldDecl* curField=
418 vector_get(struct ScriptFieldDecl*, me->fields, i);
419 printf ("script_addField, now have field %d of %d, ASCIIname %s:",i,vectorSize(me->fields),fieldDecl_getShaderScriptName(curField->fieldDecl));
420 printf ("\n");
421 }
422
423 }
424#endif
425
426
427
428 /* only do this for scripts */
429 if (me->ShaderScriptNode != NULL) {
430 if (me->ShaderScriptNode->_nodeType==NODE_Script) scriptFieldDecl_jsFieldInit(field, me->num);
431 }
432
433
434}
435/* save the script code, as found in the VRML/X3D URL for this script */
436BOOL script_initCode(struct Shader_Script* me, const char* code)
437{
438 ASSERT(!me->loaded);
439
440 SaveScriptText (me->num, (char *)code);
441 me->loaded=TRUE;
442 return TRUE;
443}
444
445
446/* get the script from this SFString. First checks to see if the string
447 contains the script; if not, it goes and tries to see if the SFString
448 contains a file that (hopefully) contains the script */
449
450static bool script_initCodeFromBLOB(struct Shader_Script* me, const char* uri, char** crv)
451{
452 size_t i;
453 //int rv;
454 //ConsoleMessage ("script_initCodeFromUri starting");
455
456 //rv = FALSE; /* initialize it */
457
458 /* strip off whitespace at the beginning JAS */
459 while ((*uri<= ' ') && (*uri>0)) uri++;
460
461 /* Try javascript protocol */
462 for(i=0; i!=ARR_SIZE(JS_PROTOCOLS); ++i)
463 {
464 const char* u=uri;
465 const char* v=JS_PROTOCOLS[i];
466
467 while(*u && *v && *u==*v)
468 {
469 ++u;
470 ++v;
471 }
472 //ConsoleMessage ("so far, u is :%s:",u);
473 /* Is this a "data:text/plain," uri? JAS*/
474 if((!*v && *u==',') || (!*v && *u==':')) {
475 if (me != NULL) {
476 //ConsoleMessage ("calling script_initCode");
477
478 return script_initCode(me, u+1); /* a script */
479 } else {
480
481 *crv = STRDUP(u+1);
482 //printf("script_initCodeFromUri, returning crv as %s\n",*crv);
483 return TRUE;
484 }
485 }
486 }
487 return FALSE;
488}
489static void script_initCodeFromMFUri_download(struct Shader_Script* me, const struct Multi_String *s){
490 /* Not a valid script text in this MFString. Lets see if this
491 is this a possible file that we have to get? */
492 resource_item_t *res, *parentres;
493
494 DEBUG_CPARSER("script_initCodeFromUri, uri is %s\n", uri);
495 //printf("script_initCodeFromUri, uri is %s\n", uri);
496
497 res = resource_create_multi(s);
498 // printf ("past resource_create_single\n");
499 parentres = ((struct X3D_Script*)(me->ShaderScriptNode))->_parentResource;
500 //resource_identify(gglobal()->resources.root_res, res);
501 resource_identify(parentres, res);
502 //printf ("past resource_identify\n");
503
504 if (res->type != rest_invalid) {
505 res->status = ress_starts_good;
506 res->media_type = resm_script;
507 res->whereToPlaceData = me;
508 res->actions = resa_download | resa_load | resa_process;
509 resitem_enqueue(ml_new(res));
510 }
511}
512/* //not a valid option?
513static void shader_initCodeFromMFUri_download(struct Shader_Script* me, struct Multi_String *s){
514 // Not a valid script text in this MFString. Lets see if this
515 // is this a possible file that we have to get?
516 resource_item_t *res, *parentres;
517
518 DEBUG_CPARSER("script_initCodeFromUri, uri is %s\n", uri);
519 //printf("script_initCodeFromUri, uri is %s\n", uri);
520
521 res = resource_create_multi(s);
522 // printf ("past resource_create_single\n");
523 parentres = ((struct X3D_Script*)(me->ShaderScriptNode))->_parentResource;
524 //resource_identify(gglobal()->resources.root_res, res);
525 resource_identify(parentres, res);
526 //printf ("past resource_identify\n");
527
528 if (res->type != rest_invalid) {
529 res->status = ress_starts_good;
530 res->media_type = resm_fshader;
531 res->whereToPlaceData = me;
532 res->actions = resa_download | resa_load | resa_process;
533 resitem_enqueue(ml_new(res));
534 }
535}
536*/
537
538/* initialize a script from a url. Expects valid input */
539BOOL script_initCodeFromMFUri(struct Shader_Script* me, const struct Multi_String* s) {
540 size_t i;
541 //int *isURL = malloc(sizeof(int)*s->n);
542 //struct Multi_String *multires = MALLOC(struct Multi_String *,sizeof(struct Multi_String));
543 //multires->p = MALLOC(struct Uni_String**,sizeof(struct Uni_String)*s->n);
544 //tmp2->family.p = MALLOC (struct Uni_String **, sizeof(struct Uni_String)*1);tmp2->family.p[0] = newASCIIString("SERIF");tmp2->family.n=1; ;
545
546 for(i=0; i!=s->n; ++i) {
547 //FREE_IF_NZ(p->buffer);
548 char *mfcrv = NULL;
549 if(script_initCodeFromBLOB(me, s->p[i]->strptr,&mfcrv)) {
550 FREE_IF_NZ(mfcrv);
551 return TRUE;
552 }
553 }
554 //not an inline script, so they must be URLs
555 script_initCodeFromMFUri_download(me, s);
556 /* failure or delayed success */
557 return FALSE;
558}
559
560/* initialize a shader from a url. returns pointer to pointer to text, if found, null otherwise */
561/* pointer is freed (if not NULL) in the Shaders code */
562char *shader_initCodeFromMFUri(const struct Multi_String* s) {
563 size_t i;
564
565 for(i=0; i!=s->n; ++i) {
566 char *mfcrv = NULL;
567 if (s->p[i]->strptr != NULL) {
568 //ConsoleMessage ("looking at :%s: ",s->p[i]->strptr);
569 //if (strncmp("data:text/plain,",s->p[i]->strptr , strlen("data:text/plain,")) == 0) {
570 if(script_initCodeFromBLOB(NULL, s->p[i]->strptr,&mfcrv)) {
571 //printf ("shader_initCodeFromMFUri, returning datalen :%d:\n",strlen(mfcrv));
572 return mfcrv;
573 }
574 //} else {
575 // ConsoleMessage ("implementation restriction - right now shader source must be in the X3D file so the url must start with \"data:text/plain,\"");
576 //}
577 }
578 }
579 //not a blob already - must be an MF URL
580 //script_initCodeFromMFUri_download(me, s); NEEDS WORK > see component_Programmableshaders.c > LOCATE_SHADER_PARTS
581
582
583 /* failure... */
584 return NULL;
585}
586
587
588int getFieldFromScript(struct Shader_Script * sp, char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value, int **valueChanged){
589 //sp = (struct Shader_Script *)snode->__scriptObj;
590 int k;
591 struct ScriptFieldDecl *sfield;
592 struct Vector *sfields;
593 struct FieldDecl *fdecl;
594 struct CRjsnameStruct *JSparamnames = getJSparamnames();
595
596
597 sfields = sp->fields;
598 for(k=0;k<sfields->n;k++)
599 {
600 char *fieldName;
601 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
602 //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
603 fdecl = sfield->fieldDecl;
604 fieldName = fieldDecl_getShaderScriptName(fdecl);
605 if(!strcmp(fieldName,fieldname)){
606 *type = fdecl->fieldType;
607 *kind = fdecl->PKWmode;
608 *value = &(sfield->value);
609 *valueChanged = &(sfield->valueChanged);
610 *iifield = k;
611 return 1;
612 }
613 }
614 return 0;
615}