FreeWRL / FreeX3D 4.3.0
JScript_duk.c
1/****************************************************************************
2 This file is part of the FreeWRL/FreeX3D Distribution.
3
4 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
5
6 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
18****************************************************************************/
19
20/* To do list July 2014
21- runQueuedDirectOutputs() - is there a way to flag a Script Node so this isn't a double loop over all scripts and fields?
22- cfwconstructor - fwtype could be extended to articulate allowed AUXTYPEs and FIELDTYPEs for a given W or P
23To do list Jan 2017
24- proxy cache could be per-script node to save one lookup loop
25*/
26
27
28#include <config.h>
29#include <system.h>
30#if defined(JAVASCRIPT_DUK)
31#include <display.h>
32#include <internal.h>
33
34#include <libFreeWRL.h>
35
36#include "../vrml_parser/Structs.h"
37#include "../main/headers.h"
38#include "../vrml_parser/CParseGeneral.h"
39#include "../vrml_parser/CRoutes.h"
40#include "../main/Snapshot.h"
41#include "../scenegraph/Collision.h"
42#include "../scenegraph/quaternion.h"
43#include "../scenegraph/Viewer.h"
44#include "../input/EAIHelpers.h"
45#include "../input/SensInterps.h"
46#include "../x3d_parser/Bindable.h"
47
48#include "JScript.h"
49#include "FWTYPE.h"
50
51//typedef int indexT;
52
53#ifdef DEBUG_MALLOC
54#define malloc(A) MALLOCV(A)
55#define free(A) FREE_IF_NZ(A)
56#define realloc(A,B) REALLOC(A,B)
57#endif
58
59FWType fwtypesArray[60]; //true statics - they only need to be defined once per process, we have about 50 types as of july 2014
60int FWTYPES_COUNT = 0;
61
62void initVRMLBrowser(FWType* typeArray, int *n);
63void initVRMLFields(FWType* typeArray, int *n);
64void initFWTYPEs(){
65 initVRMLBrowser(fwtypesArray, &FWTYPES_COUNT);
66 initVRMLFields(fwtypesArray, &FWTYPES_COUNT);
67 //printf("FWTYPE_COUNT %d\n", FWTYPES_COUNT);
68}
69FWType getFWTYPE(int itype){
70 int i;
71 for(i=0;i<FWTYPES_COUNT;i++){
72 if (itype == fwtypesArray[i]->itype) {
73 return fwtypesArray[i];
74 }
75 }
76 return NULL;
77}
78#ifdef _MSC_VER
79#define strcasecmp _stricmp
80#endif
81
82FWFunctionSpec *getFWFunc(FWType fwt,const char *key){
83 int i = 0;
84 FWFunctionSpec *fs = fwt->Functions;
85 if(fs)
86 while(fs[i].name){
87 if(!strcasecmp(fs[i].name,key)){
88 //found it - its a function, return functionSpec
89 return &fs[i];
90 }
91 i++;
92 }
93 return NULL;
94}
95FWPropertySpec *getFWProp(FWType fwt,const char *key, int *index){
96 int i = 0;
97 FWPropertySpec *ps = fwt->Properties;
98 *index = 0;
99 if(ps)
100 while(ps[i].name){
101 if(!strcasecmp(ps[i].name,key)){
102 //found it - its a property, return propertySpec
103 (*index) = ps[i].index; //index can be any +- integer
104 return &ps[i];
105 }
106 i++;
107 }
108 return NULL;
109}
110int len_properties(FWPropertySpec *ps){
111 int len = 0;
112 if(ps) while(ps[len].name) len++;
113 return len;
114}
115int len_functions(FWFunctionSpec *fs){
116 int len = 0;
117 if(fs) while(fs[len].name) len++;
118 return len;
119}
120int fwiterator_generic(int index, FWType fwt, void *pointer, const char **name, int *lastProp, int *jndex, char *type, char *readOnly){
121 //start iterating by passing -1 for index. When you get -1 back, you are done.
122 //FWPointer is for SFNode: it will have an instance-specific result from its custom iterator
123 //next property
124 int lenp, lenf, ifindex;
125 FWPropertySpec *ps;
126 FWIterator iterator;
127 FWFunctionSpec *fs;
128 (*jndex) = 0;
129 ps = fwt->Properties;
130 iterator = fwt->iterator;
131 if(ps){
132 index ++;
133 lenp = len_properties(ps);
134 if(index < lenp){
135 (*name) = ps[index].name;
136 (*jndex) = ps[index].index;
137 (*lastProp) = index;
138 (*type) = ps[index].type;
139 (*readOnly) = ps[index].readOnly;
140 return index;
141 }
142 }else if(iterator){
143 int iret = iterator(index, fwt, pointer, name, lastProp, jndex, type, readOnly);
144 if(iret > -1) return iret;
145 index++; //for functions below
146 }else{
147 index++; //may not have properties (or iterator) like SFFloat, which has a valueOf function
148 }
149 //next function
150 fs = fwt->Functions;
151 lenf = len_functions(fs);
152 ifindex = index - 1 - (*lastProp);
153 if(ifindex < lenf){
154 (*name) = fs[ifindex].name;
155 (*type) = 'f';
156 (*readOnly) = 'T';
157 return index;
158 }
159 return -1;
160}
161
162int fwhas_generic(FWType fwt, void *pointer, const char *key, int *jndex, char *type, char *readOnly){
163 const char *name;
164 int lastProp, isSet, index = -1;
165 lastProp = -1;
166 isSet = FALSE;
167
168 while( (index = fwiterator_generic(index,fwt,pointer,&name, &lastProp, jndex, type, readOnly)) > -1){
169 if(!strcasecmp(name,key)){
170 //found it
171 return TRUE;
172 }
173 }
174 if(strlen(key)>4 && !strncmp(key,"set_",4))
175 isSet = TRUE;
176
177 if(isSet){
178 const char* key2 = &key[4];
179 while( (index = fwiterator_generic(index,fwt,pointer,&name, &lastProp, jndex, type, readOnly)) > -1){
180 if(!strcasecmp(name,key2)){
181 //found it
182 return TRUE;
183 }
184 }
185 }
186 return FALSE;
187}
188
189
190
191typedef struct pJScript_duk{
192 int ijunk;
193}* ppJScript_duk;
194
195
196void *JScript_duk_constructor(){
197 void *v = MALLOCV(sizeof(struct pJScript_duk));
198 memset(v,0,sizeof(struct pJScript_duk));
199 return v;
200}
201void JScript_duk_init(struct tJScript_duk *t){
202 //public
203 t->JSglobal_return_val = NULL;
204 //private
205 t->prv = JScript_duk_constructor();
206 {
207 //ppJScript p = (ppJScript)t->prv;
208 //initialize statics
209 if(!FWTYPES_COUNT) initFWTYPEs();
210 }
211}
212// ppJScript p = (ppJScript)gglobal()->JScript.prv;
213
214//stubs the linker will be looking for
215//void jsVRMLBrowser_init(void *t){}
216//void jsUtils_init(void *t){}
217//void jsVRMLClasses_init(void *t){}
218//
219
220
221
222//==============ENGINE-AGNOSTIC HELPER CODE (could be extracted to other module) ====================
223
224
225int isECMAtype(int itype){
226 int isEcma;
227 switch(itype){
228 case FIELDTYPE_SFBool:
229 case FIELDTYPE_SFFloat:
230 case FIELDTYPE_SFTime:
231 case FIELDTYPE_SFDouble:
232 case FIELDTYPE_SFInt32:
233 case FIELDTYPE_SFString:
234 isEcma = TRUE;
235 default:
236 isEcma = FALSE;
237 }
238 return isEcma;
239}
240
241struct string_int{
242 char *c;
243 int i;
244};
245
246struct string_int lookup_fieldType[] = {
247 {"Float", FIELDTYPE_SFFloat},
248 {"Bool", FIELDTYPE_SFBool},
249 {"Int32", FIELDTYPE_SFInt32},
250 {"Time", FIELDTYPE_SFTime},
251 {"Double", FIELDTYPE_SFDouble},
252 {"Node", FIELDTYPE_SFNode},
253 {"Color", FIELDTYPE_SFColor},
254 {"ColorRGBA", FIELDTYPE_SFColorRGBA},
255 {"Rotation", FIELDTYPE_SFRotation},
256 {"Vec2f", FIELDTYPE_SFVec2f},
257 {"Vec3f", FIELDTYPE_SFVec3f},
258 {"Vec4f", FIELDTYPE_SFVec4f},
259 {"Vec2d", FIELDTYPE_SFVec2d},
260 {"Vec3d", FIELDTYPE_SFVec3d},
261 {"Vec4d", FIELDTYPE_SFVec4d},
262 {"String", FIELDTYPE_SFString},
263 {"Image", FIELDTYPE_SFImage},
264 {"Matrix3f", FIELDTYPE_SFMatrix3f},
265 {"Matrix4f", FIELDTYPE_SFMatrix4f},
266 {"Matrix3d", FIELDTYPE_SFMatrix3d},
267 {"Matrix4d", FIELDTYPE_SFMatrix4d},
268 {NULL,0}
269};
270char * itype2string(int itype){
271 int i = 0;
272 while(lookup_fieldType[i].c){
273 if(lookup_fieldType[i].i == itype) return lookup_fieldType[i].c;
274 i++;
275 }
276 return NULL;
277}
278
279int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
280
281
282int duk_get_valueChanged_flag (int fptr, int actualscript){
283 char *fullname;
284 union anyVrml* value;
285 int type, kind, ifield, found;
286 struct X3D_Node *node;
287 struct Shader_Script *script;
288 struct ScriptFieldDecl *field;
289 struct CRscriptStruct *scriptcontrol; //, *ScriptControlArr = getScriptControl();
290 struct CRjsnameStruct *JSparamnames = getJSparamnames();
291
292 scriptcontrol = getScriptControlIndex(actualscript); //&ScriptControlArr[actualscript];
293 script = scriptcontrol->script;
294 node = script->ShaderScriptNode;
295 fullname = JSparamnames[fptr].name;
296 found = getFieldFromNodeAndName(node,fullname,&type,&kind,&ifield,&value);
297 if(found){
298 field = Shader_Script_getScriptField(script, ifield);
299 gglobal()->JScript_duk.JSglobal_return_val = (void *)&field->value;
300 return field->valueChanged;
301 }
302 gglobal()->JScript_duk.JSglobal_return_val = NULL;
303 return 0;
304}
305void duk_resetScriptTouchedFlag(int actualscript, int fptr){
306 char *fullname;
307 union anyVrml* value;
308 int type, kind, ifield, found;
309 struct X3D_Node *node;
310 struct Shader_Script *script;
311 struct ScriptFieldDecl *field;
312 struct CRscriptStruct *scriptcontrol; // *ScriptControlArr = getScriptControl();
313 struct CRjsnameStruct *JSparamnames = getJSparamnames();
314
315 scriptcontrol = getScriptControlIndex(actualscript); //&ScriptControlArr[actualscript];
316 script = scriptcontrol->script;
317 node = script->ShaderScriptNode;
318 fullname = JSparamnames[fptr].name;
319 found = getFieldFromNodeAndName(node,fullname,&type,&kind,&ifield,&value);
320 if(found){
321 field = Shader_Script_getScriptField(script, ifield);
322 field->valueChanged = 0;
323 }
324 //printf("in get_valueChanged_flag\n");
325 return;
326}
327
328//const char *stringFieldtypeType (int st); //in generatedcode
329//const char *stringNodeType (int st);
330int fwType2itype(const char *fwType){
331 int i, isSF, isMF, ifield = -1;
332 const char *suffix;
333 isSF = !strncmp(fwType,"SF",2);
334 isMF = !strncmp(fwType,"MF",2);
335 if(isSF || isMF){
336 suffix = &fwType[2]; //skip SF/MF part
337 i = 0;
338 while(lookup_fieldType[i].c){
339 if(!strcasecmp(suffix,lookup_fieldType[i].c)){
340 ifield = lookup_fieldType[i].i;
341 break;
342 }
343 i++;
344 }
345 if(ifield > -1 && isMF ) ifield++;
346 }else{
347 //browser and scene/executionContext shouldn't be going through fwconstructor
348 if(!strcasecmp(fwType,"Browser")) ifield = AUXTYPE_X3DBrowser;
349 if(!strcasecmp(fwType,"X3DConstants")) ifield = AUXTYPE_X3DConstants;
350 if(!strcasecmp(fwType, "X3DMatrix3")) ifield = AUXTYPE_X3DMatrix3;
351 if(!strcasecmp(fwType, "X3DMatrix4")) ifield = AUXTYPE_X3DMatrix4;
352 if(!strcasecmp(fwType, "VrmlMatrix")) ifield = AUXTYPE_VrmlMatrix;
353
354 }
355 return ifield;
356}
357void freeField(int itype, void* any){
358 if(isSForMFType(itype) == 0){
359 //if(itype == FIELDTYPE_SFString){
360 // struct Uni_String *sf = (struct Uni_String*)any;
361 // if(sf) free(sf->strptr);
362 // free(sf);
363 //}
364 free(any); //SF
365 }else if(isSForMFType(itype) == 1){
366 //MF
367 struct Multi_Any* mf = (struct Multi_Any*)any;
368 //if(itype == FIELDTYPE_MFString){
369 // int i;
370 // struct Multi_String *ms = (struct Multi_String*)mf;
371 // for(i=0;i<ms->n;i++){
372 // struct Uni_String *sf = ms->p[i];
373 // if(sf) free(sf->strptr);
374 // free(sf);
375 // }
376 //}
377 free(mf->p); //if bombs, it could be because I'm not deep copying or medium_copy_field() everywhere I should
378 free(mf);
379 }
380}
381
382#include <math.h> //for int = round(numeric)
383unsigned long upper_power_of_two(unsigned long v);
384void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
385void medium_copy_field0(int itype, void* source, void* dest)
386{
387 /* medium-deep copies field up to and including pointer: doesn't deep copy *(SFNode*) or *(SFString*),
388 - SFString treated analogous to const char *
389 - malloc your starting type outside
390 */
391
392 int i, sfsize,sformf;
393 int sftype, isMF;
394 struct Multi_Any *mfs,*mfd;
395
396 sformf = isSForMFType(itype);
397 if(sformf < 0){
398 printf("bad type in medium_copy_field0\n");
399 return;
400 }
401 isMF = sformf == 1;
402 sftype = type2SF(itype);
403 //from EAI_C_CommonFunctions.c
404 sfsize = sizeofSF(sftype); //returnElementLength(sftype) * returnElementRowSize(sftype);
405 if(isMF)
406 {
407 int nele;
408 char *ps, *pd;
409 mfs = (struct Multi_Any*)source;
410 mfd = (struct Multi_Any*)dest;
411 //we need to malloc and do more copying
412 deleteMallocedFieldValue(itype,dest);
413 nele = mfs->n;
414 if( sftype == FIELDTYPE_SFNode ) nele = (int) upper_power_of_two(nele); //upper power of 2 is a convention for children[] to solve a realloc memory fragmentation issue during parsing of extremely large and flat files
415 mfd->p = malloc(sfsize*nele);
416 mfd->n = mfs->n;
417 ps = (char *)mfs->p;
418 pd = (char *)mfd->p;
419 for(i=0;i<mfs->n;i++)
420 {
421 medium_copy_field0(sftype,(union anyVrml*)ps,(union anyVrml*)pd);
422 ps += sfsize;
423 pd += sfsize;
424 }
425
426 }else{
427 //isSF
428 memcpy(dest,source,sfsize);
429 }
430} //return medium_copy_field
431void medium_copy_field(int itype, void* source, void** dest){
432 //void *myDestination = NULL;
433 //medium_copy_field(itype,source,&myDestination);
434 // it will malloc the size
435 (*dest) = malloc(sizeofSForMF(itype));
436 memset((*dest),0,sizeofSForMF(itype));
437 medium_copy_field0(itype,source,(*dest));
438}
439
440
441static char *DefaultScriptMethodsA = "function initialize() {}; " \
442 " function shutdown() {}; " \
443 " function eventsProcessed() {}; " \
444 " TRUE=true; FALSE=false; " \
445 "";
446
447
448static char *DefaultScriptMethodsB = " function print(x) {Browser.print(x)}; " \
449 " function println(x) {Browser.println(x)}; " \
450 " function getName() {return Browser.getName()}; "\
451 " function getVersion() {return Browser.getVersion()}; "\
452 " function getCurrentSpeed() {return Browser.getCurrentSpeed()}; "\
453 " function getCurrentFrameRate() {return Browser.getCurrentFrameRate()}; "\
454 " function getWorldURL() {return Browser.getWorldURL()}; "\
455 " function replaceWorld(x) {Browser.replaceWorld(x)}; "\
456 " function loadURL(x,y) {Browser.loadURL(x,y)}; "\
457 " function setDescription(x) {Browser.setDescription(x)}; "\
458 " function createVrmlFromString(x) {Browser.createVrmlFromString(x)}; "\
459 " function createVrmlFromURL(x,y,z) {Browser.createVrmlFromURL(x,y,z)}; "\
460 " function createX3DFromString(x) {Browser.createX3DFromString(x)}; "\
461 " function createX3DFromURL(x,y,z) {Browser.createX3DFromURL(x,y,z)}; "\
462 " function addRoute(a,b,c,d) {Browser.addRoute(a,b,c,d)}; "\
463 " function deleteRoute(a,b,c,d) {Browser.deleteRoute(a,b,c,d)}; "\
464 " function _rename_function(obj,oldf,newf) {if(typeof obj[oldf] === 'function') {obj[newf]=obj[oldf]; delete obj[oldf];}}; "\
465 "";
466 //" function _rename_function(obj,oldf,newf) {obj[newf]=obj[oldf]; delete obj[oldf];}; "
467
468/*add x3d v3.3 ecmascript X3DConstants table
469// http://www.web3d.org/files/specifications/19777-1/V3.0/index.html
470// http://www.web3d.org/files/specifications/19777-1/V3.0/Part1/functions.html
471// 7.9.11
472*/
473
474
475//==============START OF DUKTAPE-SPECIFIC CODE====================
476#include "duktape/duktape.h"
477
478const char *duk_type_to_string(int duktype){
479 const char* r = NULL;
480 switch(duktype){
481 case DUK_TYPE_NUMBER: r = "DUK_TYPE_NUMBER"; break;
482 case DUK_TYPE_BOOLEAN: r = "DUK_TYPE_BOOLEAN"; break;
483 case DUK_TYPE_STRING: r = "DUK_TYPE_STRING"; break;
484 case DUK_TYPE_OBJECT: r = "DUK_TYPE_OBJECT"; break;
485 case DUK_TYPE_NONE: r = "DUK_TYPE_NONE"; break;
486 case DUK_TYPE_UNDEFINED: r = "DUK_TYPE_UNDEFINED"; break;
487 case DUK_TYPE_NULL: r = "DUK_TYPE_NULL"; break;
488 case DUK_TYPE_POINTER: r = "DUK_TYPE_POINTER"; break;
489 default:
490 r = "UNKNOWN_TYPE";
491 break;
492 }
493 return r;
494}
495
496void show_stack(duk_context *ctx, char* comment)
497{
498 int i, itop = duk_get_top(ctx);
499 if(comment) printf("%s top=%d\n",comment,itop);
500 //printf("%10s%10s%10s\n","position","type","more");
501 printf("%10s%10s\n","position","type");
502 for(i=0;i<itop;i++){
503 int ipos = -(i+1);
504 int t = duk_get_type(ctx, ipos);
505 char *stype = NULL;
506 const char * amore = "";
507 switch(t){
508 case DUK_TYPE_NUMBER: stype ="number"; break;
509 case DUK_TYPE_STRING: stype ="string"; break;
510
511 case DUK_TYPE_OBJECT: stype ="object"; break;
512 case DUK_TYPE_NONE: stype ="none"; break;
513 case DUK_TYPE_UNDEFINED: stype ="undefined"; break;
514 case DUK_TYPE_BOOLEAN: stype ="boolean"; break;
515 case DUK_TYPE_NULL: stype ="null"; break;
516 case DUK_TYPE_POINTER: stype ="pointer"; break;
517 default:
518 stype = "unknown";
519 }
520 if(duk_is_function(ctx,ipos)){
521 char *afunc = "";
522 afunc = duk_is_c_function(ctx,ipos) ? "Cfunc" : afunc;
523 afunc = duk_is_ecmascript_function(ctx,ipos) ? "jsfunc" : afunc;
524 afunc = duk_is_bound_function(ctx,ipos) ? "boundfunc" : afunc;
525 amore = afunc;
526 }
527 if(duk_is_nan(ctx,ipos)){
528 amore = "NaN";
529 }
530 if(duk_is_object(ctx,ipos)){
531
532 }
533 printf("%10d%10s %s\n",ipos,stype,amore);
534 }
535}
536
537//Object virtualization via proxy objects: constructor, handlers (has,ownKeys,enumerate,get,set,deleteProp), finalizer
538
539// >> PROXY CACHING FUNCTIONS
540// 2017 - lazy proxies have been too lazy, we created a new "Proxy" on ever fetch
541// x and that meant if(ground == ground) would always be false if ground is a proxy
542// x in js there's no proxy trap (function overload) just for the binary == scenario,
543// x and no way to override binary == operator
544// - can do if(ground.valueOf() == ground.valueOf()) and over-ride valueOf (working now Jan 2017),
545// x but that's unconventional syntax
546// - duktape creator Sami says try caching your proxies
547// - then (ground == ground) still won't be comparing x3d node addresses,
548// but will return true because the proxy instances will be the same
549// - that means per-context/ctx caching
550// - and since we don't have a way to hook into javascript scope push and pop
551// we need to rely on finalizer for a place to remove a proxy from our cache / lookup table
552// Jan 11, 2017 proxy caching is working, now ground==ground and scenarios like
553// val[1] == ground are true if they are supposed to be the same node
554// still some wasteful re-generation of proxies
555// but within the scope of the == operator, its working, which is better than before caching
556// UNFINISHED BUISNESS JAN 2017: the lookup table for finding the cache based on ctx
557// could be changed so Script->_cache to save one lookup loop
558static Stack * proxycaches = NULL;
559typedef struct cache_table_entry {
560 duk_context *ctx;
561 Stack *cache;
562} cache_entry;
563typedef struct proxy_cache_entry {
564 struct X3D_Node *node;
565 // native proxy
566 // js proxy
567 void *jsproxy;
568} proxy_entry;
569
570cache_entry * lookup_ctx_proxy_cache(duk_context *ctx){
571 int i;
572 cache_entry *ret = NULL;
573 if(proxycaches == NULL){
574 proxycaches = newStack(cache_entry *); //* so can NULL if/when script node deleted, without needing to pack
575 }
576 for(i=0;i<vectorSize(proxycaches);i++){
577 cache_entry * ce = vector_get(cache_entry*,proxycaches,i);
578 if(ce->ctx == ctx){
579 ret = ce;
580 break;
581 }
582 }
583 if(ret == NULL){
584 cache_entry *ce = MALLOC(cache_entry*,sizeof(cache_entry));
585 stack_push(cache_entry*,proxycaches,ce);
586 ce->ctx = ctx;
587 ce->cache = newStack(proxy_entry*); //* so can NULL in cfinalizer without needing to pack table
588 ret = ce;
589 }
590 return ret;
591}
592proxy_entry *lookup_ctx_proxycache_entry_by_nodeptr(duk_context *ctx, struct X3D_Node *node){
593 proxy_entry *ret = NULL;
594 cache_entry* cache = lookup_ctx_proxy_cache(ctx);
595 if(cache){
596 int i;
597 for(i=0;i<vectorSize(cache->cache);i++){
598 proxy_entry *pe = vector_get(proxy_entry*,cache->cache,i);
599 if(pe && pe->node == node){
600 ret = pe;
601 }
602 }
603 }
604 return ret;
605}
606proxy_entry *add_ctx_proxycache_entry(duk_context *ctx, struct X3D_Node *node, void *jsproxy){
607 int i;
608 //assume we already verified it doesn't exist
609 proxy_entry *ret = NULL;
610 cache_entry *cache = lookup_ctx_proxy_cache(ctx);
611 if(cache){
612 int i, itarget;
613 proxy_entry *pe = MALLOC(proxy_entry*,sizeof(proxy_entry));
614 pe->node = node;
615 pe->jsproxy = jsproxy;
616
617 itarget = -1;
618 for(i=0;i<vectorSize(cache->cache);i++){
619 proxy_entry *pe0 = vector_get(proxy_entry*,cache->cache,i);
620 if(pe0 == NULL){
621 itarget = i;
622 vector_set(proxy_entry*,cache->cache,i,pe);
623 ret = pe;
624 break;
625 }
626 }
627 if(itarget == -1){
628 stack_push(proxy_entry*,cache->cache,pe);
629 ret = pe;
630 }
631 if(0){
632 printf("cache after add proxy\n");
633 for(i=0;i<vectorSize(cache->cache);i++){
634 proxy_entry *pe0 = vector_get(proxy_entry*,cache->cache,i);
635 if(pe0)
636 printf("%d %p %p\n",i,pe0->node,pe0->jsproxy);
637 else
638 printf("%d NULL\n",i);
639 }
640 }
641 }
642 return ret;
643}
644void remove_ctx_proxycache_entry_by_nodeptr(duk_context *ctx, struct X3D_Node *node){
645 int i;
646 //Q. is it dangerous / should we always remove by jsproxy* ?
647 proxy_entry *ret = NULL;
648 cache_entry *cache = lookup_ctx_proxy_cache(ctx);
649 if(cache){
650 int i;
651 for(i=0;i<vectorSize(cache->cache);i++){
652 proxy_entry *pe0 = vector_get(proxy_entry*,cache->cache,i);
653 if(pe0 && pe0->node == node){
654 vector_set(proxy_entry*,cache->cache,i,NULL);
655 FREE_IF_NZ(pe0);
656 break;
657 }
658 }
659 if(0){
660 printf("after cache clean\n");
661 for(i=0;i<vectorSize(cache->cache);i++){
662 proxy_entry *pe0 = vector_get(proxy_entry*,cache->cache,i);
663 if(pe0)
664 printf("%d %p %p\n",i,pe0->node,pe0->jsproxy);
665 else
666 printf("%d NULL\n",i);
667 }
668 }
669 }
670}
671void remove_ctx_proxycache_entry_by_jsproxy(duk_context *ctx, void *jsproxy){
672 int i;
673 proxy_entry *ret = NULL;
674 cache_entry *cache = lookup_ctx_proxy_cache(ctx);
675 if(cache){
676 int i;
677 for(i=0;i<vectorSize(cache->cache);i++){
678 proxy_entry *pe0 = vector_get(proxy_entry*,cache->cache,i);
679 if(pe0 && pe0->jsproxy == jsproxy){
680 vector_set(proxy_entry*,cache->cache,i,NULL);
681 FREE_IF_NZ(pe0);
682 break;
683 }
684 }
685 }
686}
687//<< PROXY CACHING FUNCTIONS
688
689int cfinalizer(duk_context *ctx){
690 int rc, itype, igc;
691 void *fwpointer = NULL;
692 itype = igc = -1;
693 rc = duk_get_prop_string(ctx,0,"fwItype");
694 if(rc == 1) itype = duk_to_int(ctx,-1);
695 duk_pop(ctx); //get prop string result
696 rc = duk_get_prop_string(ctx,0,"fwGC");
697 if(rc == 1) igc = duk_to_boolean(ctx,-1);
698 duk_pop(ctx); //get prop string result
699 rc = duk_get_prop_string(ctx,0,"fwField");
700 if(rc == 1) fwpointer = duk_to_pointer(ctx,-1);
701 duk_pop(ctx); //get prop string result
702
703
704 //printf("hi from finalizer, itype=%s igc=%d p=%p\n",itype2string(itype),igc,fwpointer);
705 if(itype == FIELDTYPE_SFNode && fwpointer){
706 //2017 remove proxy from context cache
707 //
708 //a) lookup context cache
709 //b) lookup node's proxy in context cache
710 //c) remove
711 struct X3D_Node *node = *(struct X3D_Node**)fwpointer;
712 remove_ctx_proxycache_entry_by_nodeptr(ctx, node);
713 }
714 if(igc > 0 && itype > -1 && fwpointer){
715 if(itype < AUXTYPE_X3DConstants){
716 //FIELDS
717 freeField(itype,fwpointer);
718 }else{
719 //AUXTYPES
720 free(fwpointer);
721 }
722 }
723 return 0;
724}
725
726static int doingFinalizer = 1;
727void push_typed_proxy(duk_context *ctx, int itype, void *fwpointer, int* valueChanged)
728{
729 //like push_typed_proxy2 except push this instead of push obj
730 //int rc;
731 proxy_entry *pe = NULL;
732 if(itype == FIELDTYPE_SFNode){
733 struct X3D_Node* node = *(struct X3D_Node**)fwpointer;
734 //printf("pushtyped nodetype %d\n",node->_nodeType);
735 pe = lookup_ctx_proxycache_entry_by_nodeptr(ctx, node);
736 }
737 if(pe){
738 duk_push_heapptr(ctx, pe->jsproxy);
739 }else{
740 //show_stack(ctx,"push_typed_proxy start");
741 duk_eval_string(ctx,"Proxy");
742 duk_push_this(ctx); //this
743 duk_push_pointer(ctx,fwpointer);
744 duk_put_prop_string(ctx,-2,"fwField");
745 duk_push_pointer(ctx,valueChanged);
746 duk_put_prop_string(ctx,-2,"fwChanged");
747 duk_push_int(ctx,itype);
748 duk_put_prop_string(ctx,-2,"fwItype");
749 if(doingFinalizer){
750 duk_push_boolean(ctx,TRUE);
751 duk_put_prop_string(ctx,-2,"fwGC");
752 }
753 duk_eval_string(ctx,"handler");
754 //show_stack(ctx,"push_typed_proxy should have Proxy, this, handler");
755
756 duk_new(ctx,2); /* [ global Proxy target handler ] -> [ global result ] */
757 //show_stack(ctx,"push_typed_proxy after new, proxy obj should be result???");
758
759 if(doingFinalizer){
760 //push_typed_proxy is called by constructor, that mallocs (via fwtype->constructor) and should GC
761 //
762 //Duktape.fin(a, function (x) {
763 // try {
764 // print('finalizer, foo ->', x.foo);
765 // } catch (e) {
766 // print('WARNING: finalizer failed (ignoring): ' + e);
767 // }
768 // });
769 if(itype == FIELDTYPE_SFNode){
770 struct X3D_Node* node = *(struct X3D_Node**)fwpointer;
771 void *jsproxy = duk_get_heapptr(ctx, -1);
772 add_ctx_proxycache_entry(ctx, node, jsproxy);
773 }
774 duk_eval_string(ctx,"Duktape.fin");
775 duk_dup(ctx, -2); //copy the proxy object
776 duk_push_c_function(ctx,cfinalizer,1);
777 duk_pcall(ctx,2);
778 duk_pop(ctx); //pop Duktape.fin result
779 }
780 }
781}
782
783int push_typed_proxy2(duk_context *ctx, int itype, int kind, void *fwpointer, int* valueChanged, char doGC)
784{
785 /* like fwgetter version, except with no fieldname or mode, for temp proxies
786 nativePtr
787 */
788 //int rc;
789 proxy_entry *pe = NULL;
790 int idogc = doGC ? TRUE : FALSE;
791 if(itype == FIELDTYPE_SFNode){
792 struct X3D_Node* node = *(struct X3D_Node**)fwpointer;
793 //printf("pushtyped2 nodetype %d\n",node->_nodeType);
794 pe = lookup_ctx_proxycache_entry_by_nodeptr(ctx, node);
795 }
796 if(pe){
797 duk_push_heapptr(ctx, pe->jsproxy);
798 }else{
799 duk_eval_string(ctx,"Proxy");
800 duk_push_object(ctx);
801 duk_push_pointer(ctx,fwpointer);
802 duk_put_prop_string(ctx,-2,"fwField");
803 duk_push_pointer(ctx,valueChanged);
804 duk_put_prop_string(ctx,-2,"fwChanged");
805 duk_push_int(ctx,itype);
806 duk_put_prop_string(ctx,-2,"fwItype");
807 duk_push_int(ctx,kind);
808 duk_put_prop_string(ctx,-2,"fwKind");
809
810 if(doingFinalizer) { // && idogc){
811 duk_push_boolean(ctx,idogc);
812 duk_put_prop_string(ctx,-2,"fwGC");
813 }
814
815 duk_eval_string(ctx,"handler");
816 duk_new(ctx,2); /* [ global Proxy target handler ] -> [ global result ] */
817 if(doingFinalizer) { // && idogc){
818 //push_typed_proxy2 _refers_ to script->field[i]->anyVrml (its caller fwgetter doesn't malloc) and should not GC its pointer
819 //
820 //Duktape.fin(a, function (x) {
821 // try {
822 // print('finalizer, foo ->', x.foo);
823 // } catch (e) {
824 // print('WARNING: finalizer failed (ignoring): ' + e);
825 // }
826 // });
827 if(itype == FIELDTYPE_SFNode){
828 struct X3D_Node* node = *(struct X3D_Node**)fwpointer;
829 void *jsproxy = duk_get_heapptr(ctx, -1);
830 add_ctx_proxycache_entry(ctx, node, jsproxy);
831 }
832
833 duk_eval_string(ctx,"Duktape.fin");
834 duk_dup(ctx, -2); //copy the proxy object
835 duk_push_c_function(ctx,cfinalizer,1);
836 duk_pcall(ctx,2);
837 duk_pop(ctx); //pop Duktape.fin result
838 }
839 }
840
841 return 1;
842}
843
844
845void convert_duk_to_fwvals_old(duk_context *ctx, int nargs, int istack, struct ArgListType arglist, FWval *args, int *argc){
846 int nUsable,nNeeded, i, ii;
847 FWval pars;
848 //struct Uni_String *uni;
849 nUsable = arglist.iVarArgStartsAt > -1 ? nargs : arglist.nfixedArg;
850 nNeeded = max(nUsable,arglist.nfixedArg);
851 pars = malloc(nNeeded*sizeof(struct FWVAL));
852 (*args) = pars;
853 //QC and genericization of incoming parameters
854 (*argc) = nNeeded;
855 for(i=0;i<nUsable;i++){
856 //const char* str;
857 int trhs; //RHS or incoming javascript primitive type
858 char ctype; //LHS or target type
859 ii = istack + i;
860 if(i < arglist.nfixedArg)
861 ctype = arglist.argtypes[i];
862 else
863 ctype = arglist.argtypes[arglist.iVarArgStartsAt];
864 pars[i].itype = ctype;
865 if( duk_is_object(ctx, ii)){
866 int rc, isPrimitive;
867 //if the script goes myField = new String('hi'); then it comes in here as an object (versus myField = 'hi'; which is a string)
868 rc = duk_get_prop_string(ctx,ii,"fwItype");
869 duk_pop(ctx);
870 isPrimitive = rc == 0;
871 if(isPrimitive){
872 //void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint); DUK_HINT_NONE
873 //http://www.duktape.org/api.html#duk_to_primitive
874 duk_to_primitive(ctx,ii,DUK_HINT_NONE);
875 }
876 }
877 //determine RHS / actual ecma type on stack
878 trhs = duk_get_type(ctx, ii);
879 //switch(trhs){
880 // case DUK_TYPE_NUMBER: stype ="number"; break;
881 // case DUK_TYPE_STRING: stype ="string"; break;
882
883 // case DUK_TYPE_OBJECT: stype ="object"; break;
884 // case DUK_TYPE_NONE: stype ="none"; break;
885 // case DUK_TYPE_UNDEFINED: stype ="undefined"; break;
886 // case DUK_TYPE_BOOLEAN: stype ="boolean"; break;
887 // case DUK_TYPE_NULL: stype ="null"; break;
888 // case DUK_TYPE_POINTER: stype ="pointer"; break;
889 // default:
890 //}
891 //if( duk_is_null(ctx,ii)){
892 // printf("rhs is null\n");
893 //}
894
895 switch(ctype){
896 case 'B': {
897 int bb = duk_get_boolean(ctx,ii); //duk_to_boolean(ctx,ii);
898 pars[i]._boolean = bb; // duk_to_boolean(ctx,ii);
899 }
900 break;
901 case 'I': pars[i]._integer = duk_to_int(ctx,ii); break;
902 case 'F': pars[i]._numeric = duk_to_number(ctx,ii); break;
903 case 'D': pars[i]._numeric = duk_to_number(ctx,ii); break;
904 case 'S': pars[i]._string = duk_to_string(ctx,ii); break;
905 case 'Z': //flexi-string idea - allow either String or MFString (no such thing as SFString from ecma - it uses String for that)
906 if(duk_is_string(ctx,ii)){
907 pars[i]._string = duk_get_string(ctx,ii);
908 pars[i].itype = 'S';
909 break;
910 }
911 if(!duk_is_object(ctx,i))
912 break;
913 //else fall through to W
914 case 'W': {
915 int rc, isOK, itypeRHS = -1;
916 union anyVrml *fieldRHS = NULL;
917 if(trhs == DUK_TYPE_NULL){
918 itypeRHS = 10;
919 fieldRHS = malloc(sizeof(union anyVrml));
920 fieldRHS->sfnode = NULL;
921 }else if(trhs == DUK_TYPE_OBJECT){
922 rc = duk_get_prop_string(ctx,ii,"fwItype");
923 if(rc == 1){
924 itypeRHS = duk_to_int(ctx,-1);
925 }
926 duk_pop(ctx);
927 rc = duk_get_prop_string(ctx,ii,"fwField");
928 if(rc == 1) fieldRHS = duk_to_pointer(ctx,-1);
929 duk_pop(ctx);
930 }
931 /*we don't need the RHS fwChanged=valueChanged* because we are only changing the LHS*/
932 isOK = FALSE;
933 //if(fieldRHS != NULL && itypeRHS > -1){
934 if(itypeRHS > -1){
935 // its one of our proxy field types or null. But is it the type we need?
936 //medium_copy_field(itypeRHS,fieldRHS,&pars[i]._web3dval.native); //medium copy - copies p[] in MF types but not deep copy *(p[i]) if p[i] is pointer type ie SFNode* or Uni_String*
937 pars[i]._web3dval.native = fieldRHS;
938 pars[i]._web3dval.fieldType = itypeRHS;
939 pars[i].itype = 'W';
940 // see below *valueChanged = TRUE;
941 isOK = TRUE;
942 }
943 }
944 break;
945 case 'P': {
946 int rc, isOK, itypeRHS = -1;
947 union anyVrml *fieldRHS = NULL;
948 rc = duk_get_prop_string(ctx,ii,"fwItype");
949 if(rc == 1){
950 //printf(duk_type_to_string(duk_get_type(ctx, -1)));
951 itypeRHS = duk_to_int(ctx,-1);
952 }
953 duk_pop(ctx);
954 rc = duk_get_prop_string(ctx,ii,"fwField");
955 if(rc == 1) fieldRHS = duk_to_pointer(ctx,-1);
956 duk_pop(ctx);
957 /*we don't need the RHS fwChanged=valueChanged* because we are only changing the LHS*/
958 isOK = FALSE;
959 if(fieldRHS != NULL && itypeRHS >= AUXTYPE_X3DConstants){
960 /* its one of our auxiliary types - Browser, X3DConstants, ProfileInfo, ComponentInfo, X3DRoute ...*/
961 pars[i]._pointer.native = fieldRHS;
962 pars[i]._pointer.fieldType = itypeRHS;
963 pars[i].itype = 'P';
964 // see below *valueChanged = TRUE;
965 isOK = TRUE;
966 }
967 }
968 break;
969
970 case 'O': break; //object pointer ie to js function callback object
971 }
972 }
973
974 for(i=nUsable;i<nNeeded;i++){
975 //fill
976 char ctype = arglist.argtypes[i];
977 pars[i].itype = ctype;
978 switch(ctype){
979 case 'B': pars[i]._boolean = FALSE; break;
980 case 'I': pars[i]._integer = 0; break;
981 case 'F': pars[i]._numeric = 0.0; break;
982 case 'D': pars[i]._numeric = 0.0; break;
983 case 'S': pars[i]._string = NULL; break;
984 case 'Z': pars[i]._string = NULL; pars[i].itype = 'S'; break;
985 case 'W':
986 pars[i]._web3dval.fieldType = FIELDTYPE_SFNode;
987 pars[i]._web3dval.native = NULL; break;
988 //case 'P':
989 // pars[i]._web3dval.fieldType = FIELDTYPE_SFNode; //I don't have a good default value - do I need an AUXTYPE_NULL?
990 // pars[i]._web3dval.native = NULL; break;
991 case 'O':
992 pars[i]._jsobject = NULL; break;
993 default:
994 pars[i].itype = '0';
995 }
996 }
997}
998
999void convert_duk_to_fwvals_new(duk_context *ctx, int nargs, int istack, struct ArgListType arglist, FWval *args, int *argc){
1000 int nUsable,nNeeded, i, ii, jj, k, len;
1001 FWval pars;
1002 //struct Uni_String *uni;
1003
1004 //we don't handle js lists [] very well, so we'll expand them and treat them like a flat list of args
1005 if(nargs > 0){
1006 int margs = 0;
1007 for(i=0;i<nargs;i++){
1008 ii = istack;
1009 len = 1;
1010 if( duk_is_array(ctx, ii)){
1011 //if the script goes myField = new String('hi'); then it comes in here as an object (versus myField = 'hi'; which is a string)
1012 len = duk_get_length(ctx, ii);
1013 }
1014 margs += len;
1015 }
1016 nargs = margs;
1017 }
1018
1019 nUsable = arglist.iVarArgStartsAt > -1 ? nargs : arglist.nfixedArg;
1020 nNeeded = max(nUsable,arglist.nfixedArg);
1021 pars = malloc(nNeeded*sizeof(struct FWVAL));
1022 (*args) = pars;
1023 //QC and genericization of incoming parameters
1024 (*argc) = nNeeded;
1025 ii = istack;
1026 for(i=0;i<nUsable;){
1027 //const char* str;
1028 int trhs, ipop; //RHS or incoming javascript primitive type
1029 char ctype; //LHS or target type
1030 len = 1;
1031 if( duk_is_array(ctx, ii)){
1032 //if the script goes myField = new String('hi'); then it comes in here as an object (versus myField = 'hi'; which is a string)
1033 len = duk_get_length(ctx, ii);
1034 }
1035 for(k=0;k<len;k++,i++){
1036 if(i < arglist.nfixedArg)
1037 ctype = arglist.argtypes[i];
1038 else
1039 ctype = arglist.argtypes[arglist.iVarArgStartsAt];
1040 pars[i].itype = ctype;
1041 jj = -1;
1042 if( duk_is_array(ctx, ii)){
1043 duk_get_prop_index(ctx, ii, k);
1044 } else {
1045 duk_dup(ctx,ii);
1046 }
1047 if( duk_is_object(ctx,jj) ){
1048 int rc, isPrimitive;
1049 //if the script goes myField = new String('hi'); then it comes in here as an object (versus myField = 'hi'; which is a string)
1050 rc = duk_get_prop_string(ctx,jj,"fwItype");
1051 duk_pop(ctx);
1052 isPrimitive = rc == 0;
1053 if(isPrimitive){
1054 //void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint); DUK_HINT_NONE
1055 //http://www.duktape.org/api.html#duk_to_primitive
1056 duk_to_primitive(ctx,jj,DUK_HINT_NONE);
1057 }
1058 }
1059 //determine RHS / actual ecma type on stack
1060 trhs = duk_get_type(ctx, jj);
1061 //switch(trhs){
1062 // case DUK_TYPE_NUMBER: stype ="number"; break;
1063 // case DUK_TYPE_STRING: stype ="string"; break;
1064
1065 // case DUK_TYPE_OBJECT: stype ="object"; break;
1066 // case DUK_TYPE_NONE: stype ="none"; break;
1067 // case DUK_TYPE_UNDEFINED: stype ="undefined"; break;
1068 // case DUK_TYPE_BOOLEAN: stype ="boolean"; break;
1069 // case DUK_TYPE_NULL: stype ="null"; break;
1070 // case DUK_TYPE_POINTER: stype ="pointer"; break;
1071 // default:
1072 //}
1073 //if( duk_is_null(ctx,ii)){
1074 // printf("rhs is null\n");
1075 //}
1076
1077 switch(ctype){
1078 case 'B': {
1079 int bb = duk_get_boolean(ctx,jj); //duk_to_boolean(ctx,ii);
1080 pars[i]._boolean = bb; // duk_to_boolean(ctx,ii);
1081 }
1082 break;
1083 case 'I': pars[i]._integer = duk_to_int(ctx,jj); break;
1084 case 'F': pars[i]._numeric = duk_to_number(ctx,jj); break;
1085 case 'D': pars[i]._numeric = duk_to_number(ctx,jj); break;
1086 case 'S': pars[i]._string = duk_to_string(ctx,jj); break;
1087 case 'Z': //flexi-string idea - allow either String or MFString (no such thing as SFString from ecma - it uses String for that)
1088 if(duk_is_string(ctx,jj)){
1089 pars[i]._string = duk_get_string(ctx,jj);
1090 pars[i].itype = 'S';
1091 break;
1092 }
1093 if(!duk_is_object(ctx,jj))
1094 break;
1095 //else fall through to W
1096 case 'W': {
1097 int rc, isOK, itypeRHS = -1;
1098 union anyVrml *fieldRHS = NULL;
1099 if(trhs == DUK_TYPE_NULL){
1100 itypeRHS = 10;
1101 fieldRHS = malloc(sizeof(union anyVrml));
1102 fieldRHS->sfnode = NULL;
1103 }else if(trhs == DUK_TYPE_OBJECT){
1104 rc = duk_get_prop_string(ctx,jj,"fwItype");
1105 if(rc == 1){
1106 itypeRHS = duk_to_int(ctx,-1);
1107 }
1108 duk_pop(ctx);
1109 rc = duk_get_prop_string(ctx,jj,"fwField");
1110 if(rc == 1) fieldRHS = duk_to_pointer(ctx,-1);
1111 duk_pop(ctx);
1112 }
1113 /*we don't need the RHS fwChanged=valueChanged* because we are only changing the LHS*/
1114 isOK = FALSE;
1115 //if(fieldRHS != NULL && itypeRHS > -1){
1116 if(itypeRHS > -1){
1117 // its one of our proxy field types or null. But is it the type we need?
1118 //medium_copy_field(itypeRHS,fieldRHS,&pars[i]._web3dval.native); //medium copy - copies p[] in MF types but not deep copy *(p[i]) if p[i] is pointer type ie SFNode* or Uni_String*
1119 pars[i]._web3dval.native = fieldRHS;
1120 pars[i]._web3dval.fieldType = itypeRHS;
1121 pars[i].itype = 'W';
1122 // see below *valueChanged = TRUE;
1123 isOK = TRUE;
1124 }
1125 }
1126 break;
1127 case 'P': {
1128 int rc, isOK, itypeRHS = -1;
1129 union anyVrml *fieldRHS = NULL;
1130 rc = duk_get_prop_string(ctx,jj,"fwItype");
1131 if(rc == 1){
1132 //printf(duk_type_to_string(duk_get_type(ctx, -1)));
1133 itypeRHS = duk_to_int(ctx,-1);
1134 }
1135 duk_pop(ctx);
1136 rc = duk_get_prop_string(ctx,jj,"fwField");
1137 if(rc == 1) fieldRHS = duk_to_pointer(ctx,-1);
1138 duk_pop(ctx);
1139 /*we don't need the RHS fwChanged=valueChanged* because we are only changing the LHS*/
1140 isOK = FALSE;
1141 if(fieldRHS != NULL && itypeRHS >= AUXTYPE_X3DConstants){
1142 /* its one of our auxiliary types - Browser, X3DConstants, ProfileInfo, ComponentInfo, X3DRoute ...*/
1143 pars[i]._pointer.native = fieldRHS;
1144 pars[i]._pointer.fieldType = itypeRHS;
1145 pars[i].itype = 'P';
1146 // see below *valueChanged = TRUE;
1147 isOK = TRUE;
1148 }
1149 }
1150 break;
1151
1152 case 'O': break; //object pointer ie to js function callback object
1153 }
1154 duk_pop(ctx);
1155 } //k
1156 ii = ii + 1;
1157 }
1158
1159 for(i=nUsable;i<nNeeded;i++){
1160 //fill
1161 char ctype = arglist.argtypes[i];
1162 pars[i].itype = ctype;
1163 switch(ctype){
1164 case 'B': pars[i]._boolean = FALSE; break;
1165 case 'I': pars[i]._integer = 0; break;
1166 case 'F': pars[i]._numeric = 0.0; break;
1167 case 'D': pars[i]._numeric = 0.0; break;
1168 case 'S': pars[i]._string = NULL; break;
1169 case 'Z': pars[i]._string = NULL; pars[i].itype = 'S'; break;
1170 case 'W':
1171 pars[i]._web3dval.fieldType = FIELDTYPE_SFNode;
1172 pars[i]._web3dval.native = NULL; break;
1173 //case 'P':
1174 // pars[i]._web3dval.fieldType = FIELDTYPE_SFNode; //I don't have a good default value - do I need an AUXTYPE_NULL?
1175 // pars[i]._web3dval.native = NULL; break;
1176 case 'O':
1177 pars[i]._jsobject = NULL; break;
1178 default:
1179 pars[i].itype = '0';
1180 }
1181 }
1182}
1183
1184void convert_duk_to_fwvals(duk_context *ctx, int nargs, int istack, struct ArgListType arglist, FWval *args, int *argc){
1185/*
1186 if(nargs != 1 && nargs != 0 && nargs != 2)
1187 convert_duk_to_fwvals_old(ctx,nargs,istack,arglist,args,argc);
1188 else if(nargs == 2){
1189 int ftype = -1;
1190 FWval pargs;
1191 convert_duk_to_fwvals_old(ctx,nargs,istack,arglist,args,argc);
1192 pargs = (*args);
1193 printf("old argc %d\n",*argc);
1194 for(int i=0;i<*argc;i++){
1195 printf("args[%d] %x\n",i,pargs[i]);
1196 printf("old args[%d] type %d ftype %d\n",i,pargs[i].itype, ftype);
1197 }
1198 printf("===\n");
1199 *args = NULL;
1200 convert_duk_to_fwvals_new(ctx,nargs,istack,arglist,args,argc);
1201 printf("new argc %d\n",*argc);
1202 pargs = (*args);
1203 for(int i=0;i<*argc;i++){
1204 //, args[i]->_web3dval.fieldType
1205 printf("args[%d] %x\n",i,pargs[i]);
1206 printf("new args[%d] type %d ftype %d\n",i,pargs[i].itype, ftype);
1207 }
1208
1209 }
1210 else
1211 */
1212 convert_duk_to_fwvals_new(ctx,nargs,istack,arglist,args,argc);
1213}
1214
1215
1216int cfwconstructor(duk_context *ctx) {
1217 int i, j, rc, nargs, argc, ifound;
1218 FWType fwt;
1219 FWval args;
1220 void *fwpointer;
1221 int *valueChanged = NULL; //so called 'internal' variables inside the script context don't point to a valueChanged
1222 int itype = -1;
1223 nargs = duk_get_top(ctx);
1224
1225 //show_stack(ctx,"cfwconstructor start");
1226
1227 duk_push_current_function(ctx);
1228 rc = duk_get_prop_string(ctx,-1,"fwItype");
1229 if(rc == 1) itype = duk_to_int(ctx,-1);
1230 duk_pop(ctx); //get prop string result
1231 duk_pop(ctx); //current function
1232
1233 //show_stack(ctx,"cfwconstructor after push and pop current function");
1234
1235 if(itype < 0) return 0; //no itype means it's not one of ours
1236 fwt = getFWTYPE(itype);
1237 if(!fwt->Constructor) return 0;
1238
1239 //find the contructor that matches the args best
1240 i = 0;
1241 ifound = -1;
1242 while(fwt->ConstructorArgs[i].nfixedArg > -1){
1243 int nfixed = fwt->ConstructorArgs[i].nfixedArg;
1244 int ivarsa = fwt->ConstructorArgs[i].iVarArgStartsAt;
1245 char *neededTypes = fwt->ConstructorArgs[i].argtypes;
1246 int fill = fwt->ConstructorArgs[i].fillMissingFixedWithZero == 'T';
1247 if( nargs == nfixed || (ivarsa > -1 && nargs >= nfixed ) || (ivarsa > -1 && fill)){
1248 //nargs is a match
1249 int allOK = TRUE;
1250 //check each narg for compatible type
1251 for(j=0;j<nargs;j++){
1252 char neededType;
1253 int isOK, RHS_duk_type = duk_get_type(ctx, j);
1254 isOK = FALSE;
1255 neededType = j >= nfixed ? neededTypes[ivarsa] : neededTypes[j]; //if you have varargs you specify one more type than the fixed requires
1256 // for example MFColor nfixed=0 (you can have 0 to infinity args), ivarsa=0 (varargs start at index 0), neededTypes="W" the first and subsequent varargs are of type 'W'
1257 //printf("duktype %s\n",duk_type_to_string(RHS_duk_type));
1258 switch(RHS_duk_type){
1259 case DUK_TYPE_NUMBER:
1260 if(neededType =='F' || neededType =='D' || neededType =='I') isOK = TRUE;
1261 break;
1262 case DUK_TYPE_BOOLEAN:
1263 if(neededType =='B') isOK = TRUE;
1264 break;
1265 case DUK_TYPE_STRING:
1266 if(neededType =='S' || neededType =='Z') isOK = TRUE;
1267 break;
1268 case DUK_TYPE_OBJECT:
1269 if(neededType =='W' || neededType =='P'){
1270 int rc, itypeRHS = -1;
1271 union anyVrml *fieldRHS = NULL;
1272 rc = duk_get_prop_string(ctx,j,"fwItype");
1273 if(rc == 1){
1274 //printf(duk_type_to_string(duk_get_type(ctx, -1)));
1275 itypeRHS = duk_to_int(ctx,-1);
1276 }
1277 duk_pop(ctx);
1278 rc = duk_get_prop_string(ctx,j,"fwField");
1279 if(rc == 1) fieldRHS = duk_to_pointer(ctx,-1);
1280 duk_pop(ctx);
1281 //we don't need the RHS fwChanged=valueChanged* because we are only changing the LHS
1282
1283 if(fieldRHS != NULL && itypeRHS > -1){
1284 //in theory, we could make sure somehow that we had the right kind of 'W' : add a FIELDTYPE_ / AUXTYPE_ array in arglist struct
1285 isOK = TRUE;
1286 }
1287 if(!isOK){
1288 //is it a list ie new MFVec3f([A3f,B3f])?
1289
1290 }
1291 }
1292 break;
1293 case DUK_TYPE_NONE:
1294 case DUK_TYPE_UNDEFINED:
1295 case DUK_TYPE_NULL:
1296 // are we attempting to null out the field? we aren't allowed to change its type (to undefined)
1297 case DUK_TYPE_POINTER:
1298 // don't know what this would be for if anything
1299 default:
1300 isOK = FALSE;
1301 break;
1302 }
1303 allOK = allOK && isOK;
1304 }
1305 if(fill)
1306 for(j=nargs;j<nfixed;j++){
1307 allOK = allOK && 1;
1308 }
1309 if(allOK){
1310 ifound = i;
1311 break;
1312 }
1313 }
1314 i++;
1315 }
1316 if(ifound < 0){
1317 //printf("matching constructor not found, you have %d args for %s\n",nargs,fwt->name);
1318 //Jan 2016 if you're in here, and your Script did new MFString(number,string) -heterogenous call args-
1319 //.. then I think the problem is the nested loops above are inside-out. MFString constructor
1320 //.. should be able to handle heterogenous args, and if constructor.args was the inner loop and
1321 //.. call args the outer loop, allOK would be true:
1322 //.. it would find the (only) constructor is a match.
1323 //.. don't have time to code-review, try and test this theory thoroughly today
1324 //.. temproary fix in your script: new MFString(number.toString(),string) to make args homogenous.
1325 //return 0;
1326 i = 0; //take the first one
1327 }
1328 args = NULL;
1329 convert_duk_to_fwvals(ctx, nargs, 0, fwt->ConstructorArgs[i], &args, &argc);
1330 if(fwt->ConstructorArgs[ifound].fillMissingFixedWithZero == 'T' && nargs < fwt->ConstructorArgs[ifound].nfixedArg){
1331 int nfixed = fwt->ConstructorArgs[ifound].nfixedArg;
1332 //int ivarsa = fwt->ConstructorArgs[ifound].iVarArgStartsAt;
1333 char *neededTypes = fwt->ConstructorArgs[ifound].argtypes;
1334 //int fill = fwt->ConstructorArgs[ifound].fillMissingFixedWithZero == 'T';
1335 args = realloc(args,nfixed * sizeof(struct FWVAL));
1336 for(j=nargs;j<nfixed;j++){
1337 switch(neededTypes[j]){
1338 case 'B':
1339 args[j]._boolean = FALSE; break;
1340 case 'I':
1341 args[j]._integer = 0; break;
1342 case 'F':
1343 args[j]._numeric = 0.0; break;
1344 case 'D':
1345 args[j]._numeric = 0.0; break;
1346 case 'S':
1347 args[j]._string = ""; break;
1348 case 'W':
1349 case 'P':
1350 break;
1351 }
1352 }
1353 argc = nfixed;
1354 }
1355
1356 fwpointer = fwt->Constructor(fwt,argc,args);
1357 free(args);
1358 push_typed_proxy(ctx,itype, fwpointer, valueChanged);
1359
1360 return 1;
1361}
1362int chas(duk_context *ctx) {
1363 int rc, itype, *valueChanged;
1364 const char *key;
1365 int nr, index;
1366 char type, readOnly;
1367 FWType fwt;
1368 union anyVrml *parent = NULL;
1369
1370 itype = 0;
1371 /* get type of parent object for this property*/
1372 rc = duk_get_prop_string(ctx,0,"fwItype");
1373 if(rc==1) itype = duk_get_int(ctx,-1);
1374 duk_pop(ctx);
1375 /* get the pointer to the parent object */
1376 rc = duk_get_prop_string(ctx,0,"fwField");
1377 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1378 duk_pop(ctx);
1379 /* get the pointer to the changed flag */
1380 rc = duk_get_prop_string(ctx,0,"fwChanged");
1381 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1382 duk_pop(ctx);
1383 key = duk_require_string(ctx,-1);
1384 //printf("key=%s\n",key);
1385
1386 nr = 1;
1387 fwt = getFWTYPE(itype);
1388 if(fwhas_generic(fwt,parent,key,&index,&type,&readOnly)){
1389 duk_push_true(ctx);
1390 }else{
1391 duk_push_false(ctx);
1392 }
1393 //isFunc = type == 'f';
1394 //show_stack(ctx,"in chas");
1395
1396 return nr;
1397}
1398int cownKeys(duk_context *ctx) {
1399 int rc, itype, *valueChanged, arr_idx;
1400 void *parent = NULL;
1401 int i;
1402 const char *fieldname;
1403 int lastProp, jndex; //isFunc,
1404 char type, readOnly;
1405 //FWTYPE *getFWTYPE(int itype)
1406 FWType fwt;
1407 itype = -1;
1408
1409 /* get type of parent object for this property*/
1410 rc = duk_get_prop_string(ctx,0,"fwItype");
1411 if(rc==1) itype = duk_get_int(ctx,-1);
1412 duk_pop(ctx);
1413 /* get the pointer to the parent object */
1414 rc = duk_get_prop_string(ctx,0,"fwField");
1415 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1416 duk_pop(ctx);
1417 /* get the pointer to the changed flag */
1418 rc = duk_get_prop_string(ctx,0,"fwChanged");
1419 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1420 duk_pop(ctx);
1421
1422 arr_idx = duk_push_array(ctx);
1423 if(itype < 0 || (itype < AUXTYPE_X3DConstants && parent == NULL))
1424 return 1; //return empty array
1425 i = -1;
1426 fwt = getFWTYPE(itype);
1427 //fwiterator_generic(int index, FWTYPE *fwt, FWPointer *pointer, char **name, int *lastProp, int *jndex)
1428 while( (i = fwiterator_generic(i,fwt,parent,&fieldname,&lastProp,&jndex,&type,&readOnly)) > -1 ){
1429 duk_push_string(ctx, fieldname);
1430 duk_put_prop_index(ctx, arr_idx, i);
1431 }
1432 //show_stack(ctx,"in cownKeys");
1433 return 1;
1434}
1435int cenumerate(duk_context *ctx) {
1436 int rc, itype, *valueChanged;
1437 union anyVrml *parent = NULL;
1438 int i;
1439 const char *fieldname;
1440 int lastProp, jndex; //isFunc,
1441 char type, readOnly;
1442 FWType fwt;
1443 int arr_idx;
1444
1445 itype =0;
1446 /* get type of parent object for this property*/
1447 rc = duk_get_prop_string(ctx,0,"fwItype");
1448 if(rc==1) itype = duk_get_int(ctx,-1);
1449 duk_pop(ctx);
1450 /* get the pointer to the parent object */
1451 rc = duk_get_prop_string(ctx,0,"fwField");
1452 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1453 duk_pop(ctx);
1454 /* get the pointer to the changed flag */
1455 rc = duk_get_prop_string(ctx,0,"fwChanged");
1456 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1457 duk_pop(ctx);
1458
1459 arr_idx = duk_push_array(ctx);
1460 i = -1;
1461 fwt = getFWTYPE(itype);
1462 //fwiterator_generic(int index, FWTYPE *fwt, FWPointer *pointer, char **name, int *lastProp, int *jndex)
1463 while( (i = fwiterator_generic(i,fwt,parent,&fieldname,&lastProp,&jndex,&type,&readOnly)) > -1 ){
1464 //isFunc = i > lastProp;
1465 duk_push_string(ctx, fieldname);
1466 duk_put_prop_index(ctx, arr_idx, i);
1467 }
1468 //show_stack(ctx,"in cenumerate");
1469 return 1;
1470}
1471
1472int push_duk_fieldvalueECMA(duk_context *ctx, int itype, union anyVrml *fieldvalue)
1473{
1474 /*we have the field, and even the key name.
1475 So we should be able to decide how to package the outgoing value type:
1476 according to specs:
1477 - return ecma primitive value type for SFBool, SFInt32, SFFloat, SFDouble, SFTime, SFString
1478 - return our field-type-specific object/proxy-wrapper, pointing to our global.field, for the others.
1479 */
1480 int nr;
1481 //int isOK = FALSE;
1482 nr = 1;
1483 switch(itype){
1484 case FIELDTYPE_SFBool:
1485 duk_push_boolean(ctx,fieldvalue->sfbool); break;
1486 case FIELDTYPE_SFFloat:
1487 duk_push_number(ctx,fieldvalue->sffloat); break;
1488 case FIELDTYPE_SFTime:
1489 duk_push_number(ctx,fieldvalue->sftime); break;
1490 case FIELDTYPE_SFDouble:
1491 duk_push_number(ctx,fieldvalue->sfdouble); break;
1492 case FIELDTYPE_SFInt32:
1493 duk_push_int(ctx,fieldvalue->sfint32); break;
1494 case FIELDTYPE_SFString:
1495 duk_push_string(ctx,fieldvalue->sfstring->strptr); break;
1496 default:
1497 nr = 0;
1498 break;
1499 }
1500 //show_stack(ctx,"in fwgetterNS at end");
1501 return nr;
1502}
1503
1504static int SCALARS_ARE_PRIMITIVES = TRUE;
1505/* SCALARS_ARE_PRIMITIVES
1506 the ecmascript ! operator invokes ToBoolean() which always returns true when the argument is an object
1507 http://www.ecma-international.org/ecma-262/5.1/#sec-11.4.9
1508 http://www.ecma-international.org/ecma-262/5.1/#sec-9.2
1509 the web3d.org ecmascript specs say all fields shall have getType(), isReadable(), isWritable() functions.
1510 if I have: Script {
1511 field SFBool enabled TRUE
1512 url "ecmascript: function initialize(){
1513 var A = !enabled; //A returns false if enabled is a primitive and its value is true,
1514 //but A always returns false if enabled is a proxy object
1515 var B = enabled.getType(); //eval fails with 'type error, not an object' if enabled is a primitive,
1516 //but B returns X3DConstants.SFBool if enabled is a proxy object
1517 Because there are some goodies either way, and I'm not sure what the specs intend, I've made it configurable for now,
1518 although comparisons with vivaty are closer to SCALARS_ARE_PRIMITIVES = TRUE (some scenes fail with FALSE).
1519*/
1520int fwval_duk_push(duk_context *ctx, FWval fwretval, int *valueChanged){
1521 //converts engine-agnostic FWVAL return value to duk engine specific return values and pushes them onto the duk value stack
1522 int nr = 1;
1523 switch(fwretval->itype){
1524
1525 case 'B':
1526 duk_push_boolean(ctx,fwretval->_boolean); break;
1527 case 'I':
1528 duk_push_int(ctx,fwretval->_integer); break;
1529 case 'F':
1530 duk_push_number(ctx,fwretval->_numeric); break;
1531 case 'D':
1532 duk_push_number(ctx,fwretval->_numeric); break;
1533 case 'S':
1534 duk_push_string(ctx,fwretval->_string); break;
1535
1536 case 'W':
1537 if(SCALARS_ARE_PRIMITIVES){
1538 //for pointers to web3d field types
1539 switch(fwretval->_web3dval.fieldType){
1540 case FIELDTYPE_SFBool:
1541 duk_push_boolean(ctx,fwretval->_web3dval.anyvrml->sfbool); break;
1542 case FIELDTYPE_SFInt32:
1543 duk_push_int(ctx,fwretval->_web3dval.anyvrml->sfint32); break;
1544 case FIELDTYPE_SFFloat:
1545 duk_push_number(ctx,(double)fwretval->_web3dval.anyvrml->sffloat); break;
1546 case FIELDTYPE_SFDouble:
1547 case FIELDTYPE_SFTime:
1548 duk_push_number(ctx,fwretval->_web3dval.anyvrml->sfdouble); break;
1549 case FIELDTYPE_SFString:
1550 if(fwretval->_web3dval.anyvrml->sfstring && fwretval->_web3dval.anyvrml->sfstring->strptr)
1551 duk_push_string(ctx,fwretval->_web3dval.anyvrml->sfstring->strptr);
1552 else
1553 duk_push_string(ctx,"");
1554 break;
1555 default:
1556 push_typed_proxy2(ctx,fwretval->_web3dval.fieldType,fwretval->_web3dval.kind,fwretval->_web3dval.native,valueChanged,fwretval->_web3dval.gc);
1557 }
1558 }else{
1559 //SCALARS_ARE_PROXY_OBJECTS
1560 push_typed_proxy2(ctx,fwretval->_web3dval.fieldType,fwretval->_web3dval.kind,fwretval->_web3dval.native,valueChanged,fwretval->_web3dval.gc);
1561 }
1562 break;
1563 case 'X':
1564 duk_push_pointer(ctx,fwretval->_jsobject);
1565 break;
1566 case 'P':
1567 //for web3d auxiliary types Browser, X3DFieldDefinitionArray, X3DRoute ...
1568 push_typed_proxy2(ctx,fwretval->_pointer.fieldType,fwretval->_pointer.kind,fwretval->_pointer.native,valueChanged,fwretval->_pointer.gc);
1569 break;
1570 case '0':
1571 duk_push_null(ctx);
1572 break;
1573 default:
1574 nr = 0; break;
1575 }
1576 return nr;
1577}
1578
1579int ctypefunction(duk_context *ctx) {
1580 int rc, nr, itype, kind, nargs;
1581 const char *fwFunc = NULL;
1582 //union anyVrml* field = NULL;
1583 //FWTYPE *fwt;
1584
1585 itype = -1;
1586 kind = -1;
1587 nargs = duk_get_top(ctx);
1588 //show_stack(ctx,"in cfuction");
1589 duk_push_current_function(ctx);
1590 /* get type of parent object for this property*/
1591 rc = duk_get_prop_string(ctx,-1,"fwItype");
1592 if(rc==1) itype = duk_get_int(ctx,-1);
1593 duk_pop(ctx);
1594 /*get the PKW_inputOutput read/write mode for the parent field*/
1595 rc = duk_get_prop_string(ctx,-1,"fwKind");
1596 if(rc==1) kind = duk_get_int(ctx,-1);
1597 duk_pop(ctx);
1598 /* get the name of the function called */
1599 rc = duk_get_prop_string(ctx,-1,"fwFunc");
1600 if(rc == 1) fwFunc = duk_to_string(ctx,-1);
1601 duk_pop(ctx);
1602 duk_pop(ctx); //durrent function
1603 nr = 0;
1604 if(!strcasecmp(fwFunc,"getType")){
1605 duk_push_int(ctx,itype);
1606 nr = 1;
1607 }
1608 if(!strcmp(fwFunc,"isReadable")){
1609 int isreadable = TRUE;
1610 if(kind > -1)
1611 isreadable = isreadable && (kind == PKW_inputOutput || kind == PKW_initializeOnly);
1612 if(isreadable) duk_push_true(ctx);
1613 else duk_push_false(ctx);
1614 nr = 1;
1615 }
1616 if(!strcmp(fwFunc,"isWritable")){
1617 int iswritable = TRUE;
1618 if(kind > -1)
1619 iswritable = iswritable && (kind == PKW_inputOutput || kind == PKW_outputOnly);
1620 if(iswritable) duk_push_true(ctx);
1621 else duk_push_false(ctx);
1622 nr = 1;
1623 }
1624 return nr;
1625}
1626int cfunction(duk_context *ctx) {
1627 int rc, nr, itype, nargs, *valueChanged = NULL;
1628 const char *fwFunc = NULL;
1629 union anyVrml* parent = NULL;
1630 //union anyVrml* field = NULL;
1631 FWType fwt;
1632 FWFunctionSpec *fs;
1633
1634 itype = 0;
1635 nargs = duk_get_top(ctx);
1636 //show_stack(ctx,"in cfuction");
1637 duk_push_current_function(ctx);
1638 /* get type of parent object for this property*/
1639 rc = duk_get_prop_string(ctx,-1,"fwItype");
1640 if(rc==1) itype = duk_get_int(ctx,-1);
1641 duk_pop(ctx);
1642 /* get the pointer to the parent object */
1643 rc = duk_get_prop_string(ctx,-1,"fwField");
1644 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1645 duk_pop(ctx);
1646 /* get the pointer to the changed flag */
1647 rc = duk_get_prop_string(ctx,-1,"fwChanged");
1648 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1649 duk_pop(ctx);
1650 /* get the name of the function called */
1651 rc = duk_get_prop_string(ctx,-1,"fwFunc");
1652 if(rc == 1) fwFunc = duk_to_string(ctx,-1);
1653 duk_pop(ctx);
1654 duk_pop(ctx); //durrent function
1655
1656 nr = 0;
1657
1658 fwt = getFWTYPE(itype);
1659 //check functions - if its a function push the type's specfic function
1660 fs = getFWFunc(fwt,fwFunc);
1661 if(fs){
1662 FWval pars;
1663 int argc;
1664 struct FWVAL fwretval;
1665 struct X3D_Node *scriptnode;
1666 void *ec = NULL;
1667 convert_duk_to_fwvals(ctx, nargs, 0, fs->arglist, &pars, &argc);
1668 //the object function call, using engine-agnostic parameters
1669
1670 //>>just SFNode function getNodeName needs to know the script node context (it can't use its own - it may be an IMPORT)
1671 duk_eval_string(ctx,"__script");
1672 scriptnode = (struct X3D_Node*) duk_to_pointer(ctx,-1);
1673 duk_pop(ctx);
1674 if(scriptnode)
1675 ec = (void *)scriptnode->_executionContext;
1676 //<<
1677 nr = fs->call(fwt,ec,parent,argc,pars,&fwretval);
1678 if(nr){
1679 nr = fwval_duk_push(ctx,&fwretval,valueChanged);
1680 if(nr && !strcasecmp(fwFunc,"toString")){
1681 if(fwretval.itype == 'S' && fwretval._string){
1682 //printf("gcing toString string %s\n",fwretval._string);
1683 //free(fwretval._string); //if this bombs take it out and toString strings won't be gcd. There's nothing set up to gc _string in general
1684 }
1685 }
1686 }else{
1687 if(valueChanged) *valueChanged = TRUE;
1688 }
1689 free(pars);
1690 }
1691 return nr;
1692}
1693int cget(duk_context *ctx) {
1694 int rc, nr, itype, kind, *valueChanged = NULL;
1695 //show_stack(ctx,"in cget");
1696 union anyVrml* parent = NULL;
1697 //union anyVrml* field = NULL;
1698
1699 /* get type of parent object for this property*/
1700 itype = -1;
1701 kind = -1;
1702 rc = duk_get_prop_string(ctx,0,"fwItype");
1703 if(rc==1) itype = duk_get_int(ctx,-1);
1704 duk_pop(ctx);
1705 /* get the kind of parent field PKW_inputOutput etc*/
1706 rc = duk_get_prop_string(ctx,0,"fwKind");
1707 if(rc==1) kind = duk_get_int(ctx,-1);
1708 duk_pop(ctx);
1709 /* get the pointer to the parent object */
1710 rc = duk_get_prop_string(ctx,0,"fwField");
1711 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1712 duk_pop(ctx);
1713 /* get the pointer to the changed flag */
1714 rc = duk_get_prop_string(ctx,0,"fwChanged");
1715 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1716 duk_pop(ctx);
1717 //show_stack(ctx,"in cget");
1718
1719 nr = 0;
1720 //printf("indexer is%s\n",duk_type_to_string(duk_get_type(ctx,-2)));
1721 switch(duk_get_type(ctx,-2)){
1722 case DUK_TYPE_NUMBER:{
1723 //int ikey = duk_get_int(ctx,-2);
1724 //printf("key=[%d]",ikey);
1725 }
1726 break;
1727 default: {
1728 const char *key = duk_require_string(ctx,-2);
1729 //printf("key=%s \n",key);
1730 if(!strcmp(key,"fwItype")){
1731 //someone else is asking a proxy for its fwItype (for example LHS = RHSProxy) the LHS Setter may want the RHS's fwItype
1732 duk_push_int(ctx,itype);
1733 nr = 1;
1734 return nr;
1735 }
1736 if(!strcmp(key,"fwGC")){
1737 //someone else is asking a proxy for its fwGC (for example LHS = RHSProxy)
1738 //if there's no fwGC already on it, then the answer is FALSE
1739 duk_push_boolean(ctx,FALSE);
1740 nr = 1;
1741 return nr;
1742 }
1743 if(!strcmp(key,"fwField")){
1744 //someone is asking a proxy for its fwField
1745 duk_push_pointer(ctx,parent);
1746 nr = 1;
1747 return nr;
1748 }
1749 if(!strcasecmp(key,"getType") || !strcmp(key,"isReadable") || !strcmp(key,"isWritable")){
1750 //its a function all auxtypes and fieldtypes share
1751 duk_push_c_function(ctx,ctypefunction,DUK_VARARGS);
1752 duk_push_int(ctx,itype);
1753 duk_put_prop_string(ctx,-2,"fwItype");
1754 duk_push_int(ctx,kind);
1755 duk_put_prop_string(ctx,-2,"fwKind");
1756 duk_push_string(ctx,key);
1757 duk_put_prop_string(ctx,-2,"fwFunc");
1758 nr = 1;
1759 return nr;
1760 }
1761 }
1762 break;
1763 }
1764
1765
1766 if(itype > -1){
1767 //itype is in AUXTYPE_ range
1768 const char *key = NULL;// = duk_require_string(ctx,-2);
1769 FWType fwt = getFWTYPE(itype);
1770 int jndex, found;
1771 char type, readOnly;
1772 found = 0;
1773
1774 //check numeric indexer
1775 if(duk_is_number(ctx,-2)){
1776 //indexer
1777 int index = duk_get_int(ctx,-2);
1778 if(fwt->takesIndexer){
1779 type = fwt->takesIndexer;
1780 readOnly = fwt->indexerReadOnly;
1781 jndex = index;
1782 found = 1;
1783 }else{
1784 //script is attempting to iterate over/get properties by number to get value - good luck
1785 const char *name;
1786 int lastProp;
1787 index = fwiterator_generic(index -1,fwt,parent,&name,&lastProp,&jndex,&type,&readOnly);
1788 if(index > -1) found = 1;
1789 }
1790 }else{
1791 //check properties - if a property, call the type-specific setter
1792 //int lastProp;
1793 key = duk_get_string(ctx,-2);
1794 found = fwhas_generic(fwt,parent,key,&jndex,&type,&readOnly);
1795 if(!found && strcmp(key,"valueOf")){
1796 //annoying valueOf ususally thunks properly to toString, so just show other keys not found
1797 static int once = 0;
1798 if(!once)
1799 ConsoleMessage("type %s has no property or function %s - please check your typing\n",fwt->name,key);
1800 once = 1;
1801 }
1802 }
1803 if(found && type=='f'){
1804 FWFunctionSpec *fw = getFWFunc(fwt,key);
1805 if(fw){
1806 //its a function
1807 duk_push_c_function(ctx,cfunction,DUK_VARARGS);
1808 duk_push_pointer(ctx,parent);
1809 duk_put_prop_string(ctx,-2,"fwField");
1810 duk_push_pointer(ctx,valueChanged);
1811 duk_put_prop_string(ctx,-2,"fwChanged");
1812 duk_push_int(ctx,itype);
1813 duk_put_prop_string(ctx,-2,"fwItype");
1814 duk_push_string(ctx,key);
1815 duk_put_prop_string(ctx,-2,"fwFunc");
1816 nr = 1;
1817 }
1818 }else if(found && fwt->Getter){
1819 struct FWVAL fwretval;
1820 struct X3D_Node *scriptnode;
1821 void *ec = NULL;
1822 //>>just SFNode function getNodeName needs to know the script node context (it can't use its own - it may be an IMPORT)
1823 duk_eval_string(ctx,"__script");
1824 scriptnode = (struct X3D_Node*) duk_to_pointer(ctx,-1);
1825 duk_pop(ctx);
1826 if(scriptnode)
1827 ec = (void *)scriptnode->_executionContext;
1828 //<<
1829
1830 nr = fwt->Getter(fwt,jndex,ec,parent,&fwretval);
1831 if(nr){
1832 nr = fwval_duk_push(ctx,&fwretval,valueChanged);
1833 }
1834 }
1835 }
1836 return nr;
1837}
1838int cset(duk_context *ctx) {
1839 int rc, itype, *valueChanged = NULL;
1840 union anyVrml *parent = NULL;
1841 itype = -1;
1842 /* get type of parent object for this property*/
1843 rc = duk_get_prop_string(ctx,0,"fwItype");
1844 if(rc==1) itype = duk_get_int(ctx,-1);
1845 duk_pop(ctx);
1846 /* get the pointer to the parent object */
1847 rc = duk_get_prop_string(ctx,0,"fwField");
1848 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1849 duk_pop(ctx);
1850 /* get the pointer to the changed flag */
1851 rc = duk_get_prop_string(ctx,0,"fwChanged");
1852 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1853 duk_pop(ctx);
1854
1855
1856 switch(duk_get_type(ctx,-3)){
1857 case DUK_TYPE_NUMBER:{
1858 //int ikey = duk_get_int(ctx,-3);
1859 //printf("key=[%d] ",ikey);
1860 }
1861 break;
1862 default: {
1863 //const char *key = duk_require_string(ctx,-3);
1864 //printf("key=%s ",key);
1865 }
1866 break;
1867 }
1868 switch(duk_get_type(ctx,-2)){
1869 case DUK_TYPE_NUMBER:{
1870 int ival = duk_get_int(ctx,-2);
1871 //printf("val=[%d]\n",ival);
1872 }
1873 break;
1874 case DUK_TYPE_STRING:{
1875 const char *cval = duk_get_string(ctx,-2);
1876 //printf("val=%s\n",cval);
1877 }
1878 break;
1879 default:
1880 //printf("val is object\n");
1881 break;
1882 }
1883
1884
1885 if(itype > -1) {
1886 //itype is in FIELDTYPE_ and AUXTYPE_ range
1887 const char* key;
1888 FWType fwt = getFWTYPE(itype);
1889 int jndex, found;
1890 char type, readOnly;
1891 //check numeric indexer
1892 if(duk_is_number(ctx,-3) && fwt->takesIndexer){
1893 //indexer
1894 jndex = duk_get_int(ctx,-3);
1895 type = fwt->takesIndexer;
1896 readOnly = fwt->indexerReadOnly;
1897 found = 1;
1898 }else{
1899 //check properties - if a property, call the type-specific setter
1900 //int lastProp;
1901 key = duk_get_string(ctx,-3);
1902 found = fwhas_generic(fwt,parent,key,&jndex,&type,&readOnly) && (type != 'f');
1903 }
1904 if(found && (readOnly != 'T') && fwt->Setter){
1905 FWval fwsetval = NULL;
1906 struct ArgListType arglist;
1907 int argc;
1908 arglist.argtypes = &type;
1909 arglist.fillMissingFixedWithZero = 0;
1910 arglist.nfixedArg = 1;
1911 arglist.iVarArgStartsAt = -1;
1912 convert_duk_to_fwvals(ctx, 1, -2, arglist, &fwsetval, &argc);
1913 if(argc == 1){
1914 struct X3D_Node *scriptnode;
1915 void *ec = NULL;
1916 //>>just SFNode function getNodeName needs to know the script node context (it can't use its own - it may be an IMPORT)
1917 duk_eval_string(ctx,"__script");
1918 scriptnode = (struct X3D_Node*) duk_to_pointer(ctx,-1);
1919 duk_pop(ctx);
1920 if(scriptnode)
1921 ec = (void *)scriptnode->_executionContext;
1922 //<<
1923
1924 fwt->Setter(fwt,jndex,ec,parent,fwsetval);
1925 if(valueChanged)
1926 (*valueChanged) = 1;
1927 }
1928 free(fwsetval);
1929 }
1930 }
1931 return 0;
1932}
1933int cdel(duk_context *ctx) {
1934 int rc, itype, *valueChanged;
1935 union anyVrml *parent;
1936
1937 /* get type of parent object for this property*/
1938 rc = duk_get_prop_string(ctx,0,"fwItype");
1939 if(rc==1) itype = duk_get_int(ctx,-1);
1940 duk_pop(ctx);
1941 //if(fwType) printf("fwType in cget=%s\n",fwType);
1942 /* get the pointer to the parent object */
1943 rc = duk_get_prop_string(ctx,0,"fwField");
1944 if(rc == 1) parent = duk_to_pointer(ctx,-1);
1945 duk_pop(ctx);
1946 /* get the pointer to the changed flag */
1947 rc = duk_get_prop_string(ctx,0,"fwChanged");
1948 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
1949 duk_pop(ctx);
1950
1951 show_stack(ctx,"in cdel");
1952 //duk_push_string(ctx, nativeValue);
1953 return 1;
1954}
1955
1956//c-side helper adds the generic handler to global, for use when creating each proxy
1957void addHandler(duk_context *ctx){
1958 int iglobal, ihandler; // , rc;
1959 iglobal = duk_get_top(ctx) -1;
1960
1961 duk_push_object(ctx);
1962 duk_put_prop_string(ctx, iglobal, "handler");
1963
1964 duk_get_prop_string(ctx,iglobal,"handler"); //get handler from global
1965 ihandler = duk_get_top(ctx) -1; //+ve
1966 duk_push_c_function(ctx,chas,2);
1967 duk_put_prop_string(ctx, ihandler, "has");
1968 duk_push_c_function(ctx,cownKeys,1);
1969 duk_put_prop_string(ctx, ihandler, "ownKeys");
1970 duk_push_c_function(ctx,cenumerate,1);
1971 duk_put_prop_string(ctx, ihandler, "enumerate");
1972 duk_push_c_function(ctx,cget,3);
1973 duk_put_prop_string(ctx, ihandler, "get");
1974 duk_push_c_function(ctx,cset,4);
1975 duk_put_prop_string(ctx, ihandler, "set");
1976 duk_push_c_function(ctx,cdel,2);
1977 duk_put_prop_string(ctx, ihandler, "del");
1978 duk_pop(ctx); //pop handler off stack
1979
1980}
1981void addCustomProxyType(duk_context *ctx, int iglobal, const char *typeName)
1982{
1983 int itype;
1984 duk_push_c_function(ctx,cfwconstructor,DUK_VARARGS);
1985 //put fname=SFVec3f on c_function, so in constructor we can tell what we are trying to construct
1986 itype = fwType2itype(typeName);
1987 duk_push_int(ctx,itype);
1988 duk_put_prop_string(ctx,-2,"fwItype");
1989 //put SFVec3f = c_fuction on global
1990 duk_put_prop_string(ctx,iglobal,typeName);
1991}
1992void add_duk_global_property(duk_context *ctx, int itype, const char *fieldname, int *valueChanged, struct X3D_Node *node);
1993
1994
1995/* www.duktape.org javascript engine used here */
1996//A DUK helper function
1997static char *eval_string_defineAccessor = "\
1998function defineAccessor(obj, key, set, get) { \
1999 Object.defineProperty(obj, key, { \
2000 enumerable: true, configurable: true, \
2001 set: set, get: get \
2002 }); \
2003}";
2004
2005
2006
2007/* create the script context for this script. This is called from the thread
2008 that handles script calling in the fwl_RenderSceneUpdateScene */
2009void duk_JSCreateScriptContext(int num) {
2010 int i, iglobal; // , rc;
2011 //jsval rval;
2012 duk_context *ctx; /* these are set here */
2013 struct Shader_Script *script;
2014 struct X3D_Node *scriptnode;
2015 //JSObject *_globalObj; /* these are set here */
2016 //BrowserNative *br; /* these are set here */
2017 //ppJScript p = (ppJScript)gglobal()->JScript.prv;
2018 struct CRscriptStruct *ScriptControl; // = getScriptControl();
2019
2020 ScriptControl = getScriptControlIndex(num);
2021 script = ScriptControl->script;
2022 scriptnode = script->ShaderScriptNode;
2023 //CREATE CONTEXT
2024 ctx = duk_create_heap_default();
2025
2026 //ADD STANDARD JS GLOBAL OBJECT/CLASSES
2027 duk_push_global_object(ctx);
2028 iglobal = duk_get_top(ctx) -1;
2029
2030 //SAVE OUR CONTEXT IN OUR PROGRAM'S SCRIPT NODE FOR LATER RE-USE
2031 ScriptControl->cx = ctx;
2032 //ScriptControl[num].glob = (void *)malloc(sizeof(int));
2033 //*((int *)ScriptControl[num].glob) = iglobal; //we'll be careful not to pop our global for this context (till context cleanup)
2034 ((int *)&ScriptControl->glob)[0] = iglobal; //we'll be careful not to pop our global for this context (till context cleanup)
2035
2036 //ADD HELPER PROPS AND FUNCTIONS
2037 duk_push_pointer(ctx,scriptnode); //I don't think we need to know the script this way, but in the future, you might
2038 duk_put_prop_string(ctx,iglobal,"__script"); //oct 2014 the future arrived. sfnode.getNodeName needs the DEFnames from the broto context, and script seems to know its broto context
2039
2040 duk_push_string(ctx,eval_string_defineAccessor);
2041 duk_eval(ctx);
2042 duk_pop(ctx);
2043
2044 //ADD CUSTOM TYPES - Browser, X3DConstants, web3d field types
2045 addHandler(ctx); //add helper called handler, to global object
2046 //add types that can be newed ie var a = new SFVec3f();
2047 // they will have a non-null constructor function
2048 // generally, it's all our SF and MF field types
2049 for(i=0;i<FWTYPES_COUNT;i++)
2050 if(fwtypesArray[i]->Constructor)
2051 addCustomProxyType(ctx,iglobal,fwtypesArray[i]->name);
2052 //show_stack(ctx,"before adding Browser");
2053 //add static singltons on global object ie global.Browser global.X3DConstants
2054 add_duk_global_property(ctx, AUXTYPE_X3DBrowser, "Browser", NULL, NULL);
2055 add_duk_global_property(ctx, AUXTYPE_X3DConstants,"X3DConstants", NULL, NULL);
2056 //add Global methods and defines for VMRL/X3D (some redirecting to the Browser object ie print = Browser.println)
2057 duk_eval_string(ctx,DefaultScriptMethodsA);
2058 duk_pop(ctx);
2059 duk_eval_string(ctx,DefaultScriptMethodsB);
2060 duk_pop(ctx);
2061
2062 /* send this data over to the routing table functions. */
2063 CRoutes_js_new (num, JAVASCRIPT);
2064
2065 //tests, if something is broken these tests might help
2066 if(1){
2067 void *scriptnode;
2068 struct X3D_Node *snode;
2069 //duk_eval_string(ctx,"print('this.__script='+this.__script);"); //checks the NodeScript availability
2070 //duk_pop(ctx);
2071 duk_eval_string(ctx,"__script");
2072 scriptnode = duk_to_pointer(ctx,-1);
2073 duk_pop(ctx);
2074 snode = (struct X3D_Node *)scriptnode;
2075 //printf("script node = %p",scriptnode);
2076 }
2077 if(0){
2078 duk_eval_string(ctx,"print(Object.keys(Browser));"); //invokes ownKeys
2079 duk_pop(ctx);
2080 duk_eval_string(ctx,"print(Object.getOwnPropertyNames(Browser));"); //invokes ownKeys
2081 duk_pop(ctx);
2082 duk_eval_string(ctx,"for (k in Browser) {print(k);}"); //invokes enumerate
2083 duk_pop(ctx);
2084 duk_eval_string(ctx,"if('println' in Browser) print('have println'); else print('no println');"); //invokes has
2085 duk_pop(ctx);
2086 duk_eval_string(ctx,"print('X3DConstants.outputOnly='); print(X3DConstants.outputOnly);"); //invokes custom iterator in generic has
2087 duk_pop(ctx);
2088 duk_eval_string(ctx,"print(Object.keys(X3DConstants));"); //invokes custom iterator in ownKeys
2089 duk_pop(ctx);
2090 }
2091 if(0){
2092 duk_eval_string(ctx,"Browser.println('hi from brwsr.println');");
2093 duk_pop(ctx);
2094 duk_eval_string(ctx,"Browser.description = 'funny description happened on the way to ..';");
2095 duk_pop(ctx);
2096 duk_eval_string(ctx,"Browser.println(Browser.description);");
2097 duk_pop(ctx);
2098 duk_eval_string(ctx,"print('hi from print');");
2099 duk_pop(ctx);
2100 duk_eval_string(ctx,"print(Browser.version);");
2101 duk_pop(ctx);
2102
2103 }
2104 if(0){
2105 duk_eval_string(ctx,"print('Browser.supportedComponents.length = ');");duk_pop(ctx);
2106 duk_eval_string(ctx,"print(Browser.supportedComponents.length);"); duk_pop(ctx);
2107 duk_eval_string(ctx,"for(var i=0;i<Browser.supportedComponents.length;i++) {print(Browser.supportedComponents[i].name + ' '+Browser.supportedComponents[i].level);}"); duk_pop(ctx);
2108 }
2109 if(0){
2110 duk_eval_string(ctx,"var myvec3 = new SFVec3f(1.0,2.0,3.0);");
2111 duk_pop(ctx);
2112 duk_eval_string(ctx,"print(myvec3.x.toString());");
2113 duk_pop(ctx);
2114 duk_eval_string(ctx,"myvec3.y = 45.0;");
2115 duk_pop(ctx);
2116 duk_eval_string(ctx,"print('sb45='+myvec3.y);");
2117 duk_pop(ctx);
2118 }
2119
2120 return;
2121}
2122
2123
2124
2125/* fwsetterNS, fwgetterNS are for our Script node dynamic fields, or
2126 more precisely, for the javascript property we create on the js>context>global object,
2127 one global>property for each script field, with the name of the script field on the property
2128*/
2129
2130int SFNode_Setter0(FWType fwt, int index, void *ec, void * fwn, FWval fwval, int isCurrentScriptNode);
2131int fwsetterNS(duk_context *ctx) {
2132 /* myfield = new SFVec3f(1,2,3);
2133 * if myfield is a property we set on the global object, and we've assigned this setter to it,
2134 * we'll come in here. We can set the *valueChanged and value on the LHS object, by copying, as per specs
2135 * terminology: LHS: left hand side of equation (ie myfield) RHS: right hand side of equation (ie result of new SFVec3f() )
2136 * if we come in here for AUXTYPES we should not write - AUXTYPE_X3DBrowser, and AUXTYPE_X3DConstants are static singletons
2137 */
2138 int nargs; // , nr;
2139 int rc, itype, *valueChanged;
2140 //union anyVrml *field;
2141 const char *key;
2142 struct X3D_Node* parent = NULL;
2143 nargs = duk_get_top(ctx);
2144
2145 /* retrieve key from nonstandard arg */
2146 //show_stack(ctx,"in fwsetterNS");
2147 // nativeValue = duk_require_string(ctx, 0);
2148 //implicit key by setter C function //char *key = duk_require_string(ctx, 1);
2149 key = duk_require_string(ctx,1); //"myprop";
2150 //printf("\nfwsetterNS, key=%s value=%s\n",key,nativeValue);
2151
2152 itype = -1;
2153 /* get details of LHS object */
2154 /* retrieve field pointer from Cfunc */
2155 duk_push_current_function(ctx);
2156 /* get type of parent object for this property*/
2157 rc = duk_get_prop_string(ctx,-1,"fwItype");
2158 if(rc==1) itype = duk_get_int(ctx,-1);
2159 duk_pop(ctx);
2160 if(itype > -1 && itype < AUXTYPE_X3DConstants){
2161 //our script fields
2162 rc = duk_get_prop_string(ctx,-1,"fwNode");
2163 if(rc==1) parent = duk_to_pointer(ctx,-1);
2164 duk_pop(ctx);
2165 /* get the pointer to the changed flag */
2166 rc = duk_get_prop_string(ctx,-1,"fwChanged");
2167 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
2168 duk_pop(ctx);
2169 }
2170 duk_pop(ctx); //pop current function
2171
2172 if(itype > -1 && itype < AUXTYPE_X3DConstants){
2173 //code borrowed from cget and modified to not set setEventIn on self (auto-eventing this script)
2174 //const char* key;
2175 FWType fwt = getFWTYPE(FIELDTYPE_SFNode);
2176 int jndex, found;
2177 char type, readOnly;
2178 //check properties - if a property, call the type-specific setter
2179 //int lastProp;
2180 union anyVrml any;
2181 any.sfnode = parent;
2182
2183 found = fwhas_generic(fwt,&any,key,&jndex,&type,&readOnly) && (type != 'f');
2184 if(found){
2185 FWval fwsetval = NULL;
2186 struct ArgListType arglist;
2187 int argc;
2188 arglist.argtypes = &type;
2189 arglist.fillMissingFixedWithZero = 0;
2190 arglist.nfixedArg = 1;
2191 arglist.iVarArgStartsAt = -1;
2192 convert_duk_to_fwvals(ctx, 1, -2, arglist, &fwsetval, &argc);
2193 if(argc == 1){
2194 struct X3D_Node *scriptnode;
2195 void *ec = NULL;
2196 //>>just SFNode function getNodeName needs to know the script node context (it can't use its own - it may be an IMPORT)
2197 duk_eval_string(ctx,"__script");
2198 scriptnode = (struct X3D_Node*) duk_to_pointer(ctx,-1);
2199 duk_pop(ctx);
2200 if(scriptnode)
2201 ec = (void *)scriptnode->_executionContext;
2202 //<<
2203
2204 SFNode_Setter0(fwt,jndex,ec,&any,fwsetval,TRUE);
2205 //if(valueChanged)
2206 // (*valueChanged) = 1; //DONE IN SFNODE_SETTER0
2207 }
2208 free(fwsetval);
2209 }
2210 }
2211 return 0;
2212}
2213
2214void push_typed_proxy_fwgetter(duk_context *ctx, int itype, int mode, const char* fieldname, void *fwpointer, int* valueChanged)
2215{
2216 /* called by fwgetter (for referenced script->fields)
2217 1. push_object (fresh object)
2218 2. fwpointer: reference to script->field[i]->anyvrml
2219 */
2220 //int rc;
2221 proxy_entry *pe = NULL;
2222 if(itype == FIELDTYPE_SFNode){
2223 struct X3D_Node* node = *(struct X3D_Node**)fwpointer;
2224 printf("pushtyped2 nodetype %d\n",node->_nodeType);
2225 pe = lookup_ctx_proxycache_entry_by_nodeptr(ctx, node);
2226 }
2227 if(pe){
2228 duk_push_heapptr(ctx,pe->jsproxy);
2229 }else{
2230
2231 duk_eval_string(ctx,"Proxy");
2232 duk_push_object(ctx);
2233 duk_push_pointer(ctx,fwpointer);
2234 duk_put_prop_string(ctx,-2,"fwField");
2235 duk_push_pointer(ctx,valueChanged);
2236 duk_put_prop_string(ctx,-2,"fwChanged");
2237 duk_push_int(ctx,itype);
2238 duk_put_prop_string(ctx,-2,"fwItype");
2239 duk_eval_string(ctx,"handler");
2240 duk_new(ctx,2); /* [ global Proxy target handler ] -> [ global result ] */
2241
2242 //2017 >
2243 if(doingFinalizer) { // && idogc){
2244 //push_typed_proxy2 _refers_ to script->field[i]->anyVrml (its caller fwgetter doesn't malloc) and should not GC its pointer
2245 //
2246 //Duktape.fin(a, function (x) {
2247 // try {
2248 // print('finalizer, foo ->', x.foo);
2249 // } catch (e) {
2250 // print('WARNING: finalizer failed (ignoring): ' + e);
2251 // }
2252 // });
2253 if(itype == FIELDTYPE_SFNode){
2254 struct X3D_Node* node = *(struct X3D_Node**)fwpointer;
2255 void *jsproxy = duk_get_heapptr(ctx, -1);
2256 add_ctx_proxycache_entry(ctx, node, jsproxy);
2257 }
2258 duk_eval_string(ctx,"Duktape.fin");
2259 duk_dup(ctx, -2); //copy the proxy object
2260 duk_push_c_function(ctx,cfinalizer,1);
2261 duk_pcall(ctx,2);
2262 duk_pop(ctx); //pop Duktape.fin result
2263 }
2264 }
2265
2266}
2267
2268
2269int push_duk_fieldvalue(duk_context *ctx, int itype, int mode, const char* fieldname, union anyVrml *field, int *valueChanged)
2270{
2271 /*we have the field, and even the key name.
2272 So we should be able to decide how to package the outgoing value type:
2273 according to specs:
2274 - return ecma primitive value type for SFBool, SFInt32, SFFloat, SFDouble, SFTime, SFString
2275 - return our field-type-specific object/proxy-wrapper, pointing to our global.field, for the others.
2276 */
2277 int nr;
2278 nr = 0;
2279 if(field){
2280 //int isOK = FALSE;
2281 nr = 1;
2282 switch(itype){
2283 case FIELDTYPE_SFBool:
2284 duk_push_boolean(ctx,field->sfbool); break;
2285 case FIELDTYPE_SFFloat:
2286 duk_push_number(ctx,field->sffloat); break;
2287 case FIELDTYPE_SFTime:
2288 duk_push_number(ctx,field->sftime); break;
2289 case FIELDTYPE_SFDouble:
2290 duk_push_number(ctx,field->sfdouble); break;
2291 case FIELDTYPE_SFInt32:
2292 duk_push_int(ctx,field->sfint32); break;
2293 case FIELDTYPE_SFString:
2294 duk_push_string(ctx,field->sfstring->strptr); break;
2295 default:
2296 //we need an object with our c handlers and pointer to our script->field[i]
2297 if(0){
2298 if(itype == FIELDTYPE_SFNode){
2299 //test to compare anyVrml.SFNode with X3D_Node*
2300 //typedef struct X3D_Node* vrmlNodeT;
2301
2302 struct X3D_Node *anode;
2303 //anode = (struct X3D_Node *)(field); //WRONG (but how? H0: struct/union word alignment WRONG H1: off by a pointer * or & RIGHT)
2304 //anode = (struct X3D_Node *)&(field); //WRONG
2305 //anode = (struct X3D_Node *)&(*field); //WRONG
2306 //anode = (struct X3D_Node *)(*field); //I think this is numerically RIGHT, but syntactically awkward/WRONG for compilers
2307 (memcpy(&anode,field,sizeof(void *))); //RIGHT, works, same as above line: the contents of struct anyVrml is a pointer
2308 printf("anode._nodeType=%d ",anode->_nodeType);
2309 printf("anyvrml.sfnode._nodetype=%d\n",field->sfnode->_nodeType);
2310 anode = field->sfnode; //RIGHT
2311 printf("anode = anyvrml.sfnode ._nodetype=%d\n",anode->_nodeType);
2312 printf("same?\n");
2313 }
2314 }
2315 push_typed_proxy_fwgetter(ctx, itype, mode, fieldname, field, valueChanged);
2316 break;
2317 }
2318 }
2319 //show_stack(ctx,"in fwgetterNS at end");
2320 return nr;
2321}
2322
2323
2324int fwgetter0(duk_context *ctx,void *parent,int itype, const char *key, int *valueChanged){
2325 //uses fwtype SFNode's getter
2326 FWType fwt = getFWTYPE(itype);
2327 int jndex, found, nr;
2328 char type, readOnly;
2329 nr = 0;
2330 //check properties - if a property, call the type-specific setter
2331 found = fwhas_generic(fwt,parent,key,&jndex,&type,&readOnly); //SFNode_Iterator
2332 if(found && fwt->Getter){
2333 struct FWVAL fwretval;
2334 struct X3D_Node *scriptnode;
2335 void *ec = NULL;
2336 //>>just SFNode function getNodeName needs to know the script node context (it can't use its own - it may be an IMPORT)
2337 duk_eval_string(ctx,"__script");
2338 scriptnode = (struct X3D_Node*) duk_to_pointer(ctx,-1);
2339 duk_pop(ctx);
2340 if(scriptnode)
2341 ec = (void *)scriptnode->_executionContext;
2342 //<<
2343
2344 nr = fwt->Getter(fwt,jndex,ec,parent,&fwretval); //SFNode_Getter
2345 if(nr){
2346 nr = fwval_duk_push(ctx,&fwretval,valueChanged);
2347 }
2348 }
2349 return nr;
2350}
2351int fwgetterNS(duk_context *ctx) {
2352 /* when we initializeContext we assign 2 kinds of properties to the global object in the context:
2353 1. FIELDTYPES: our Script Node's dynamic (scene-authored) fields (or more precisely, their js proxys), with features:
2354 - has valueChanged, getName, getMode (getType is part of all FIELDTYPEs and AUXTYPEs)
2355 - reference when getting if non-primitive, deep copy when setting
2356 2. AUXTYPES: a) Browser (AUXTYPE_X3DBrowser) b) X3DConstants (AUXTYPE_X3DConstants)
2357 - reference when getting, never set (these two are static singletons)
2358 */
2359 int nargs, nr;
2360 int rc, itype, *valueChanged = NULL;
2361 //const char *fwName = NULL;
2362 const char *fieldname;
2363 struct X3D_Node *thisScriptNode = NULL;
2364 //union anyVrml *field;
2365
2366 nargs = duk_get_top(ctx);
2367 itype = 0;
2368 /* retrieve key from nonstandard arg */
2369 //show_stack(ctx,"in fwgetterNS at start");
2370 fieldname = duk_require_string(ctx,0);
2371 //printf("\nfwgetterNS key=%s\n",fieldname);
2372
2373 /* retrieve field pointer from Cfunc */
2374 duk_push_current_function(ctx);
2375 /* get type of parent object for this property*/
2376 rc = duk_get_prop_string(ctx,-1,"fwItype");
2377 if(rc==1) itype = duk_get_int(ctx,-1);
2378 duk_pop(ctx);
2379 if(itype < AUXTYPE_X3DConstants){
2380 //our script fields
2381 rc = duk_get_prop_string(ctx,-1,"fwNode");
2382 if(rc==1) thisScriptNode = duk_to_pointer(ctx,-1);
2383 duk_pop(ctx);
2384 /* get the pointer to the changed flag */
2385 rc = duk_get_prop_string(ctx,-1,"fwChanged");
2386 if(rc == 1) valueChanged = duk_to_pointer(ctx,-1);
2387 duk_pop(ctx);
2388 }
2389 duk_pop(ctx); //pop current function
2390
2391
2392 nr = 0;
2393 if(itype < AUXTYPE_X3DConstants){
2394 //our script fields
2395 union anyVrml any;
2396 any.sfnode = thisScriptNode;
2397 nr = fwgetter0(ctx,&any,FIELDTYPE_SFNode,fieldname,valueChanged);
2398 }else{
2399 //X3DBrowser, X3DConstants
2400 push_typed_proxy_fwgetter(ctx, itype, PKW_initializeOnly, fieldname, NULL, NULL);
2401 nr = 1;
2402 }
2403 return nr;
2404}
2405
2406void add_duk_global_property(duk_context *ctx, int itype, const char *fieldname, int *valueChanged, struct X3D_Node *node ){
2407 //int rc;
2408 //char *str;
2409
2410 duk_eval_string(ctx, "defineAccessor"); //defineAccessor(obj,propName,setter,getter)
2411 /* push object */
2412 duk_eval_string(ctx,"this"); //global object
2413 /* push key */
2414 duk_push_string(ctx,fieldname); //"myScriptFieldName"
2415 /* push setter */
2416 duk_push_c_function(ctx,fwsetterNS,2); //1 extra parameter is nonstandard (NS) key
2417 if(itype < AUXTYPE_X3DConstants){
2418 duk_push_pointer(ctx,valueChanged);
2419 duk_put_prop_string(ctx,-2,"fwChanged");
2420 duk_push_pointer(ctx,node);
2421 duk_put_prop_string(ctx,-2,"fwNode");
2422 }
2423 duk_push_int(ctx,itype);
2424 duk_put_prop_string(ctx,-2,"fwItype");
2425 /* push getter */
2426 duk_push_c_function(ctx,fwgetterNS,1); //0 extra parameter is nonstandard (NS) key
2427 if(itype < AUXTYPE_X3DConstants){
2428 duk_push_pointer(ctx,node);
2429 duk_put_prop_string(ctx,-2,"fwNode");
2430 duk_push_pointer(ctx,valueChanged);
2431 duk_put_prop_string(ctx,-2,"fwChanged");
2432 }
2433 duk_push_int(ctx,itype);
2434 duk_put_prop_string(ctx,-2,"fwItype");
2435
2436 duk_call(ctx, 4);
2437 duk_pop(ctx);
2438}
2439
2440void InitScriptField2(struct CRscriptStruct *scriptcontrol, int itype, int kind, const char* fieldname, int *valueChanged, struct X3D_Node* parent)
2441{
2442 /* Creates a javascript-context twin of a Script node for fields of type:
2443 * field/initializeOnly, eventOut/outputOnly, and the field/eventOut part of exposedField/inputOutput
2444 * (not for eventIn/inputOnly, which linked elsewhere to scene author's javascript functions)
2445 * puts the twin as a property on the context's global object
2446 * should make the property 'strict' meaning the property can't be deleted by the script during execution
2447 * but get/set should work normally on the property
2448 * a set should cause a valueChanged flag to be set somewhere, so gatherScriptEventOuts
2449 * can route from eventOut/outputOnly or the eventOut part of exposedField/inputOutput
2450 * InitScriptField2 version: instead of jsNative, hook back into Script_Node->fields[i] for get/set storage
2451 */
2452 duk_context *ctx;
2453 int haveFunc;
2454 char strline[256];
2455
2456 //int iglobal;
2457 //printf("in InitScriptField\n");
2458
2459 // create twin property
2460 ctx = scriptcontrol->cx;
2461 //iglobal = *(int*)scriptcontrol->glob;
2462
2463 //any inputOnly or inputOutput eventIn scripts we need to rename to set_?
2464 //if(kind == PKW_inputOnly ||
2465 if( kind == PKW_inputOutput){
2466
2467 // uses conditional rename_function - only renames if object exists and its typeof function
2468 sprintf(strline,"_rename_function(this,\"%s\",\"set_%s\");",fieldname,fieldname);
2469 //printf("%s\n",strline);
2470 duk_push_string(ctx,strline);
2471 if(duk_peval(ctx) != 0) {
2472 printf("Script error: %s\n", duk_safe_to_string(ctx, -1));
2473 printf("rename didn't work\n");
2474 }
2475 duk_pop(ctx);
2476
2477
2478 }
2479 add_duk_global_property(ctx,itype,fieldname, valueChanged,parent);
2480
2481 return;
2482}
2483
2484void duk_JSInitializeScriptAndFields (int num) {
2485 /* 1. creates javascript-context twins of Script node dynamic/authored fields
2486 2. runs the script as written by the scene author, which has the effect of
2487 declaring all the author's functions (and checking author's syntax)
2488 */
2489 struct Shader_Script *script;
2490 struct ScriptFieldDecl *field;
2491 int i,nfields, kind, itype;
2492 const char *fieldname;
2493 struct CRscriptStruct *scriptcontrol; //*ScriptControlArray,
2494 //ScriptControlArray = getScriptControl();
2495 scriptcontrol = getScriptControlIndex(num); //&ScriptControlArray[num];
2496
2497 //run user's code first to set their functions
2498 if(1) if (!jsActualrunScript(num, scriptcontrol->scriptText)) {
2499 ConsoleMessage ("JSInitializeScriptAndFields, script failure\n");
2500 scriptcontrol->scriptOK = FALSE;
2501 scriptcontrol->_initialized = TRUE;
2502 return;
2503 }
2504
2505 /* run through fields in order of entry in the X3D file */
2506 // and if a fieldname == function name, change function name to set_
2507 script = scriptcontrol->script;
2508 //printf("adding fields from script %p\n",script);
2509 nfields = Shader_Script_getScriptFieldCount(script);
2510 for(i=0;i<nfields;i++){
2511 field = Shader_Script_getScriptField(script,i);
2512 fieldname = ScriptFieldDecl_getName(field);
2513 kind = ScriptFieldDecl_getMode(field);
2514 itype = ScriptFieldDecl_getType(field);
2515 if (kind != PKW_inputOnly) { //we'll hook input events to the author's functions elsewhere
2516 //everything else -fields, eventOuts- needs a strict property twin created on the global object
2517 field->valueChanged = 0;
2518 InitScriptField2(scriptcontrol, itype, kind, fieldname, &field->valueChanged, script->ShaderScriptNode);
2519 }
2520 }
2521
2522 if(0) if (!jsActualrunScript(num, scriptcontrol->scriptText)) {
2523 ConsoleMessage ("JSInitializeScriptAndFields, script failure\n");
2524 scriptcontrol->scriptOK = FALSE;
2525 scriptcontrol->_initialized = TRUE;
2526 return;
2527 }
2528 FREE_IF_NZ(scriptcontrol->scriptText);
2529 scriptcontrol->_initialized = TRUE;
2530 scriptcontrol->scriptOK = TRUE;
2531
2532 return;
2533}
2534
2535int duk_jsActualrunScript(int num, char *script){
2536 int len, rc, iret;
2537 duk_context *ctx;
2538 int iglobal;
2539 struct CRscriptStruct *ScriptControl; // = getScriptControl();
2540 //printf("in jsActualrunScript\n");
2541
2542 ScriptControl = getScriptControlIndex(num);
2543 /* get context and global object for this script */
2544 ctx = (duk_context *)ScriptControl->cx;
2545 //iglobal = *((int *)ScriptControl[num].glob);
2546 iglobal = ((int *)&ScriptControl->glob)[0];
2547
2548 //CLEANUP_JAVASCRIPT(_context)
2549
2550 len = (int) strlen(script);
2551 iret = TRUE;
2552 if(0){
2553 rc=0;
2554 //this will do a popup abort, with no diagnostic message
2555 duk_eval_string(ctx, script);
2556 if(rc<0){
2557 printf ("ActualrunScript - JS_EvaluateScript failed for %s", script);
2558 printf ("\n");
2559 ConsoleMessage ("ActualrunScript - JS_EvaluateScript failed for %s", script);
2560 iret = FALSE;
2561 }
2562 duk_pop(ctx); //pop result which we don't use
2563 }else{
2564 //this shows the diagnostic message, and allows the program to continue running with the script not run
2565 duk_push_string(ctx, script);
2566 if (duk_peval(ctx) != 0) {
2567 ConsoleMessage("eval failed: %s\n", duk_safe_to_string(ctx, -1));
2568 iret = FALSE;
2569 } else if(0) {
2570 printf("result is: %s\n", duk_safe_to_string(ctx, -1));
2571 }
2572 duk_pop(ctx); //pop result which we don't use
2573 }
2574
2575
2576 return iret;
2577}
2578void duk_SaveScriptField (int num, indexT kind, indexT type, const char* field, union anyVrml value){
2579 return;
2580}
2581static int duk_once = 0;
2582void duk_process_eventsProcessed(){
2583 duk_context *ctx;
2584 int rc, counter;
2585 struct CRscriptStruct *scriptcontrol;
2586 ttglobal tg;
2587 ppJScript_duk p;
2588
2589 //if(!duk_once) printf("in process_eventsProcessed\n");
2590 //call function eventsProcessed () {
2591
2592 duk_once++;
2593
2594 tg = gglobal();
2595 p = (ppJScript_duk)tg->JScript_duk.prv;
2596 for (counter = 0; counter <= tg->CRoutes.max_script_found_and_initialized; counter++) {
2597 scriptcontrol = getScriptControlIndex(counter);
2598 if(scriptcontrol){
2599 //if (scriptcontrol->eventsProcessed == NULL) {
2600 // //compile function - duktape doesn't have this
2601 // scriptcontrol->eventsProcessed = ???
2602 //}
2603 ctx = scriptcontrol->cx;
2604 if(scriptcontrol->thisScriptType != NOSCRIPT && ctx){
2605 duk_eval_string(ctx,"eventsProcessed"); //gets the evenin function on the stack
2606 //push double TickTime(); as arg
2607 duk_push_number(ctx,TickTime());
2608 rc = duk_pcall(ctx, 1);
2609 if (rc != DUK_EXEC_SUCCESS) {
2610 printf("error: '%s' happened in js function %s called from process_eventsProcessed\n", duk_to_string(ctx, -1),"eventsProcessed");
2611 }
2612 duk_pop(ctx); //pop undefined that results from void myfunc(){}
2613 }
2614 }
2615 }
2616
2617 return;
2618}
2619void duk_js_cleanup_script_context(int counter){
2620 //printf("in js_cleanup_script_context\n");
2621 return;
2622}
2623void duk_js_setField_javascriptEventOut_B(union anyVrml* any, int fieldType, unsigned len, int extraData, int actualscript){
2624 //I think in here there is nothing to do for brotos, because the job of _B was to copy values out of javascript and
2625 //into script fields, and the _B broto approach to routing would then do routing from the script fields.
2626 //here in the duk / proxy method, we are already doing the setting of script fields directly.
2627 //printf("in js_setField_javascriptEventOut_B\n");
2628 return;
2629}
2630
2631void duk_setField_javascriptEventOut(struct X3D_Node *tn,unsigned int tptr, int fieldType, unsigned len, int extraData) {
2632 //this proxy method already writes to the script field, so there's nothing to update in javascript
2633 //- can just copy anyVrml from script field to endpoint on Route
2634 // (Brotos don't come in this function)
2635 char *memptr;
2636 char *fromptr;
2637 //int datasize;
2638 ttglobal tg = gglobal();
2639
2640 /* set up a pointer to where to put this stuff */
2641 memptr = offsetPointer_deref(char *, tn, tptr);
2642 //the from -our current script field value- is coming in through JSglobal_return_val
2643 fromptr = tg->JScript_duk.JSglobal_return_val;
2644
2645 medium_copy_field0(fieldType,fromptr,memptr); //will copy p data in MF
2646 return;
2647}
2648void duk_js_setField_javascriptEventOut(struct X3D_Node *tn,unsigned int tptr, int fieldType, unsigned len, int extraData, int actualscript) {
2649 struct CRscriptStruct *scriptcontrol;
2650
2651 scriptcontrol = getScriptControlIndex(actualscript);
2652 duk_setField_javascriptEventOut(tn,tptr,fieldType, len, extraData);
2653}
2654
2655
2656
2657
2658void duk_set_one_ECMAtype (int tonode, int toname, int dataType, void *Data, int datalen) {
2659 char scriptline[100];
2660 //FWVAL newval;
2661 duk_context *ctx;
2662 int obj, rc;
2663 struct CRscriptStruct *ScriptControl; // = getScriptControl();
2664 struct CRjsnameStruct *JSparamnames = getJSparamnames();
2665
2666 //printf("in set_one_ECMAtype\n");
2667
2668 #ifdef SETFIELDVERBOSE
2669 printf ("set_one_ECMAtype, to %d namepointer %d, fieldname %s, datatype %d length %d\n",
2670 tonode,toname,JSparamnames[toname].name,dataType,datalen);
2671 #endif
2672
2673 /* get context and global object for this script */
2674 ScriptControl = getScriptControlIndex(tonode);
2675 ctx = (duk_context *)ScriptControl->cx;
2676 //ctx = (duk_context *)ScriptControl[tonode].cx;
2677 //obj = *(int*)ScriptControl[tonode].glob; //don't need
2678 //obj = ((int*)&ScriptControl[tonode].glob)[0]; //don't need
2679 obj = ((int*)&ScriptControl->glob)[0]; //don't need
2680
2681
2682 //get function by name
2683 scriptline[0] = 0;
2684 if(JSparamnames[toname].kind == PKW_inputOutput)
2685 strcat(scriptline,"set_");
2686 strcat(scriptline,JSparamnames[toname].name);
2687
2688 duk_push_string(ctx,scriptline);
2689 if(duk_peval(ctx) != 0){
2690 printf("Script error: %s\n", duk_safe_to_string(ctx, -1));
2691 printf("ouch - no function named %s\n",scriptline);
2692 duk_pop(ctx);
2693 return;
2694 }
2695 //duk_eval_string(ctx,scriptline); //JSparamnames[toname].name); //gets the evenin function on the stack
2696
2697 //push ecma value as arg
2698 {
2699 int rc;
2700 struct FWVAL fwval;
2701 fwval._web3dval.native = Data;
2702 fwval._web3dval.fieldType = dataType;
2703 fwval._web3dval.gc = 0;
2704 fwval.itype = 'W';
2705 rc = fwval_duk_push(ctx, &fwval, NULL);
2706 //if(rc == 1) OK
2707 }
2708 //push double TickTime(); as arg
2709 duk_push_number(ctx,TickTime());
2710 //run function
2711 rc = duk_pcall(ctx, 2); /* [ ... func 2 3 ] -> [ 5 ] */
2712 if (rc != DUK_EXEC_SUCCESS) {
2713 printf("Script error: %s\n", duk_safe_to_string(ctx, -1));
2714 printf("error: '%s' happened in js function %s called from set_one_ECMAType\n", duk_to_string(ctx, -1),JSparamnames[toname].name);
2715 }
2716
2717 duk_pop(ctx); //pop undefined that results from void myfunc(){}
2718 //printf("end ecma\n");
2719}
2720
2721
2722
2723/* setScriptECMAtype called by getField_ToJavascript for
2724 case FIELDTYPE_SFBool:
2725 case FIELDTYPE_SFFloat:
2726 case FIELDTYPE_SFTime:
2727 case FIELDTYPE_SFDouble:
2728 case FIELDTYPE_SFInt32:
2729 case FIELDTYPE_SFString:
2730*/
2731
2732void duk_setScriptECMAtype (int num) {
2733 void *fn;
2734 int tptr;
2735 int len;
2736 int to_counter;
2737 CRnodeStruct *to_ptr = NULL;
2738 struct CRStruct *CRoutes = getCRoutes();
2739 struct CRjsnameStruct *JSparamnames = getJSparamnames();
2740 //printf("in setScriptECMAtype\n");
2741 fn = offsetPointer_deref(void *, CRoutes[num].routeFromNode, CRoutes[num].fnptr);
2742 len = CRoutes[num].len;
2743
2744 for (to_counter = 0; to_counter < CRoutes[num].tonode_count; to_counter++) {
2745 struct Shader_Script *myObj;
2746
2747 to_ptr = &(CRoutes[num].tonodes[to_counter]);
2748 myObj = X3D_SCRIPT(to_ptr->routeToNode)->__scriptObj;
2749 /* printf ("setScriptECMAtype, myScriptNumber is %d\n",myObj->num); */
2750 tptr = to_ptr->foffset;
2751 set_one_ECMAtype (myObj->num, tptr, JSparamnames[tptr].type, fn,len);
2752 }
2753}
2754
2755void duk_set_one_MultiElementType (int tonode, int tnfield, void *Data, int dataLen){
2756 //tonode - script array num
2757 //tnfield - integer index into jsparamname[] array
2758 //void* Data - pointer to anyVrml of the from node
2759 //datalen - size of anyVrml to memcpy
2760 //FWVAL newval;
2761 duk_context *ctx;
2762 int obj, rc;
2763 int itype;
2764 void *datacopy;
2765 int isEventin;
2766 struct CRscriptStruct *ScriptControl; // = getScriptControl();
2767 struct CRjsnameStruct *JSparamnames = getJSparamnames();
2768
2769 ScriptControl = getScriptControlIndex(tonode);
2770 //ctx = (duk_context *)ScriptControl[tonode].cx;
2771 ctx = (duk_context *)ScriptControl->cx;
2772 //obj = *(int*)ScriptControl[tonode].glob;
2773 //obj = ((int*)&ScriptControl[tonode].glob)[0];
2774 obj = ((int*)&ScriptControl->glob)[0];
2775
2776 //printf("in set_one_MultiElementType\n");
2777 //get function by name
2778 //show_stack(ctx,"before evale field name");
2779 {
2780 char scriptline[100];
2781 scriptline[0] = 0;
2782 if(JSparamnames[tnfield].kind == PKW_inputOutput)
2783 strcat(scriptline,"set_");
2784 strcat(scriptline,JSparamnames[tnfield].name);
2785
2786 duk_push_string(ctx,scriptline);
2787 //duk_eval_string(ctx,scriptline); //JSparamnames[tnfield].name); //gets the evenin function on the stack
2788 if(duk_peval(ctx) != 0){
2789 ConsoleMessage("couldn't find eventin function %s\n",scriptline); //JSparamnames[tnfield].name);
2790 duk_pop(ctx);
2791 return;
2792 }
2793 }
2794 isEventin = duk_is_ecmascript_function(ctx, -1);
2795 if(isEventin){
2796 //you might not have an eventin, especially if it was an inputOutput field
2797 // you may just want to route to/from the field value
2798 itype = JSparamnames[tnfield].type;
2799 //medium copy
2800 datacopy = NULL;
2801 medium_copy_field(itype,Data,&datacopy);
2802 push_typed_proxy2(ctx,itype,PKW_inputOutput,datacopy,NULL,'T');
2803 duk_push_number(ctx,TickTime());
2804 //duk_call(ctx,2);
2805 rc = duk_pcall(ctx, 2); /* [ ... func 2 3 ] -> [ 5 ] */
2806 if (rc != DUK_EXEC_SUCCESS) {
2807 printf("error: '%s' happened in js function %s called from set_one_Multi_ElementType\n", duk_to_string(ctx, -1),JSparamnames[tnfield].name);
2808 }
2809 //show_stack(ctx,"after calling isOver");
2810 }
2811 duk_pop(ctx); //pop undefined that results from void myfunc(){}
2812 //show_stack(ctx,"before return");
2813 return;
2814}
2815void duk_set_one_MFElementType(int tonode, int toname, int dataType, void *Data, int datalen){
2816 //tonode - script array num
2817 //tnfield - integer index into jsparamname[] array
2818 //void* Data - MF.p
2819 //datalen - MF.n
2820 //FWVAL newval;
2821 duk_context *ctx;
2822 int obj;
2823 int itype, isEventin;
2824 union anyVrml *any;
2825 void *datacopy = NULL;
2826 //char *source = (char *)Data - sizeof(int); //backup so we get the whole MF including .n
2827 struct Multi_Any maData;
2828 char *source;
2829 struct CRscriptStruct *ScriptControl; // = getScriptControl();
2830 struct CRjsnameStruct *JSparamnames = getJSparamnames();
2831
2832 ScriptControl = getScriptControlIndex(tonode);
2833 //ctx = (duk_context *)ScriptControl[tonode].cx;
2834 ctx = (duk_context *)ScriptControl->cx;
2835 //obj = *(int*)ScriptControl[tonode].glob;
2836 //obj = ((int*)&ScriptControl[tonode].glob)[0];
2837 obj = ((int*)&ScriptControl->glob)[0];
2838
2839 //printf("in set_one_MFElementType\n");
2840 //get function by name
2841 {
2842 char scriptline[100];
2843 scriptline[0] = 0;
2844 if(JSparamnames[toname].kind == PKW_inputOutput)
2845 strcat(scriptline,"set_");
2846 //sprintf(scriptline,"set_%s",JSparamnames[toname].name);
2847 strcat(scriptline,JSparamnames[toname].name);
2848 duk_push_string(ctx,scriptline);
2849 //duk_eval_string(ctx,scriptline); //JSparamnames[tnfield].name); //gets the evenin function on the stack
2850 if(duk_peval(ctx) != 0){
2851 ConsoleMessage("couldn't find eventin function %s\n",scriptline); //JSparamnames[toname].name);
2852 duk_pop(ctx);
2853 return;
2854 }
2855 }
2856 isEventin = duk_is_ecmascript_function(ctx, -1);
2857 if(isEventin){
2858 itype = dataType; //JSparamnames[toname].type;
2859 //medium copy
2860 maData.n = datalen;
2861 maData.p = Data;
2862 source = (char *)&maData;
2863 any = (void*)source;
2864
2865 medium_copy_field(itype,source,&datacopy);
2866 any = datacopy;
2867 push_typed_proxy2(ctx,itype,PKW_inputOutput,datacopy,NULL,'T');
2868 duk_push_number(ctx,TickTime());
2869 duk_call(ctx,2);
2870 }
2871 //show_stack(ctx,"after calling isOver");
2872 duk_pop(ctx); //pop undefined that results from void myfunc(){}
2873 return;
2874}
2875int duk_jsIsRunning(){
2876 //printf("in jsIsRunning\n");
2877 return 1;
2878}
2879void duk_JSDeleteScriptContext(int num){
2880 struct CRscriptStruct *ScriptControl;
2881 //printf("in JSDeleteScriptContext\n");
2882 ScriptControl = getScriptControlIndex(num);
2883 duk_destroy_heap(ScriptControl->cx);
2884 return;
2885}
2886void duk_jsShutdown(){
2887 //printf("in jsShutdown\n");
2888 return;
2889}
2890void duk_jsClearScriptControlEntries(int num){
2891 //printf("in jsClearScriptControlEntries\n");
2892 return;
2893}
2894/* run the script from within Javascript */
2895/*
2896int jsrrunScript(duk_context *ctx, char *script, FWval retval) {
2897 double val;
2898 int ival, itype, isOK;
2899 const char *cval;
2900 duk_eval_string(ctx,script);
2901 int RHS_duk_type = duk_get_type(ctx, -1);
2902 isOK = FALSE;
2903 switch(RHS_duk_type){
2904 case DUK_TYPE_NUMBER:
2905 retval->_numeric = duk_require_number(ctx,-1);
2906 retval->itype = 'D';
2907 isOK = TRUE;
2908 break;
2909 case DUK_TYPE_BOOLEAN:
2910 retval->_boolean = duk_require_boolean(ctx,-1);
2911 retval->itype = 'B';
2912 isOK = TRUE;
2913 break;
2914 case DUK_TYPE_STRING:
2915 retval->_string = duk_require_string(ctx,-1);
2916 retval->itype = 'S';
2917 isOK = TRUE;
2918 break;
2919 case DUK_TYPE_OBJECT:
2920 {
2921 int rc, itypeRHS = -1;
2922 union anyVrml *fieldRHS = NULL;
2923 rc = duk_get_prop_string(ctx,-1,"fwItype");
2924 if(rc == 1){
2925 //printf(duk_type_to_string(duk_get_type(ctx, -1)));
2926 itypeRHS = duk_to_int(ctx,-1);
2927 }
2928 duk_pop(ctx);
2929 rc = duk_get_prop_string(ctx,-1,"fwField");
2930 if(rc == 1) fieldRHS = duk_to_pointer(ctx,-1);
2931 duk_pop(ctx);
2932 //we don't need the RHS fwChanged=valueChanged* because we are only changing the LHS
2933
2934 if(fieldRHS != NULL && itypeRHS > -1){
2935 retval->_web3dval.native = fieldRHS; //shallow copy - won't copy p[] in MF types
2936 retval->_web3dval.fieldType = itypeRHS;
2937 isOK = TRUE;
2938 }
2939 }
2940 break;
2941 case DUK_TYPE_NONE:
2942 case DUK_TYPE_UNDEFINED:
2943 case DUK_TYPE_NULL:
2944 // are we attempting to null out the field? we aren't allowed to change its type (to undefined)
2945 case DUK_TYPE_POINTER:
2946 // don't know what this would be for if anything
2947 default:
2948 isOK = FALSE;
2949 break;
2950 }
2951 duk_pop(ctx); //the duk_eval_string result;
2952 return isOK; //we leave results on stack
2953}
2954*/
2955int isScriptControlOK(int actualscript);
2956int isScriptControlInitialized(int actualscript);
2957void getField_ToJavascript_B(int shader_num, int fieldOffset, int type, union anyVrml *any, int len);
2958int duk_runQueuedDirectOutputs()
2959{
2960 /*
2961 http://www.web3d.org/files/specifications/19775-1/V3.3/Part01/components/scripting.html#directoutputs
2962 http://www.web3d.org/files/specifications/19775-1/V3.3/Part01/components/scripting.html#Accessingfieldsandevents
2963
2964 Interpretation: The reason the SAI specs say to queue directOutputs in an event queue,
2965 is because external SAIs are running in a different thread: the rendering thread could be
2966 using a node just when you want to write to it from the SAI thread.
2967 I'll assume here we are working on the internal/javascript/ecmascript SAI, and that it is
2968 synchronous with the rendering thread, so it can safely write to nodes without queuing.
2969
2970 So our effort here is just to make it convenient to write to eventIn/inputOnly
2971 (or the eventIn/inputOnly part of exposedField/inputOutput fields).
2972
2973 Writing to builtin nodes from a script is already implemented in freewrl by directly writing
2974 the fields immediately during the script. However writing to another script wassn't working properly July 8, 2014.
2975 The following proposed algo was the result of analyzing the behaviour of other vrml/x3d browsers.
2976
2977 DIRECTOUTPUT ALGO:
2978 When writing to another script node from the current script:
2979 a) write unconditionally to the other script->field->value, including to field/initializeOnly and eventIn/inputOnly
2980 b) set a valueSet flag on the field (like valueChanged for output) and the valueChanged flag
2981 c) set the node _changed or isActive flag to trigger updates
2982 d) either
2983 i) have a stack of queues of script nodes changed and process after each script function OR
2984 ii) like gatherScriptEventOuts() have a spot in the routing loop to look at the valueSet flag
2985 for script fields and if valueSet then if the field is inputOnly/eventIn or exposedField/inputOutput
2986 take the field->value and pass it the the eventIn function (with the current/same timestamp).
2987
2988 It's this d) ii) we are implementing here.
2989 */
2990 ttglobal tg = gglobal();
2991 struct Shader_Script *script;
2992 struct ScriptFieldDecl *field;
2993 int i,num,kind, itype;
2994 const char *fieldname;
2995 static int doneOnce = 0;
2996 int moreAction;
2997 struct CRscriptStruct *scriptcontrol; //*ScriptControlArray,
2998 //ScriptControlArray = getScriptControl();
2999
3000 if(!doneOnce){
3001 // printf("in runQueuedDirectOutputs\n");
3002 printf("javascript engine duktape version %ld\n", DUK_VERSION);
3003 doneOnce++;
3004 }
3005 moreAction = FALSE;
3006 for(num=0;num< tg->CRoutes.max_script_found_and_initialized;num++){
3007 scriptcontrol = getScriptControlIndex(num); //&ScriptControlArray[num];
3008 if(scriptcontrol)
3009 {
3010 script = scriptcontrol->script;
3011 if(scriptcontrol->thisScriptType != NOSCRIPT && script){
3012 if(isScriptControlInitialized(script->num) && isScriptControlOK(script->num)){
3013 int nfields = Shader_Script_getScriptFieldCount(script);
3014 for(i=0;i<nfields;i++){
3015 field = Shader_Script_getScriptField(script,i);
3016 fieldname = ScriptFieldDecl_getName(field);
3017 kind = ScriptFieldDecl_getMode(field);
3018 itype = ScriptFieldDecl_getType(field);
3019 if(field->eventInSet){
3020 if( (kind == PKW_inputOnly || kind == PKW_inputOutput)){
3021 int isMF, sftype, len, isize;
3022 int JSparamNameIndex = field->fieldDecl->JSparamNameIndex;
3023 mark_script(script->num);
3024 //run script eventIn function with field->value and tickTime
3025 isMF = itype % 2; //WRONG - use a function to lookup
3026 sftype = itype - isMF;
3027 //from EAI_C_CommonFunctions.c
3028 isize = returnElementLength(sftype) * returnElementRowSize(sftype);
3029 if(isMF) len = sizeof(int) + sizeof(void*);
3030 else len = isize;
3031
3032 field->eventInSet = FALSE;
3033 getField_ToJavascript_B(script->num, JSparamNameIndex, itype, &field->value, len);
3034 //printf("+eventInSet and input kind=%d value=%f\n",kind,field->value.sffloat);
3035 moreAction = TRUE;
3036 }else{
3037 //printf("-eventInSet but not input kind=%d value=%f\n",kind,field->value.sffloat);
3038 field->eventInSet = FALSE;
3039 }
3040 }
3041 }
3042 }
3043 }
3044 }
3045 }
3046 return moreAction; //IF TRUE will make routing do another loop on the same timestamp
3047}
3048
3049
3050#endif /* defined(JAVASCRIPT_DUK) */
Definition Viewer.h:141