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