FreeWRL/FreeX3D  3.0.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" */
62 const 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 
72 typedef struct pCScripts{
73  /* Next handle to be assinged */
74  int handleCnt;//=0;
75  //JAS - gives threading collision errors char *buffer;// = NULL;
76 
77 }* ppCScripts;
78 void *CScripts_constructor(){
79  void *v = MALLOCV(sizeof(struct pCScripts));
80  memset(v,0,sizeof(struct pCScripts));
81  return v;
82 }
83 void 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 
103 struct 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])
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 */
141 struct 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 */
157 struct 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 
173 struct 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 
192 void 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 */
202 void 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 
211 void 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,
217 so JScript_duk/duktape can use Shader_Script->fields ScriptFieldDecls instead of jsNative*/
218 int ScriptFieldDecl_getMode(struct ScriptFieldDecl* sfd)
219 {
220  return fieldDecl_getAccessType(sfd->fieldDecl);
221 }
222 int ScriptFieldDecl_getType(struct ScriptFieldDecl* sfd){
223  return fieldDecl_getType(sfd->fieldDecl);
224 }
225 const char* ScriptFieldDecl_getName(struct ScriptFieldDecl* sfd){
226  struct CRjsnameStruct *JSparamnames = getJSparamnames();
227  return fieldDecl_getShaderScriptName(sfd->fieldDecl);
228 }
229 
230 struct ScriptFieldDecl* Shader_Script_getScriptField(struct Shader_Script* script, int ifield)
231 {
232  return vector_get(struct ScriptFieldDecl*,script->fields,ifield);
233 
234 }
235 int 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 
246 int 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 */
259 void 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;
282 int 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. */
292 struct 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 */
306 void 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 */
314 struct 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 }
325 struct 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 
356 void 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... */
371 struct 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 
389 struct 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 
404 void 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 */
436 BOOL 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 
450 static 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 }
489 static void script_initCodeFromMFUri_download(struct Shader_Script* me, 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?
513 static 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 */
539 BOOL 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 */
562 char *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 }