FreeWRL / FreeX3D 4.3.0
CParseParser.c
1/*
2
3
4 ???
5
6*/
7
8/****************************************************************************
9 This file is part of the FreeWRL/FreeX3D Distribution.
10
11 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12
13 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Lesser Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25****************************************************************************/
26
27
28
29#include <config.h>
30#include <system.h>
31#include <display.h>
32#include <internal.h>
33
34#include <libFreeWRL.h>
35
36
37#include "../vrml_parser/Structs.h"
38#include "../main/headers.h"
39#include "CParseGeneral.h"
40#include "../scenegraph/Vector.h"
41#include "../vrml_parser/CFieldDecls.h"
42#include "../world_script/JScript.h"
43#include "../world_script/CScripts.h"
44#include "../world_script/fieldSet.h"
45#include "../input/EAIHeaders.h" /* resolving implicit declarations */
46#include "../input/EAIHelpers.h" /* resolving implicit declarations */
47#include "CParseParser.h"
48#include "CParseLexer.h"
49#include "CParse.h"
50#include "CRoutes.h" /* for upper_power_of_two */
51#include "../opengl/OpenGL_Utils.h"
52#include "../scenegraph/LinearAlgebra.h"
53
54#define PARSE_ERROR(msg) \
55 { \
56 CPARSE_ERROR_CURID(msg); \
57 FREE_IF_NZ(me->lexer->curID); \
58 PARSER_FINALLY; \
59 }
60#define PARSER_FINALLY
61
62#define DEFMEM_INIT_SIZE 16
63
64#define DJ_KEEP_COMPILER_WARNING 0
65
66typedef struct pCParseParser{
67 char fw_outline[2000];
68 int foundInputErrors;// = 0;
69 int latest_protoDefNumber;
70}* ppCParseParser;
71void *CParseParser_constructor(){
72 void *v = MALLOCV(sizeof(struct pCParseParser));
73 memset(v,0,sizeof(struct pCParseParser));
74 return v;
75}
76void CParseParser_init(struct tCParseParser *t){
77 //public
78 //private
79 t->prv = CParseParser_constructor();
80 {
81 ppCParseParser p = (ppCParseParser)t->prv;
82 p->foundInputErrors = 0;
83 p->latest_protoDefNumber = 1;
84 }
85}
86 //ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
87
88//static int foundInputErrors = 0;
89void resetParseSuccessfullyFlag(void) {
90 ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
91 p->foundInputErrors = 0;
92}
93int parsedSuccessfully(void) {
94 ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
95 return p->foundInputErrors == 0;
96}
97
98/* Parsing a specific type */
99/* NOTE! We have to keep the order of these function calls the same
100 as the FIELDTYPE names, created from the @VRML::Fields = qw/ in
101 VRMLFields.pm (which writes the FIELDTYPE* defines in
102 CFuncs/Structs.h. Currently (September, 2008) this is the list:
103 SFFloat
104 MFFloat
105 SFBool
106 MFBool
107 SFInt32
108 MFInt32
109 SFTime
110 MFTime
111 SFDouble
112 MFDouble
113 SFNode
114 MFNode
115 SFColor
116 MFColor
117 SFColorRGBA
118 MFColorRGBA
119 SFRotation
120 MFRotation
121 SFVec2f
122 MFVec2f
123 SFVec3f
124 MFVec3f
125 SFVec4f
126 MFVec4f
127 SFVec2d
128 MFVec2d
129 SFVec3d
130 MFVec3d
131 SFVec4d
132 MFVec4d
133 SFString
134 MFString
135 SFImage
136 MFImage
137 SFMatrix3f
138 MFMatrix3f
139 SFMatrix4f
140 MFMatrix4f
141 SFMatrix3d
142 MFMatrix3d
143 SFMatrix4d
144 MFMatrix4d
145 FreeWRLPTR
146 FreeWRLThread
147*/
148
149/* Parses nodes, fields and other statements. */
150static BOOL parser_routeStatement(struct VRMLParser*);
151static BOOL parser_componentStatement(struct VRMLParser*);
152static BOOL parser_exportStatement(struct VRMLParser*);
153static BOOL parser_importStatement(struct VRMLParser*);
154static BOOL parser_metaStatement(struct VRMLParser*);
155static BOOL parser_unitStatement(struct VRMLParser*);
156static BOOL parser_profileStatement(struct VRMLParser*);
157
158//static BOOL parser_protoStatement(struct VRMLParser*);
159static BOOL parser_nodeStatement(struct VRMLParser*, vrmlNodeT*);
160static BOOL parser_node(struct VRMLParser*, vrmlNodeT*, int);
161static BOOL parser_field(struct VRMLParser*, struct X3D_Node*);
162
163
164
165static BOOL parser_sffloatValue_ (struct VRMLParser *, void *);
166static BOOL parser_sfboolValue(struct VRMLParser*, void*);
167static BOOL parser_sfint32Value_ (struct VRMLParser *, void *);
168static BOOL parser_sftimeValue (struct VRMLParser *, void *);
169static BOOL parser_sfdoubleValue(struct VRMLParser*, void*);
170static BOOL parser_sfnodeValue (struct VRMLParser *, void *);
171static BOOL parser_sfcolorValue(struct VRMLParser*, void*);
172static BOOL parser_sfcolorrgbaValue(struct VRMLParser*, void*);
173static BOOL parser_sfrotationValue (struct VRMLParser *, void *);
174static BOOL parser_sfvec2fValue(struct VRMLParser*, void*);
175static BOOL parser_sfvec3fValue(struct VRMLParser*, void*);
176static BOOL parser_sfvec4fValue(struct VRMLParser*, void*);
177static BOOL parser_sfvec2dValue(struct VRMLParser*, void*);
178static BOOL parser_sfvec3dValue(struct VRMLParser*, void*);
179static BOOL parser_sfvec4dValue(struct VRMLParser*, void*);
180static BOOL parser_sfstringValue_(struct VRMLParser*, void*);
181static BOOL parser_sfimageValue(struct VRMLParser*, void*);
182static BOOL parser_sfmatrix3fValue (struct VRMLParser *, void *);
183static BOOL parser_sfmatrix4fValue (struct VRMLParser *, void *);
184static BOOL parser_sfmatrix3dValue (struct VRMLParser *, void *);
185static BOOL parser_sfmatrix4dValue (struct VRMLParser *, void *);
186
187static BOOL parser_mffloatValue(struct VRMLParser*, void*);
188static BOOL parser_mfboolValue(struct VRMLParser*, void*);
189static BOOL parser_mfint32Value(struct VRMLParser*, void*);
190static BOOL parser_mftimeValue(struct VRMLParser*, void*);
191static BOOL parser_mfdoubleValue(struct VRMLParser*, void*);
192static BOOL parser_mfnodeValue(struct VRMLParser*, void*);
193static BOOL parser_mfcolorValue(struct VRMLParser*, void*);
194static BOOL parser_mfcolorrgbaValue(struct VRMLParser*, void*);
195static BOOL parser_mfrotationValue(struct VRMLParser*, void*);
196static BOOL parser_mfvec2fValue(struct VRMLParser*, void*);
197static BOOL parser_mfvec3fValue(struct VRMLParser*, void*);
198static BOOL parser_mfvec4fValue(struct VRMLParser*, void*);
199static BOOL parser_mfvec2dValue(struct VRMLParser*, void*);
200static BOOL parser_mfvec3dValue(struct VRMLParser*, void*);
201static BOOL parser_mfvec4dValue(struct VRMLParser*, void*);
202static BOOL parser_mfstringValue(struct VRMLParser*, void*);
203static BOOL parser_mfimageValue(struct VRMLParser*, void*);
204static BOOL parser_mfmatrix3fValue(struct VRMLParser*, void*);
205static BOOL parser_mfmatrix4fValue(struct VRMLParser*, void*);
206static BOOL parser_mfmatrix3dValue(struct VRMLParser*, void*);
207static BOOL parser_mfmatrix4dValue(struct VRMLParser*, void*);
208
209
210
211//#define parser_sfvec3fValue(me, ret) \
212// parser_sfcolorValue(me, ret)
213
214
215/* for those types not parsed yet, call this to print an error message */
216static BOOL parser_fieldTypeNotParsedYet(struct VRMLParser* me, void* ret);
217
218/*PARSE_TYPE[] entries must be sychnronized with the FIELDTYPES values in Structs.h */
219BOOL (*PARSE_TYPE[])(struct VRMLParser*, void*)={
220 &parser_sffloatValue_, &parser_mffloatValue, // 0,1 float
221 &parser_sfboolValue,&parser_mfboolValue, // 6,7 Bool
222 &parser_sfint32Value_,&parser_mfint32Value, // 8,9 Int32
223 &parser_sftimeValue,&parser_mftimeValue, // 16,17 Time
224 &parser_sfdoubleValue,&parser_mfdoubleValue, // 26,27 Double
225 &parser_sfnodeValue,&parser_mfnodeValue, // 10,11 Node
226 &parser_sfcolorValue,&parser_mfcolorValue, // 12,13 Color
227 &parser_sfcolorrgbaValue,&parser_mfcolorrgbaValue, // 14,15 ColorRGBA
228 &parser_sfrotationValue, &parser_mfrotationValue, // 2,3 rotation
229 &parser_sfvec2fValue,& parser_mfvec2fValue, // 20,21 Vec2f
230 &parser_sfvec3fValue, &parser_mfvec3fValue, // 4,5 Vec3f
231 &parser_sfvec4fValue,& parser_mfvec4fValue, // 38,39 Vec4f
232 &parser_sfvec2dValue,& parser_mfvec2dValue, // 36,37 Vec2d //&parser_fieldTypeNotParsedYet,
233 &parser_sfvec3dValue,& parser_mfvec3dValue, // 24,25 Vec3d
234 &parser_sfvec4dValue,& parser_mfvec4dValue, // 40,41 Vec4d //&parser_fieldTypeNotParsedYet,
235 &parser_sfstringValue_, &parser_mfstringValue, // 18,19 String
236 &parser_sfimageValue, &parser_mfimageValue, // Image
237 &parser_sfmatrix3fValue, &parser_mfmatrix3fValue, // 28,29 Matrix3f
238 &parser_sfmatrix4fValue, &parser_mfmatrix4fValue, // 32,33 Matrix4f
239 &parser_sfmatrix3dValue, &parser_mfmatrix3dValue, // 30,31 Matrix3d
240 &parser_sfmatrix4dValue, &parser_mfmatrix4dValue, // 34,35 Matrix4d
241 &parser_fieldTypeNotParsedYet,& parser_fieldTypeNotParsedYet, // 22, FREEWRL_PTR, 42 FreeWRLThread
242
243};
244
245
246/************************************************************************************************/
247/* parse an SF/MF; return the parsed value in the defaultVal field */
248BOOL parseType(struct VRMLParser* me, int type, union anyVrml *defaultVal) {
249 ASSERT(PARSE_TYPE[type]);
250
251 //ConsoleMessage ("parseType, type %d, dfv %p",type,defaultVal);
252 if (type == ID_UNDEFINED) return false;
253
254 return PARSE_TYPE[type](me, (void*)defaultVal);
255}
256
257/* ************************************************************************** */
258/* ******************************* ProtoFieldDecl *************************** */
259/* ************************************************************************** */
260
261/* Constructor and destructor */
262/* ************************** */
263
264/* Without default value (event) */
265struct ProtoFieldDecl* newProtoFieldDecl(indexT mode, indexT type, indexT name)
266{
267 struct ProtoFieldDecl* ret=MALLOC(struct ProtoFieldDecl*, sizeof(struct ProtoFieldDecl));
268 bzero(ret,sizeof(struct ProtoFieldDecl));
269 /* printf("creating ProtoFieldDecl %p\n", ret); */
270 ret->mode=mode;
271 ret->type=type;
272 ret->name=name;
273 ret->alreadySet=FALSE;
274 ret->fieldString = NULL;
275 ret->cname = NULL;
276 ret->scriptDests = NULL;
277 ret->defaultVal.mfnode.p = NULL;
278 ret->defaultVal.mfnode.n = 0;
279 return ret;
280}
281struct ProtoFieldDecl* copy_ProtoFieldDecl(struct ProtoFieldDecl *sdecl) {
282 struct ProtoFieldDecl *ddecl;
283 ddecl = newProtoFieldDecl(sdecl->mode,sdecl->type,sdecl->name);
284 if(sdecl->cname)
285 ddecl->cname = STRDUP(sdecl->cname);
286 //if(sdecl->mode == PKW_inputOnly || sdecl->mode == PKW_inputOutput){
287 //I seem to need unconditional otherwise something bombs when cleaning up / freeing
288 shallow_copy_field(sdecl->type,&(sdecl->defaultVal),&(ddecl->defaultVal));
289 //}
290 return ddecl;
291}
292void clearASCIIString(struct Uni_String *us);
293void freeASCIIString(struct Uni_String *us);
294void clearMFString(struct Multi_String *ms);
295void freeMFString(struct Multi_String **ms);
296void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr)
297{
298 //deletes just the malloced part, assuming another replacement value will be deep copied in its place
299 if(fieldPtr) {
300 int isMF;
301 isMF =type % 2;
302 if(type == FIELDTYPE_FreeWRLPTR){
303 if(0) FREE_IF_NZ(fieldPtr->sfstring);
304 } else if(type == FIELDTYPE_SFString){
305 struct Uni_String *us;
306 //union anyVrml holds a struct Uni_String * (a pointer to Uni_String)
307 us = fieldPtr->sfstring;
308 clearASCIIString(us); //fieldPtr);
309 FREE_IF_NZ(fieldPtr->sfstring);
310 //fieldPtr->sfstring = NULL;
311 }else if(type == FIELDTYPE_MFString){
312 clearMFString(&fieldPtr->mfstring);
313 fieldPtr->mfstring.n = 0;
314 } else if(isMF) {
315 //if(type == FIELDTYPE_SFImage){
316 FREE_IF_NZ(fieldPtr->mfnode.p);
317 fieldPtr->mfnode.n = 0;
318 }
319 }
320}
321
322void deleteProtoFieldDecl(struct ProtoFieldDecl* me)
323{
324 int type;
325 union anyVrml *fieldPtr;
326 FREE_IF_NZ(me->cname);
327 FREE_IF_NZ(me->fieldString);
328 fieldPtr = &(me->defaultVal);
329 type = me->type;
330 deleteMallocedFieldValue(type,fieldPtr);
331 FREE_IF_NZ(me);
332}
333
334
335/* ************************************************************************** */
336/* ******************************** ProtoDefinition ************************* */
337/* ************************************************************************** */
338
339struct ProtoDefinition* newProtoDefinition()
340{
341 /* Attention! protoDefinition_copy also sets up data from raw MALLOC! Don't
342 * forget to mimic any changes to this method there, too!
343 */
344
345 struct ProtoDefinition* ret;
346 ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
347
348 ret=MALLOC(struct ProtoDefinition*, sizeof(struct ProtoDefinition));
349 ASSERT(ret);
350
351 /* printf("creating new ProtoDefinition %u\n", ret); */
352
353 ret->iface=newVector(struct ProtoFieldDecl*, 4);
354 ASSERT(ret->iface);
355
356 /* proto bodies are tokenized to help IS and routing to/from PROTOS */
357/*
358 ret->deconstructedProtoBody=newVector(struct ProtoElementPointer*, 128);
359 ASSERT(ret->deconstructedProtoBody);
360*/
361 ret->deconstructedProtoBody = NULL;
362
363
364
365 ret->protoDefNumber = p->latest_protoDefNumber++;
366 ret->estimatedBodyLen = 0;
367 ret->protoName = NULL;
368 ret->isCopy = FALSE;
369 ret->isExtern = FALSE;
370
371 return ret;
372}
373void deleteProtoDefinition(struct ProtoDefinition *ret) {
374 if(ret){
375 if(ret->iface){
376 int i;
377 for(i=0;i<vectorSize(ret->iface);i++) {
378 struct ProtoFieldDecl* iface = vector_get(struct ProtoFieldDecl*,ret->iface,i);
379 if(iface){
380 deleteProtoFieldDecl(iface);
381 }
382 }
383 }
384 deleteVector(struct ProtoFieldDecl*,ret->iface);
385 FREE_IF_NZ(ret->protoName);
386 }
387 //FREE_IF_NZ(ret);
388}
389/* Other members */
390/* ************* */
391
392/* Retrieve a field by its "name" */
393struct ProtoFieldDecl* protoDefinition_getField(struct ProtoDefinition* me,
394 indexT ind, indexT mode)
395{
396 /* TODO: O(log(n)) by sorting */
397 size_t i;
398 /* printf ("protoDefinition_getField; sizeof iface %d\n",vectorSize(me->iface)); */
399 if (!me) return NULL; /* error here, can not go through fields */
400 for(i=0; i!=vectorSize(me->iface); ++i)
401 {
402 struct ProtoFieldDecl* f=vector_get(struct ProtoFieldDecl*, me->iface, i);
403 if(f->name==ind && f->mode==mode) {
404 /* printf ("protoDefinition_getField, comparing %d %d and %d %d\n", f->name, ind, f->mode, mode); */
405 return f;
406 }
407 }
408
409 return NULL;
410}
411
412
413struct ProtoDefinition *getVRMLbrotoDefinition (struct X3D_Proto *me) {
414 return (struct ProtoDefinition *)me->__protoDef;
415}
416
417BOOL isProto(struct X3D_Node *node)
418{
419 BOOL retval = FALSE;
420 if(node)
421 if(node->_nodeType == NODE_Proto){
422 //as of sept 2014, the broto2 scene is sharing the x3dproto struct, it has a bit flag set: __protoFlags & 1
423 //we don't want to treat the scene like a protoinstance, because we want to render all a scenes children. Not so for protoinstance.
424 retval = TRUE;
425 }
426 return retval;
427}
428void add_empty_proto_vectors(struct X3D_Node* node) {
429 // javascript interface wants to do this:
430 // Browser.print('Context: number of protos='+Browser.currentScene.protos.length);
431 // and our lazy-intialization tactic makes it bomb if the protos vector is null.
432 // so we will create non-empty vectors here.
433 // perhaps I should have made these broto fields MFNode-like with .n .p built in and initialized to 0
434
435 if (!node)return;
436 if (node->_nodeType != NODE_Proto && node->_nodeType != NODE_Inline) return;
437 struct X3D_Proto* proto = (struct X3D_Proto*)node;
438 proto->__protoDeclares = newStack(struct X3D_Proto*);
439 proto->__externProtoDeclares = newStack(struct X3D_Proto*);
440 proto->__nodes = newStack(struct X3D_Node*);
441 proto->__subcontexts = newStack(struct X3D_Proto*);
442 //proto->__GC = 0;
443 //proto->__protoDef = 0;
444 //proto->__protoFlags = 0;
445 //proto->__prototype = NULL;
446 //proto->__parentProto = NULL;
447 proto->__ROUTES = newStack(struct CRStruct*);
448 proto->__EXPORTS = newStack(struct IMEXPORT*);
449 proto->__IMPORTS = newStack(struct IMEXPORT*);
450 proto->__DEFnames = newStack(struct brotoDefpair);
451 proto->__IS = newStack(struct brotoIS*);
452 proto->__scripts = newStack(struct X3D_Node*);
453
454}
455
456/* ************************************************************************** */
457/* Constructor and destructor */
458
459struct VRMLParser* newParser(void *ectx, void* ptr, unsigned ofs, int parsingX3DfromXML) {
460 struct VRMLParser* ret=MALLOC(struct VRMLParser *, sizeof(struct VRMLParser));
461 ret->lexer=newLexer();
462 ASSERT(ret->lexer);
463 ret->ectx=ectx;
464 ret->ptr=ptr;
465 ret->ofs=ofs;
466 ret->curPROTO=NULL;
467 ret->DEFedNodes = NULL;
468 ret->PROTOs = NULL;
469 ret->parsingX3DfromXML = parsingX3DfromXML;
470 ret->brotoDEFedNodes = NULL;
471 return ret;
472}
473
474struct VRMLParser* reuseParser(void *ectx, void* ptr, unsigned ofs) {
475 struct VRMLParser* ret;
476 struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
477
478 /* keep the defined nodes around, etc */
479 ret = globalParser;
480
481 /* keep the old lexer around, so that the ASSERTs do not get confused with sizes of stacks, etc
482 if (ret->lexer != NULL) deleteLexer(ret->lexer);
483 ret->lexer=newLexer();
484 */
485 ASSERT(ret->lexer);
486 ret->ectx=ectx;
487 ret->ptr=ptr;
488 ret->ofs=ofs;
489/* We now need to keep the PROTOS and DEFS around
490 ret->curPROTO=NULL;
491 ret->DEFedNodes = NULL;
492 ret->PROTOs = NULL;
493*/
494
495 return ret;
496}
497
498void deleteParser(struct VRMLParser* me)
499{
500 ASSERT(me->lexer);
501 deleteLexer(me->lexer);
502
503 FREE_IF_NZ (me);
504}
505
506static void parser_scopeOut_DEFUSE();
507static void parser_scopeOut_PROTO();
508void parser_destroyData(struct VRMLParser* me)
509{
510
511 /* printf ("\nCParser: parser_destroyData, destroyCParserData: , destroying data, me->DEFedNodes %u\n",me->DEFedNodes); */
512
513 /* DEFed Nodes. */
514 if(me->DEFedNodes)
515 {
516 while(!stack_empty(me->DEFedNodes))
517 parser_scopeOut_DEFUSE(me);
518 deleteStack(struct Vector*, me->DEFedNodes);
519 me->DEFedNodes=NULL;
520 }
521 ASSERT(!me->DEFedNodes);
522
523 /* PROTOs */
524 /* FIXME: PROTOs must not be stacked here!!! */
525 if(me->PROTOs)
526 {
527 while(!stack_empty(me->PROTOs))
528 parser_scopeOut_PROTO(me);
529 deleteStack(struct Vector*, me->PROTOs);
530 me->PROTOs=NULL;
531 }
532 ASSERT(!me->PROTOs);
533 if(me->lexer)
534 lexer_destroyData(me->lexer);
535 //FREE_IF_NZ(me->lexer);
536
537 /* zero script count */
538 zeroScriptHandles ();
539}
540
541/* Scoping */
542
543static void parser_scopeIn_DEFUSE(struct VRMLParser* me)
544{
545 if(!me->DEFedNodes)
546 me->DEFedNodes=newStack(struct Vector*);
547
548 ASSERT(me->DEFedNodes);
549 stack_push(struct Vector*, me->DEFedNodes,
550 newVector(struct X3D_Node*, DEFMEM_INIT_SIZE));
551 ASSERT(!stack_empty(me->DEFedNodes));
552}
553
554/* PROTOs are scope by the parser in the PROTOs vector, and by the lexer in the userNodeTypesVec vector.
555 This is accomplished by keeping track of the number of PROTOs defined so far in a the userNodeTypesStack.
556 When a new scope is entered, the number of PROTOs defined up to this point is pushed onto the stack. When
557 we leave the scope the number of PROTOs now defined is compared to the top value of the stack, and the newest
558 PROTOs are removed until the number of PROTOs defined equals the top value of the stack.
559
560 Management of the userNodeTypesStack is accomplished by the lexer. Therefore, scoping in PROTOs for the parser
561 does nothing except to make sure that the PROTOs vector has been initialized. */
562static void parser_scopeIn_PROTO(struct VRMLParser* me)
563{
564 if(!me->PROTOs) {
565 me->PROTOs=newVector(struct ProtoDefinition*, DEFMEM_INIT_SIZE);
566 }
567}
568
569static void parser_scopeOut_DEFUSE(struct VRMLParser* me)
570{
571 ASSERT(!stack_empty(me->DEFedNodes));
572 /* FIXME: Can't delete individual nodes, as they might be referenced! */
573 deleteVector(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes));
574 stack_pop(struct Vector*, me->DEFedNodes);
575}
576
577/* Scoping out of PROTOs. Check the difference between the number of PROTO definitions currently
578 available and the number of PROTO definitions available when we first entered this scope (this is
579 the top value on the userNodeTypesVec stack). Remove all PROTO definitions from the PROTOs list that have
580 been added since we first entered this scope. */
581static void parser_scopeOut_PROTO(struct VRMLParser* me)
582{
583 /* Do not delete the ProtoDefinitions, as they are referenced in the scene
584 * graph! TODO: How to delete them properly? */
585
586 vector_popBackN(struct ProtoDefinition*, me->PROTOs, lexer_getProtoPopCnt(me->lexer));
587 lexer_scopeOut_PROTO(me->lexer);
588}
589
590void parser_scopeIn(struct VRMLParser* me)
591{
592 lexer_scopeIn(me->lexer);
593 parser_scopeIn_DEFUSE(me);
594 parser_scopeIn_PROTO(me);
595}
596void parser_scopeOut(struct VRMLParser* me)
597{
598 parser_scopeOut_DEFUSE(me);
599 parser_scopeOut_PROTO(me);
600 lexer_scopeOut(me->lexer);
601}
602/* save your spot in the lexer stream so if you're in the wrong handler
603 you can backup and let something else try to handle it*/
604#define STRDUP_IF_NZ(_ptr) ((_ptr) ? STRDUP(_ptr) : NULL)
605#define DECLAREUP char *saveNextIn, *saveCurID = NULL;
606#define SAVEUP { FREE_IF_NZ(saveCurID); \
607 saveCurID = STRDUP_IF_NZ(me->lexer->curID); \
608 saveNextIn = me->lexer->nextIn;}
609#define BACKUP {FREE_IF_NZ(me->lexer->curID); \
610 me->lexer->curID = saveCurID; \
611 me->lexer->nextIn = saveNextIn; }
612#define FREEUP {FREE_IF_NZ(saveCurID);}
613
614static BOOL parser_brotoStatement(struct VRMLParser* me);
615
616void parse_proto_body(struct VRMLParser* me)
617{
618 DECLAREUP
619
620 /* As long as there are nodes, routes, or protos to be parsed keep doing so */
621 while(TRUE)
622 {
623 /* Try nodeStatement */
624 SAVEUP
625 {
626 vrmlNodeT node;
627 /* This will parse a builtin node, including all nested ROUTES and PROTOs, and return
628 a pointer to the node that was parsed.
629 If the node is a user-defined node (PROTO expansion) this will expand the PROTO (propagate
630 all field values, and add all routes to the CRoute table), and returns a pointer to the
631 root node of the scene graph for this PROTO */
632#ifdef CPARSERVERBOSE
633 printf("parser_vrmlScene: Try node\n");
634#endif
635 if(parser_nodeStatement(me, &node))
636 {
637 /* Add the node just parsed to the ROOT node for this scene */
638 if (node != NULL)
639 AddRemoveChildren(me->ptr, offsetPointer_deref(void *,me->ptr,me->ofs), &node, 1, 1,__FILE__,__LINE__);
640#ifdef CPARSERVERBOSE
641 printf("parser_vrmlScene: node parsed\n");
642#endif
643 //printf("pp.children.n=%d\n",pp->children.n);
644 continue;
645 }
646 }
647 BACKUP
648 /* Try routeStatement */
649 /* Checks that the ROUTE statement is valid (i.e. that the referenced node and field combinations
650 exist, and that they are compatible) and then adds the route to the CRoutes table of routes. */
651
652#ifdef CPARSERVERBOSE
653 printf("parser_vrmlScene: Try route\n");
654#endif
655
656
657 /* try ROUTE, COMPONENT, EXPORT, IMPORT, META, PROFILE statements here */
658 BLOCK_STATEMENT(parser_vrmlScene)
659 BACKUP
660 /* Try protoStatement */
661 /* Add the PROTO name to the userNodeTypesVec list of names. Create and fill in a new protoDefinition structure and add it to the PROTOs list.
662 Goes through the interface declarations for the PROTO and adds each user-defined field name to the appropriate list of user-defined names (user_initializeOnly,
663 user_inputOnly, Out, or user_inputOutput), creates a new protoFieldDecl for the field and adds it to the iface vector of the ProtoDefinition,
664 and, in the case of fields and inputOutputs, gets the default value of the field and stores it in the protoFieldDecl.
665 Parses the body of the PROTO. Nodes are added to the scene graph for this PROTO. Routes are parsed and a new ProtoRoute structure
666 is created for each one and added to the routes vector of the ProtoDefinition. PROTOs are recursively parsed!
667 */
668#ifdef CPARSERVERBOSE
669 printf("parser_vrmlScene: Try proto\n");
670#endif
671// if(parser_protoStatement(me)) {
672//#ifdef CPARSERVERBOSE
673// printf("parser_vrmlScene: PROTO parsed\n");
674//#endif
675// continue;
676// }
677 BACKUP
678 if(parser_brotoStatement(me)) {
679#ifdef CPARSERVERBOSE
680 printf("parser_vrmlScene: BROTO parsed\n");
681#endif
682 continue;
683 }
684
685 break;
686 }
687}
688
689void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name);
690static BOOL parser_node_B(struct VRMLParser* me, vrmlNodeT* ret, int ind);
691
692static BOOL parser_node(struct VRMLParser* me, vrmlNodeT* node, int ival)
693{
694 return parser_node_B(me,node,ival);
695}
696
697/* ************************************************************************** */
698/* The start symbol */
699
700/* ************************************************************************** */
701/* The start symbol */
702
703BOOL parser_vrmlScene_B(struct VRMLParser* me)
704{
705 parse_proto_body(me);
706
707 /* We were unable to keep parsing Nodes, ROUTEs, or PROTOs. Check that this is indeed the end of the file. If it isn't,
708 there is an error, so we return FALSE. */
709
710 return lexer_eof(me->lexer);
711}
712BOOL parser_vrmlScene(struct VRMLParser* me)
713{
714 //ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
715 //if((X3D_NODE(me->ectx)->_nodeType == NODE_Proto) || (X3D_NODE(me->ectx)->_nodeType == NODE_Inline)) {
716 /* (sorry for documenting instead of refactoring)
717 broto era: me->ptr is both the executionContext node (scene, proto, inline)
718 and the where node of the (where,offset) place to put the parsed nodes.
719 for brotos (binary proto parsing) the context has a set of arrays where data is put during parsing:
720 ROUTES, EXPORTS, IMPORTS, DEFnames, protoDeclares, externProtoDeclares
721 and (as of sept 2014) these arrays are used later for instancing declared user prototype nodes
722 but (as of sept 2014) not used for rendering scenes - that's still in old arrays scattered around freewrl.
723 me->ptr could be split in the future, so me->ptr is just the where node
724 and a separate me->ctx would hold the context (scene, proto, inline)
725 -ctx either the node ie ctxnode, or if context is separated into a struct, just the struct ie ctxStruct
726 if ctxnode, then when parsing protobody, besides me->ptr = proto, do me->ctx = proto
727 its just this top level where the ctxnode and (where,) might be separated, ie js createVrmlFromString()
728 parses nodes into an MFNode that's not a Proto, or Inline (but the script should know what executionContext its in).
729 Sept 2014 Proto and Inline have the same structure, so one can be cast to the other. But in theory, if you
730 separate context out, so its a struct on its own, then Proto and Inline could be different, and both hold
731 a context struct as a private field.
732 */
733 return parser_vrmlScene_B(me);
734 //}else{
735 // // older vrml tradition:
736 // // me->ptr is the where node for (where,offset) to put parsed nodes
737 // return parser_vrmlScene_A(me);
738 //}
739}
740/* ************************************************************************** */
741/* Nodes and fields */
742
743/* Parses an interface declaration and adds it to the PROTO or Script definition */
744/* Adds the user-defined name to the appropriate user-defined name list (user_initializeOnly, user_inputOutput, user_inputOnly, or Out)
745 Creates a protoFieldDecl or scriptFieldDecl structure to hold field data.
746 Parses and stores the default value of fields and inputOutputs.
747 Adds the protoFieldDecl or scriptFieldDecl to the list of fields in the ProtoDefinition or Script structure. */
748static BOOL parser_interfaceDeclaration(struct VRMLParser* me, struct ProtoDefinition* proto, struct Shader_Script* script) {
749 int mode;
750 int type;
751 int name = 0;
752 int externproto;
753 union anyVrml defaultVal;
754 DECLAREUP
755 struct ProtoFieldDecl* pdecl=NULL;
756 struct ProtoFieldDecl* pField=NULL;
757 struct ScriptFieldDecl* sdecl=NULL;
758 char *startOfField = NULL;
759 int startOfFieldLexerLevel = INT_ID_UNDEFINED;
760
761
762#ifdef CPARSERVERBOSE
763 printf ("start of parser_interfaceDeclaration\n");
764#endif
765
766 bzero (&defaultVal, sizeof (union anyVrml));
767
768 /* Either PROTO or Script interface! */
769 ASSERT((proto || script) && !(proto && script));
770
771 /* lexer_protoFieldMode is #defined as
772 lexer_specialID(me, r, NULL, PROTOKEYWORDS, PROTOKEYWORDS_COUNT, NULL) */
773 /* Looks for the next token in the array PROTOKEYWORDS (inputOnly, outputOnly, inputOutput, field)
774 and returns the appropriate index in mode */
775 SAVEUP
776 if(!lexer_protoFieldMode(me->lexer, &mode)) {
777#ifdef CPARSERVERBOSE
778 printf ("parser_interfaceDeclaration, not lexer_protoFieldMode, returning\n");
779#endif
780 BACKUP
781 return FALSE;
782 }
783
784 /* Script can not take inputOutputs */
785 if(0) //if(version == VRML2 OR LESS)
786 if (script != NULL) {
787 if(script->ShaderScriptNode->_nodeType==NODE_Script && mode==PKW_inputOutput)
788 {
789 PARSE_ERROR("Scripts must not have inputOutputs!")
790 //printf("dug9: maybe scripts can have inputOutputs\n");
791 }
792 }
793
794 /* lexer_fieldType is #defined as lexer_specialID(me, r, NULL, FIELDTYPES, FIELDTYPES_COUNT, NULL) */
795 /* Looks for the next token in the array FIELDTYPES and returns the index in type */
796 if(!lexer_fieldType(me->lexer, &type))
797 PARSE_ERROR("Expected fieldType after proto-field keyword!")
798
799#ifdef CPARSERVERBOSE
800 printf ("parser_interfaceDeclaration, switching on mode %s\n",PROTOKEYWORDS[mode]);
801#endif
802
803
804 switch(mode)
805 {
806#define LEX_DEFINE_FIELDID(suff) \
807 case PKW_##suff: \
808 if(!lexer_define_##suff(me->lexer, &name)) \
809 PARSE_ERROR("Expected fieldNameId after field type!") \
810 break;
811
812 LEX_DEFINE_FIELDID(initializeOnly)
813 LEX_DEFINE_FIELDID(inputOnly)
814 LEX_DEFINE_FIELDID(outputOnly)
815 LEX_DEFINE_FIELDID(inputOutput)
816
817
818
819#ifndef NDEBUG
820 default:
821 ASSERT(FALSE);
822#endif
823 }
824
825 /* If we are parsing a PROTO, create a new protoFieldDecl.
826 If we are parsing a Script, create a new scriptFieldDecl. */
827 externproto = FALSE;
828 if(proto) {
829#ifdef CPARSERVERBOSE
830 printf ("parser_interfaceDeclaration, calling newProtoFieldDecl\n");
831#endif
832
833 pdecl=newProtoFieldDecl(mode, type, name);
834 pdecl->cname = STRDUP(protoFieldDecl_getStringName(me->lexer, pdecl));
835 //pdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
836 externproto = proto->isExtern;
837#ifdef CPARSERVERBOSE
838 printf ("parser_interfaceDeclaration, finished calling newProtoFieldDecl\n");
839#endif
840 } else {
841#ifdef CPARSERVERBOSE
842 printf ("parser_interfaceDeclaration, calling newScriptFieldDecl\n");
843#endif
844 //lexer_stringUser_fieldName(me,name,mod)
845 sdecl=newScriptFieldDecl(me->lexer, mode, type, name);
846 //sdecl=newScriptFieldDecl(lexer_stringUser_fieldName(me->lexer,name,mod), mode, type, name);
847 //sdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
848
849 }
850
851
852 /* If this is a field or an exposed field */
853 if((mode==PKW_initializeOnly || mode==PKW_inputOutput) ) {
854#ifdef CPARSERVERBOSE
855 printf ("parser_interfaceDeclaration, mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
856#endif
857 if(!externproto){
858
859 /* Get the next token(s) from the lexer and store them in defaultVal as the appropriate type.
860 This is the default value for this field. */
861 if (script && lexer_keyword(me->lexer, KW_IS)) {
862 int fieldE;
863 int fieldO;
864 struct ScriptFieldInstanceInfo* sfield;
865
866 /* Find the proto field that this field is mapped to */
867 if(!lexer_field(me->lexer, NULL, NULL, &fieldO, &fieldE))
868 PARSE_ERROR("Expected fieldId after IS!")
869
870 if(fieldO!=ID_UNDEFINED)
871 {
872 /* Get the protoFieldDeclaration for the field at index fieldO */
873 pField=protoDefinition_getField(me->curPROTO, fieldO, PKW_initializeOnly);
874 if(!pField)
875 PARSE_ERROR("IS source is no field of current PROTO!")
876 ASSERT(pField->mode==PKW_initializeOnly);
877 } else {
878 /* If the field was found in user_inputOutputs */
879 ASSERT(fieldE!=ID_UNDEFINED);
880 /* Get the protoFieldDeclaration for the inputOutput at index fieldO */
881 pField=protoDefinition_getField(me->curPROTO, fieldE, PKW_inputOutput);
882 if(!pField)
883 PARSE_ERROR("IS source is no field of current PROTO!")
884 ASSERT(pField->mode==PKW_inputOutput);
885 }
886
887 if (pField) {
888 /* Add this scriptfielddecl to the list of script fields mapped to this proto field */
889 sfield = newScriptFieldInstanceInfo(sdecl, script);
890 vector_pushBack(struct ScriptFieldInstanceInfo*, pField->scriptDests, sfield);
891 defaultVal = pField->defaultVal;
892 }
893
894 } else {
895 /* else proto or script but not KW_IS */
896 startOfField = (char *)me->lexer->nextIn;
897 startOfFieldLexerLevel = me->lexer->lexerInputLevel;
898
899 /* set the defaultVal to something - we might have a problem if the parser expects this to be
900 a MF*, and there is "garbage" in there, as it will expect to free it. */
901 bzero (&defaultVal, sizeof (union anyVrml));
902
903 if (!parseType(me, type, &defaultVal)) {
904 /* Invalid default value parsed. Delete the proto or script declaration. */
905 CPARSE_ERROR_CURID("Expected default value for field!");
906 if(pdecl) deleteProtoFieldDecl(pdecl);
907 if(sdecl) deleteScriptFieldDecl(sdecl);
908 FREEUP
909 return FALSE;
910 }
911 }
912 }
913 /* Store the default field value in the protoFieldDeclaration or scriptFieldDecl structure */
914 if(proto) {
915 pdecl->defaultVal=defaultVal;
916 }
917 else
918 {
919 ASSERT(script);
920 scriptFieldDecl_setFieldValue(sdecl, defaultVal);
921 }
922 } else {
923#ifdef CPARSERVERBOSE
924 printf ("parser_interfaceDeclaration, NOT mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
925#endif
926
927 /* If this is a Script inputOnly/outputOnly IS statement */
928 if (script && lexer_keyword(me->lexer, KW_IS)) {
929 int evE, evO;
930 struct ScriptFieldInstanceInfo* sfield;
931 BOOL isIn = FALSE, isOut = FALSE;
932
933#ifdef CPARSERVERBOSE
934 printf ("parser_interfaceDeclaration, got IS\n");
935#endif
936
937 /* Get the inputOnly or outputOnly that this field IS */
938 if (mode == PKW_inputOnly) {
939 if (lexer_inputOnly(me->lexer, NULL, NULL, NULL, &evO, &evE)) {
940 isIn = TRUE;
941 isOut = (evE != ID_UNDEFINED);
942 }
943 } else {
944 if (lexer_outputOnly(me->lexer, NULL, NULL, NULL, &evO, &evE)) {
945 isOut = TRUE;
946 }
947 }
948
949 /* Check that the event was found somewhere ... */
950 if (!isIn && !isOut) {
951#ifdef CPARSERVERBOSE
952 printf ("parser_interfaceDeclaration, NOT isIn Nor isOut\n");
953#endif
954 FREEUP
955 return FALSE;
956 }
957
958
959 /* Get the Proto field definition for the field that this IS */
960 pField = protoDefinition_getField(me->curPROTO, evO, isIn ? PKW_inputOnly: PKW_outputOnly); /* can handle inputOnly, outputOnly */
961
962 ASSERT(pField);
963
964 /* Add this script as a destination for this proto field */
965 sfield = newScriptFieldInstanceInfo(sdecl, script);
966 if (pField) vector_pushBack(struct ScriptFieldInstanceInfo*, pField->scriptDests, sfield);
967 }
968 }
969
970 /* Add the new field declaration to the list of fields in the Proto or Script definition.
971 For a PROTO, this means adding it to the iface vector of the ProtoDefinition.
972 For a Script, this means adding it to the fields vector of the ScriptDefinition. */
973 if(proto) {
974 /* protoDefinition_addIfaceField is #defined as vector_pushBack(struct ProtoFieldDecl*, (me)->iface, field) */
975 /* Add the protoFieldDecl structure to the iface vector of the protoDefinition structure */
976
977 /* copy the ASCII text over and save it as part of the field */
978 if (startOfField != NULL) {
979 if (startOfFieldLexerLevel == me->lexer->lexerInputLevel) {
980
981 size_t sz = (size_t) ((me->lexer->nextIn)-startOfField);
982 /* printf ("non-recursive PROTO interface copy, string size is %d\n", sz); */
983
984 FREE_IF_NZ(pdecl->fieldString);
985 pdecl->fieldString = MALLOC (char *, sz + 2);
986 if (NULL != pdecl->fieldString)
987 {
988 memcpy(pdecl->fieldString,startOfField,sz);
989 pdecl->fieldString[sz]='\0';
990 }
991 } else {
992 int i;
993 size_t sz;
994 char *curStrPtr;
995
996 /* we had a PROTO field come in here; this gets difficult as we have to get different
997 lexer levels, not do simple "from here to here" string math */
998
999 /* this is what happens:
1000 me->lexerInputLevel ++;
1001 me->startOfStringPtr[me->lexerInputLevel]=str;
1002 me->oldNextIn[me->lexerInputLevel] = me->nextIn;
1003 me->nextIn=str;
1004 */
1005
1006 /* the "original" level contains a PROTO call; we skip this one, but the
1007 following code will show how to get it if you wish
1008 sz = (size_t) (me->lexer->oldNextIn[startOfFieldLexerLevel+1] - startOfField);
1009 printf ("complex recursive copy of PROTO invocation fields\n");
1010 printf ("for level %d, size is %d\n",startOfFieldLexerLevel, sz);
1011 */
1012
1013 /* we start off with a string of zero length */
1014 sz = 0;
1015
1016 /* we go through any intermediate layers */
1017 for (i=startOfFieldLexerLevel+1; i<me->lexer->lexerInputLevel; i++) {
1018 printf ("CAUTION: unverified code in recursive PROTO invocations in classic VRML parser\n");
1019 printf ("level %d\n",i);
1020 printf ("size of this level, %d\n",(int) (me->lexer->oldNextIn[i+1] - me->lexer->startOfStringPtr[i]));
1021 sz += (size_t) (me->lexer->oldNextIn[i+1] - me->lexer->startOfStringPtr[i]);
1022
1023 }
1024 /* printf ("final level, size %d\n",(int)(me->lexer->nextIn - me->lexer->startOfStringPtr[me->lexer->lexerInputLevel])); */
1025 sz += (size_t)(me->lexer->nextIn - me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]);
1026
1027 /* for good luck, and for the trailing null... */
1028 sz += 2;
1029
1030 /* now, copy over the "stuff" */
1031
1032 FREE_IF_NZ(pdecl->fieldString);
1033 pdecl->fieldString = MALLOC(char *, sz);
1034 curStrPtr = pdecl->fieldString;
1035
1036 /* now, copy the actual strings... */
1037 /* first layer */
1038 /* if we copy this, we will get the PROTO invocation, so we skip this one
1039 sz = (size_t) (me->lexer->oldNextIn[startOfFieldLexerLevel+1] - startOfField);
1040 strncpy(curStrPtr, startOfField, sz);
1041 curStrPtr += sz;
1042 curStrPtr[1] = '\0';
1043 printf ("first layer, we have %d len in copied string\n",strlen(pdecl->fieldString));
1044 printf ("and, it results in :%s:\n",pdecl->fieldString);
1045 */
1046
1047 /* and, the intermediate layers... */
1048 for (i=startOfFieldLexerLevel+1; i<me->lexer->lexerInputLevel; i++) {
1049 sz = (size_t) (me->lexer->oldNextIn[i+1] - me->lexer->startOfStringPtr[i]);
1050 memcpy(curStrPtr,me->lexer->startOfStringPtr[i],sz);
1051 curStrPtr += sz;
1052 }
1053
1054 /* and the final level */
1055 sz = (size_t)(me->lexer->nextIn - me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]);
1056 memcpy(curStrPtr,me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],sz);
1057 curStrPtr += sz;
1058
1059 /* trailing null */
1060 //curStrPtr ++; dug9 dec6,2012 I found this was letting 1 char of junk into the string
1061 *curStrPtr = '\0';
1062 }
1063 }
1064 #ifdef CPARSERVERBOSE
1065 printf ("pdecl->fieldString is :%s:\n",pdecl->fieldString);
1066 #endif
1067
1068 protoDefinition_addIfaceField(proto, pdecl);
1069 } else {
1070 /* Add the scriptFieldDecl structure to the fields vector of the Script structure */
1071 ASSERT(script);
1072 script_addField(script, sdecl);
1073 }
1074
1075 #ifdef CPARSERVERBOSE
1076 printf ("end of parser_interfaceDeclaration\n");
1077 #endif
1078 FREEUP
1079 return TRUE;
1080}
1081
1082//#include "broto2.h"
1083
1084
1085/* Parses a protoStatement */
1086/* Adds the PROTO name to the userNodeTypesVec list of names.
1087 Creates a new protoDefinition structure and adds it to the PROTOs list.
1088 Goes through the interface declarations for the PROTO and adds each user-defined field name to the appropriate list of user-defined names (user_initializeOnly,
1089 user_inputOnly, user_outputOnly, or user_inputOutput), creates a new protoFieldDecl for the field and adds it to the iface vector of the ProtoDefinition,
1090 and, in the case of fields and inputOutputs, gets the default value of the field and stores it in the protoFieldDecl.
1091 Parses the body of the PROTO. Nodes are added to the scene graph for this PROTO. Routes are parsed and a new ProtoRoute structure
1092 is created for each one and added to the routes vector of the ProtoDefinition. PROTOs are recursively parsed!
1093*/
1094
1095static BOOL parser_componentStatement(struct VRMLParser* me) {
1096 char *cname, *clevel;
1097 char cfullname[200];
1098 int myComponent = INT_ID_UNDEFINED;
1099 int myLevel = INT_ID_UNDEFINED;
1100
1101#if DJ_KEEP_COMPILER_WARNING
1102#define COMPSTRINGSIZE 20
1103#endif
1104
1105 ASSERT(me->lexer);
1106 lexer_skip(me->lexer);
1107
1108 /* Is this a COMPONENT statement? */
1109 if(!lexer_keyword(me->lexer, KW_COMPONENT)) return FALSE;
1110
1111#ifdef CPARSERVERBOSE
1112 printf ("parser_componentStatement...\n");
1113#endif
1114
1115 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS a COMPONENT statement */
1116 ASSERT(me->lexer->curID);
1117
1118 //Feb 2016 Core:2 will be all one string now, thanks to allowing : in identifiers Sept 2015
1119 {
1120 //new way to handle 'Core:2' chunk
1121 int i,len;
1122 strcpy(cfullname,me->lexer->curID);
1123 /* now, we are finished with this COMPONENT */
1124 FREE_IF_NZ(me->lexer->curID);
1125
1126 cname = cfullname;
1127 clevel = NULL;
1128 len = strlen(cfullname);
1129 for(i=0;i<len;i++)
1130 if(cfullname[i] == ':'){
1131 cfullname[i] = '\0';
1132 clevel = &cfullname[i+1];
1133 break;
1134 }
1135 char *cname1 = cname;
1136 if(!strcmp(cname,"H-Anim")) cname1 = "HAnim";
1137 myComponent = findFieldInCOMPONENTS(cname1);
1138 myLevel = 0;
1139 if(clevel) myLevel = atoi(clevel);
1140 }
1141 handleComponent(myComponent,myLevel);
1142
1143 return TRUE;
1144}
1145
1146
1147struct X3D_Proto *hasContext(struct X3D_Node* node){
1148 //returns non-null if this node type has a web3d executionContext
1149 //for us that's one of 2 (equivalent) types in our system:
1150 // X3D_Proto -used by ProtoInstance, ExternProtoInstance, Scene, libraryScene, ProtoDeclare, ExternProtoDeclare
1151 // X3D_Inline
1152 struct X3D_Proto * context = NULL;
1153 if(node)
1154 switch(node->_nodeType){
1155 case NODE_Proto:
1156 context = (struct X3D_Proto*)node; //offsetPointer_deref(void*, node, offsetof(struct X3D_Proto,__context));
1157 break;
1158 case NODE_Inline:
1159 context = (struct X3D_Proto*)node; // offsetPointer_deref(void*, node, offsetof(struct X3D_Inline,__context));
1160 break;
1161 }
1162 return context;
1163}
1164struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
1165
1166void handleExport_B (void *ctxnodeptr, char *nodename, char *as) {
1167 /* handle export statements. as will be either a string pointer, or NULL */
1168 struct X3D_Proto *context = hasContext(ctxnodeptr);
1169 if(context){
1170 struct X3D_Node *node = NULL;
1171 struct IMEXPORT *mxport = MALLOCV(sizeof(struct IMEXPORT));
1172 if(!context->__EXPORTS) context->__EXPORTS = newVector(struct IMEXPORT *,4);
1173 mxport->mxname = STRDUP(nodename);
1174 mxport->as = mxport->mxname;
1175 if(as)
1176 mxport->as = STRDUP(as);
1177 node = broto_search_DEFname(context,mxport->mxname);
1178 mxport->nodeptr = node;
1179 vector_pushBack(struct IMEXPORT*,context->__EXPORTS,mxport);
1180 }
1181 #ifdef CAPABILITIESVERBOSE
1182 printf ("handleExport: node :%s: ",node);
1183 if (as != NULL) printf (" AS :%s: ",node);
1184 printf ("\n");
1185 #endif
1186}
1187
1188
1189void handleImport_B (struct X3D_Node *nodeptr, char *nodeName,char *nodeImport, char *as) {
1190 /* handle Import statements. as will be either a string pointer, or NULL
1191 nodename - name of Inline node
1192 nodeImport - name of inline's node we expect Inline to export to us
1193 as - our execution context/scene's DEF name / alias - can be null in which case use nodeImport
1194 */
1195 struct X3D_Proto *context = hasContext(nodeptr);
1196 if(context){
1197 struct IMEXPORT *mxport = MALLOCV(sizeof(struct IMEXPORT));
1198 if(!context->__IMPORTS) context->__IMPORTS = newVector(struct IMEXPORT *,4);
1199 mxport->mxname = STRDUP(nodeImport);
1200 mxport->inlinename = STRDUP(nodeName);
1201 mxport->as = mxport->mxname;
1202 if(as)
1203 mxport->as = STRDUP(as);
1204 mxport->nodeptr = NULL; //IMPORT doesn't use this. Import is a char* mapping only.
1205 vector_pushBack(struct IMEXPORT*,context->__IMPORTS,mxport);
1206 }
1207
1208 #ifdef CAPABILITIESVERBOSE
1209 printf ("handleImport: inlineNodeName :%s: nodeToImport :%s:",nodeName, nodeImport);
1210 if (as != NULL) printf (" AS :%s: ",as);
1211 printf ("\n");
1212 #endif
1213}
1214
1215static BOOL parser_exportStatement(struct VRMLParser* me) {
1216 char *nodeToExport = NULL;
1217 char *alias = NULL;
1218
1219 ASSERT(me->lexer);
1220 lexer_skip(me->lexer);
1221
1222 /* Is this a EXPORT statement? */
1223 if(!lexer_keyword(me->lexer, KW_EXPORT)) return FALSE;
1224
1225#ifdef CPARSERVERBOSE
1226 printf ("parser_exportStatement...\n");
1227#endif
1228
1229 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an EXPORT statement... */
1230 ASSERT(me->lexer->curID);
1231
1232 /* save this, and find the next token... */
1233 nodeToExport = me->lexer->curID;
1234 me->lexer->curID = NULL;
1235
1236 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an EXPORT statement...*/
1237 ASSERT(me->lexer->curID);
1238
1239 /* do we have an "AS" statement? */
1240 if (strcmp("AS",me->lexer->curID) == 0) {
1241 FREE_IF_NZ(me->lexer->curID);
1242 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an EXPORT statement...*/
1243 ASSERT(me->lexer->curID);
1244 alias = me->lexer->curID;
1245 }
1246
1247 /* do the EXPORT */
1248 handleExport_B(me->ectx,nodeToExport, alias);
1249
1250 /* free things up, only as required */
1251 FREE_IF_NZ(nodeToExport);
1252 if (alias != NULL) {FREE_IF_NZ(me->lexer->curID);}
1253 return TRUE;
1254}
1255
1256static BOOL parser_importStatement(struct VRMLParser* me) {
1257 char *inlineNodeName = NULL;
1258 char *alias = NULL;
1259 char *nodeToImport = NULL;
1260
1261 ASSERT(me->lexer);
1262 lexer_skip(me->lexer);
1263
1264 /* Is this a IMPORT statement? */
1265 if(!lexer_keyword(me->lexer, KW_IMPORT)) return FALSE;
1266
1267#ifdef CPARSERVERBOSE
1268 printf ("parser_importStatement...\n");
1269#endif
1270
1271 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an IMPORT statement... */
1272 ASSERT(me->lexer->curID);
1273
1274 /* save this, and find the next token... */
1275 inlineNodeName = STRDUP(me->lexer->curID);
1276 FREE_IF_NZ(me->lexer->curID);
1277
1278 /* we should have a "." then an integer supportLevel */
1279 if (!lexer_point(me->lexer)) {
1280 CPARSE_ERROR_CURID("expected period in IMPORT statement")
1281 return TRUE;
1282 }
1283
1284 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an IMPORT statement... */
1285 ASSERT(me->lexer->curID);
1286
1287 /* ok, now, we should have the nodeToImport name... */
1288 nodeToImport = STRDUP(me->lexer->curID);
1289 FREE_IF_NZ(me->lexer->curID);
1290
1291 /* get the next token */
1292 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an IMPORT statement...*/
1293 ASSERT(me->lexer->curID);
1294
1295 /* do we have an "AS" statement? */
1296 if (strcmp("AS",me->lexer->curID) == 0) {
1297 FREE_IF_NZ(me->lexer->curID);
1298 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an IMPORT statement...*/
1299 ASSERT(me->lexer->curID);
1300 alias = STRDUP(me->lexer->curID);
1301 FREE_IF_NZ(me->lexer->curID);
1302 }
1303
1304 /* do the IMPORT */
1305 handleImport_B(me->ectx,inlineNodeName, nodeToImport, alias);
1306
1307 FREE_IF_NZ (inlineNodeName);
1308 FREE_IF_NZ (nodeToImport);
1309 FREE_IF_NZ (alias);
1310 return TRUE;
1311}
1312static BOOL parser_metaStatement(struct VRMLParser* me) {
1313 vrmlStringT val1, val2;
1314
1315 ASSERT(me->lexer);
1316 lexer_skip(me->lexer);
1317
1318 /* Is this a META statement? */
1319 if(!lexer_keyword(me->lexer, KW_META)) return FALSE;
1320
1321#ifdef CPARSERVERBOSE
1322 printf ("parser_metaStatement...\n");
1323#endif
1324
1325 /* META lines have 2 strings */
1326
1327 /* Otherwise, a real vector */
1328 val1=NULL; val2 = NULL;
1329
1330 if(!parser_sfstringValue (me, &val1)) {
1331 CPARSE_ERROR_CURID("Expected a string after a META keyword")
1332 }
1333
1334 if(!parser_sfstringValue (me, &val2)) {
1335 CPARSE_ERROR_CURID("Expected a string after a META keyword")
1336 }
1337
1338 if ((val1 != NULL) && (val2 != NULL)) { handleMetaDataStringString(me->ectx, val1->strptr,val2->strptr); }
1339
1340 /* cleanup */
1341 if (val1 != NULL) {FREE_IF_NZ(val1->strptr); FREE_IF_NZ(val1);}
1342 if (val2 != NULL) {FREE_IF_NZ(val2->strptr); FREE_IF_NZ(val2);}
1343 return TRUE;
1344}
1345static BOOL parser_unitStatement(struct VRMLParser* me) {
1346 // vrmlStringT val1, val2; //, val3;
1347 double conversionfactor;
1348 char *categoryname = NULL;
1349 char *unitname = NULL;
1350
1351
1352 ASSERT(me->lexer);
1353 lexer_skip(me->lexer);
1354
1355 /* Is this a UNIT statement? */
1356 if(!lexer_keyword(me->lexer, KW_UNIT)) return FALSE;
1357
1358#ifdef CPARSERVERBOSE
1359 printf ("parser_unitStatement...\n");
1360#endif
1361
1362 /* UNIT lines have 2 IDs and a double */
1363
1364 /* Otherwise, a real vector */
1365 categoryname=NULL; unitname = NULL; conversionfactor = 0.0; //val3 = NULL;
1366
1367 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is a UNIT statement...*/
1368 ASSERT(me->lexer->curID);
1369
1370 categoryname = STRDUP(me->lexer->curID);
1371 FREE_IF_NZ(me->lexer->curID);
1372
1373 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is a UNIT statement...*/
1374 ASSERT(me->lexer->curID);
1375
1376 unitname = STRDUP(me->lexer->curID);
1377 FREE_IF_NZ(me->lexer->curID);
1378
1379 if(!parser_sftimeValue(me,&conversionfactor)) {
1380 CPARSE_ERROR_CURID("Expected a numeric string after a UNIT keyword")
1381 }
1382
1383 if ((categoryname != NULL) && (unitname != NULL) && (conversionfactor != 0.0)) {
1384 handleUnitDataStringString(me->ectx,categoryname,unitname,conversionfactor);
1385 }
1386
1387 /* cleanup */
1388 if (categoryname != NULL) FREE_IF_NZ(categoryname);
1389 if (unitname != NULL) FREE_IF_NZ(unitname);
1390 return TRUE;
1391}
1392
1393
1394static BOOL parser_profileStatement(struct VRMLParser* me) {
1395 int myProfile = INT_ID_UNDEFINED;
1396
1397 ASSERT(me->lexer);
1398 lexer_skip(me->lexer);
1399
1400 /* Is this a PROFILE statement? */
1401 if(!lexer_keyword(me->lexer, KW_PROFILE)) return FALSE;
1402
1403#ifdef CPARSERVERBOSE
1404 printf ("parser_profileStatement...\n");
1405#endif
1406
1407 if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an PROFILE statement... */
1408 ASSERT(me->lexer->curID);
1409
1410 myProfile = findFieldInPROFILES(me->lexer->curID);
1411
1412 if (myProfile != ID_UNDEFINED) {
1413 handleProfile(myProfile);
1414 } else {
1415 CPARSE_ERROR_CURID("Expected a profile after a PROFILE keyword")
1416 return TRUE;
1417 }
1418
1419 /* XXX FIXME - do something with the Profile statement */
1420#ifdef CPARSERVERBOSE
1421 printf ("my profile is %d\n",myProfile);
1422#endif
1423 /* now, we are finished with this PROFILE */
1424 FREE_IF_NZ(me->lexer->curID);
1425 return TRUE;
1426}
1427//#include "broto4.h"
1428
1429
1430
1431
1432//#include "broto5.h"
1433static BOOL parser_routeStatement_B(struct VRMLParser* me);
1434
1435static BOOL parser_routeStatement(struct VRMLParser* me)
1436{
1437 return parser_routeStatement_B(me);
1438}
1439
1440/* Register a ROUTE here */
1441/* If we are in a PROTO add a new ProtoRoute structure to the vector ProtoDefinition->routes */
1442/* Otherwise, add the ROUTE to the routing table CRoutes */
1443void parser_registerRoute(struct VRMLParser* me,
1444 struct X3D_Node* fromNode, int fromOfs,
1445 struct X3D_Node* toNode, int toOfs,
1446 int ft)
1447{
1448 ASSERT(me);
1449 if ((fromOfs == ID_UNDEFINED) || (toOfs == ID_UNDEFINED)) {
1450 ConsoleMessage ("problem registering route - either fromField or toField invalid");
1451 } else {
1452 CRoutes_RegisterSimple(fromNode, fromOfs, toNode, toOfs, ft);
1453 }
1454}
1455//#include "broto6.h"
1456
1457/* parse a DEF statement. Return a pointer to a vrmlNodeT */
1458static vrmlNodeT parse_KW_DEF(struct VRMLParser *me) {
1459 int ind = ID_UNDEFINED;
1460 vrmlNodeT node;
1461
1462 /* lexer_defineNodeName is #defined as lexer_defineID(me, ret, stack_top(struct Vector*, userNodeNames), TRUE) */
1463 /* Checks if this node already exists in the userNodeNames vector. If it doesn't, adds it. */
1464 if(!lexer_defineNodeName(me->lexer, &ind))
1465 PARSE_ERROR("Expected nodeNameId after DEF!\n")
1466 ASSERT(ind!=ID_UNDEFINED);
1467
1468
1469 /* If the DEFedNodes stack has not already been created. If not, create new stack and add an X3D_Nodes vector to that stack */
1470 if(!me->DEFedNodes || stack_empty(me->DEFedNodes)) {
1471 /* printf ("parsing KW_DEF, creating new Vectors...\n"); */
1472 parser_scopeIn_DEFUSE(me);
1473 }
1474 ASSERT(me->DEFedNodes);
1475 ASSERT(!stack_empty(me->DEFedNodes));
1476
1477 /* Did we just add the name to the userNodeNames vector? If so, then the node hasn't yet been
1478 added to the DEFedNodes vector, so add it */
1479 ASSERT(ind<=vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
1480 if(ind==vectorSize(stack_top(struct Vector*, me->DEFedNodes))) {
1481 vector_pushBack(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), NULL);
1482 }
1483 ASSERT(ind<vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
1484
1485
1486 /* Parse this node. Create an X3D_Node structure of the appropriate type for this node
1487 and fill in the values for the fields specified.
1488 Add any routes to the CRoutes table. Add any PROTOs to the PROTOs vector */
1489#ifdef CPARSERVERBOSE
1490 printf("parser_KW_DEF: parsing DEFed node \n");
1491#endif
1492 if(!parser_node(me, &node,ind)) {
1493 /* PARSE_ERROR("Expected node in DEF statement!\n") */
1494 /* try to make a better error message. */
1495 CPARSE_ERROR_CURID("ERROR:Expected an X3D node in a DEF statement, got \"");
1496 PARSER_FINALLY;
1497 return NULL;
1498 }
1499#ifdef CPARSERVERBOSE
1500 printf("parser_KW_DEF: DEFed node successfully parsed\n");
1501#endif
1502
1503 /* Return a pointer to the node in the variable ret */
1504 return (vrmlNodeT) vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind);
1505}
1506
1507
1508
1509/* parse a USE statement. Return a pointer to a vrmlNodeT */
1510static vrmlNodeT parse_KW_USE(struct VRMLParser *me) {
1511 int ind;
1512
1513 /* lexer_nodeName is #defined as
1514 lexer_specialID(me, NULL, ret, NULL, 0, stack_top(struct Vector*, userNodeNames)) */
1515 /* Look for the nodename in list of user-defined node names (userNodeNames) and return the index in ret */
1516 if(!lexer_nodeName(me->lexer, &ind)) {
1517 CPARSE_ERROR_CURID("ERROR:Expected valid DEF name after USE; found: ");
1518 FREE_IF_NZ(me->lexer->curID);
1519 return NULL;
1520 }
1521#ifdef CPARSERVERBOSE
1522 printf("parser_KW_USE: parsing USE\n");
1523#endif
1524
1525 /* If we're USEing it, it has to already be defined. */
1526 ASSERT(ind!=ID_UNDEFINED);
1527
1528 /* It also has to be in the DEFedNodes stack */
1529 ASSERT(me->DEFedNodes && !stack_empty(me->DEFedNodes) &&
1530 ind<vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
1531
1532 #ifdef CPARSERVERBOSE
1533 printf ("parser_KW_USE, returning vector %u\n", vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind));
1534 #endif
1535
1536 /* Get a pointer to the X3D_Node structure for this DEFed node and return it in ret */
1537 return (vrmlNodeT) vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind);
1538}
1539
1540
1541
1542/* Parses a node (node non-terminal) */
1543/* Looks up the node type on the builtin NODES list and the userNodeNames list.
1544 If this is a builtin node type, creates a new X3D_Node structure of the appropriate type for the node, and then parses the statements for that node.
1545 For each field statement, gets the value for that field and stores it in the X3D_Node structure.
1546 For each ROUTE statement, adds the route to the CRoutes table.
1547 For each PROTO statement, adds the PROTO definition to te PROTOs list.
1548 Return a pointer to the X3D_Node structure that holds the information for this node.
1549 If this is a user-defined node type (i.e. a PROTO expansion), complete the proto expansion.
1550 For each field in the ProtoDefinition either parse and propagate the specified value for this field, or
1551 propagate the default value of the field. (i.e. copy the appropriate value into every node/field combination in
1552 the dests list.)
1553 For each route in the routes list of the ProtoDefinition, add the route to the CRoutes table.
1554 Return a pointer to the X3D_Node structure that is the scenegraph for this PROTO.
1555*/
1556/* Specific initialization of node fields */
1557void push_binding_stack_set(struct X3D_Node* layersetnode);
1558void push_next_layerId_from_binding_stack_set(struct X3D_Node *layer);
1559void pop_binding_stack_set();
1560
1561static BOOL parser_nodeStatement(struct VRMLParser* me, vrmlNodeT* ret)
1562{
1563 ASSERT(me->lexer);
1564
1565 /* A DEF-statement? */
1566 if(lexer_keyword(me->lexer, KW_DEF)) {
1567 //vrmlNodeT * node = ret;
1568 //*node = parse_KW_DEF(me);
1569 *ret = parse_KW_DEF(me);
1570 return TRUE;
1571 }
1572
1573 /* A USE-statement? */
1574 if(lexer_keyword(me->lexer, KW_USE)) {
1575 *ret= parse_KW_USE(me);
1576 return TRUE;
1577 }
1578
1579 /* Otherwise, simply a node. */
1580 return parser_node(me, ret, ID_UNDEFINED);
1581}
1582//#include "broto7.h"
1583
1584
1585
1586/* add_parent for Multi_Node */
1587void mfnode_add_parent(struct Multi_Node* node, struct X3D_Node* parent)
1588{
1589 int i;
1590 for(i=0; i!=node->n; ++i) {
1591 ADD_PARENT(node->p[i], parent);
1592 }
1593}
1594
1595
1596/* Parses a field value (literally or IS) */
1597/* Gets the actual value of a field and stores it in a node, or, for an IS statement, adds this node and field as a destination to the appropriate protoFieldDecl */
1598/* Passed pointer to the parser, an offsetPointer structure pointing to the current node and an offset to the field being parsed, type of the event value (i.e. MFString) index in FIELDTYPES, */
1599/* index of the field in the FIELDNAMES (or equivalent) array */
1600/* Parses a field value of a certain type (literally or IS) */
1601void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
1602static BOOL parser_fieldValue(struct VRMLParser* me, struct X3D_Node *node, int offs,
1603 int type, int origFieldE, BOOL protoExpansion, struct ProtoDefinition* pdef, struct ProtoFieldDecl* origField)
1604{
1605#undef PARSER_FINALLY
1606#define PARSER_FINALLY
1607
1608#ifdef CPARSERVERBOSE
1609 printf ("start of parser_fieldValue\n");
1610 printf ("me->curPROTO = %u\n",me->curPROTO);
1611#endif
1612
1613 {
1614#ifdef CPARSERVERBOSE
1615 printf ("parser_fieldValue, not an IS\n");
1616#endif
1617 /* Get a pointer to the actual field */
1618#define myOffsetPointer_deref(t, me) \
1619 ((t)(((char*)(node))+offs))
1620
1621 void* directRet=myOffsetPointer_deref(void*, ret);
1622 deleteMallocedFieldValue(type,directRet);
1623 /* we could print out a type, as shown below for the first element of a Multi_Color:
1624 { struct Multi_Color * mc;
1625 mc = (struct Multi_Color *) directRet;
1626 printf ("directret n is %d\n",mc->n);
1627
1628 printf ("directret orig is %u, %f %f %f\n",
1629 mc->p,
1630 mc->p[0].c[0],
1631 mc->p[0].c[1],
1632 mc->p[0].c[2]);
1633 }
1634 */
1635
1636 PARSER_FINALLY;
1637 #ifdef CPARSERVERBOSE
1638 printf ("parser_fieldValue, me %u, directRet %u\n",me,directRet);
1639 #endif
1640
1641 /* Get the actual value from the file (next token from lexer) and store it as the appropriate type in the node */
1642 return PARSE_TYPE[type](me, directRet);
1643 }
1644
1645#undef PARSER_FINALLY
1646#define PARSER_FINALLY
1647}
1648
1649
1650/* Specific initialization of node fields */
1651void parser_specificInitNode_B(struct X3D_Node* n, struct VRMLParser* me)
1652{
1653#define NODE_SPECIFIC_INIT(type, code) \
1654 case NODE_##type: \
1655 { \
1656 struct X3D_##type* node=(struct X3D_##type*)n; \
1657 code \
1658 break; \
1659 }
1660
1661 switch(n->_nodeType)
1662 {
1663 /* Scripts get a script object associated to them */
1664 NODE_SPECIFIC_INIT(Script, node->__scriptObj=new_Shader_ScriptB(X3D_NODE(node));)
1665 NODE_SPECIFIC_INIT(ShaderProgram, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1666 NODE_SPECIFIC_INIT(PackagedShader, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1667 NODE_SPECIFIC_INIT(ComposedShader, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1668 NODE_SPECIFIC_INIT(Effect, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1669 }
1670}
1671
1672/* ************************************************************************** */
1673/* Built-in fields */
1674/* Parses a built-in field and sets it in node */
1675
1676/*
1677 UNIT statement http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#UNITStatement
1678 unit categories http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/concepts.html#Standardunitscoordinates
1679 problem: not all derived unit categories are represent. Missing:
1680 torque = force * length, ie kg * m**2 / s**2
1681 moment of inertia = mass * length**2, ie kg*m**2
1682 solution:
1683 automatically compute all derived units factors from base unit factors scene designer specifies
1684 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#UNITStatement
1685 "Direct modification of conversion factors for derived units is not allowed."
1686 problem: force is/should be/could be a derived unit
1687 force = mass * length / time**2, ie newton = kg * m / s**2
1688 problem: what if scene designer mixes force and mass incoherently?
1689 Then how should torque factor be calculated - from force or from mass et al?
1690 solution: force is calculated as a derived unit unless explicitly set
1691 then Torque is computed from force
1692
1693 3 kinds of units
1694 #1 length -
1695 option1 one-step: applied during parsing to all length unit fields (with #3.a below)
1696 applied after all node fields are parsed, so geoSystem is known for interpreting geo coords
1697 and so even defaults like Cylinder.height 2.0 are scaled
1698 option2 two-step: applied during rendering as a relative scale between scenefile-contexts
1699 by context-wrapper-transform (see Component_Grouping.c prep_ and fin_unitscale
1700 #2 angle - applied during parsing of literal (authored over-ride of default)
1701 so that defaults aren't scaled
1702 That's because a few like viewpoint.fieldOfView, ArcClose2D.endAngle are already have
1703 common-sense default values SI radians
1704 #3 the others: mass, force and derived units - converted to SI / standard units at parse time
1705 separately for each scene file
1706 a) for #1.option1 one-step derived units - all factors are combined
1707 b) for #1.option2 two-step one length factor is removed from each derived unit that involves length
1708
1709 see src/lib/main/headers.h for latest enum
1710enum {
1711 UNCA_NONE = 0,
1712 UNCA_LENGTH = 1,
1713 UNCA_BLENGTH, //bboxCenter, bboxSize
1714 UNCA_ANGLE,
1715 UNCA_PLANE, //first 3 are plane normal, 4th is scaleable distance
1716 UNCA_MASS,
1717 UNCA_FORCE,
1718 UNCA_ACCEL,
1719 UNCA_ANGLERATE,
1720 UNCA_AREA,
1721 UNCA_SPEED,
1722 UNCA_VOLUME,
1723 UNCA_TORQUE,
1724 UNCA_MOMENT,
1725 UNCA_GEO, //don't know if its angle or length untill geoSystem field parsed
1726};
1727
1728 Oct 4, 2017 current state:
1729 what's working:
1730 one-step and two-step both seem to be working
1731 with 2-step a glitch in particle systems wind physics
1732 geo coords seem to be working with one-step
1733 strict interpretation ie v3.3 is in base units by default, not degrees
1734 force as derived unit unless specified - works
1735 tested with length, angle, geo, RBP mass and speed, particles mass, area, speed
1736 what's missing/uncertain:
1737 - 2 ways to do length:
1738 one-step (parse time)
1739 - uncertainties: which utility/interpolator nodes are in world coords
1740 two-step (render-time for length, parse-time for everything else)
1741 - uncertainties: how handle derived units properly, wrong to scale geo or Layout
1742 - static unca table - assumes only one freewrl instance running in one process
1743 -so only one parsing thread, doing one scenefile at a time
1744 -so static variables here are good for parsing one file, then discarded
1745 - future needs:
1746 -if multiple freewrl instances in one process (browser plugins ...) then move
1747 unca table to gglobal
1748 -if unit converter nodes (proposed by dug9 to web3d) are implemented, then
1749 unca table to resource_item_t or (new) scenefile_table in gglobal,
1750 with pointer stored in each context pointing to units table to use
1751
1752*/
1753
1754#define UNCA_BASE 0X01 //BASE units like angle, length, mass - specified by scene author
1755#define UNCA_DRVD 0x10 //DERIVED units like torque, moments - computed below from base units
1756#define UNCA_BOTH 0x11 //BASE and DERIVED - for force which specs say is base, but could/should/might be scene-authored as derived
1757struct unca {
1758 char *catname;
1759 int iunca;
1760 int lengthpower; //L 0-none 1=length 2=area 3=volume -1 = 1/length -2 = 1/length**2
1761 int derived; //D
1762 int ichanged; //C
1763 double factor; //F
1764 char *uname;
1765} uncas [] = {
1766 //catname iunca L D C F uname
1767 //base
1768 {"length", UNCA_LENGTH, 1,UNCA_BASE,0,1.0,"meters", },
1769 {"angle", UNCA_ANGLE, 0,UNCA_BASE,0,1.0,"radians", },
1770 {"mass", UNCA_MASS, 0,UNCA_BASE,0,1.0,"kilograms", },
1771 //force both derived and base, compute if needed before torque
1772 {"force", UNCA_FORCE, 1,UNCA_BOTH,0,1.0,"newtons", },
1773 //drived, should not need to lookup from scene designer input
1774 {"acceleration",UNCA_ACCEL, 1,UNCA_DRVD,0,1.0,"meters/second**2", },
1775 {"angular_rate",UNCA_ANGLERATE,0,UNCA_DRVD,0,1.0,"radians/second", },
1776 {"area", UNCA_AREA, 2,UNCA_DRVD,0,1.0,"meters**2", },
1777 {"speed", UNCA_SPEED, 1,UNCA_DRVD,0,1.0,"meters/seccond", },
1778 {"volume", UNCA_VOLUME, 3,UNCA_DRVD,0,1.0,"meters**3", },
1779 {"torque", UNCA_TORQUE, 2,UNCA_DRVD,0,1.0,"kg*meters**2/second**2",},
1780 {"moment", UNCA_MOMENT, 2,UNCA_DRVD,0,1.0,"kg*meters**2", },
1781
1782 {NULL,0},
1783};
1784
1785#ifdef _MSC_VER
1786#define strcasecmp _stricmp
1787#endif
1788#define UNITMETHOD_ONESTEP 1 //parse-time for all units
1789#define UNITMETHOD_TWOSTEP 2 //parse-time for non-length, render-time for length
1790static int unitmethod = UNITMETHOD_ONESTEP;
1791static int UNITSTRICT33 = TRUE; //TRUE only web3d version 3.3+ scene files gets units applied as per specs (strict), FALSE any version can have UNITS
1792
1793static int isunits = 0; //#2 the others, parse-time
1794static double unitlengthfactor = 1.0;
1795double getunitlengthfactor(){
1796 return unitlengthfactor;
1797}
1798int isUnits(){
1799 return isunits;
1800}
1801void setUnits(int isOn){
1802 isunits = isOn;
1803}
1804static Stack * units2vec = NULL;
1805void zeroUnits(){
1806 isunits = 0;
1807 if(units2vec) units2vec->n = 0;
1808 unitlengthfactor = 1.0;
1809}
1810static int do_lengthunits = 0;
1811
1812struct unitsB {
1813 char *catname;
1814 int iunca;
1815 int lengthpower; //L 0-none 1=length 2=area 3=volume -1 = 1/length -2 = 1/length**2
1816 int derived; //D
1817 int ichanged; //C
1818 double factor; //F
1819 char uname[40];
1820};
1821enum {
1822 LENGTHMETHOD_NONE = 0,
1823 LENGTHMETHOD_FULL,
1824 LENGTHMETHOD_MINUSONE,
1825};
1826void addUnits(void *ecx, char *category, char *unit, double factor){
1827 struct unitsB u2;
1828 struct unitsB *uptr, *u2length, *u2mass, *u2force, *u2angle;
1829 struct unca *uc;
1830 int i, iuc, lengthmethod;
1831
1832 if(!units2vec || (units2vec->n == 0)){
1833 //set default base units and derived units factors for this scenefile
1834 //by copying from statics
1835 if(!units2vec)
1836 units2vec = newVector(struct unitsB,20);
1837 iuc = 0;
1838 do {
1839 uc = &uncas[iuc];
1840 memcpy(&u2,uc,sizeof(struct unca));
1841 memset(&u2.uname,0,20);
1842 memcpy(&u2.uname[0],uc->uname,min(39,strlen(uc->uname)+1));
1843 vector_pushBack(struct unitsB,units2vec,u2);
1844 iuc++;
1845 }while(uncas[iuc].catname);
1846 }
1847 //find category name in base units (derived not allowed)
1848 for(i=0;i<vectorSize(units2vec);i++){
1849 uptr = vector_get_ptr(struct unitsB,units2vec,i);
1850 if(!strcasecmp(uptr->catname,category)){
1851 //copy in new unit and factor, and set changed flag
1852 if(uptr->derived & UNCA_BASE){
1853 memcpy(&uptr->uname[0],unit,min(39,strlen(unit)+1));
1854 uptr->factor = factor;
1855 uptr->ichanged = TRUE;
1856 if(uptr->iunca == UNCA_LENGTH) {
1857 //for length units, we rescale during rendering
1858 struct X3D_Proto *ec = (struct X3D_Proto*)ecx;
1859 unitlengthfactor = factor;
1860 ec->__unitlengthfactor = unitlengthfactor;
1861 do_lengthunits = TRUE; //tell rendering to apply unitlengthfactor
1862 }
1863 setUnits(TRUE);
1864 }
1865 break;
1866 }
1867 }
1868 //pull out our base units for easy access
1869 u2mass = u2angle = u2length = u2force = NULL;
1870 for(i=0;i<vectorSize(units2vec);i++){
1871 uptr = vector_get_ptr(struct unitsB,units2vec,i);
1872 if(uptr->derived & UNCA_BASE){
1873 switch(uptr->iunca){
1874 case UNCA_MASS:
1875 u2mass = uptr; break;
1876 case UNCA_ANGLE:
1877 u2angle = uptr; break;
1878 case UNCA_LENGTH:
1879 u2length = uptr; break;
1880 case UNCA_FORCE:
1881 u2force = uptr; break;
1882 default:
1883 break;
1884 }
1885 }
1886 }
1887 //recalculate derived units from base units
1888 //WARNING: I'm not sure how much of the length-derived we should be re-factoring here
1889 // because some effects are done by runtime rescaling of the context
1890 // which is a 3D re-scaling
1891 lengthmethod = LENGTHMETHOD_FULL;
1892 if(unitmethod == UNITMETHOD_TWOSTEP)
1893 lengthmethod = LENGTHMETHOD_MINUSONE;
1894 for(i=0;i<vectorSize(units2vec);i++){
1895 uptr = vector_get_ptr(struct unitsB,units2vec,i);
1896 if(uptr->derived & UNCA_DRVD){
1897 double factor = uptr->factor;
1898 switch(uptr->iunca){
1899 case UNCA_FORCE:
1900 if(!uptr->ichanged){
1901 //web3d specs list force as a base unit, not derived.
1902 //but it should be derived, and so if it hasn't been set above
1903 //we compute it here
1904 if(lengthmethod == LENGTHMETHOD_FULL)
1905 factor = u2mass->factor * u2length->factor;
1906 if(lengthmethod == LENGTHMETHOD_MINUSONE)
1907 factor = u2mass->factor;
1908 }
1909 break;
1910 case UNCA_ACCEL:
1911 if(lengthmethod == LENGTHMETHOD_FULL)
1912 factor = u2length->factor;
1913 break;
1914 case UNCA_ANGLERATE:
1915 factor = u2angle->factor;
1916 break;
1917 case UNCA_AREA:
1918 if(lengthmethod == LENGTHMETHOD_FULL)
1919 factor = u2length->factor * u2length->factor;
1920 if(lengthmethod == LENGTHMETHOD_MINUSONE)
1921 factor = u2length->factor;
1922 break;
1923 case UNCA_SPEED:
1924 if(lengthmethod == LENGTHMETHOD_FULL)
1925 factor = u2length->factor;
1926 break;
1927 case UNCA_MOMENT:
1928 // moment of intertia (for rotational momentum)
1929 // mass * length**2
1930 if(lengthmethod == LENGTHMETHOD_FULL)
1931 factor = u2length->factor * u2length->factor * u2mass->factor;
1932 if(lengthmethod == LENGTHMETHOD_MINUSONE)
1933 factor = u2length->factor * u2mass->factor;
1934 if(lengthmethod == LENGTHMETHOD_NONE)
1935 factor = u2mass->factor;
1936 break;
1937 case UNCA_VOLUME:
1938 {
1939 double dpow = 0.0; //remember anything**0 == 1
1940 if(lengthmethod == LENGTHMETHOD_FULL)
1941 dpow = 3.0;
1942 if(lengthmethod == LENGTHMETHOD_MINUSONE)
1943 dpow = 2.0;
1944 factor = pow(u2length->factor,dpow);
1945 }
1946 break;
1947 case UNCA_TORQUE:
1948 // torque = force * length = (mass * length / time**2) * length
1949 if(lengthmethod == LENGTHMETHOD_FULL)
1950 factor = u2force->factor * u2length->factor;
1951 if(lengthmethod == LENGTHMETHOD_MINUSONE)
1952 factor = u2force->factor;
1953 break;
1954 default:
1955 break;
1956 }
1957 uptr->factor = factor;
1958 u2.ichanged = TRUE;
1959 }
1960 }
1961
1962}
1963
1964int doLengthUnits(){
1965 //called by Component_Grouping to see if 2-step units
1966 return ( do_lengthunits && unitmethod == UNITMETHOD_TWOSTEP ) ? TRUE : FALSE;
1967}
1968int isUnitSpecVersionOK(int specversion){
1969 //strict: specs say only versions >= 3.3 of specs should apply UNIT statement units
1970 //called
1971 //a) during parse-time i) after literals parsed ii) after node-parsed
1972 //b) (in component_grouping.c) at render-time for length units if doing 2-step method
1973 return (!UNITSTRICT33 || specversion > 320) ? TRUE : FALSE;
1974}
1975
1976// Oct 4, 2017 change: only ANGLES get units applied at field-literal-parse-time
1977// - to preserve radian defaults not authored-over
1978// other unit types are applied after node is parsed so as to also convert non-authored-over-defaults
1979void sfunitf(int nodetype,char *fieldname, float *var, int n, int iunca) {
1980 int i,k,specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
1981 if(isUnits() && isUnitSpecVersionOK(specversion)){
1982 int ok;
1983 ok = iunca && (iunca == UNCA_ANGLE || iunca == UNCA_ANGLERATE);
1984 if(ok){
1985 struct unitsB *uptr;
1986 for(i=0;i<vectorSize(units2vec);i++){
1987 uptr = vector_get_ptr(struct unitsB,units2vec,i);
1988 if(uptr->iunca == iunca){
1989 for(k=0;k<n;k++){
1990 var[k] *= (float)uptr->factor;
1991 }
1992 break;
1993 }
1994 }
1995 }
1996 }
1997}
1998void mfunitrotation(int nodetype,char *fieldname, struct SFRotation *var, int n, int iunca){
1999 int i,k, specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
2000 if(isUnits() && isUnitSpecVersionOK(specversion)){
2001 //check if we need to convert units on this node->field
2002 int ok;
2003 ok = iunca && (iunca == UNCA_ANGLE || iunca == UNCA_ANGLERATE);
2004 if(ok){
2005 struct unitsB *uptr;
2006 for(i=0;i<vectorSize(units2vec);i++){
2007 uptr = vector_get_ptr(struct unitsB,units2vec,i);
2008 if(uptr->iunca == iunca){
2009 for(k=0;k<n;k++){
2010 var[k].c[3] *= (float)uptr->factor;
2011 }
2012 break;
2013 }
2014 }
2015 }
2016
2017 }
2018}
2019void mfunit3f(int nodetype,char *fieldname, struct SFVec3f *var, int n, int iunca){
2020 int i,k, specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
2021 if(isUnits() && isUnitSpecVersionOK(specversion)){
2022 int ok;
2023 ok = iunca && (iunca == UNCA_ANGLE || iunca == UNCA_ANGLERATE);
2024 if(ok){
2025 struct unitsB *uptr;
2026 for(i=0;i<vectorSize(units2vec);i++){
2027 uptr = vector_get_ptr(struct unitsB,units2vec,i);
2028 if(uptr->iunca == iunca){
2029 for(k=0;k<n;k++){
2030 vecscale3f(var[k].c,var[k].c,(float)uptr->factor);
2031 }
2032 break;
2033 }
2034 }
2035 }
2036
2037 }
2038}
2039
2040void sfunitd(int nodeType,char *fieldname, double *var, int n, int iunca) {
2041 if(isUnits()){
2042 }
2043}
2044int isNodeGeospatial(struct X3D_Node* node);
2045void applyUnitsToNode(struct X3D_Node *node){
2046 //v3.3+ if there were any UNIT statements, apply to the parsed node, so both defaults
2047 // and explicitly/literally set values get converted
2048 //- except angles, do those as literals (above) since already in SI units (fieldOfView, ArcClose2D startAngle endAngle etc)
2049 //parsed-node method - apply unit factors right after node is parsed (all fields parsed)
2050 //this method would scale also defaults not explicitly set in the scenefile
2051 //except angles - continue to do them on literals, to avoid doing it to defaults which are usually
2052 // sensible angles in radians already
2053 int specversion = X3D_PROTO(node->_executionContext)->__specversion;
2054 if(isUnits() && isUnitSpecVersionOK(specversion)){
2055 fieldinfo offsets;
2056 fieldinfo field;
2057 int i,k, ifield;
2058 if(isNodeGeospatial(node)){
2059 struct unitsB *uptr;
2060 int isgeosystemGD;
2061 double factorA, factorL, factorC;
2062
2063 //get unit conversionFactors for angle and length if available
2064 factorA = factorL = factorC = 1.0;
2065 for(i=0;i<vectorSize(units2vec);i++){
2066 uptr = vector_get_ptr(struct unitsB,units2vec,i);
2067 if(uptr->iunca == UNCA_ANGLE) factorA = uptr->factor;
2068 if(uptr->iunca == UNCA_LENGTH) factorL = uptr->factor;
2069 }
2070
2071
2072 //find geoSystem field, to see if GD (geodetic) with lat,long
2073 offsets = (fieldinfo)NODE_OFFSETS[(node)->_nodeType];
2074 ifield = 0;
2075 field = &offsets[ifield];
2076 //printf("\n");
2077 isgeosystemGD = TRUE;
2078 while( field->nameIndex > -1)
2079 {
2080 const char *name = FIELDNAMES[field->nameIndex];
2081 if(!strcmp(name,"geoSystem")){
2082 union anyVrml *value = (union anyVrml*)&((char*)node)[field->offset];
2083 struct Uni_String *ustring = value->mfstring.p[0];
2084 if(strcmp(ustring->strptr,"GD"))
2085 isgeosystemGD = FALSE;
2086 break;
2087 }
2088 ifield++;
2089 field = &offsets[ifield];
2090 } //while fieldindex
2091
2092 //decide what factors apply to first 2 values in SFVec3d
2093 if(isgeosystemGD)
2094 factorC = factorA; //first 2 coords are lat,long in some order, apply angle factor
2095 else
2096 factorC = factorL; //first 2 coords are length either utm N,E or GC x,y, apply length factor
2097
2098 //find all UNCA_GEO fields in node, and apply unit factors
2099 //printf("isGeo ");
2100 offsets = (fieldinfo)NODE_OFFSETS[(node)->_nodeType];
2101 ifield = 0;
2102 field = &offsets[ifield];
2103 //printf("\n");
2104 while( field->nameIndex > -1)
2105 {
2106 int iunca = field->unca;
2107 const char *name = FIELDNAMES[field->nameIndex];
2108 union anyVrml *value = (union anyVrml*)&((char*)node)[field->offset];
2109 if(iunca == UNCA_GEO){
2110 struct SFVec3d *sfvar;
2111 double *dvar;
2112 //angles are done only at literal parse time, not to default field values which are already radians SI
2113 switch(field->typeIndex){
2114 case FIELDTYPE_SFDouble:
2115 //printf("sfdouble ");
2116 value->sfdouble *= factorC; //if SFDouble and lableled UNCA_GEO, assume its lat or long,x or y,east or north
2117 break;
2118 case FIELDTYPE_MFDouble:
2119 //geoelevationgrid.height is done below via LENGTH, not sure where else mfdouble for geo
2120 printf("mfdouble nixpa7 ");
2121 break;
2122 case FIELDTYPE_SFVec3d:
2123 dvar = value->sfvec2d.c;
2124 dvar[0] *= factorC;
2125 dvar[1] *= factorC;
2126 dvar[2] *= factorL;
2127 break;
2128 case FIELDTYPE_MFVec3d:
2129 for(k=0;k<value->mfvec3d.n;k++){
2130 sfvar = &value->mfvec3d.p[k];
2131 dvar = sfvar->c;
2132 dvar[0] *= factorC;
2133 dvar[1] *= factorC;
2134 dvar[2] *= factorL;
2135 }
2136 break;
2137 default:
2138 break;
2139 }
2140 }
2141 ifield++;
2142 field = &offsets[ifield];
2143 } //while fieldindex
2144
2145 }
2146 // apply unitfactors to other non-geo units except angle
2147 offsets = (fieldinfo)NODE_OFFSETS[(node)->_nodeType];
2148 ifield = 0;
2149 field = &offsets[ifield];
2150 //printf("\n");
2151 while( field->nameIndex > -1)
2152 {
2153 int iunca = field->unca;
2154 if(iunca == UNCA_PLANE) iunca = UNCA_LENGTH;
2155 const char *name = FIELDNAMES[field->nameIndex];
2156 union anyVrml *value = (union anyVrml*)&((char*)node)[field->offset];
2157 if(iunca != UNCA_NONE && iunca != UNCA_ANGLE && iunca != UNCA_ANGLERATE && iunca != UNCA_GEO){
2158 //angles are done only at literal parse time, not to default field values which are already radians SI
2159 //geos are done in the loops above
2160 if(!(iunca == UNCA_LENGTH && unitmethod == UNITMETHOD_TWOSTEP)){
2161 //one-step: length done here (two-step done at render time with wrapper scale)
2162 float factor;
2163 struct unitsB *uptr;
2164 factor = 1.0;
2165 for(i=0;i<vectorSize(units2vec);i++){
2166 uptr = vector_get_ptr(struct unitsB,units2vec,i);
2167 if(uptr->iunca == iunca){
2168 factor = (float)uptr->factor;
2169 break;
2170 }
2171 }
2172 iunca = field->unca; //restore if plane
2173 switch(field->typeIndex){
2174 case FIELDTYPE_SFRotation:
2175 value->sfrotation.c[3] *= factor;
2176 break;
2177 case FIELDTYPE_SFFloat:
2178 value->sffloat *= factor;
2179 break;
2180 case FIELDTYPE_MFFloat:
2181 for(i=0;i<value->mffloat.n;i++)
2182 value->mffloat.p[i] *= factor;
2183 break;
2184 case FIELDTYPE_SFVec3f:
2185 vecscale3f(value->sfvec3f.c,value->sfvec3f.c,(float)factor);
2186 break;
2187 case FIELDTYPE_SFVec4f:
2188 if(iunca == UNCA_PLANE)
2189 value->sfvec4f.c[3] *= factor;
2190 else
2191 vecscale4f(value->sfvec4f.c,value->sfvec4f.c,(float)factor);
2192 break;
2193 case FIELDTYPE_SFVec2f:
2194 vecscale2f(value->sfvec2f.c,value->sfvec2f.c,(float)factor);
2195 break;
2196 case FIELDTYPE_MFVec3f:
2197 for(i=0;i<value->mfvec3f.n;i++)
2198 vecscale3f(value->mfvec3f.p[i].c,value->mfvec3f.p[i].c,(float)factor);
2199 break;
2200 case FIELDTYPE_SFMatrix3f:
2201 for(i=0;i<9;i++)
2202 value->sfmatrix3f.c[i] *= factor;
2203 break;
2204 case FIELDTYPE_MFRotation:
2205 for(i=0;i<value->mfrotation.n;i++)
2206 value->mfrotation.p[i].c[3] *= factor;
2207 break;
2208 case FIELDTYPE_SFDouble:
2209 value->sfdouble *= factor;
2210 break;
2211 //missing a few mfdouble, mfvec3d, a few more matrix types...
2212 default:
2213 break;
2214 }
2215 } //if not 2-step lengths
2216 } //if not angles or geo
2217 ifield++;
2218 field = &offsets[ifield];
2219 } //while fieldindex
2220 } //if isunits
2221}
2222
2223
2224/* The init codes used. */
2225#define INIT_CODE_sfnode(var,fieldname) \
2226 ADD_PARENT(node2->var, X3D_NODE(node2));
2227#define INIT_CODE_mfnode(var,fieldname) \
2228 mfnode_add_parent(&node2->var, X3D_NODE(node2));
2229#define INIT_CODE_sfbool(var,fieldname)
2230#define INIT_CODE_sfcolor(var,fieldname)
2231#define INIT_CODE_sfcolorrgba(var,fieldname)
2232#define INIT_CODE_sffloat(var,fieldname) sfunitf(node2->_nodeType,fieldname, (float*)&node2->var, 1,iunca);
2233#define INIT_CODE_sfimage(var,fieldname)
2234#define INIT_CODE_sfint32(var,fieldname)
2235#define INIT_CODE_sfrotation(var,fieldname) sfunitf(node2->_nodeType,fieldname, &node2->var.c[3], 1,iunca);
2236#define INIT_CODE_sfstring(var,fieldname)
2237#define INIT_CODE_sftime(var,fieldname)
2238#define INIT_CODE_sfvec2f(var,fieldname) sfunitf(node2->_nodeType,fieldname, node2->var.c, 2, iunca);
2239#define INIT_CODE_sfvec3f(var,fieldname) sfunitf(node2->_nodeType,fieldname, node2->var.c, 3, iunca);
2240#define INIT_CODE_sfvec3d(var,fieldname)
2241#define INIT_CODE_mfbool(var,fieldname)
2242#define INIT_CODE_mfcolor(var,fieldname)
2243#define INIT_CODE_mfcolorrgba(var,fieldname)
2244#define INIT_CODE_mffloat(var,fieldname) sfunitf(node2->_nodeType,fieldname,node2->var.p, node2->var.n,iunca);
2245#define INIT_CODE_mfint32(var,fieldname)
2246#define INIT_CODE_mfrotation(var,fieldname) mfunitrotation(node2->_nodeType,fieldname, node2->var.p, node2->var.n,iunca);
2247#define INIT_CODE_mfstring(var,fieldname)
2248#define INIT_CODE_mftime(var,fieldname)
2249#define INIT_CODE_mfvec2f(var,fieldname)
2250#define INIT_CODE_mfvec3f(var,fieldname) mfunit3f(node2->_nodeType,fieldname, node2->var.p, node2->var.n, iunca);
2251#define INIT_CODE_mfvec3d(var,fieldname)
2252#define INIT_CODE_sfdouble(var,fieldname)
2253#define INIT_CODE_mfdouble(var,fieldname)
2254#define INIT_CODE_sfvec4d(var,fieldname)
2255#define INIT_CODE_mfmatrix3f(var,fieldname)
2256#define INIT_CODE_mfmatrix4f(var,fieldname)
2257
2258#define INIT_CODE_mfmatrix3d(var,fieldname)
2259#define INIT_CODE_mfmatrix4d(var,fieldname)
2260#define INIT_CODE_mfvec2d(var,fieldname)
2261#define INIT_CODE_mfvec4d(var,fieldname)
2262#define INIT_CODE_mfvec4f(var,fieldname)
2263#define INIT_CODE_sfmatrix3d(var,fieldname)
2264#define INIT_CODE_sfmatrix3f(var,fieldname) sfunitf(node2->_nodeType,fieldname,node2->var.c, 9,iunca);
2265#define INIT_CODE_sfmatrix4d(var,fieldname)
2266#define INIT_CODE_sfmatrix4f(var,fieldname)
2267#define INIT_CODE_sfvec2d(var,fieldname)
2268#define INIT_CODE_sfvec4f(var,fieldname) {if(iunca==UNCA_PLANE) sfunitf(node2->_nodeType,fieldname, &node2->var.c[3], 1, UNCA_LENGTH); else sfunitf(node2->_nodeType,fieldname, node2->var.c, 4, iunca); }
2269
2270/* Parses a fieldvalue for a built-in field and sets it in node */
2271static BOOL parser_field_B(struct VRMLParser* me, struct X3D_Node* node)
2272{
2273 int fieldO;
2274 int fieldE;
2275 int iunca;
2276 //BOOL retval;
2277 DECLAREUP
2278 ASSERT(me->lexer);
2279
2280 /* printf ("start of parser_field, me->lexer->nextIn :%s:\n",me->lexer->nextIn); */
2281
2282 /* Ask the lexer to find the field (next lexer token) in either the FIELDNAMES array or
2283 the EXPOSED_FIELD array. The index of the field in the array is returned in fieldO
2284 (if found in FIELDNAMES) or fieldE (if found in EXPOSED_FIELD).
2285 If the fieldname is found in neither array, lexer_field will return FALSE. */
2286 SAVEUP
2287
2288 if(!lexer_field(me->lexer, &fieldO, &fieldE, NULL, NULL))
2289 {
2290 /* If lexer_field does return false, this is an inputOnly/outputOnly IS user_definedField statement.
2291 Add a Offset_Pointer structure to the dests list for the protoFieldDecl for
2292 the user defined field. The Offset_Pointer structure contains a pointer to the node currently
2293 being parsed along with an offset that references the field that is linked to the
2294 user defined field.
2295
2296 i.e. for a statement "rotation IS myrot" the protoFieldDecl for myrot is retrieved,
2297 and an Offset_Pointer structure is added to the dests list which contains a pointer
2298 to the current node and the offset for the "rotation" field in that node.
2299
2300 If we've done all this, then we've parsed the field statement completely, and we return. */
2301 BACKUP
2302 return FALSE;
2303 }
2304 FREEUP
2305 /* Ignore all events */
2306#define EVENT_IN(n, f, t, v, realType)
2307#define EVENT_OUT(n, f, t, v, realType)
2308
2309 /* End of node is the same for fields and inputOutputs */
2310#define END_NODE(type) \
2311 } \
2312 } \
2313 break;
2314
2315/* The field type indices */
2316#define FTIND_sfnode FIELDTYPE_SFNode
2317#define FTIND_sfbool FIELDTYPE_SFBool
2318#define FTIND_sfcolor FIELDTYPE_SFColor
2319#define FTIND_sfcolorrgba FIELDTYPE_SFColorRGBA
2320#define FTIND_sffloat FIELDTYPE_SFFloat
2321#define FTIND_sfimage FIELDTYPE_SFImage
2322#define FTIND_sfint32 FIELDTYPE_SFInt32
2323#define FTIND_sfrotation FIELDTYPE_SFRotation
2324#define FTIND_sfstring FIELDTYPE_SFString
2325#define FTIND_sftime FIELDTYPE_SFTime
2326#define FTIND_sfdouble FIELDTYPE_SFDouble
2327#define FTIND_sfvec2f FIELDTYPE_SFVec2f
2328#define FTIND_sfvec2d FIELDTYPE_SFVec2d
2329#define FTIND_sfvec3f FIELDTYPE_SFVec3f
2330#define FTIND_sfvec3d FIELDTYPE_SFVec3d
2331#define FTIND_sfvec4f FIELDTYPE_SFVec4f
2332#define FTIND_sfvec4d FIELDTYPE_SFVec4d
2333#define FTIND_sfmatrix3f FIELDTYPE_SFMatrix3f
2334#define FTIND_sfmatrix4f FIELDTYPE_SFMatrix4f
2335#define FTIND_sfmatrix3d FIELDTYPE_SFMatrix3d
2336#define FTIND_sfmatrix4d FIELDTYPE_SFMatrix4d
2337
2338#define FTIND_mfnode FIELDTYPE_MFNode
2339#define FTIND_mfbool FIELDTYPE_MFBool
2340#define FTIND_mfcolor FIELDTYPE_MFColor
2341#define FTIND_mfcolorrgba FIELDTYPE_MFColorRGBA
2342#define FTIND_mffloat FIELDTYPE_MFFloat
2343#define FTIND_mfint32 FIELDTYPE_MFInt32
2344#define FTIND_mfrotation FIELDTYPE_MFRotation
2345#define FTIND_mfstring FIELDTYPE_MFString
2346#define FTIND_mfimage FIELDTYPE_MFImage
2347#define FTIND_mftime FIELDTYPE_MFTime
2348#define FTIND_mfvec2f FIELDTYPE_MFVec2f
2349#define FTIND_mfvec2d FIELDTYPE_MFVec2d
2350#define FTIND_mfvec3f FIELDTYPE_MFVec3f
2351#define FTIND_mfvec3d FIELDTYPE_MFVec3d
2352#define FTIND_mfvec4d FIELDTYPE_MFVec4d
2353#define FTIND_mfvec4f FIELDTYPE_MFVec4f
2354#define FTIND_mfdouble FIELDTYPE_MFDouble
2355#define FTIND_mfmatrix3f FIELDTYPE_MFMatrix3f
2356#define FTIND_mfmatrix4f FIELDTYPE_MFMatrix4f
2357#define FTIND_mfmatrix3d FIELDTYPE_MFMatrix3d
2358#define FTIND_mfmatrix4d FIELDTYPE_MFMatrix4d
2359
2360/* Process a field (either exposed or ordinary) generally */
2361/* For a normal "field value" (i.e. position 1 0 1) statement gets the actual value of the field
2362 from the file (next token(s) to be processed) and stores it in the node
2363 For an IS statement, adds this node-field combo as a destination to the appropriate protoFieldDecl */
2364#define PROCESS_FIELD_B(exposed, node, field, fieldType, var, fe, junca) \
2365 case exposed##FIELD_##field: \
2366 if(!parser_fieldValue(me, \
2367 X3D_NODE(node2), (int) offsetof(struct X3D_##node, var), \
2368 FTIND_##fieldType, fe, FALSE, NULL, NULL)) {\
2369 PARSE_ERROR("Expected " #fieldType " Value for a fieldtype!") }\
2370 iunca = junca; \
2371 INIT_CODE_##fieldType(var,#field) \
2372 return TRUE;
2373
2374 //INIT_CODE_##fieldType(var) \ we're doing this add_parent during instancing as of feb 2013
2375 //return TRUE;
2376
2377/* Default action if node is not encountered in list of known nodes */
2378#define NODE_DEFAULT_B \
2379 default: \
2380 PARSE_ERROR("Parser PROCESS_FIELD_B, Unsupported node!")
2381
2382/* printf ("at XXX, fieldE = %d, fieldO = %d nodeType %s\n",fieldE, fieldO,stringNodeType (node->_nodeType));
2383 if (fieldE!=ID_UNDEFINED) printf (".... field is %s\n",EXPOSED_FIELD[fieldE]);
2384 if (fieldO!=ID_UNDEFINED) printf (".... field is %s\n",FIELD[fieldO]); */
2385
2386/* Field was found in EXPOSED_FIELD list. Parse value or IS statement */
2387if(fieldE!=ID_UNDEFINED)
2388 switch(node->_nodeType)
2389{
2390
2391/* Processes exposed fields for node */
2392#define BEGIN_NODE(type) \
2393 case NODE_##type: \
2394 { \
2395 struct X3D_##type* node2=(struct X3D_##type*)node; \
2396 /* printf ("at YYY, in case for node %s\n",stringNodeType(NODE_##type)); */ \
2397 UNUSED(node2); /* for compiler warning reductions */ \
2398 switch(fieldE) \
2399 {
2400
2401/* Process exposed fields */
2402#define EXPOSED_FIELD(node, field, fieldType, var, realType,iunca) \
2403 PROCESS_FIELD_B(EXPOSED_, node, field, fieldType, var, fieldE,iunca)
2404
2405/* Ignore just fields */
2406#define FIELD(n, f, t, v, realType,iunca)
2407
2408/* Process it */
2409#include "NodeFields.h"
2410
2411/* Undef the field-specific macros */
2412#undef BEGIN_NODE
2413#undef FIELD
2414#undef EXPOSED_FIELD
2415
2416NODE_DEFAULT_B
2417
2418}
2419
2420/* Field was found in FIELDS list. Parse value or IS statement */
2421if(fieldO!=ID_UNDEFINED)
2422 switch(node->_nodeType)
2423{
2424
2425 /* Processes ordinary fields for node */
2426#define BEGIN_NODE(type) \
2427 case NODE_##type: \
2428 { \
2429 struct X3D_##type* node2=(struct X3D_##type*)node; \
2430 UNUSED(node2); /* for compiler warning reductions */ \
2431 switch(fieldO) \
2432 {
2433
2434 /* Process fields */
2435#define FIELD(node, field, fieldType, var, realType,iunca) \
2436 PROCESS_FIELD_B(, node, field, fieldType, var, ID_UNDEFINED,iunca)
2437
2438 /* Ignore exposed fields */
2439#define EXPOSED_FIELD(n, f, t, v, realType,iunca)
2440
2441 /* Process it */
2442#include "NodeFields.h"
2443
2444 /* Undef the field-specific macros */
2445#undef BEGIN_NODE
2446#undef FIELD
2447#undef EXPOSED_FIELD
2448
2449 NODE_DEFAULT_B
2450
2451 }
2452
2453/* Clean up */
2454#undef END_NODE
2455#undef EVENT_IN
2456#undef EVENT_OUT
2457
2458/* If field was found, return TRUE; would have happened! */
2459PARSE_ERROR("Unsupported field for node!")
2460 return FALSE;
2461 }
2462
2463
2464static BOOL parser_field(struct VRMLParser* me, struct X3D_Node* node)
2465{
2466 return parser_field_B(me,node);
2467}
2468static union anyVrml ignore_field;
2469static BOOL found_ignore_field(struct VRMLParser* me, struct X3D_Node* node)
2470{
2471 int mode;
2472 int type;
2473 int source;
2474 int ifield;
2475 char *nodeFieldName;
2476 DECLAREUP
2477 union anyVrml *targetVal;
2478 void *fdecl;
2479
2480 //get the fieldname
2481 SAVEUP //save the lexer spot so if it's not a 'fieldname <fieldValue>' we can backup
2482 /* get nodeFieldName */
2483 if(!lexer_setCurID(me->lexer)) return FALSE;
2484 ASSERT(me->lexer->curID);
2485 nodeFieldName = STRDUP(me->lexer->curID);
2486
2487 FREE_IF_NZ(me->lexer->curID);
2488
2489 //retrieve field mode, type
2490 targetVal = &ignore_field;
2491 if(strcmp(nodeFieldName,"_xy")){
2492 BACKUP
2493 FREE_IF_NZ(nodeFieldName);
2494 return FALSE; //couldn't find field in user or builtin fields anywhere
2495 }
2496 type = FIELDTYPE_SFVec2f;
2497 if (!parseType(me, type, targetVal)) {
2498 /* Invalid default value parsed. Delete the proto or script declaration. */
2499 CPARSE_ERROR_CURID("Expected default value for field!");
2500 //if(pdecl) deleteProtoFieldDecl(pdecl);
2501 //if(sdecl) deleteScriptFieldDecl(sdecl);
2502 FREE_IF_NZ(nodeFieldName);
2503 return FALSE;
2504 }
2505 FREEUP
2506 FREE_IF_NZ(nodeFieldName);
2507 return TRUE;
2508}
2509
2510/* ************************************************************************** */
2511/* MF* field values */
2512
2513/* take a USE field, and stuff it into a Multi*type field - see parser_mf routines below */
2514
2515static void stuffDEFUSE(struct Multi_Node *outMF, vrmlNodeT in, int type) {
2516 /* printf ("stuff_it_in, got vrmlT vector successfully - it is a type of %s\n",stringNodeType(in->_nodeType));
2517 printf ("stuff_it_in, ret is %d\n",out); */
2518
2519 /* convert, say, a X3D_something to a struct Multi_Node { int n; int *p; }; */
2520 switch (type) {
2521 /* convert the node pointer into the "p" field of a Multi_MFNode */
2522 case FIELDTYPE_MFNode:
2523 /*struct Multi_Node { int n; void * *p; };*/
2524 outMF->n=1;
2525 outMF->p=MALLOC(void *, sizeof(struct X3D_Node*));
2526 outMF->p[0] = in;
2527 break;
2528
2529 case FIELDTYPE_MFFloat:
2530 case FIELDTYPE_MFBool:
2531 case FIELDTYPE_MFInt32:
2532 case FIELDTYPE_MFTime:
2533 case FIELDTYPE_MFDouble:
2534 case FIELDTYPE_MFColor:
2535 case FIELDTYPE_MFColorRGBA:
2536 case FIELDTYPE_MFRotation:
2537 case FIELDTYPE_MFVec2f:
2538 case FIELDTYPE_MFVec3f:
2539 case FIELDTYPE_MFVec4f:
2540 case FIELDTYPE_MFVec2d:
2541 case FIELDTYPE_MFVec3d:
2542 case FIELDTYPE_MFVec4d:
2543 case FIELDTYPE_MFString:
2544 case FIELDTYPE_MFImage:
2545 case FIELDTYPE_MFMatrix3f:
2546 case FIELDTYPE_MFMatrix4f:
2547 case FIELDTYPE_MFMatrix3d:
2548 case FIELDTYPE_MFMatrix4d:
2549 { size_t localSize;
2550 localSize = returnRoutingElementLength(convertToSFType(type)); /* converts MF to equiv SF type */
2551 /* struct Multi_Float { int n; float *p; }; */
2552 /* treat these all the same, as the data type is same size */
2553 outMF->n=1;
2554 outMF->p=MALLOC(void *, localSize);
2555 memcpy (&outMF->p[0], &in, localSize);
2556 break;
2557 }
2558 default: {
2559 ConsoleMessage("VRML Parser; stuffDEFUSE, unhandled type");
2560 }
2561 }
2562}
2563
2564
2565/* if we expect to find a MF field, but the user only puts a SF Field, we make up the MF field with
2566 1 entry, and copy the data over */
2567static void stuffSFintoMF(struct Multi_Node *outMF, vrmlNodeT *inSF, int type) {
2568 int rsz;
2569 int elelen;
2570 int i;
2571
2572 /* printf ("stuffSFintoMF, got vrmlT vector successfully - it is a type of %s\n",FIELDTYPES[type]); */
2573
2574 rsz = returnElementRowSize(type);
2575 elelen = returnElementLength(type);
2576
2577 /* printf ("stuffSFintoMF - rowsize %d length %d\n",rsz,elelen); */
2578
2579 /* convert, say, a X3D_something to a struct Multi_Node { int n; int *p; }; */
2580 /* convert the node pointer into the "p" field of a Multi_MFNode */
2581
2582 /* struct Multi_Float { int n; float *p; }; */
2583 /* struct Multi_Vec3f { int n; struct SFColor *p; }; */
2584 /* treat these all the same, as the data type is same size */
2585
2586 /* is the "old" size something other than 1? */
2587 /* I am not sure when this would ever happen, but one never knows... */
2588
2589 /* free up old memory here */
2590 for (i=0; i<outMF->n; i++) {
2591 if (type == FIELDTYPE_MFString) {
2592 struct Uni_String *m = (struct Uni_String *)outMF->p[i];
2593 /* printf ("freeing string :%s:\n",m->strptr); */
2594 FREE_IF_NZ(m->strptr);
2595 }
2596
2597 }
2598
2599 if (outMF->n != 1) {
2600 /* printf ("deleting pointer %p\n",outMF->p); */
2601 FREE_IF_NZ(outMF->p);
2602 outMF->n=1;
2603 outMF->p=MALLOC(void *, rsz * elelen);
2604 }
2605
2606 /* { float *ptr; ptr = (float *) in; for (n=0; n<rsz; n++) { printf ("float %d is %f\n",n,*ptr); ptr++; } } */
2607
2608 memcpy (outMF->p, inSF, rsz * elelen);
2609}
2610
2611/* Parse a MF* field */
2612#define PARSER_MFFIELD(name, type) \
2613 static BOOL parser_mf##name##Value(struct VRMLParser* me, void *ret) { \
2614 struct Vector* vec; \
2615 vrmlNodeT RCX; \
2616 struct Multi_##type *rv; \
2617 RCX = NULL; \
2618 vec = NULL; \
2619 \
2620 /* printf ("start of a mfield parse for type %s curID :%s: me %u lexer %u\n",FIELDTYPES[FIELDTYPE_MF##type], me->lexer->curID,me,me->lexer); */ \
2621 /* printf (" str :%s:\n",me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]); */ \
2622 /* if (me->lexer->curID != NULL) printf ("parser_MF, have %s\n",me->lexer->curID); else printf("parser_MF, NULL\n"); */ \
2623\
2624 if (!(me->parsingX3DfromXML)) { \
2625 /* is this a USE statement? */ \
2626 if(lexer_keyword(me->lexer, KW_USE)) { \
2627 /* printf ("parser_MF, got a USE!\n"); */ \
2628 /* Get a pointer to the X3D_Node structure for this DEFed node and return it in ret */ \
2629 RCX=parse_KW_USE(me); \
2630 if (RCX == NULL) return FALSE; \
2631 /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2632 stuffDEFUSE(ret, RCX, FIELDTYPE_MF##type); \
2633 return TRUE; \
2634 } \
2635 \
2636 else if (lexer_keyword(me->lexer, KW_DEF)) { \
2637 /* printf ("parser_MF, got the DEF!\n"); */ \
2638 /* Get a pointer to the X3D_Node structure for this DEFed node and return it in ret */ \
2639 RCX=parse_KW_DEF(me); \
2640 if (RCX == NULL) return FALSE; \
2641 \
2642 /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2643 stuffDEFUSE(ret, RCX, FIELDTYPE_MF##type); \
2644 return TRUE; \
2645 } \
2646 }\
2647\
2648/* printf ("step 2... curID :%s:\n", me->lexer->curID); */ \
2649/* possibly a SFNodeish type value?? */ \
2650if (me->lexer->curID != NULL) { \
2651 /* printf ("parser_MF, curID was not null (it is %s) me %u lexer %u... lets just parse node\n",me->lexer->curID,me,me->lexer); */ \
2652 if (!parser_node(me, &RCX, ID_UNDEFINED)) { \
2653 return FALSE; \
2654 } \
2655 if (RCX == NULL) return FALSE; \
2656 /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2657 stuffDEFUSE(ret, RCX, FIELDTYPE_MF##type); \
2658 return TRUE; \
2659 } \
2660/* Just a single value? */ \
2661/* NOTE: the XML parser will ALWAYS give this without the brackets */ \
2662if((!lexer_openSquare(me->lexer)) && (!(me->parsingX3DfromXML))) { \
2663 vrml##type##T RCXRet; \
2664 /* printf ("parser_MF, not an opensquare, lets just parse node\n"); */ \
2665 if(!parser_sf##name##Value(me, &RCXRet)) { \
2666 return FALSE; \
2667 } \
2668 /* printf ("after sf parse rcx %u\n",RCXRet); */ \
2669 /* RCX is the return value, if this value IN THE VRML FILE IS ZERO, then this valid parse will fail... */ \
2670 /* so it is commented out if (RCX == NULL) return FALSE; */ \
2671 /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2672 stuffSFintoMF(ret, (vrmlNodeT *)&RCXRet, FIELDTYPE_MF##type); \
2673 return TRUE; \
2674} \
2675\
2676 /* Otherwise, a real vector */ \
2677 /* printf ("parser_MF, this is a real vector:%s:\n",me->lexer->nextIn); */ \
2678 vec=newVector(vrml##type##T, 128); \
2679 if (!me->parsingX3DfromXML) { \
2680 while(!lexer_closeSquare(me->lexer)) { \
2681 vrml##type##T val; \
2682 if(!parser_sf##name##Value(me, &val)) { \
2683 CPARSE_ERROR_CURID("ERROR:Expected \"]\" before end of MF-Value") \
2684 break; \
2685 } \
2686 vector_pushBack(vrml##type##T, vec, val); \
2687 } \
2688 } else { \
2689 lexer_skip(me->lexer); \
2690 while(*me->lexer->nextIn != '\0') { \
2691 vrml##type##T val; \
2692 if(!parser_sf##name##Value(me, &val)) { \
2693 CPARSE_ERROR_CURID("ERROR:Expected \"]\" before end of MF-Value") \
2694 break; \
2695 } \
2696 vector_pushBack(vrml##type##T, vec, val); \
2697 lexer_skip(me->lexer); \
2698 } \
2699 }\
2700 rv = (struct Multi_##type*) ret; \
2701 rv->n=vectorSize(vec); \
2702 rv->p=vector_releaseData(vrml##type##T, vec); \
2703 \
2704 deleteVector(vrml##type##T, vec); \
2705 return TRUE; \
2706 }
2707
2708
2709 PARSER_MFFIELD(bool, Bool)
2710 PARSER_MFFIELD(color, Color)
2711 PARSER_MFFIELD(colorrgba, ColorRGBA)
2712 PARSER_MFFIELD(float, Float)
2713 PARSER_MFFIELD(int32, Int32)
2714 PARSER_MFFIELD(node, Node)
2715 PARSER_MFFIELD(rotation, Rotation)
2716 PARSER_MFFIELD(string, String)
2717 PARSER_MFFIELD(time, Time)
2718 PARSER_MFFIELD(double, Double)
2719 PARSER_MFFIELD(vec2f, Vec2f)
2720 PARSER_MFFIELD(vec3f, Vec3f)
2721 PARSER_MFFIELD(vec3d, Vec3d)
2722 PARSER_MFFIELD(vec2d, Vec2d)
2723 PARSER_MFFIELD(vec4f, Vec4f)
2724 PARSER_MFFIELD(vec4d, Vec4d)
2725 PARSER_MFFIELD(image, Image)
2726 PARSER_MFFIELD(matrix3f, Matrix3f)
2727 PARSER_MFFIELD(matrix4f, Matrix4f)
2728 PARSER_MFFIELD(matrix3d, Matrix3d)
2729 PARSER_MFFIELD(matrix4d, Matrix4d)
2730
2731/* ************************************************************************** */
2732/* SF* field values */
2733
2734/* Parses a fixed-size vector-field of floats (SFColor, SFRotation, SFVecXf) */
2735#define PARSER_FIXED_VEC(name, type, cnt) \
2736 BOOL parser_sf##name##Value(struct VRMLParser* me, void* ret) \
2737 { \
2738 int i; \
2739 vrml##type##T *rv; \
2740 ASSERT(me->lexer); \
2741 rv = (vrml##type##T *) ret; \
2742 for(i=0; i!=cnt; ++i) {\
2743 if(!parser_sffloatValue(me, rv->c+i)) \
2744 return FALSE; \
2745 }\
2746 return TRUE; \
2747 }
2748
2749/* Parses a fixed-size vector-field of floats (SFColor, SFRotation, SFVecXf) */
2750#define PARSER_FIXED_DOUBLE_VEC(name, type, cnt) \
2751 BOOL parser_sf##name##Value(struct VRMLParser* me, void* ret) \
2752 { \
2753 int i; \
2754 vrml##type##T *rv; \
2755 ASSERT(me->lexer); \
2756 rv = (vrml##type##T *) ret; \
2757 for(i=0; i!=cnt; ++i) {\
2758 if(!parser_sfdoubleValue_(me, rv->c+i)) \
2759 return FALSE; \
2760 }\
2761 return TRUE; \
2762 }
2763
2764 BOOL parser_sfdoubleValue_(struct VRMLParser* me, vrmlDoubleT* ret)
2765 {
2766 return lexer_double(me->lexer, ret);
2767 }
2768static BOOL parser_sffloatValue_(struct VRMLParser* me, void* ret)
2769 {
2770 vrmlFloatT *rf;
2771 rf = (vrmlFloatT*)ret;
2772 return lexer_float(me->lexer, rf);
2773 }
2774static BOOL parser_sfint32Value_(struct VRMLParser* me, void* ret)
2775 {
2776 vrmlInt32T* rf;
2777 rf = (vrmlInt32T*)ret;
2778 return lexer_int32(me->lexer, rf);
2779 }
2780
2781
2782
2783static BOOL set_X3Dstring(struct VRMLLexer* me, vrmlStringT* ret) {
2784 /* printf ("lexer_X3DString, setting string to be :%s:\n",me->startOfStringPtr[me->lexerInputLevel]); */
2785 *ret=newASCIIString((char *)me->startOfStringPtr[me->lexerInputLevel]);
2786 return TRUE;
2787}
2788
2789static BOOL parser_sfstringValue_(struct VRMLParser* me, void* ret) {
2790 vrmlStringT* rv;
2791
2792 rv = (vrmlStringT*)ret;
2793
2794 /* are we parsing the "classic VRML" formatted string? Ie, one with
2795 starting and finishing quotes? */
2796 if (!me->parsingX3DfromXML) return lexer_string(me->lexer, rv);
2797
2798 else return set_X3Dstring(me->lexer, rv);
2799
2800 return TRUE;
2801}
2802
2803static BOOL parser_sfboolValue(struct VRMLParser* me, void* ret) {
2804 vrmlBoolT *rv;
2805
2806 rv = (vrmlBoolT*)ret;
2807
2808 /* are we in the VRML (x3dv) parser? */
2809 if (!me->parsingX3DfromXML) {
2810 //try proper TRUE FALSE
2811 if(lexer_keyword(me->lexer, KW_TRUE)) {
2812 *rv=TRUE;
2813 return TRUE;
2814 }
2815 if(lexer_keyword(me->lexer, KW_FALSE)) {
2816 *rv=FALSE;
2817 return TRUE;
2818 }
2819 //try x3d true false
2820 if(lexer_keyword(me->lexer, KW_true)) {
2821 *rv=TRUE;
2822 return TRUE;
2823 }
2824 if(lexer_keyword(me->lexer, KW_false)) {
2825 *rv=FALSE;
2826 return TRUE;
2827 }
2828 return FALSE;
2829 }else{
2830 //try proper x3d true false
2831 if(lexer_keyword(me->lexer, KW_true)) {
2832 *rv=TRUE;
2833 return TRUE;
2834 }
2835 if(lexer_keyword(me->lexer, KW_false)) {
2836 *rv=FALSE;
2837 return TRUE;
2838 }
2839 //try wrl stype TRUE FALSE
2840 if(lexer_keyword(me->lexer, KW_TRUE)) {
2841 *rv=TRUE;
2842 return TRUE;
2843 }
2844 if(lexer_keyword(me->lexer, KW_FALSE)) {
2845 *rv=FALSE;
2846 return TRUE;
2847 }
2848
2849 return FALSE;
2850
2851 }
2852 /*
2853 // possibly, this is from the XML Parser
2854 if (!strncmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"true",4)) {
2855 *rv = TRUE;
2856 return TRUE;
2857 }
2858 if (!strncmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"false",5)) {
2859 *rv = FALSE;
2860 return TRUE;
2861 }
2862 // possibly this is from the XML parser, but there is a case problem
2863 if (!gglobal()->internalc.global_strictParsing && (!strcmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"TRUE"))) {
2864 CPARSE_ERROR_CURID("found upper case TRUE in XML file - should be lower case");
2865 *rv = TRUE;
2866 return TRUE;
2867 }
2868 if (!gglobal()->internalc.global_strictParsing && (!strcmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"FALSE"))) {
2869 CPARSE_ERROR_CURID ("found upper case FALSE in XML file - should be lower case");
2870 *rv = FALSE;
2871 return TRUE;
2872 }
2873 */
2874
2875
2876
2877 /* Noperooni - this was from X3D, but did not parse */
2878 *rv = FALSE;
2879 return FALSE;
2880}
2881
2882 PARSER_FIXED_VEC(color, Color, 3)
2883 PARSER_FIXED_VEC(colorrgba, ColorRGBA, 4)
2884 PARSER_FIXED_VEC(rotation, Rotation, 4)
2885 PARSER_FIXED_VEC(vec2f, Vec2f, 2)
2886 PARSER_FIXED_VEC(vec3f, Vec3f, 3)
2887 PARSER_FIXED_VEC(vec4f, Vec4f, 4)
2888 PARSER_FIXED_DOUBLE_VEC(vec2d, Vec2d, 2)
2889 PARSER_FIXED_DOUBLE_VEC(vec3d, Vec3d, 3)
2890 PARSER_FIXED_DOUBLE_VEC(vec4d, Vec4d, 4)
2891 PARSER_FIXED_VEC(matrix3f, Matrix3f, 9)
2892 PARSER_FIXED_VEC(matrix4f, Matrix4f, 16)
2893 PARSER_FIXED_DOUBLE_VEC(matrix3d, Matrix3d, 9)
2894 PARSER_FIXED_DOUBLE_VEC(matrix4d, Matrix4d, 16)
2895
2896/* JAS this code assumes that the ret points to a SFInt_32 type, and just
2897 fills in the values. */
2898
2899 static BOOL parser_sfimageValue(struct VRMLParser* me, void* ret)
2900 {
2901 vrmlImageT *rv;
2902 vrmlInt32T width, height, depth;
2903 vrmlInt32T* ptr;
2904
2905 rv = (vrmlImageT*) ret;
2906
2907 if(!lexer_int32(me->lexer, &width))
2908 return FALSE;
2909 if(!lexer_int32(me->lexer, &height))
2910 return FALSE;
2911 if(!lexer_int32(me->lexer, &depth))
2912 return FALSE;
2913
2914
2915 rv->arr.n=width*height;
2916 rv->arr.p=MALLOC(int *, sizeof(int) * rv->arr.n);
2917 rv->whc[0]=width;
2918 rv->whc[1]=height;
2919 rv->whc[2]=depth;
2920
2921 for(ptr=rv->arr.p; ptr!=rv->arr.p+rv->arr.n; ++ptr)
2922 if(!lexer_int32(me->lexer, ptr))
2923 {
2924 FREE_IF_NZ(rv->arr.p);
2925 rv->arr.n=0;
2926 return FALSE;
2927 }
2928
2929 return TRUE;
2930 }
2931
2932
2933static BOOL parser_sfnodeValue(struct VRMLParser* me, void* ret) {
2934 intptr_t tmp;
2935 vrmlNodeT* rv;
2936
2937 ASSERT(me->lexer);
2938 rv = (vrmlNodeT*)ret;
2939
2940 if(lexer_keyword(me->lexer, KW_NULL)) {
2941 *rv=NULL;
2942 return TRUE;
2943 }
2944
2945 /* are we parsing from a proto expansion? */
2946 if (!me->parsingX3DfromXML) {
2947 return parser_nodeStatement(me, rv);
2948 } else {
2949 /* expect something like a number (memory pointer) to be here */
2950 // https://stackoverflow.com/questions/15610053/correct-printf-format-specifier-for-size-t-zu-or-iu
2951 if (sscanf(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel], "%zu", & tmp) != 1) {
2952 CPARSE_ERROR_FIELDSTRING ("error finding SFNode id on line :%s:",
2953 me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]);
2954 *rv=NULL;
2955 return FALSE;
2956 }
2957 *rv = (vrmlNodeT)tmp;
2958 }
2959 return TRUE;
2960}
2961
2962
2963static BOOL parser_sftimeValue(struct VRMLParser* me, void* ret)
2964 {
2965 vrmlTimeT *rv;
2966 rv = (vrmlTimeT*)ret;
2967 return lexer_double(me->lexer, rv);
2968 }
2969
2970static BOOL parser_sfdoubleValue(struct VRMLParser* me, void* ret)
2971{
2972 vrmlDoubleT* rv;
2973 rv = (vrmlDoubleT*)ret;
2974 return lexer_double(me->lexer, rv);
2975}
2976
2977
2978static BOOL parser_fieldTypeNotParsedYet(struct VRMLParser* me, void* ret) {
2979 CPARSE_ERROR_CURID ("received a request to parse a type not supported yet");
2980 return FALSE;
2981}
2982
2983
2984/* prettyprint this error */
2985 #define OUTLINELEN 800
2986 #define FROMSRC 140
2987void cParseErrorCurID(struct VRMLParser *me, char *str) {
2988 char fw_outline[OUTLINELEN];
2989 ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
2990
2991 if (strlen(str) > FROMSRC) { //str[FROMSRC] = '\0';
2992 memcpy(fw_outline,str,FROMSRC);
2993 fw_outline[FROMSRC-1] = '\0';
2994 }else{
2995 strcpy(fw_outline,str);
2996 }
2997 if (me->lexer->curID != ((void *)0)) {
2998 strcat (fw_outline, "; current token :");
2999 strcat (fw_outline, me->lexer->curID);
3000 strcat (fw_outline, ": ");
3001 }
3002 if (me->lexer->nextIn != NULL) {
3003 strcat (fw_outline," at: \"");
3004 strncat(fw_outline,me->lexer->nextIn,FROMSRC);
3005 if (strlen(me->lexer->nextIn) > FROMSRC)
3006 strcat (fw_outline,"...");
3007 strcat (fw_outline,"\"");
3008 }
3009
3010 p->foundInputErrors++;
3011 ConsoleMessage(fw_outline);
3012}
3013
3014void cParseErrorFieldString(struct VRMLParser *me, char *str, const char *str2) {
3015
3016 char fw_outline[OUTLINELEN];
3017 int str2len = (int) strlen(str2);
3018 ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
3019
3020 if (strlen(str) > FROMSRC) str[FROMSRC] = '\0';
3021 strcpy(fw_outline,str);
3022 strcat (fw_outline," (");
3023 strncat (fw_outline,str2,str2len);
3024 strcat (fw_outline, ") ");
3025 if (me->lexer->curID != ((void *)0)) strcat (fw_outline, me->lexer->curID);
3026 if (me->lexer->nextIn != NULL) {
3027 strcat (fw_outline," at: \"");
3028 strncat(fw_outline,me->lexer->nextIn,FROMSRC);
3029 if (strlen(me->lexer->nextIn) > FROMSRC)
3030 strcat (fw_outline,"...");
3031 strcat (fw_outline,"\"");
3032 }
3033
3034 p->foundInputErrors++;
3035 ConsoleMessage(fw_outline);
3036}
3037
3038//
3039//
3040// ******************** BROTO section *********************************************************
3041//
3042//
3043
3044/*
3045Sept 2014
3046X3D_Proto is now being used for non-node entities as well as ProtoInstance:
3047a) protoInstance PI
3048b) protoDeclare PD
3049c) externProtoInstance EPI
3050d) externProtoDeclare EPD
3051e) sceneInstance SI (rootNodes parent, deep)
3052f) protoLibrary PL (scene declare, shallow)
3053
3054WRL Parsing now uses the same code for both scene and protoBody, recursing as deep as needed,
3055and uses a 'depth' flag for deciding whether to instance what its parsing (ie for scene) or not
3056(protoDeclares, shallow).
3057
3058deep - instancing a live scene, so nodes are registered, routes are registered, scripts are registered, PIs are deep copied
3059shallow - we are in a protoDeclare -perhaps in its body- so we just copy the interface of any contained PIs for routing,
3060 we do not register nodes, scripts, or do any binding
3061
3062executionContext EC: scene or protoBody (according to specs), basically a name context, and where routes are supposed to be
3063
3064X3D_Proto fields
3065 void * __DEFnames; //besides giving def names to the parser, it also saves them in a Vector per-EC
3066 void * __IS; //the IS keyword details are parsed to this, per EC, and a function generates browser ROUTES if deep
3067 void * __ROUTES; //ROUTES are saved here per EC, as well as registered with browser when deep
3068 void * __afterPound; //for EPD, if url is myfile.wrl#Geom then Geom is the afterPound, and is the name of the desired PD in the proto library
3069 void * __externProtoDeclares; //besides giving EPD type names back to parser, the EPDs are stored here per-EC
3070 void * __loadResource; //for network types, like EPD, this is the resource its monitoring that's downloading the PL
3071 int __loadstatus; //for network types like EPD, helps EPD advance step-wise on each visit, as the resource is loaded and parsed
3072 struct X3D_Node *__parentProto; //parent EC, when instancing
3073 void * __protoDeclares; //besides giving PD type name back to parser, the parsed PD is stored here per-EC
3074 void * __nodes; //flat table of malloced builtin and x3d_proto nodes (for future recursive startofloopnodeupdates and/or node-wise GC)
3075 void * __subcontexts; //flat table of any protoInstances/externProtoInstances and Inlines (for future recursive startofloopnodeupdates, routing, script running, sensor running)
3076 void * __GC; //Garbage collection table - vector of mallocs to free, from Vectors, vector elements, strdups etc
3077 void * __protoDef; //struct for holding user fields, as used for Script, Proto
3078 int __protoFlags; //char [4] 0) deep=1, shallow=0 1) 1 means useBrotos=0 old way 2) 0-declare 1-instance 2-scene 3) extern=1, else 0
3079 struct X3D_Node *__prototype; //for PI, EPI: will be PD, EPD, so when deep_copying it can get the body
3080 void * __scripts; //stores script nodes parsed here per EC as well as registering with browser when instancing
3081 void * __typename; //for PD,EPD (and PI, EPI): besides giving PD user-defined type name (vs builtin type) back to parser, its stored here
3082 struct Multi_String __url; //for network types like EPD - the parsed URL for downloading
3083 void * _parentResource; //for network types, like EPD, this is a resource_item_t * of the main scene, to get its absolute URL in resource_identify
3084
3085 //familiar fields:
3086 struct Multi_Node _children; //same use as children[] field in Group/Transform, except hidden as _children for some scenes t85.wrl that name a user field as children
3087 struct Multi_Node _sortedChildren;
3088 struct Multi_Node addChildren;
3089 struct X3D_Node *metadata;
3090 struct Multi_Node removeChildren;
3091 struct SFVec3f bboxCenter;
3092 struct SFVec3f bboxSize;
3093*/
3094
3095
3096
3097/* Parses a node (node non-terminal) */
3098/* Looks up the node type on the builtin NODES list and the userNodeNames list.
3099 If this is a builtin node type, creates a new X3D_Node structure of the appropriate type for the node,
3100 and then parses the statements for that node.
3101 For each field statement, gets the value for that field and stores it in the X3D_Node structure.
3102 For each ROUTE statement, adds the route to the CRoutes table.
3103 For each PROTO statement, adds the PROTO definition to the PROTOs list.
3104 Return a pointer to the X3D_Node structure that holds the information for this node.
3105 If this is a user-defined node type (i.e. a PROTO expansion/instance), complete the proto expansion/instance
3106 For each field in the ProtoDefinition either parse and propagate the specified value for this field, or
3107 propagate the default value of the field. (i.e. copy the appropriate value into every node/field combination in
3108 the dests list.)
3109 For each route in the routes list of the ProtoDefinition, add the route to the CRoutes table.
3110 Return a pointer to the X3D_Node structure that is the scenegraph for this PROTO.
3111*/
3112struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep);
3113static BOOL parser_field_user(struct VRMLParser* me, struct X3D_Node *node);
3114static BOOL parser_interfaceDeclarationB(struct VRMLParser* me, struct ProtoDefinition* proto, struct Shader_Script* script);
3115void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest);
3116void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url);
3117void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
3118
3119static BOOL parser_externbrotoStatement(struct VRMLParser* me);
3120static BOOL parser_node_B(struct VRMLParser* me, vrmlNodeT* ret, int ind) {
3121 int nodeTypeB, nodeTypeU, isBroto;
3122 struct X3D_Node* node=NULL;
3123 struct X3D_Proto *currentContext;
3124 char pflagdepth;
3125 struct Shader_Script* script=NULL;
3126 struct Shader_Script* shader=NULL;
3127 DECLAREUP
3128 //struct X3D_Node* what_am_I = X3D_NODE(me->ptr);
3129 currentContext = (struct X3D_Proto*)me->ectx;
3130 pflagdepth = ciflag_get(currentContext->__protoFlags,0); //((char *)(&currentContext->__protoFlags))[0];
3131
3132
3133 ASSERT(me->lexer);
3134 *ret=node; /* set this to NULL, for now... if this is a real node, it will return a node pointer */
3135
3136 /* lexer_node( ... ) #defined to lexer_specialID(me, r1, r2, NODES, NODES_COUNT, userNodeTypesVec) where userNodeTypesVec is a list of PROTO defs */
3137 /* this will get the next token (which will be the node type) and search the NODES array for it. If it is found in the NODES array nodeTypeB will be set to
3138 the index of type in the NODES array. If it is not in NODES, the list of user-defined nodes will be searched for the type. If it is found in the user-defined
3139 list nodeTypeU will be set to the index of the type in userNodeTypesVec. A return value of FALSE indicates that the node type wasn't found in either list */
3140
3141#ifdef CPARSERVERBOSE
3142 printf ("parser_node START, curID :%s: nextIn :%s:\n",me->lexer->curID, me->lexer->nextIn);
3143#endif
3144
3145
3146//#define XBLOCK_STATEMENT_B(LOCATION)
3147 if(parser_routeStatement(me)) {
3148 return TRUE;
3149 }
3150
3151 if (parser_componentStatement(me)) {
3152 return TRUE;
3153 }
3154
3155 if (parser_exportStatement(me)) {
3156 return TRUE;
3157 }
3158
3159 if (parser_importStatement(me)) {
3160 return TRUE;
3161 }
3162
3163 if (parser_metaStatement(me)) {
3164 return TRUE;
3165 }
3166
3167 if (parser_profileStatement(me)) {
3168 return TRUE;
3169 }
3170 if(parser_brotoStatement(me)) {
3171 return TRUE;
3172 }
3173 if(parser_externbrotoStatement(me)) {
3174 return TRUE;
3175 }
3176
3177
3178
3179
3180 if(!lexer_node(me->lexer, &nodeTypeB, &nodeTypeU)) {
3181#ifdef CPARSERVERBOSE
3182 printf ("parser_node, not lexed - is this one of those special nodes?\n");
3183#endif
3184 return FALSE;
3185 }
3186
3187 /* printf ("after lexer_node, at this point, me->lexer->curID :%s:\n",me->lexer->curID); */
3188 /* could this be a proto expansion?? */
3189
3190 /* Checks that the next non-whitespace non-comment character is '{' and skips it. */
3191 if(!lexer_openCurly(me->lexer))
3192 PARSE_ERROR("Expected { after node-type id!")
3193
3194#ifdef CPARSERVERBOSE
3195 printf ("parser_node: have nodeTypeB %d nodeTypeU %d\n",nodeTypeB, nodeTypeU);
3196#endif
3197 isBroto = FALSE;
3198 if (nodeTypeU != ID_UNDEFINED) {
3199 /* The node name was located in userNodeTypesVec (list of defined PROTOs),
3200 therefore this is an attempt to instantiate a PROTO */
3201 /* expand this PROTO, put the code right in line, and let the parser
3202 go over it as if there was never a proto here... */
3203 struct X3D_Proto *proto; //, *currentContext;
3204 char *protoname = vector_get(char*, me->lexer->userNodeTypesVec, nodeTypeU);
3205 //currentContext = (struct X3D_Proto*)me->ptr;
3206 //BOOL isAvailableBroto(char *pname, struct X3D_Proto* currentContext, struct X3D_Proto **proto);
3207 //struct X3D_Proto *shallowBrotoInstance(X3D_Proto* proto);
3208 if( isAvailableBroto(protoname, currentContext , &proto))
3209 {
3210 /* its a binary proto, new in 2013 */
3211 int idepth = 0; //if its old brotos (2013) don't do depth until sceneInstance. If 2014 broto2, don't do depth here if we're in a protoDeclare or externProtoDeclare
3212 idepth = pflagdepth == 1; //2014 broto2: if we're parsing a scene (or Inline) then deepcopy proto to instance it, else shallow
3213 node=X3D_NODE(brotoInstance(proto,idepth));
3214 node->_executionContext = X3D_NODE(currentContext); //me->ptr;
3215 add_node_to_broto_context(currentContext,node);
3216 //moved below, for all nodes if(idepth) add_parent(node,X3D_NODE(currentContext),__FILE__,__LINE__); //helps propagate VF_Sensitive to parent of proto, if proto's 1st node is sensor
3217 isBroto = TRUE;
3218 ASSERT(node);
3219 if (ind != ID_UNDEFINED) {
3220 char *name;
3221 /* Set the top memmber of the DEFed nodes stack to this node */
3222 vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind)=node;
3223#ifdef CPARSERVERBOSE
3224 printf("parser_node: adding DEFed node (pointer %p) to DEFedNodes vector\n", node);
3225#endif
3226 name = vector_get(char*, stack_top(struct Vector*, me->lexer->userNodeNames), ind);
3227 broto_store_DEF((struct X3D_Proto*)(me->ectx),node, name);
3228 }
3229 }
3230 }
3231
3232 /* Built-in node */
3233 /* Node was found in NODES array */
3234 if(nodeTypeB!=ID_UNDEFINED) {
3235#ifdef CPARSERVERBOSE
3236 printf("parser_node: parsing builtin node\n");
3237#endif
3238
3239 /* Get malloced struct of appropriate X3D_Node type with default values filled in */
3240 if(pflagdepth){
3241 node=X3D_NODE(createNewX3DNode((int)nodeTypeB)); //registers node types like sensors, textures in tables for scene
3242 if(node->_nodeType == NODE_Inline){
3243 if(X3D_NODE(me->ectx)->_nodeType != NODE_Inline && X3D_NODE(me->ectx)->_nodeType != NODE_Proto)
3244 printf("ouch trying to caste a %d nodetype to inline or proto\n",X3D_NODE(me->ectx)->_nodeType);
3245 X3D_INLINE(node)->__parentProto = me->ectx;
3246 }
3247 }else{
3248 node=X3D_NODE(createNewX3DNode0((int)nodeTypeB)); //doesn't register node types in tables, for protoDeclare
3249 }
3250 node->_executionContext = X3D_NODE(currentContext); //me->ptr;
3251 add_node_to_broto_context(currentContext,node);
3252 ASSERT(node);
3253
3254 /* if ind != ID_UNDEFINED, we have the first node of a DEF. Save this node pointer, in case
3255 some code uses it. eg: DEF xx Transform {children Script {field yy USE xx}} */
3256 if (ind != ID_UNDEFINED) {
3257 /* Set the top memmber of the DEFed nodes stack to this node */
3258 char *name;
3259 vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind)=node;
3260 name = vector_get(char*, stack_top(struct Vector*, me->lexer->userNodeNames), ind);
3261 broto_store_DEF((struct X3D_Proto*)(me->ectx),node, name);
3262
3263#ifdef CPARSERVERBOSE
3264 printf("parser_node: adding DEFed node (pointer %p) to DEFedNodes vector\n", node);
3265#endif
3266 }
3267
3268
3269 /* Node specific initialization */
3270 /* From what I can tell, this only does something for Script nodes. It sets node->__scriptObj to new_Shader_Script() */
3271 parser_specificInitNode_B(node, me);
3272
3273 /* Set flag for Shaders/Scripts - these ones can have any number of fields */
3274 switch (node->_nodeType) {
3275 case NODE_Script: script=X3D_SCRIPT(node)->__scriptObj; break;
3276 case NODE_ShaderProgram: shader=(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
3277 case NODE_PackagedShader: shader=(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
3278 case NODE_ComposedShader: shader=(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
3279 case NODE_Effect: shader=(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
3280 case NODE_LayerSet:
3281 push_binding_stack_set(node); break;
3282 case NODE_LayoutLayer:
3283 case NODE_Layer:
3284 push_next_layerId_from_binding_stack_set(node); break;
3285 default: {}
3286 }
3287 } /*endif nodetypeB*/
3288
3289 /* As long as the lexer is returning field statements, ROUTE statements,
3290 or PROTO statements continue parsing node */
3291
3292 /* to get IS handling in the main scene parsing code including for Script user fields
3293 I split up the script interface parser so it only creates the field, then
3294 BACKUPs the lexer and lets field_user and found_IS take a crack at it
3295 */
3296 if( (nodeTypeB!=ID_UNDEFINED) || isBroto)
3297 {
3298 #define SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING 1
3299 while(TRUE)
3300 {
3301 /* Try to parse the next statement as a field. For normal "field value" statements
3302 (i.e. position 1 0 1) this gets the value of the field from the lexer (next token(s)
3303 to be processed) and stores it as the appropriate type in the node.
3304 For IS statements (i.e. position IS mypos) this adds the node-field combo
3305 (as an offsetPointer) to the dests list for the protoFieldDecl associated with the user
3306 defined field (in the given case, this would be mypos). */
3307#ifdef CPARSERVERBOSE
3308 printf("parser_node: try parsing field ... \n");
3309#endif
3310 //if( found_ignore_field(me,node)){
3311 // continue;
3312 //}
3313 /* check for IS - can be any mode, and builtin or user field on builtin node or usernode/protoInstance */
3314 if( found_IS_field(me,node) ){
3315 continue;
3316 }
3317
3318 if(SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING)
3319 if(parser_field_user(me,node)) {
3320 continue;
3321 }
3322
3323 /*check for builtin field value on builtin node or usernode/protoInstance*/
3324 if(parser_field(me, node)) {
3325#ifdef CPARSERVERBOSE
3326 printf("parser_node: field parsed\n");
3327#endif
3328 continue;
3329 }
3330
3331
3332 /* Try to parse the next statement as a ROUTE (i.e. statement starts with ROUTE). This checks that the ROUTE statement is valid (i.e. that the referenced node and field combinations
3333 exist, and that they are compatible) and then adds the route to either the CRoutes table of routes, or adds a new ProtoRoute structure to the vector
3334 ProtoDefinition->routes if we are parsing a PROTO */
3335#ifdef CPARSERVERBOSE
3336 printf("parser_node: try parsing ROUTE ... \n");
3337#endif
3338
3339 /* try ROUTE, COMPONENT, EXPORT, IMPORT, META, PROFILE statements here */
3340 SAVEUP
3341 BLOCK_STATEMENT(parser_node);
3342
3343 /* Try to parse the next statement as a PROTO (i.e. statement starts with PROTO). */
3344 /* Add the PROTO name to the userNodeTypesVec list of names. Create and fill in a new protoDefinition structure and add it to the PROTOs list.
3345 Goes through the interface declarations for the PROTO and adds each user-defined field name to the appropriate list of user-defined names (user_initializeOnly,
3346 user_inputOnly, Out, or user_inputOutput), creates a new protoFieldDecl for the field and adds it to the iface vector of the ProtoDefinition,
3347 and, in the case of fields and inputOutputs, gets the default value of the field and stores it in the protoFieldDecl.
3348 Parses the body of the PROTO. Nodes are added to the scene graph for this PROTO. Routes are parsed and a new ProtoRoute structure
3349 is created for each one and added to the routes vector of the ProtoDefinition. PROTOs are recursively parsed!
3350 */
3351#ifdef CPARSERVERBOSE
3352 printf("parser_node: try parsing PROTO ... \n");
3353#endif
3354 BACKUP
3355
3356// if(parser_protoStatement(me)) {
3357//#ifdef CPARSERVERBOSE
3358// printf("parser_node: PROTO parsed\n");
3359//#endif
3360// continue;
3361// }
3362
3363 if(parser_brotoStatement(me)) {
3364#ifdef CPARSERVERBOSE
3365 printf("parser_vrmlScene: BROTO parsed\n");
3366#endif
3367 continue;
3368 }
3369
3370#ifdef CPARSERVERBOSE
3371 printf("parser_node: try parsing Script or Shader field\n");
3372#endif
3373
3374 /* check for user field declaration on builtin node of type script or shaderprogram
3375 'mode fieldtype fieldname <fieldvalue>'
3376 and create the field
3377 aside: protoDeclares and protoInstances handled elsewhere:
3378 - protoInstance 'fieldname fieldvalue' are handled like builtins in found_IS and parser_field
3379 - protoDeclare 'mode fieldtype fieldname <fieldvalue>' are handled in parser_protostatement
3380 */
3381 if(SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING) //this one just adds the field, and leave it to others to parse the 'fieldname fieldvalue'
3382 if(script && parser_interfaceDeclarationB(me, NULL, script)){
3383 continue;
3384 }
3385 if(!SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING)
3386 if(script && parser_interfaceDeclaration(me, NULL, script)) {
3387#ifdef CPARSERVERBOSE
3388 printf("parser_node: SCRIPT field parsed\n");
3389#endif
3390 continue;
3391 }
3392
3393 if(shader && parser_interfaceDeclaration(me, NULL, shader)) {
3394#ifdef CPARSERVERBOSE
3395 printf("parser_node: Shader field parsed\n");
3396#endif
3397 continue;
3398 }
3399
3400 break;
3401 }
3402
3403 applyUnitsToNode(node);
3404 /* Init code for Scripts */
3405 if(script) {
3406#ifdef CPARSERVERBOSE
3407 printf("parser_node: try parsing SCRIPT url\n");
3408#endif
3409 if(pflagdepth) //broto1: do this later in sceneInstance broto2: do it during instancing here and brotoInstance
3410 //script_initCodeFromMFUri(script, &X3D_SCRIPT(node)->url);
3411 initialize_one_script(script,&X3D_SCRIPT(node)->url);
3412#ifdef CPARSERVERBOSE
3413 printf("parser_node: SCRIPT url parsed\n");
3414#endif
3415 } /* nodetypeB or brotoInstance */
3416
3417 if(isBroto && pflagdepth){
3418 //copying the body _after_ the protoInstance field values have been parsed
3419 //allows ISd fields in body nodes to get the pkw_initializeOnly/inputOutput value
3420 //from the protoInstance interface
3421 //if(1){
3422 // deep_copy_broto_body2(&X3D_PROTO(X3D_PROTO(node)->__prototype),&X3D_PROTO(node));
3423 //}else{
3424 struct X3D_Proto *ptype, *pdest;
3425 ptype = X3D_PROTO(X3D_PROTO(node)->__prototype);
3426 pdest = X3D_PROTO(node);
3427 deep_copy_broto_body2(&ptype,&pdest);
3428 //}
3429 }
3430 // if(pflagdepth) add_parent(node,parent??,__FILE__,__LINE__); //helps propagate VF_Sensitive to parent of proto, if proto's 1st node is sensor. We do in macro PROCESS_FIELD_B
3431
3432 /* We must have a node that we've parsed at this point. */
3433 ASSERT(node);
3434 }
3435
3436 /* Check that the node is closed by a '}', and skip this token */
3437#ifdef CPARSERVERBOSE
3438 printf ("calling lexer_closeCurly at B\n");
3439#endif
3440
3441 if(!lexer_closeCurly(me->lexer)) {
3442 CPARSE_ERROR_CURID("ERROR: Expected a closing brace after fields of a node;")
3443 PARSER_FINALLY;
3444 return FALSE;
3445 }
3446 if(node->_nodeType == NODE_LayerSet)
3447 pop_binding_stack_set();
3448
3449 /* Return the parsed node */
3450
3451 #ifdef CPARSERVERBOSE
3452 printf ("returning at end of parser_node, ret %u\n",node);
3453 if (node != NULL) printf ("and, node type is %s\n",stringNodeType(node->_nodeType));
3454 #endif
3455 *ret=node;
3456 return TRUE;
3457}
3458
3459
3460//#include "broto1.h"
3461/* mode fieldtype fieldname <fieldValue>
3462 Goal: just create the field and let other functions parse fieldvalue
3463 read the first 3 tokens, Quality Assure them.
3464 create the field, iniitalize to bzero
3465 add the field to proto/script field list
3466 if mode is field (not event) backup lexer to fieldname
3467 exit
3468 (and other functions will parse and set fieldValue)
3469*/
3470static BOOL parser_interfaceDeclarationB(struct VRMLParser* me, struct ProtoDefinition* proto, struct Shader_Script* script) {
3471 int mode;
3472 int type;
3473 int name;
3474 DECLAREUP
3475 union anyVrml defaultVal;
3476 struct ProtoFieldDecl* pdecl=NULL;
3477 //struct ProtoFieldDecl* pField=NULL;
3478 struct ScriptFieldDecl* sdecl=NULL;
3479 //char *startOfField = NULL;
3480 //int startOfFieldLexerLevel = INT_ID_UNDEFINED;
3481
3482
3483#ifdef CPARSERVERBOSE
3484 printf ("start of parser_interfaceDeclaration\n");
3485#endif
3486
3487
3488 /* Either PROTO or Script interface! */
3489 ASSERT((proto || script) && !(proto && script));
3490
3491 /* lexer_protoFieldMode is #defined as
3492 lexer_specialID(me, r, NULL, PROTOKEYWORDS, PROTOKEYWORDS_COUNT, NULL) */
3493 /* Looks for the next token in the array PROTOKEYWORDS (inputOnly, outputOnly, inputOutput, field)
3494 and returns the appropriate index in mode */
3495 SAVEUP
3496 if(!lexer_protoFieldMode(me->lexer, &mode)) {
3497#ifdef CPARSERVERBOSE
3498 printf ("parser_interfaceDeclaration, not lexer_protoFieldMode, returning\n");
3499#endif
3500 BACKUP
3501 return FALSE;
3502 }
3503
3504 /* Script can not take inputOutputs */
3505 if(0) // change in post-DUK era - we allow inputoutputs now
3506 if (script != NULL) {
3507 if(script->ShaderScriptNode->_nodeType==NODE_Script && mode==PKW_inputOutput)
3508 {
3509 PARSE_ERROR("Scripts must not have inputOutputs!")
3510 //printf("dug9: maybe scripts can have inputOutputs\n");
3511 }
3512 }
3513
3514 /* lexer_fieldType is #defined as lexer_specialID(me, r, NULL, FIELDTYPES, FIELDTYPES_COUNT, NULL) */
3515 /* Looks for the next token in the array FIELDTYPES and returns the index in type */
3516 if(!lexer_fieldType(me->lexer, &type))
3517 PARSE_ERROR("Expected fieldType after proto-field keyword!")
3518
3519#ifdef CPARSERVERBOSE
3520 printf ("parser_interfaceDeclaration, switching on mode %s\n",PROTOKEYWORDS[mode]);
3521#endif
3522
3523 //save fieldname - if field (not event) we'll back up here when we exit
3524 //so something else can parse IS or fieldValue
3525 SAVEUP
3526
3527 switch(mode)
3528 {
3529#define LEX_DEFINE_FIELDID(suff) \
3530 case PKW_##suff: \
3531 if(!lexer_define_##suff(me->lexer, &name)) \
3532 PARSE_ERROR("Expected fieldNameId after field type!") \
3533 break;
3534
3535 LEX_DEFINE_FIELDID(initializeOnly)
3536 LEX_DEFINE_FIELDID(inputOnly)
3537 LEX_DEFINE_FIELDID(outputOnly)
3538 LEX_DEFINE_FIELDID(inputOutput)
3539
3540
3541
3542#ifndef NDEBUG
3543 default:
3544 ASSERT(FALSE);
3545#endif
3546 }
3547
3548 /* If we are parsing a PROTO, create a new protoFieldDecl.
3549 If we are parsing a Script, create a new scriptFieldDecl. */
3550 if(proto) {
3551#ifdef CPARSERVERBOSE
3552 printf ("parser_interfaceDeclaration, calling newProtoFieldDecl\n");
3553#endif
3554
3555 pdecl=newProtoFieldDecl(mode, type, name);
3556 //pdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
3557
3558#ifdef CPARSERVERBOSE
3559 printf ("parser_interfaceDeclaration, finished calling newProtoFieldDecl\n");
3560#endif
3561 } else {
3562#ifdef CPARSERVERBOSE
3563 printf ("parser_interfaceDeclaration, calling newScriptFieldDecl\n");
3564#endif
3565 //lexer_stringUser_fieldName(me,name,mod)
3566 sdecl=newScriptFieldDecl(me->lexer, mode, type, name);
3567 //sdecl=newScriptFieldDecl(lexer_stringUser_fieldName(me->lexer,name,mod), mode, type, name);
3568 //sdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
3569
3570 }
3571
3572
3573 /* If this is a field or an exposed field give it a bzero default value*/
3574 if(mode==PKW_initializeOnly || mode==PKW_inputOutput) {
3575#ifdef CPARSERVERBOSE
3576 printf ("parser_interfaceDeclaration, mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
3577#endif
3578 bzero (&defaultVal, sizeof (union anyVrml));
3579
3580 /* Store the default field value in the protoFieldDeclaration or scriptFieldDecl structure */
3581 if(proto) {
3582 pdecl->defaultVal=defaultVal;
3583 }
3584 else
3585 {
3586 ASSERT(script);
3587 //defaultVal.sfcolor.c[1] = .333;
3588 scriptFieldDecl_setFieldValue(sdecl, defaultVal);
3589 }
3590 }
3591
3592 /* Add the new field declaration to the list of fields in the Proto or Script definition.
3593 For a PROTO, this means adding it to the iface vector of the ProtoDefinition.
3594 For a Script, this means adding it to the fields vector of the ScriptDefinition. */
3595 if(proto) {
3596 /* protoDefinition_addIfaceField is #defined as vector_pushBack(struct ProtoFieldDecl*, (me)->iface, field) */
3597 /* Add the protoFieldDecl structure to the iface vector of the protoDefinition structure */
3598 protoDefinition_addIfaceField(proto, pdecl);
3599 } else {
3600 /* Add the scriptFieldDecl structure to the fields vector of the Script structure */
3601 ASSERT(script);
3602 vector_pushBack(struct ScriptFieldDecl*, script->fields, sdecl);
3603 //script_addField(script, sdecl); //this also registered the field. We'll do that during sceneInstance
3604 }
3605
3606 #ifdef CPARSERVERBOSE
3607 printf ("end of parser_interfaceDeclaration\n");
3608 #endif
3609 //if(mode == PKW_initializeOnly || mode == PKW_inputOutput)
3610 BACKUP //backup so something else parses 'fieldname <fieldvalue>' or 'fieldname IS protofieldname'
3611 //if it's just fieldname -it's an event with no IS- parser_field_user will detect and just swallow the fieldname
3612 //else
3613 //{
3614 // FREE_IF_NZ(me->lexer->curID); //event - swallow fieldname
3615 //}
3616 return TRUE;
3617}
3618
3619BOOL find_anyfield_by_name(struct VRMLLexer* lexer, struct X3D_Node* node, union anyVrml **anyptr, int *imode, int *itype, char* nodeFieldName, int *isource, void **fdecl, int *ifield);
3620void scriptFieldDecl_jsFieldInit(struct ScriptFieldDecl* me, int num);
3621
3622// OLD_IPHONE_AQUA #ifdef AQUA
3623// OLD_IPHONE_AQUA #include <malloc/malloc.h>
3624// OLD_IPHONE_AQUA #else
3625
3626#include <malloc.h>
3627
3628// OLD_IPHONE_AQUA #endif
3629
3630static BOOL parser_field_user(struct VRMLParser* me, struct X3D_Node *node) {
3631 int mode;
3632 int type;
3633 //int user;
3634 int source;
3635 int ifield;
3636 char *nodeFieldName;
3637 //int len;
3638 DECLAREUP
3639 //struct ProtoDefinition* proto;
3640 //struct Shader_Script* shader;
3641 union anyVrml *targetVal;
3642 void *fdecl;
3643 //struct ProtoFieldDecl* pdecl=NULL;
3644 //struct ProtoFieldDecl* pField=NULL;
3645 //struct ScriptFieldDecl* sdecl=NULL;
3646
3647
3648#ifdef CPARSERVERBOSE
3649 printf ("start of parser_field_user\n");
3650#endif
3651
3652
3653 /* Either PROTO or Script interface! */
3654 //ASSERT((proto || script) && !(proto && script));
3655
3656 //get the fieldname
3657 SAVEUP //save the lexer spot so if it's not a 'fieldname <fieldValue>' we can backup
3658 /* get nodeFieldName */
3659 if(!lexer_setCurID(me->lexer)) return FALSE;
3660 ASSERT(me->lexer->curID);
3661 //len = strlen(me->lexer->curID);
3662 //nodeFieldName = alloca(len+1); //this also works but hard to verify cleanup
3663 //nodeFieldName = MALLOCV(len+1); //also works
3664 //strcpy(nodeFieldName,me->lexer->curID);
3665 nodeFieldName = STRDUP(me->lexer->curID);
3666 //nodeFieldName= me->lexer->curID;
3667 //if(!nodeFieldName){
3668 // nodeFieldName = "";
3669 //}
3670
3671 //BACKUP;
3672 FREE_IF_NZ(me->lexer->curID);
3673
3674 //retrieve field mode, type
3675 targetVal = NULL;
3676 if(!find_anyfield_by_name(me->lexer,node,&targetVal,&mode,&type,nodeFieldName,&source,&fdecl,&ifield)){
3677 //if(!find_anyfield_by_name(me->lexer,node,&targetVal,&mode,&type,me->lexer->curID,&source,&fdecl,&ifield)){
3678 BACKUP
3679 FREE_IF_NZ(nodeFieldName);
3680 return FALSE; //couldn't find field in user or builtin fields anywhere
3681 }
3682 if(source < 1){
3683 BACKUP
3684 FREE_IF_NZ(nodeFieldName);
3685 return FALSE; //we don't want builtins -handled elsewhere- just user fields
3686 }
3687
3688 /* If this is a field or an exposed field */
3689 if(mode==PKW_initializeOnly || mode==PKW_inputOutput) {
3690#ifdef CPARSERVERBOSE
3691 printf ("parser_field_user, mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
3692#endif
3693
3694 /* set the defaultVal to something - we might have a problem if the parser expects this to be
3695 a MF*, and there is "garbage" in there, as it will expect to free it. */
3696 //bzero (&defaultVal, sizeof (union anyVrml)); //default val pulled from existing field default
3697 deleteMallocedFieldValue(type,targetVal);
3698 if (!parseType(me, type, targetVal)) {
3699 /* Invalid default value parsed. Delete the proto or script declaration. */
3700 CPARSE_ERROR_CURID("Expected default value for field!");
3701 //if(pdecl) deleteProtoFieldDecl(pdecl);
3702 //if(sdecl) deleteScriptFieldDecl(sdecl);
3703 FREE_IF_NZ(nodeFieldName);
3704 return FALSE;
3705 }
3706 if(source==3){
3707 //externProtoDeclares don't set an initial value, yet externProtoInstances copy the declare fields, even if junk or null
3708 // (versus regular protoDeclares which must set initial field values on inputOutput/initializeOnly)
3709 //so the alreadySet flag is to say that the EPI had a value set here, and when
3710 //filling out a late-ariving externprotodefinition EPD, only EPI fields that were initialzed are copied to the child PI
3711 //-see load_externProtoInstance()
3712 struct X3D_Proto *pnode = X3D_PROTO(node);
3713 //I could filter and just do extern proto, but lazy, so do any proto
3714 struct ProtoDefinition *pd = pnode->__protoDef;
3715 struct ProtoFieldDecl * pf = protoDefinition_getFieldByNum(pd, ifield);
3716 pf->alreadySet = 1;
3717 }
3718 if(source==1)
3719 {
3720 //((struct ScriptFieldDecl*) fdecl)->valueSet=TRUE;
3721 //((struct ScriptFieldDecl*) fdecl)->value = *targetVal;
3722 //X3D_SCRIPT(node)->__scriptObj
3723 //if(0) //don't do this during parsing, do it during scene instancing.
3724 //scriptFieldDecl_jsFieldInit(
3725 // (struct ScriptFieldDecl*) fdecl,
3726 // ((struct Shader_Script*)X3D_SCRIPT(node)->__scriptObj)->num);
3727 }
3728 //printf("n=%f\n",targetVal->sfcolor.c[0]);
3730 //if(proto) {
3731 // pdecl->defaultVal=defaultVal;
3732 //}
3733 //else
3734 //{
3735 // ASSERT(shader);
3736 // scriptFieldDecl_setFieldValue(sdecl, defaultVal);
3737 //}
3738 }
3739 #ifdef CPARSERVERBOSE
3740 printf ("end of parser_user_field\n");
3741 #endif
3742 FREEUP
3743 FREE_IF_NZ(nodeFieldName);
3744 return TRUE;
3745}
3746
3747/* PROTO keyword handling.
3748 Like PROTO above: parses ProtoDeclare Interface
3749 Unlike PROTO above: parses the ProtoDeclare Body like a mini-scene,
3750 through re-entrant/recursive call to the same function that parses the main scene
3751 So a SceneDeclare is-a ProtoDeclare and vice versa.
3752*/
3753static BOOL parser_brotoStatement(struct VRMLParser* me)
3754{
3755 int name;
3756 struct ProtoDefinition* obj;
3757 //char *startOfBody;
3758 //char *endOfBody;
3759 //char *initCP;
3760 //uintptr_t bodyLen;
3761 struct X3D_Proto *proto, *parent;
3762 void *ptr;
3763 void *ectx;
3764 DECLAREUP
3765 unsigned int ofs;
3766
3767
3768 /* Really a PROTO? */
3769 SAVEUP
3770 if(!lexer_keyword(me->lexer, KW_PROTO)) //KW_BROTO))
3771 {
3772 BACKUP
3773 return FALSE;
3774 }
3775
3776 /* Our name */
3777 /* lexer_defineNodeType is #defined as lexer_defineID(me, ret, userNodeTypesVec, FALSE) */
3778 /* Add the PROTO name to the userNodeTypesVec list of names return the index of the name in the list in name */
3779 if(!lexer_defineNodeType(me->lexer, &name))
3780 PARSE_ERROR("Expected nodeTypeId after PROTO!\n")
3781 ASSERT(name!=ID_UNDEFINED);
3782
3783 /* Create a new blank ProtoDefinition structure to contain the data for this PROTO */
3784 obj=newProtoDefinition();
3785
3786 /* save the name, if we can get it - it will be the last name on the list, because we will have JUST parsed it. */
3787 if (vectorSize(me->lexer->userNodeTypesVec) != ID_UNDEFINED) {
3788 obj->protoName = STRDUP(vector_get(const char*, me->lexer->userNodeTypesVec, vectorSize(me->lexer->userNodeTypesVec)-1));
3789 } else {
3790 printf ("warning - have proto but no name, so just copying a default string in\n");
3791 obj->protoName = STRDUP("noProtoNameDefined");
3792 }
3793
3794 #ifdef CPARSERVERBOSE
3795 printf ("parser_protoStatement, working on proto :%s:\n",obj->protoName);
3796 #endif
3797
3798 /* If the PROTOs stack has not yet been created, create it */
3799 if(!me->PROTOs) {
3800 parser_scopeIn_PROTO(me);
3801 }
3802
3803 ASSERT(me->PROTOs);
3804 /* ASSERT(name==vectorSize(me->PROTOs)); */
3805
3806 /* Add the empty ProtoDefinition structure we just created onto the PROTOs stack */
3807 vector_pushBack(struct ProtoDefinition*, me->PROTOs, obj);
3808
3809 /* Now we want to fill in the information in the ProtoDefinition */
3810
3811 /* Interface declarations */
3812
3813 /* Make sure that the next token is a '['. Skip over it. */
3814 if(!lexer_openSquare(me->lexer))
3815 PARSE_ERROR("Expected [ to start interface declaration!")
3816
3817 /* Read the next line and parse it as an interface declaration. */
3818 /* Add the user-defined field name to the appropriate list of user-defined names (user_initializeOnly, user_inputOnly, Out, or user_inputOutput).
3819 Create a new protoFieldDecl for this field and add it to the iface vector for the ProtoDefinition obj.
3820 For fields and inputOutputs, get the default value of the field and store it in the protoFieldDecl. */
3821 while(parser_interfaceDeclaration(me, obj, NULL));
3822
3823 /* Make sure that the next token is a ']'. Skip over it. */
3824 if(!lexer_closeSquare(me->lexer))
3825 PARSE_ERROR("Expected ] after interface declaration!")
3826
3827 //pseudocode:
3828 //proto = new Proto() //off scenegraph storage please
3829 //proto.__protoDef = obj
3830 //contextParent.declared_protos.add(proto);
3831 //parser_proto_body(proto)
3832 //return NULL; //no scenegraph node created, or more precisely: nothing to link in to parent's children
3833
3834 //create a ProtoDeclare
3835 proto = createNewX3DNode(NODE_Proto);
3836 //add it to the current context's list of declared protos
3837 if(X3D_NODE(me->ectx)->_nodeType != NODE_Proto && X3D_NODE(me->ectx)->_nodeType != NODE_Inline )
3838 printf("ouch trying to caste node type %d to proto\n",X3D_NODE(me->ectx)->_nodeType);
3839 parent = (struct X3D_Proto*)me->ectx;
3840 if(parent->__protoDeclares == NULL)
3841 parent->__protoDeclares = newVector(struct X3D_Proto*,4);
3842 vector_pushBack(struct X3D_Proto*,parent->__protoDeclares,proto);
3843
3844 proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
3845 proto->__protoFlags = parent->__protoFlags;
3846 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
3848 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
3849 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,3); //((char*)(&proto->__protoFlags))[3] = 0; //not an externProtoDeclare
3850 //set ProtoDefinition *obj
3851 proto->__protoDef = obj;
3852 proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
3853 proto->__typename = STRDUP(obj->protoName);
3854 proto->__unitlengthfactor = getunitlengthfactor();
3855 proto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
3856
3857 /* PROTO body */
3858 /* Make sure that the next oken is a '{'. Skip over it. */
3859 if(!lexer_openCurly(me->lexer))
3860 PARSE_ERROR("Expected { to start PROTO body!")
3861
3862 /* record the start of this proto body - keep the text around */
3863 //startOfBody = (char *) me->lexer->nextIn;
3864 //initCP = (char *) me->lexer->startOfStringPtr[me->lexer->lexerInputLevel];
3865
3866 /* Create a new vector of nodes and push it onto the DEFedNodes stack */
3867 /* This is the list of nodes defined for this scope */
3868 /* Also checks that the PROTOs vector exists, and creates it if it does not */
3869 parser_scopeIn(me);
3870
3871 /* Parse body */
3872 {
3873
3874#ifdef CPARSERVERBOSE
3875 printf ("about to parse PROTO body; new proto def %p\n",obj);
3876#endif
3877
3878 //me->curPROTO=obj;
3879 ectx = me->ectx;
3880 ptr = me->ptr;
3881 ofs = me->ofs; //Q. does this change? Or are we always ofs of children in Proto? H: parseFromString different
3882 me->ectx = proto;
3883 me->ptr = proto;
3884 me->ofs = offsetof(struct X3D_Proto, __children);
3885 parse_proto_body(me);
3886 me->ectx = ectx;
3887 me->ptr = ptr;
3888 me->ofs = ofs;
3889
3890 /* We are done parsing this proto. Set the curPROTO to the last proto we were parsing. */
3891 // me->curPROTO=oldCurPROTO;
3892 }
3893 if(!lexer_closeCurly(me->lexer))
3894 PARSE_ERROR("Expected } to end PROTO body!")
3895
3896 /* Takes the top DEFedNodes vector off of the stack. The local scope now refers to the next vector in the DEFedNodes stack */
3897 parser_scopeOut(me);
3898
3899 /* Make sure that the next token is a '}'. Skip over it. */
3900#ifdef CPARSERVERBOSE
3901 printf ("calling lexer_closeCurly at A\n");
3902printf ("parser_protoStatement, FINISHED proto :%s:\n",obj->protoName);
3903#endif
3904 FREEUP
3905 return TRUE;
3906}
3907
3908/* EXTERNPROTO keyword handling.
3909 Like PROTO above: parses ExternProtoDeclare Interface as a X3D_Proto
3910 - with __url and resource for fetching the definition
3911*/
3912#define LOAD_INITIAL_STATE 0
3913static BOOL parser_externbrotoStatement(struct VRMLParser* me)
3914{
3915 int name;
3916 struct ProtoDefinition* obj;
3917 //char *startOfBody;
3918 //char *endOfBody;
3919 //char *initCP;
3920 //intptr_t bodyLen;
3921 struct X3D_Proto *proto, *parent;
3922 //void *ptr;
3923 DECLAREUP
3924 //unsigned int ofs;
3925
3926
3927 /* Really a EXTERNPROTO? */
3928 SAVEUP
3929 if(!lexer_keyword(me->lexer, KW_EXTERNPROTO))
3930 {
3931 BACKUP
3932 return FALSE;
3933 }
3934
3935 /* Our name */
3936 /* lexer_defineNodeType is #defined as lexer_defineID(me, ret, userNodeTypesVec, FALSE) */
3937 /* Add the EXTERNPROTO name to the userNodeTypesVec list of names return the index of the name in the list in name */
3938 if(!lexer_defineNodeType(me->lexer, &name))
3939 PARSE_ERROR("Expected nodeTypeId after EXTERNPROTO!\n")
3940 ASSERT(name!=ID_UNDEFINED);
3941
3942 /* Create a new blank ProtoDefinition structure to contain the data for this EXTERNPROTO */
3943 obj=newProtoDefinition();
3944 obj->isExtern = TRUE;
3945 /* save the name, if we can get it - it will be the last name on the list, because we will have JUST parsed it. */
3946 if (vectorSize(me->lexer->userNodeTypesVec) != ID_UNDEFINED) {
3947 obj->protoName = STRDUP(vector_get(const char*, me->lexer->userNodeTypesVec, vectorSize(me->lexer->userNodeTypesVec)-1));
3948 } else {
3949 printf ("warning - have proto but no name, so just copying a default string in\n");
3950 obj->protoName = STRDUP("noProtoNameDefined");
3951 }
3952
3953 #ifdef CPARSERVERBOSE
3954 printf ("parser_protoStatement, working on proto :%s:\n",obj->protoName);
3955 #endif
3956
3957 /* If the PROTOs stack has not yet been created, create it */
3958 if(!me->PROTOs) {
3959 parser_scopeIn_PROTO(me);
3960 }
3961
3962 ASSERT(me->PROTOs);
3963 /* ASSERT(name==vectorSize(me->PROTOs)); */
3964
3965 /* Add the empty ProtoDefinition structure we just created onto the PROTOs stack */
3966 vector_pushBack(struct ProtoDefinition*, me->PROTOs, obj);
3967
3968 /* Now we want to fill in the information in the ProtoDefinition */
3969
3970 /* Interface declarations */
3971
3972 /* Make sure that the next token is a '['. Skip over it. */
3973 if(!lexer_openSquare(me->lexer))
3974 PARSE_ERROR("Expected [ to start interface declaration!")
3975
3976 /* Read the next line and parse it as an interface declaration. */
3977 /* Add the user-defined field name to the appropriate list of user-defined names (user_initializeOnly, user_inputOnly, Out, or user_inputOutput).
3978 Create a new protoFieldDecl for this field and add it to the iface vector for the ProtoDefinition obj.
3979 For fields and inputOutputs, get the default value of the field and store it in the protoFieldDecl. */
3980 while(parser_interfaceDeclaration(me, obj, NULL));
3981
3982 /* Make sure that the next token is a ']'. Skip over it. */
3983 if(!lexer_closeSquare(me->lexer))
3984 PARSE_ERROR("Expected ] after interface declaration!")
3985
3986 //pseudocode:
3987 //proto = new Proto() //off scenegraph storage please
3988 //proto.__protoDef = obj
3989 //contextParent.declared_protos.add(proto);
3990 //parser_proto_body(proto)
3991 //return NULL; //no scenegraph node created, or more precisely: nothing to link in to parent's children
3992
3993 //create a ProtoDeclare
3994 proto = createNewX3DNode0(NODE_Proto);
3995 //add it to the current context's list of declared protos
3996 parent = (struct X3D_Proto*)me->ectx;
3997 if(parent->__externProtoDeclares == NULL)
3998 parent->__externProtoDeclares = newVector(struct X3D_Proto*,4);
3999 vector_pushBack(struct X3D_Proto*,parent->__externProtoDeclares,proto);
4000
4001
4002 proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
4003 proto->__protoFlags = parent->__protoFlags;
4004 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
4006 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
4007 proto->__protoFlags = ciflag_set(proto->__protoFlags,1,3); //((char*)(&proto->__protoFlags))[3] = 1; //an externProtoDeclare
4008 //set ProtoDefinition *obj
4009 proto->__protoDef = obj;
4010 proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
4011 proto->__typename = (void *)STRDUP(obj->protoName);
4012 proto->__unitlengthfactor = getunitlengthfactor();
4013 proto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
4014
4015 /* EXTERNPROTO url */
4016 {
4017 //struct Multi_String url;
4018 //unsigned char *buffer;
4019 //char *pound;
4020 //resource_item_t *res;
4021
4022 /* get the URL string */
4023 if (!parser_mfstringValue(me,&proto->url)) {
4024 PARSE_ERROR ("EXTERNPROTO - problem reading URL string");
4025 }
4026 proto->__loadstatus = LOAD_INITIAL_STATE;
4027 /*the rest is done in load_externProto during rendering*/
4028 }
4029
4030 FREEUP
4031 return TRUE;
4032}
4033
4034/*Q. could/should brotoRoutes resolve to pointers early during parsing (as they are now)
4035 or late (by storing char* DEFNode, char* fieldname)?
4036 - late might help with Inline IMPORT/EXPORT, where routes are declared
4037 before the nodes appear.
4038*/
4039//see CRoutes.h
4040//struct brotoRoute
4041//{
4042// struct X3D_Node* fromNode;
4043// int fromOfs;
4044// struct X3D_Node* toNode;
4045// int toOfs;
4046// int ft;
4047//};
4048struct brotoRoute *createNewBrotoRoute();
4049void broto_store_route(struct X3D_Proto* proto,
4050 struct X3D_Node* fromNode, int fromIndex, int fromBuiltIn,
4051 struct X3D_Node* toNode, int toIndex, int toBuiltIn,
4052 int ft)
4053{
4054 Stack* routes;
4055 struct brotoRoute* route;
4056 //struct X3D_Proto* protoDeclare = (struct X3D_Proto*)me->ptr;
4057 ASSERT(proto);
4058 if ((fromIndex == ID_UNDEFINED) || (toIndex == ID_UNDEFINED)) {
4059 ConsoleMessage ("problem registering route - either fromField or toField invalid");
4060 return;
4061 }
4062
4063 route = createNewBrotoRoute();
4064 route->from.node = fromNode;
4065 route->from.ifield = fromIndex;
4066 route->from.builtIn = fromBuiltIn;
4067 route->to.node = toNode;
4068 route->to.ifield = toIndex;
4069 route->to.builtIn = toBuiltIn;
4070 route->lastCommand = 1; //??
4071 route->ft = ft;
4072
4073 routes = proto->__ROUTES;
4074 if( routes == NULL){
4075 routes = newStack(struct brotoRoute *);
4076 proto->__ROUTES = routes;
4077 }
4078 stack_push(struct brotoRoute *, routes, route);
4079 return;
4080}
4081//struct ImportRoute
4082//{
4083// char* fromNode;
4084// char* fromField;
4085// char* toNode;
4086// char* toField;
4087//};
4088//void broto_store_ImportRoute_old(struct X3D_Proto* proto, char *fromNode, char *fromField, char *toNode, char* toField)
4089//{
4090// struct ImportRoute* improute;
4091// if( proto->__IMPROUTES == NULL)
4092// proto->__IMPROUTES= newStack(struct ImportRoute *);
4093// improute = MALLOC(struct ImportRoute*,sizeof(struct ImportRoute));
4094// improute->fromNode = strdup(fromNode);
4095// improute->fromField = strdup(fromField);
4096// improute->toNode = strdup(toNode);
4097// improute->toField = strdup(toField);
4098// stack_push(struct ImportRoute *, proto->__IMPROUTES, improute);
4099//}
4100void broto_store_ImportRoute_obsolete(struct X3D_Proto* proto, char *fromNode, char *fromField, char *toNode, char* toField)
4101{
4102 //there could be combinations of known/strong/node* and weak char* route ends - in that case split up this function
4103 struct brotoRoute* route;
4104 if( proto->__ROUTES == NULL)
4105 proto->__ROUTES= newStack(struct brotoRoute *);
4106 route = createNewBrotoRoute();
4107 route->ft = -1;
4108 route->lastCommand = 0; //not added to CRoutes until inline loaded
4109 route->from.weak = 2; //weak references to publish/from,subscribe/to ends not loaded yet
4110 route->from.cnode = STRDUP(fromNode);
4111 route->from.cfield = STRDUP(fromField);
4112 route->from.ftype = -1; //unknown
4113 route->to.weak = 2;
4114 route->to.cnode = STRDUP(toNode);
4115 route->to.cfield = STRDUP(toField);
4116 route->to.ftype = -1; //unknown
4117 stack_push(struct brotoRoute *, proto->__ROUTES, route);
4118}
4119struct brotoRoute *createNewBrotoRoute(){
4120 struct brotoRoute* route;
4121 route = MALLOC(struct brotoRoute*,sizeof(struct brotoRoute));
4122 memset(route,0,sizeof(struct brotoRoute));
4123 return route;
4124}
4125void broto_store_broute(struct X3D_Proto* context,struct brotoRoute *route){
4126 if( context->__ROUTES == NULL)
4127 context->__ROUTES= newStack(struct brotoRoute *);
4128 stack_push(struct brotoRoute *, context->__ROUTES, route);
4129}
4130void free_brouteEnd(struct brouteEnd *bend){
4131 FREE_IF_NZ(bend->cnode);
4132 FREE_IF_NZ(bend->cfield);
4133}
4134void free_broute(struct brotoRoute *route){
4135 free_brouteEnd(&route->from);
4136 free_brouteEnd(&route->to);
4137}
4138//BOOL route_parse_nodefield(pre, eventType)
4139//used by parser_routeStatement:
4140
4141BOOL route_parse_nodefield(struct VRMLParser* me, int *NodeIndex, struct X3D_Node** Node, int KW_eventType,
4142 int *Ofs, int *fieldType, struct ScriptFieldDecl** ScriptField)
4143{
4144 int PKW_eventType = PKW_outputOnly;
4145 char *cerror1;
4146
4147 int mode;
4148 int type;
4149 int source;
4150 int ifield; //, iprotofield;
4151 char *nodeFieldName;
4152 //DECLAREUP
4153 int foundField;
4154 union anyVrml *fieldPtr;
4155 void *fdecl = NULL;
4156
4157 *Ofs = 0;
4158 //Node = NULL;
4159 *ScriptField=NULL;
4160 cerror1 = "";
4161
4162 if(KW_eventType == KW_outputOnly){
4163 PKW_eventType = PKW_outputOnly;
4164 cerror1 = "Expected an event of type : outputOnly :";
4165 }else if(KW_eventType == KW_inputOnly) {
4166 PKW_eventType = PKW_inputOnly;
4167 cerror1 = "Expected an event of type : inputOnly :";
4168 }
4169
4170 /* Target-node */
4171
4172 /* Look for the current token in the userNodeNames vector (DEFed names) */
4173 if(!lexer_nodeName(me->lexer, NodeIndex)) {
4174 /* The current token is not a valid DEFed name. Error. */
4175 CPARSE_ERROR_CURID("ERROR:ROUTE: Expected a valid DEF name; found \"");
4176 PARSER_FINALLY;
4177 return FALSE;
4178 }
4179
4180
4181 /* Check that there are DEFedNodes in the DEFedNodes vector, and that the index given for this node is valid */
4182 ASSERT(me->DEFedNodes && !stack_empty(me->DEFedNodes) && *NodeIndex<vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
4183 /* Get the X3D_Node structure for the DEFed node we just looked up in the userNodeNames list */
4184 *Node=vector_get(struct X3D_Node*,
4185 stack_top(struct Vector*, me->DEFedNodes),
4186 *NodeIndex);
4187 /* We were'nt able to get the X3D_Node structure for the DEFed node. Error. */
4188 if (*Node == NULL) {
4189 /* we had a bracket underflow, from what I can see. JAS */
4190 CPARSE_ERROR_CURID("ERROR:ROUTE: no DEF name found - check scoping and \"}\"s");
4191 PARSER_FINALLY;
4192 return FALSE;
4193 }
4194
4195
4196 /* The next character has to be a '.' - skip over it */
4197 if(!lexer_point(me->lexer)) {
4198 CPARSE_ERROR_CURID("ERROR:ROUTE: Expected \".\" after the NODE name")
4199 PARSER_FINALLY;
4200 return FALSE;
4201 }
4202 //SAVEUP //save the lexer spot so if it's not an IS we can back up
4203 /* get nodeFieldName */
4204 if(!lexer_setCurID(me->lexer)) return FALSE;
4205 ASSERT(me->lexer->curID);
4206 nodeFieldName = STRDUP(me->lexer->curID);
4207 //BACKUP;
4208 FREE_IF_NZ(me->lexer->curID);
4209
4210 fieldPtr = NULL;
4211 foundField = find_anyfield_by_nameAndRouteDir( *Node, &fieldPtr, &mode, &type,
4212 nodeFieldName, &source, &fdecl, &ifield, PKW_eventType);
4213 if(foundField)
4214 {
4215 if(source == 0)
4216 *Ofs = NODE_OFFSETS[(*Node)->_nodeType][ifield*FIELDOFFSET_LENGTH + 1];
4217 else
4218 *Ofs = ifield;
4219 *ScriptField = fdecl;
4220 *fieldType = type;
4221 return TRUE;
4222 }
4223 if((*Node)->_nodeType==NODE_Script && !fdecl) {
4224 PARSE_ERROR("Event-field invalid for this PROTO/Script!")
4225 } else {
4226 PARSE_ERROR(cerror1)
4227 }
4228 FREE_IF_NZ(nodeFieldName);
4229 PARSER_FINALLY;
4230 return FALSE;
4231}
4232struct IMEXPORT *broto_search_IMPORTname(struct X3D_Proto *context, const char *name);
4233BOOL route_parse_nodefield_B(struct VRMLParser* me, char **ssnode, char **ssfield)
4234{
4235 /* parse a route node.field
4236 this _B version is designed to
4237 1. be a little less tragic if things don't go well - just don't register a bad route, warn the user
4238 2. look for DEF names in the proto context instead of global browser context, as per specs, if we aren't doing that already
4239 3. to accomodate routes to/from late-arriving inline IMPORT nodes
4240 */
4241 char *snode,*sfield;
4242 //struct X3D_Node* xnode;
4243 //int foundField;
4244
4245 /* Get the next token */
4246 if(!lexer_setCurID(me->lexer))
4247 return FALSE;
4248 ASSERT(me->lexer->curID);
4249 snode = STRDUP(me->lexer->curID);
4250 FREE_IF_NZ(me->lexer->curID);
4251
4252
4253 /* The next character has to be a '.' - skip over it */
4254 if(!lexer_point(me->lexer)) {
4255 CPARSE_ERROR_CURID("ERROR:ROUTE: Expected \".\" after the NODE name")
4256 PARSER_FINALLY;
4257 return FALSE;
4258 }
4259
4260 /* get fieldName */
4261 if(!lexer_setCurID(me->lexer))
4262 return FALSE;
4263 ASSERT(me->lexer->curID);
4264 sfield = STRDUP(me->lexer->curID);
4265 FREE_IF_NZ(me->lexer->curID);
4266
4267 *ssnode = snode;
4268 *ssfield = sfield;
4269
4270 PARSER_FINALLY;
4271 return TRUE;
4272}
4273
4274
4275void QAandRegister_parsedRoute_B(struct X3D_Proto *context, char* fnode, char* ffield, char* tnode, char* tfield);
4276
4277// modified by dug9 oct25, 2014
4278// this one is designed not to crash if theres an IMPORT route
4279static BOOL parser_routeStatement_B(struct VRMLParser* me)
4280{
4281 char *sfnode, *sffield;
4282 char *stnode, *stfield;
4283 int foundfrom, foundto, gotTO;
4284
4285 ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
4286
4287 ASSERT(me->lexer);
4288 lexer_skip(me->lexer);
4289
4290 /* Is this a routeStatement? */
4291 if(!lexer_keyword(me->lexer, KW_ROUTE))
4292 return FALSE;
4293
4294 /* Parse the elements. */
4295
4296 /* Parse the first part of a routing statement: DEFEDNODE.event by locating the node DEFEDNODE in either the builtin or user-defined name arrays
4297 and locating the event in the builtin or user-defined event name arrays */
4298 //ROUTE_PARSE_NODEFIELD(from, outputOnly);
4299 foundfrom = route_parse_nodefield_B(me,&sfnode, &sffield);
4300
4301 /* Next token has to be "TO" */
4302 gotTO = TRUE;
4303 if(!lexer_keyword(me->lexer, KW_TO)) {
4304 /* try to make a better error message. */
4305 char *buf = p->fw_outline;
4306 strcpy (buf,"ERROR:ROUTE: Expected \"TO\" found \"");
4307 if (me->lexer->curID != NULL) strcat (buf, me->lexer->curID); else strcat (buf, "(EOF)");
4308 CPARSE_ERROR_CURID(buf);
4309 PARSER_FINALLY;
4310 //return FALSE;
4311 gotTO = FALSE;
4312 }
4313/* Parse the second part of a routing statement: DEFEDNODE.event by locating the node DEFEDNODE in either the builtin or user-defined name arrays
4314 and locating the event in the builtin or user-defined event name arrays */
4315 //ROUTE_PARSE_NODEFIELD(to, inputOnly);
4316 foundto = route_parse_nodefield_B(me,&stnode, &stfield);
4317
4318 if(!(foundfrom && gotTO && foundto)){
4319 FREE_IF_NZ(sfnode);
4320 FREE_IF_NZ(sffield);
4321 FREE_IF_NZ(stnode);
4322 FREE_IF_NZ(stfield);
4323 PARSER_FINALLY;
4324 return FALSE;
4325 }
4326
4327 QAandRegister_parsedRoute_B(X3D_PROTO(me->ectx), sfnode, sffield, stnode, stfield);
4328 FREE_IF_NZ(sfnode);
4329 FREE_IF_NZ(sffield);
4330 FREE_IF_NZ(stnode);
4331 FREE_IF_NZ(stfield);
4332
4333 return TRUE;
4334}
4335
4336/*
4337 Binary Protos aka Brotos - allows deeply nested protos, by using scene parsing code to parse protobodies
4338 recursively, as Flux2008 likely does
4339 History:
4340 Jan 2013, Broto1- did first version for .wrl parsing, but it unrolled the results into the main scene tables
4341 (Routes, scripts, etc) via function sceneInstance() - and didn't do .x3d parsing, nor externProtos
4342 Sept 2014 Broto2 - attempt to render directly from Broto-format scene, and fix externProtos
4343 Concepts:
4344 deep vs shallow: when instancing a prototype, you go deep if you copy the protoDeclare body
4345 to the body of the protoInstance, and recursively deepen any contained protoInstances.
4346 You go shallow if you just copy the interface (so you can route to it) leaving the body empty. Related to proto expansion.
4347 Scene as Proto - to allow the parser to use the same code to parse the scene and protobodies -recursing-
4348 the scene and protos need to have a common format. Once parsed, Broto1 converted the SceneProto to old tables and structs.
4349 Broto2 is rendering the SceneProto directly, saving awkward conversion, and requiring rendering
4350 algorithms that recurse
4351 ExternProtoDeclare/instance - design goal: have externProtoDeclare wrap/contain a protoDeclare,
4352 and instance the protodeclare as its first node once loaded, and have an algorithm that ISes
4353 between the externProtoDeclare interface and the contained protoInstance fields. This 'wrapper' design
4354 allows flexibility in ordering of fields, and can do minor PKW mode conversions, and allow the parser
4355 to continue parsing the scene while the externproto definition downloads and parses asynchronously
4356 p2p - pointer2pointer node* lookup table when copying a binary protoDeclare to a protoInstance:
4357 tables in the declare -such as routes and DEFs- are in terms of the Declare node*, and after new nodoes
4358 are created for the protoInstance, the protoDeclare-to-protoInstance node* lookup can be done during
4359 copying of the tables
4360 Broto2: 6 things share an X3D_Proto node structure:
4361 1. ProtoInstance - the only one of these 5 that's shown as a node type in web3d.org specs
4362 2. ProtoDeclare - we don't register the struct as a node when mallocing, and we don't expand (deepen) its contained protoInstances
4363 3. ExternProtoInstance - in the specs, this would be just another ProtoInstance.
4364 4. ExternProtoDeclare - will be like ProtoDeclare, with a URL and a way to watch for it's protodefinition being loaded, like Inline
4365 5. Scene - so that parsing can parse protoDeclares and Scene using the same code, we use the same struct.
4366 - Broto1 parsed the scene shallow, then in a second step sceneInstance() deepened the brotos while converting to old scene format
4367 - Broto2 parses deep for scenes and inlines, shallow for protodeclares and externProtodeclares
4368 6. Inline - declared as a separatey X3D_Inline type, but maintained as identical struct to X3D_Proto
4369 To keep these 5 distinguished,
4370 char *pflags = (char *)(int* &__protoFlags)
4371 pflag[0]: deep parsing instruction
4372 1= parse deep: deepen any protoInstances recursively, and register nodes when mallocing (for scene, inline)
4373 0= parse shallow: instance protos with no body, don't register nodes during mallocing (for protoDeclare, externProtoDeclare)
4374 pflag[1]: oldway parsing instruction
4375 1= oldway, for where to send routes etc
4376 0= broto1, broto2 way
4377 pflag[2]: declare, instance, or scene object
4378 0 = protoDeclare or externProtoDeclare //shouldn't be rendered
4379 1 = ProtoInstance or externProtoInstance //first child node is in the render transform stack
4380 2 = scene //all child nodes are rendered
4381 pflag[3]: extern or intern object
4382 0 = scene, protodeclare, protoInstance
4383 1 = externProtoInstance, externprotodeclare
4384*/
4385
4386//moved to header:
4387//struct brotoDefpair{
4388// struct X3D_Node* node;
4389// char* name;
4390//};
4391void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name)
4392{
4393 Stack *defs;
4394 struct brotoDefpair def;
4395 def.node = node;
4396 def.name = STRDUP(name);
4397 defs = proto->__DEFnames;
4398 if( defs == NULL)
4399 {
4400 defs = newStack(struct brotoDefpair);
4401 proto->__DEFnames = defs;
4402 }
4403 stack_push(struct brotoDefpair, defs, def);
4404}
4405int broto_search_DEF_index_by_node(struct X3D_Proto* proto, struct X3D_Node *node){
4406 int index;
4407 Stack *defs = proto->__DEFnames;
4408 index = -1;
4409 if(defs){
4410 int i;
4411 for(i=0;i<vectorSize(defs);i++){
4412 struct brotoDefpair def = vector_get(struct brotoDefpair,defs,i);
4413 if(def.node == node){
4414 index = i;
4415 break;
4416 }
4417 }
4418 }
4419 return index;
4420}
4421
4422void broto_clear_DEF_by_node(struct X3D_Proto* proto,struct X3D_Node* node)
4423{
4424 int index;
4425 Stack *defs;
4426 struct brotoDefpair def;
4427 index = broto_search_DEF_index_by_node(proto,node);
4428 if(index > -1){
4429 defs = proto->__DEFnames;
4430 def = vector_get(struct brotoDefpair,defs,index);
4431 FREE_IF_NZ(def.name);
4432 vector_removeElement(sizeof(struct brotoDefpair),defs,index);
4433 }
4434}
4435struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name){
4436 int i, istart, iend;
4437 struct brotoDefpair def;
4438 //in theory we should search backward. test 9.wrl has 2 TRs. If you make the first one with no children,
4439 // and the second one around the viewpoint, and you send an animation via route to TR.translation
4440 // octaga, instant and viv route to the 2nd one / last TR before the ROUTE
4441 if(context->__DEFnames){
4442 istart = vectorSize(context->__DEFnames) -1;
4443 iend = 0;
4444 for(i=istart;i>=iend; i--) {
4445 def = vector_get(struct brotoDefpair, context->__DEFnames,i);
4446 if(!strcmp(def.name, name)) return def.node;
4447 }
4448 }
4449 return NULL;
4450}
4451struct IMEXPORT *broto_search_IMPORTname(struct X3D_Proto *context, const char *name){
4452 int i;
4453 struct IMEXPORT *def;
4454 if(context->__IMPORTS)
4455 for(i=0;i<vectorSize(context->__IMPORTS);i++){
4456 def = vector_get(struct IMEXPORT *, context->__IMPORTS,i);
4457 if(!strcmp(def->as,name)) return def;
4458 }
4459 return NULL;
4460}
4461struct IMEXPORT *broto_search_EXPORTname(struct X3D_Proto *context, const char *name){
4462 int i;
4463 struct IMEXPORT *def;
4464 if(context->__EXPORTS)
4465 for(i=0;i<vectorSize(context->__EXPORTS);i++){
4466 def = vector_get(struct IMEXPORT *, context->__EXPORTS,i);
4467 if(!strcmp(def->as,name)) return def;
4468 }
4469 return NULL;
4470}
4471
4472
4473BOOL isAvailableBroto(const char *pname, struct X3D_Proto* currentContext, struct X3D_Proto **proto)
4474{
4475 /* search list of already-defined binary protos in current context,
4476 and in ancestor proto contexts*/
4477 int i;
4478 struct ProtoDefinition* obj;
4479 struct X3D_Proto *p;
4480 struct X3D_Proto* context;
4481 //struct Multi_Node *plist;
4482 struct Vector *plist;
4483
4484 *proto = NULL;
4485 /* besides current context list also search parent context list if there is one */
4486 context = currentContext;
4487 do {
4488 int j;
4489 //flux,vivaty search top-down, cortona,blaxxun,white_dune search bottom-up within context,
4490 // this only makes a difference if you have more than one protodefinition with the same protoName
4491 // in the same context
4492 BOOL bottomUp = TRUE;
4493 //plist = &context->__protoDeclares;
4494 plist = (struct Vector*) context->__protoDeclares;
4495 if(plist){
4496 int n = vectorSize(plist);
4497 for(i=0;i<n;i++)
4498 {
4499 j = i;
4500 if(bottomUp) j = n - 1 - i;
4501 //p = (struct X3D_Proto*)plist->p[j];
4502 p = vector_get(struct X3D_Proto*,plist,j);
4503 obj = p->__protoDef;
4504 if(!strcmp(obj->protoName,pname))
4505 {
4506 *proto = p;
4507 return TRUE;
4508 }
4509 }
4510 }
4511 plist = (struct Vector*) context->__externProtoDeclares;
4512 if(plist){
4513 int n = vectorSize(plist);
4514 for(i=0;i<n;i++)
4515 {
4516 j = i;
4517 if(bottomUp) j = n - 1 - i;
4518 //p = (struct X3D_Proto*)plist->p[j];
4519 p = vector_get(struct X3D_Proto*,plist,j);
4520 obj = p->__protoDef;
4521 if(!strcmp(obj->protoName,pname))
4522 {
4523 *proto = p;
4524 return TRUE;
4525 }
4526 }
4527 }
4528 context = (struct X3D_Proto*)context->__parentProto;
4529 }while(context);
4530 printf("ouch no broto definition found\n");
4531 return FALSE;
4532}
4534 struct X3D_Node* pp; //old or protoDeclare pointer
4535 struct X3D_Node* pn; //new or protoInstance pointer
4536};
4537
4538struct X3D_Node* inPointerTable(struct X3D_Node* source,struct Vector *p2p)
4539{
4540 int i;
4541 struct X3D_Node *dest = NULL;
4542 struct pointer2pointer pair;
4543 for(i=0;i<p2p->n;i++)
4544 {
4545 pair = vector_get(struct pointer2pointer, p2p, i);
4546 if(pair.pp == source){
4547 dest = pair.pn;
4548 break;
4549 }
4550 }
4551 return dest;
4552}
4553struct X3D_Node *p2p_lookup(struct X3D_Node *pnode, struct Vector *p2p);
4554void copy_routes2(Stack *routes, struct X3D_Proto* target, struct Vector *p2p)
4555{
4556 //for 2014 broto2, deep copying of brotodeclare to brotoinstance
4557 int i;
4558 struct brotoRoute *route;
4559 struct X3D_Node *fromNode, *toNode;
4560 if(routes == NULL) return;
4561 for(i=0;i<routes->n;i++)
4562 {
4563 route = vector_get(struct brotoRoute*, routes, i);
4564 //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4565 //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4566 fromNode = p2p_lookup(route->from.node,p2p);
4567 toNode = p2p_lookup(route->to.node,p2p);
4568 CRoutes_RegisterSimpleB(fromNode, route->from.ifield, route->from.builtIn, toNode, route->to.ifield, route->to.builtIn, route->ft);
4569 //we'll also store in the deep broto instance, although they aren't used there (yet), and
4570 //if target is the main scene, they are abandoned. Maybe someday they'll be used.
4571 //if( target )
4572 broto_store_route(target,fromNode,route->from.ifield,route->from.builtIn, toNode, route->to.ifield, route->to.builtIn, route->ft);
4573 }
4574}
4575//copy broto defnames to single global scene defnames, for node* to defname lookup in parser_getNameFromNode
4576//but can't go the other way (name to node) because there can be duplicate nodes with the same name in
4577//different contexts
4578//this version for 2014 broto2
4579void copy_defnames2(Stack *defnames, struct X3D_Proto* target, struct Vector *p2p)
4580{
4581 //Stack* defs;
4582 //struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
4583
4584 //defs = globalParser->brotoDEFedNodes;
4585 //if( defs == NULL)
4586 //{
4587 // defs = newStack(struct brotoDefpair *);
4588 // globalParser->brotoDEFedNodes = defs;
4589 //}
4590 if(target->__DEFnames == NULL)
4591 target->__DEFnames = newStack(struct brotoDefpair);
4592 if(defnames)
4593 {
4594 int i,n;
4595 struct brotoDefpair def, def2;
4596 n = vectorSize(defnames);
4597 for(i=0;i<n;i++){
4598 def = vector_get(struct brotoDefpair,defnames,i);
4599 def2.name = STRDUP(def.name); //I wonder who owns this name
4600 def2.node = p2p_lookup(def.node, p2p);
4601 //stack_push(struct brotoDefpair*, defs, def2);
4602 stack_push(struct brotoDefpair, target->__DEFnames, def2); //added for broto2
4603 }
4604 }
4605}
4606
4607void copy_IS(Stack *istable, struct X3D_Proto* target, struct Vector *p2p);
4608void copy_IStable(Stack **sourceIS, Stack** destIS);
4609void copy_field(int typeIndex, union anyVrml* source, union anyVrml* dest, struct Vector *p2p,
4610 Stack *instancedScripts, struct X3D_Proto *ctx, struct X3D_Node *parent);
4611void initialize_scripts(Stack *instancedScripts);
4612void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest)
4613{
4614 //for use with 2014 broto2 when parsing scene/inline and we want to deep-instance brotos as we parse
4615 //converts from binary proto/broto format to old scene format:
4616 // - ROUTES are registered in global ROUTE registry
4617 // - nodes are instanced and registered in memoryTable for startOfLoopNodesUpdate and killNode access
4618 // - sensors, viewpoints etc are registered
4619 //proto - broto instance with
4620 // - a pointer __prototype to its generic prototype
4621 //dest - protoinstance with user fields filled out for this instance already
4622 // - children/body not filled out yet - it's done here
4623 // - any field/exposedField values in interface IS copied to body node fields
4624 // - broto ROUTES registered in global route registry, with this instances' node* addresses
4625 // ? ( sensors, viewpoints will be directly registered in global/main scene structs)
4626 //what will appear different in the scene:
4627 // old: PROTO instances appear as Group nodes with metaSF nodes for interface routing, mangled DEFnames
4628 // new: PROTO instances will appear as X3DProto nodes with userfields for interface routing, local DEFnames
4629
4630 //DEEP COPYING start here
4631 //we're instancing for the final scene, so go deep
4632 //0. setup pointer lookup table proto to instance
4633 //1. copy nodes, recursing on MFNode,SFnode fields
4634 // to copy, instance a new node of the same type and save (new pointer, old pointer) in lookup table
4635 // iterate over proto's node's fields, copying, and recursing on MFNode, SFNode
4636 // if node is a ProtoInstance, deepcopy it
4637 //2. copy ROUTE table, looking up new_pointers in pointer lookup table
4638 //3. copy IS table, looking up new_pointers in pointer lookup table
4639 //4. copy DEFname table, looking up new pointers in pointer lookup table
4640 //
4641
4642 struct X3D_Proto *prototype, *p;
4643 struct X3D_Node *parent;
4644 Stack *instancedScripts;
4645 struct Vector *p2p = newVector(struct pointer2pointer,10);
4646
4647 //2. copy body from source's _prototype.children to dest.children, ISing initialvalues as we go
4648 p=(*dest);
4649 p->__children.n = 0;
4650 p->__children.p = NULL;
4651 parent = (struct X3D_Node*) (*dest); //NULL;
4652 prototype = (struct X3D_Proto*)(*proto)->__prototype;
4653
4654 p->__prototype = X3D_NODE(prototype);
4655 //p->__protoFlags = prototype->__protoFlags; //done in brotoInstance
4656 p->__protoFlags = ciflag_set(p->__protoFlags,1,2); //deep instancing of protoInstances inside a protoDeclare
4657
4658 //prototype = (struct X3D_Proto*)p->__prototype;
4659 //2.c) copy IS
4660 //p->__IS = copy IStable from prototype, and the targetNode* pointer will be wrong until p2p
4661 //copy_IStable(&((Stack*)prototype->__IS), &((Stack*)p->__IS));
4662
4663 copy_IStable((Stack **) &(prototype->__IS), (Stack **) &(p->__IS));
4664
4665 instancedScripts = (*dest)->__scripts;
4666 if( instancedScripts == NULL)
4667 {
4668 instancedScripts = newStack(struct X3D_Node *);
4669 (*dest)->__scripts = instancedScripts;
4670 }
4671
4672 //2.a) copy rootnodes
4673 copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(prototype->__children),(union anyVrml*)&(p->__children),
4674 p2p,instancedScripts,p,parent);
4675 //2.b) copy routes
4676 copy_routes2(prototype->__ROUTES, p, p2p);
4677 //2.d) copy defnames
4678 copy_defnames2(prototype->__DEFnames, p, p2p);
4679 //2.e) copy protodeclares
4680 // copy_protodeclares2
4681 struct X3D_Proto* pp;
4682 for (int i = 0; i < vectorSize(prototype->__protoDeclares); i++) {
4683 pp = vector_get(struct X3D_Proto*, prototype->__protoDeclares, i);
4684 vector_pushBack(struct X3D_Proto*, p->__protoDeclares, pp);
4685 }
4686 // copy_externprotodeclares2
4687 for (int i = 0; i < vectorSize(prototype->__externProtoDeclares); i++) {
4688 pp = vector_get(struct X3D_Proto*, prototype->__externProtoDeclares, i);
4689 vector_pushBack(struct X3D_Proto*, p->__externProtoDeclares, pp);
4690 }
4691
4693 copy_IS(p->__IS, p, p2p);
4694
4695 initialize_scripts(instancedScripts);
4696
4697 //*dest = p;
4698 deleteVector(struct pointer2pointer,p2p); //free p2p
4699 return;
4700}
4701struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep)
4702{
4703 //shallow copy - just the user-fields, and point back to the *prototype for later
4704 // deep copy of body and IS-table (2014 broto2 when parsing a protoDeclare or externProtoDeclare)
4705 //deep copy - copy body and tables, and if an item in the body is a protoInstance, deep copy it (recursively)
4706 // (2014 broto2 when parsing a scene or inline)
4707
4708 int i;
4709 //int iProtoDeclarationLevel;
4710 struct ProtoDefinition *pobj,*nobj;
4711 struct ProtoFieldDecl *pdecl,*ndecl;
4712 struct X3D_Proto *p;
4713 if(ideep){
4714 int pflags;
4715 pushInputResource(proto->_parentResource);
4716 p = createNewX3DNode(NODE_Proto);
4717 popInputResource();
4718 //memcpy(p,proto,sizeof(struct X3D_Proto)); //dangerous, make sure you re-instance all pointer variables
4719 p->__children.n = 0; //don't copy children in here - see below
4720 p->__children.p = NULL;
4721 pflags = 0;
4722 //char pflags[4];
4723 pflags = ciflag_set(pflags,1,0); //pflags[0] = 1; //deep
4724 //pflags[1] = 0; //new way/brotos
4725 pflags = ciflag_set(pflags,1,2); //pflags[2] = 1; //this is a protoInstance
4726 pflags = ciflag_set(pflags,0,3); //pflags[3] = 0; //not an extern
4727 if(ciflag_get(proto->__protoFlags,3)==1)
4728 pflags = ciflag_set(pflags,1,3); //its an externProtoInstance
4729 //memcpy(&p->__protoFlags,pflags,sizeof(int));
4730 p->__protoFlags = pflags;
4731 }else{
4732 //shallow
4733 p = createNewX3DNode0(NODE_Proto);
4734 //memcpy(p,proto,sizeof(struct X3D_Proto)); //dangerous, make sure you re-instance all pointer variables
4735 p->__children.n = 0; //don't copy children in here.
4736 p->__children.p = NULL;
4737 //char pflags[4];
4738 //pflags[0] = 0; //shallow
4739 //pflags[1] = 0; //new way/brotos
4740 //pflags[2] = 0; //this is a protoDeclare if shallow
4741 //pflags[3] = 0; //not an extern
4742 //memcpy(&p->__protoFlags,pflags,sizeof(int));
4743 p->__protoFlags = 0;
4744 //if(ciflag_get(proto->__protoFlags,3)==1) //+ Jan 2015
4745 // p->__protoFlags = ciflag_set(p->__protoFlags,1,3); //+ Jan 2015, its an externProtoInstance
4746 }
4747 //memcpy(p,proto,sizeof(struct X3D_Proto)); //dangerous, make sure you re-instance all pointer variables
4748 p->__prototype = proto->__prototype;
4749 p->_nodeType = proto->_nodeType;
4750 p->__unitlengthfactor = proto->__unitlengthfactor;
4751 p->__specversion = proto->__specversion;
4752 p->_defaultContainer = proto->_defaultContainer;
4753 p->_renderFlags = proto->_renderFlags;
4754 pobj = proto->__protoDef;
4755 if(pobj){ //Prodcon doesn't bother mallocing this for scene nRn
4756 nobj = MALLOC(struct ProtoDefinition*,sizeof(struct ProtoDefinition));
4757 memcpy(nobj,pobj,sizeof(struct ProtoDefinition));
4758 nobj->iface = newVector(struct ProtoFieldDecl *, pobj->iface->n);
4759 if(pobj->protoName)
4760 nobj->protoName = STRDUP(pobj->protoName);
4761 for(i=0;i<pobj->iface->n;i++)
4762 {
4763 pdecl = protoDefinition_getFieldByNum(pobj, i);
4764 if(0){
4765 ndecl=newProtoFieldDecl(pdecl->mode, pdecl->type, pdecl->name);
4766 //memcpy(ndecl,pdecl,sizeof(struct ProtoFieldDecl *)); //not just the pointer
4767 memcpy(ndecl,pdecl,sizeof(struct ProtoFieldDecl)); //.. the whole struct
4768 }else{
4769 ndecl = copy_ProtoFieldDecl(pdecl);
4770 }
4771 protoDefinition_addIfaceField(nobj, ndecl);
4772 }
4773 p->__protoDef = nobj;
4774 }
4775 //if(0) if(ideep) moved to after field parsing, so ISing of initial values on the ProtoInstance get into the body
4776 // deep_copy_broto_body2(&proto,&p);
4777 return p;
4778}
4779struct X3D_Node *p2p_lookup(struct X3D_Node *pnode, struct Vector *p2p)
4780{
4781 int i;
4782 struct pointer2pointer pair;
4783 for(i=0;i<p2p->n;i++)
4784 {
4785 pair = vector_get(struct pointer2pointer, p2p, i);
4786 if(pnode == pair.pp) return pair.pn;
4787 }
4788 return NULL;
4789}
4790//copy broto routes to old-style global scene routes
4791void copy_routes(Stack *routes, struct X3D_Proto* target, struct Vector *p2p)
4792{
4793 int i;
4794 struct brotoRoute *route;
4795 struct X3D_Node *fromNode, *toNode;
4796 if(routes == NULL) return;
4797 for(i=0;i<routes->n;i++)
4798 {
4799 route = vector_get(struct brotoRoute*, routes, i);
4800 //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4801 //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4802 fromNode = p2p_lookup(route->from.node,p2p);
4803 toNode = p2p_lookup(route->to.node,p2p);
4804 CRoutes_RegisterSimpleB(fromNode, route->from.ifield, route->from.builtIn, toNode, route->to.ifield, route->to.builtIn, route->ft);
4805 //we'll also store in the deep broto instance, although they aren't used there (yet), and
4806 //if target is the main scene, they are abandoned. Maybe someday they'll be used.
4807 //if( target )
4808 // broto_store_route(target,fromNode,route->fromOfs, toNode, route->toOfs, route->ft);
4809 }
4810}
4811//struct ISrecord {
4812// int protoFieldIndex;
4813// int nodeFieldSource; //target node field source: builtin=0, script user field=1, broto user field =2
4814// int nodeFieldIndexOrOffset; //int OFFSET for builtin fields, int field index for user fields in script, broto
4815// struct X3D_Node* node; //target node
4816//};
4818{
4819 struct X3D_Proto *proto;
4820 char *protofieldname;
4821 int pmode;
4822 int iprotofield;
4823 int pBuiltIn;
4824 int type;
4825 struct X3D_Node *node;
4826 char* nodefieldname;
4827 int mode;
4828 int ifield;
4829 int builtIn;
4830 int source; //0= builtin field, 1=script, 2={ComposedShader,ShaderProgram,PackagedShader} 3=Proto
4831};
4832
4833//copy broto IS to old-style global scene routes
4834void copy_IS(Stack *istable, struct X3D_Proto* target, struct Vector *p2p)
4835{
4836 int i;
4837 struct brotoIS *is;
4838 struct X3D_Node *node, *pnode;
4839 if(istable == NULL) return;
4840 for(i=0;i<istable->n;i++)
4841 {
4842 int ifield, builtIn, iprotofield;
4843 is = vector_get(struct brotoIS*, istable, i);
4844 //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4845 //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4846 node = p2p_lookup(is->node,p2p);
4847 is->node = node; //replace protodeclare's body node - we need the new one for unregistering these routes
4848 pnode = X3D_NODE(target);
4849 ifield = is->ifield;
4850 builtIn = is->builtIn;
4851 //if(node->_nodeType != NODE_Script && node->_nodeType != NODE_Proto)
4852 // ifield = NODE_OFFSETS[node->_nodeType][ifield*5 +1];
4853 iprotofield = is->iprotofield;
4854 //if(pnode->_nodeType != NODE_Script && pnode->_nodeType != NODE_Proto)
4855 // iprotofield = NODE_OFFSETS[node->_nodeType][offset*5 +1];
4856 if(is->pmode == PKW_outputOnly){ //we should use pmode instead of mode, because pmode is more restrictive, so we don't route from pmode initializeOnly (which causes cycles in 10.wrl)
4857 //idir = 0;
4858 //if(node->_nodeType == NODE_Script) idir = FROM_SCRIPT;
4859 CRoutes_RegisterSimpleB(node, ifield, builtIn, pnode, iprotofield, FALSE, 0);
4860
4861 }else if(is->pmode == PKW_inputOnly){
4862 CRoutes_RegisterSimpleB(pnode, iprotofield, FALSE, node, ifield, builtIn, 0);
4863 }else if(is->pmode == PKW_inputOutput){
4864 CRoutes_RegisterSimpleB(node, ifield, builtIn, pnode, iprotofield, FALSE, 0);
4865 CRoutes_RegisterSimpleB(pnode, iprotofield, FALSE, node, ifield, builtIn, 0);
4866 }else{
4867 //initialize Only - nothing to do routing wise
4868 }
4869 }
4870}
4871void unregister_IStableRoutes(Stack* istable, struct X3D_Proto* target){
4872 // goal reverse browser route registering we did in copy_IS,
4873 // for example if we unload an inline, and in the inline was protoInstance,
4874 // then 'construction' routes like these injected for ISing will be left dangling
4875 // in the route registry unless we unregister them here.
4876 int i;
4877 struct brotoIS *is;
4878 struct X3D_Node *node, *pnode;
4879 if(istable == NULL) return;
4880 for(i=0;i<istable->n;i++)
4881 {
4882 int ifield, builtIn, iprotofield;
4883 is = vector_get(struct brotoIS*, istable, i);
4884 //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4885 //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4886 node = is->node;
4887 is->node = node; //replace protodeclare's body node - we need the new one for unregistering these routes
4888 pnode = X3D_NODE(target);
4889 ifield = is->ifield;
4890 builtIn = is->builtIn;
4891 //if(node->_nodeType != NODE_Script && node->_nodeType != NODE_Proto)
4892 // ifield = NODE_OFFSETS[node->_nodeType][ifield*5 +1];
4893 iprotofield = is->iprotofield;
4894 //if(pnode->_nodeType != NODE_Script && pnode->_nodeType != NODE_Proto)
4895 // iprotofield = NODE_OFFSETS[node->_nodeType][offset*5 +1];
4896 if(is->pmode == PKW_outputOnly){ //we should use pmode instead of mode, because pmode is more restrictive, so we don't route from pmode initializeOnly (which causes cycles in 10.wrl)
4897 //idir = 0;
4898 //if(node->_nodeType == NODE_Script) idir = FROM_SCRIPT;
4899 CRoutes_RemoveSimpleB(node, ifield, builtIn, pnode, iprotofield, FALSE, 0);
4900
4901 }else if(is->pmode == PKW_inputOnly){
4902 CRoutes_RemoveSimpleB(pnode, iprotofield, FALSE, node, ifield, builtIn, 0);
4903 }else if(is->pmode == PKW_inputOutput){
4904 CRoutes_RemoveSimpleB(node, ifield, builtIn, pnode, iprotofield, FALSE, 0);
4905 CRoutes_RemoveSimpleB(pnode, iprotofield, FALSE, node, ifield, builtIn, 0);
4906 }else{
4907 //initialize Only - nothing to do routing wise
4908 }
4909 }
4910
4911}
4912void copy_IStable(Stack **sourceIS, Stack** destIS)
4913{
4914 int i;
4915 if(*sourceIS){
4916 struct brotoIS *iss, *isd;
4917 *destIS = newStack(struct brotoIS*);
4918
4919 for(i=0;i<(*sourceIS)->n;i++)
4920 {
4921 isd = MALLOC(struct brotoIS*,sizeof(struct brotoIS));
4922 iss = vector_get(struct brotoIS*,*sourceIS,i);
4923 memcpy(isd,iss,sizeof(struct brotoIS));
4924 //(*isd) = (*iss); //deep copy struct brotoIS?
4925 stack_push(struct brotoIS*, *destIS, isd);
4926 }
4927 }
4928}
4929struct brotoIS * in_IStable(struct X3D_Node *target, int ifield, Stack *IS, int source)
4930{
4931 int i;
4932 struct Vector* IStable = (struct Vector*)IS;
4933 if(IStable){
4934 for(i=0;i<IStable->n;i++)
4935 {
4936 struct brotoIS * record = vector_get(struct brotoIS*,IStable,i);
4937 if(target == record->node){
4938 if(ifield == record->ifield && source == record->source){
4939 //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
4940 return record;
4941 }
4942 }
4943 }
4944 }
4945 return NULL;
4946}
4947//copy broto defnames to single global scene defnames, for node* to defname lookup in parser_getNameFromNode
4948//but can't go the other way (name to node) because there can be duplicate nodes with the same name in
4949//different contexts
4950void copy_defnames(Stack *defnames, struct X3D_Proto* target, struct Vector *p2p)
4951{
4952 Stack* defs;
4953 struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
4954
4955 defs = globalParser->brotoDEFedNodes;
4956 if( defs == NULL)
4957 {
4958 defs = newStack(struct brotoDefpair *);
4959 globalParser->brotoDEFedNodes = defs;
4960 }
4961 if(defnames)
4962 {
4963 int i,n;
4964 struct brotoDefpair* def, *def2;
4965 n = vectorSize(defnames);
4966 for(i=0;i<n;i++){
4967 def = vector_get(struct brotoDefpair*,defnames,i);
4968 def2 = MALLOC(struct brotoDefpair*,sizeof(struct brotoDefpair));
4969 def2->name = def->name; //I wonder who owns this name
4970 def2->node = p2p_lookup(def->node, p2p);
4971 stack_push(struct brotoDefpair*, defs, def2);
4972 }
4973 }
4974}
4975char *broto_getNameFromNode(struct X3D_Node* node)
4976{
4977 char *ret;
4978 Stack* defs;
4979 struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
4980 ret = NULL;
4981 if(globalParser){
4982 defs = globalParser->brotoDEFedNodes;
4983 if(defs){
4984 int i,n;
4985 struct brotoDefpair* def;
4986 n = vectorSize(defs);
4987 for(i=0;i<n;i++){
4988 def = vector_get(struct brotoDefpair*,defs,i);
4989 if(def->node == node){
4990 ret = def->name;
4991 break;
4992 }
4993 }
4994 }
4995 }
4996 return ret;
4997}
4998void deep_copy_node(struct X3D_Node** source, struct X3D_Node** dest, struct Vector *p2p,
4999 Stack *instancedScripts, struct X3D_Proto *ctx);
5000//void deep_copy_broto(struct X3D_Proto** proto, struct X3D_Proto** dest, Stack *instancedScripts);
5001
5002void copy_field(int typeIndex, union anyVrml* source, union anyVrml* dest, struct Vector *p2p,
5003 Stack *instancedScripts, struct X3D_Proto *ctx, struct X3D_Node *parent)
5004{
5005 int i, isize;
5006 int sftype, isMF;
5007 struct Multi_Node *mfs,*mfd;
5008
5009 isMF = typeIndex % 2; //this is wrong - you need a functional lookup or re-arrange the #defines
5010 sftype = typeIndex - isMF;
5011 //from EAI_C_CommonFunctions.c
5012 //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
5013 isize = sizeofSForMF(sftype);
5014 if(isMF)
5015 {
5016 int nele;
5017 char *ps, *pd;
5018 mfs = (struct Multi_Node*)source;
5019 mfd = (struct Multi_Node*)dest;
5020 deleteMallocedFieldValue(typeIndex,dest);
5021 //we need to malloc and do more copying
5022 nele = mfs->n;
5023 if( sftype == FIELDTYPE_SFNode ) nele = (int) upper_power_of_two(nele);
5024 if(!nele){
5025 mfd->p = NULL;
5026 }else{
5027 mfd->p = MALLOC (struct X3D_Node **, isize*nele);
5028 bzero(mfd->p,isize*nele);
5029 //mfd->n = mfs->n;
5030 ps = (char *)mfs->p;
5031 pd = (char *)mfd->p;
5032 for(i=0;i<mfs->n;i++)
5033 {
5034 copy_field(sftype,(union anyVrml*)ps,(union anyVrml*)pd,p2p,instancedScripts,ctx,parent);
5035 ps += isize;
5036 pd += isize;
5037 }
5038 }
5039 mfd->n = mfs->n; //ATOMIC OP
5040 }else{
5041 //isSF
5042 switch(typeIndex)
5043 {
5044 case FIELDTYPE_SFNode:
5045 {
5046 if(source->sfnode){
5047 deep_copy_node(&source->sfnode,&dest->sfnode,p2p,instancedScripts,ctx);
5048 add_parent(dest->sfnode,parent,__FILE__,__LINE__);
5049 }else{
5050 dest->sfnode = NULL;
5051 }
5052 }
5053 break;
5054 case FIELDTYPE_SFString:
5055 {
5056 struct Uni_String **ss, *sd;
5057 deleteMallocedFieldValue(typeIndex,dest);
5058 ss = (struct Uni_String **)source;
5059 sd = (struct Uni_String *)MALLOC (struct Uni_String*, sizeof(struct Uni_String));
5060 memcpy(sd,*ss,sizeof(struct Uni_String));
5061 sd->strptr = STRDUP((*ss)->strptr);
5062 dest->sfstring = sd;
5063 }
5064 break;
5065 default:
5066 //memcpy(dest,source,sizeof(union anyVrml));
5067 memcpy(dest,source,isize);
5068 break;
5069 }
5070 }
5071} //return copy_field
5072
5073//deep_copy_broto_body((struct X3D_Proto**)source,(struct X3D_Proto**)dest,p2p,instancedScripts);
5074void deep_copy_broto_body(struct X3D_Proto** proto, struct X3D_Proto** dest, Stack *instancedScripts)
5075{
5076 //converts from binary proto/broto format to old scene format:
5077 // - ROUTES are registered in global ROUTE registry
5078 // - nodes are instanced and registered in memoryTable for startOfLoopNodesUpdate and killNode access
5079 // - sensors, viewpoints etc are registered
5080 //proto - broto instance with
5081 // - a pointer __prototype to its generic prototype
5082 //dest - protoinstance with user fields filled out for this instance already
5083 // - children/body not filled out yet - it's done here
5084 // - any field/exposedField values in interface IS copied to body node fields
5085 // - broto ROUTES registered in global route registry, with this instances' node* addresses
5086 // ? ( sensors, viewpoints will be directly registered in global/main scene structs)
5087 //what will appear different in the scene:
5088 // old: PROTO instances appear as Group nodes with metaSF nodes for interface routing, mangled DEFnames
5089 // new: PROTO instances will appear as X3DProto nodes with userfields for interface routing, local DEFnames
5090
5091 //DEEP COPYING start here
5092 //we're instancing for the final scene, so go deep
5093 //0. setup pointer lookup table proto to instance
5094 //1. copy nodes, recursing on MFNode,SFnode fields
5095 // to copy, instance a new node of the same type and save (new pointer, old pointer) in lookup table
5096 // iterate over proto's node's fields, copying, and recursing on MFNode, SFNode
5097 // if node is a ProtoInstance, deepcopy it
5098 //2. copy ROUTE table, looking up new_pointers in pointer lookup table
5099 //3. copy IS table, looking up new_pointers in pointer lookup table
5100 //4. copy DEFname table, looking up new pointers in pointer lookup table
5101 //
5102
5103 struct X3D_Proto *prototype, *p;
5104 struct X3D_Node *parent;
5105 struct Vector *p2p = newVector(struct pointer2pointer,10);
5106
5107 //2. copy body from source's _prototype.children to dest.children, ISing initialvalues as we go
5108 p=(*dest);
5109 p->__children.n = 0;
5110 p->__children.p = NULL;
5111 parent = (struct X3D_Node*) (*dest); //NULL;
5112 prototype = (struct X3D_Proto*)(*proto)->__prototype;
5113 //prototype = (struct X3D_Proto*)p->__prototype;
5114 //2.c) copy IS
5115 //p->__IS = copy IStable from prototype, and the targetNode* pointer will be wrong until p2p
5116 //copy_IStable(&((Stack*)prototype->__IS), &((Stack*)p->__IS));
5117
5118 copy_IStable((Stack **) &(prototype->__IS), (Stack **) &(p->__IS));
5119
5120 //2.a) copy rootnodes
5121 copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(prototype->__children),(union anyVrml*)&(p->__children),
5122 p2p,instancedScripts,p,parent);
5123 //2.b) copy routes
5124 copy_routes(prototype->__ROUTES, p, p2p);
5125 //2.d) copy defnames
5126 copy_defnames(prototype->__DEFnames, p, p2p);
5127
5128 //3. convert IS events to backward routes
5129 copy_IS(p->__IS, p, p2p);
5130
5131 //*dest = p;
5132 //free p2p
5133 return;
5134}
5135
5136/* shallow_copy_field - a step beyond memcpy(anyvrml,anyvrml,len) by getting the MF elements
5137 malloced and copied too, except shallow in that SFNodes aren't deep copied - just the
5138 pointers are copied
5139*/
5140void shallow_copy_field(int typeIndex, union anyVrml* source, union anyVrml* dest)
5141{
5142 int i, isize;
5143 int sftype, isMF;
5144 struct Multi_Node *mfs,*mfd;
5145
5146 isMF = typeIndex % 2;
5147 sftype = typeIndex - isMF;
5148 //from EAI_C_CommonFunctions.c
5149 //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
5150 isize = sizeofSForMF(sftype);
5151 if(isMF)
5152 {
5153 int nele;
5154 char *ps, *pd;
5155 mfs = (struct Multi_Node*)source;
5156 mfd = (struct Multi_Node*)dest;
5157 //self assignment is no-op
5158 if(mfs->p != mfd->p){
5159 //we need to malloc and do more copying
5160 deleteMallocedFieldValue(typeIndex,dest);
5161 nele = mfs->n;
5162 if( sftype == FIELDTYPE_SFNode ) nele = (int) upper_power_of_two(nele);
5163 if(!nele){
5164 mfd->p = NULL;
5165 mfd->n = 0;
5166 }else{
5167 mfd->p = MALLOC (struct X3D_Node **, isize*nele);
5168 bzero(mfd->p,isize*nele);
5169 mfd->n = mfs->n;
5170 ps = (char *)mfs->p;
5171 pd = (char *)mfd->p;
5172 for(i=0;i<mfs->n;i++)
5173 {
5174 shallow_copy_field(sftype,(union anyVrml*)ps,(union anyVrml*)pd);
5175 ps += isize;
5176 pd += isize;
5177 }
5178 }
5179 }
5180 }else{
5181 //isSF
5182 switch(typeIndex)
5183 {
5184 case FIELDTYPE_SFString:
5185 {
5186 //go deep, same as copy_field
5187 struct Uni_String **ss, *sd;
5188 if(source != dest){
5189 deleteMallocedFieldValue(typeIndex,dest);
5190 ss = (struct Uni_String **)source;
5191 if(*ss){
5192 sd = (struct Uni_String *)MALLOC (struct Uni_String*, sizeof(struct Uni_String));
5193 memcpy(sd,*ss,sizeof(struct Uni_String));
5194 sd->strptr = STRDUP((*ss)->strptr);
5195 dest->sfstring = sd;
5196 }
5197 }
5198 }
5199 break;
5200 case FIELDTYPE_SFImage:
5201 {
5202 struct SFImage* si, * di;
5203 si = &source->sfimage;
5204 di = &dest->sfimage;
5205 if (di == si) return; //don't copy to self
5206 //we need to malloc and do more copying
5207 //deleteMallocedFieldValue(typeIndex, dest);
5208 FREE_IF_NZ(di->arr.p);
5209 int nele = si->arr.n;
5210 nele = (int)upper_power_of_two(nele);
5211 if (!nele) {
5212 di->arr.p = NULL;
5213 di->arr.n = 0; //should be in here, always 3+
5214 di->whc[0] = di->whc[1] = di->whc[2] = 0;
5215 }
5216 else {
5217 int jsize = sizeof(int);
5218 di->arr.p = MALLOC(int *, jsize * nele);
5219 bzero(di->arr.p, jsize * nele);
5220 di->arr.n = si->arr.n;
5221 memcpy(di->arr.p, si->arr.p, jsize * si->arr.n);
5222 memcpy(di->whc, si->whc, 3 * sizeof(int));
5223 //printf("in shallow_copy_field SFImage: \n");
5224 //for (int k = 0; k < di->n; k++) printf("%d ", di->p[k]);
5225 //printf("\n");
5226 }
5227 }
5228 break;
5229 default:
5230 //memcpy(dest,source,sizeof(union anyVrml));
5231 memcpy(dest,source,isize);
5232
5233 break;
5234 }
5235 }
5236} //return copy_field
5237
5238
5239int PKW_from_KW(int KW_index)
5240{
5241 /* translates the KEYWORDS[KW_index] field mode found in the 4th column of the OFFSETS_
5242 into an index that works in the PROTOKEYWORDS[] array */
5243 int pkw = -1;
5244 switch(KW_index)
5245 {
5246 case KW_initializeOnly:
5247 pkw = PKW_initializeOnly; break;
5248 case KW_inputOnly:
5249 pkw = PKW_inputOnly; break;
5250 case KW_outputOnly:
5251 pkw = PKW_outputOnly; break;
5252 case KW_inputOutput:
5253 pkw = PKW_inputOutput; break;
5254 case KW_field:
5255 pkw = PKW_field; break;
5256 case KW_eventIn:
5257 pkw = PKW_eventIn; break;
5258 case KW_eventOut:
5259 pkw = PKW_eventOut; break;
5260 case KW_exposedField:
5261 pkw = PKW_exposedField; break;
5262 default:
5263 pkw = -1;
5264 }
5265 return pkw;
5266}
5267BOOL isManagedField(int mode, int type, BOOL isPublic);
5268void registerParentIfManagedField(int type, int mode, BOOL isPublic, union anyVrml* any, struct X3D_Node* parent)
5269{
5270 //puts what you say is the parent of the sfnode/mfnodes into the parentVector of each sfnode/mfnodes
5271 // if its a managed field.
5272 //isPublic - no leading _ on field name, or script/proto user field - you tell us, its easier that way
5273 //managed field: public && node field && value holding
5274 //int isManagedField;
5275 //isManagedField = isPublic && (type == FIELDTYPE_SFNode || type == FIELDTYPE_MFNode);
5276 //isManagedField = isManagedField && (mode == PKW_initializeOnly || mode == PKW_inputOutput);
5277 if(isManagedField(mode,type,isPublic))
5278 {
5279 int n,k,haveSomething;
5280 struct X3D_Node **plist, *sfn;
5281 haveSomething = (type==FIELDTYPE_SFNode && any->sfnode) || (type==FIELDTYPE_MFNode && any->mfnode.n);
5282 haveSomething = haveSomething && parent;
5283 if(haveSomething){
5284 if(type==FIELDTYPE_SFNode){
5285 plist = &any->sfnode;
5286 n = 1;
5287 }else{
5288 plist = any->mfnode.p;
5289 n = any->mfnode.n;
5290 }
5291 for(k=0;k<n;k++)
5292 {
5293 sfn = plist[k];
5294 if(sfn){
5295 if( !sfn->_parentVector)
5296 sfn->_parentVector = newVector(struct X3D_Node*,2);
5297 vector_pushBack(struct X3D_Node*, sfn->_parentVector, parent);
5298 }
5299 }
5300 }
5301 }
5302}
5303void freeMallocedNodeFields(struct X3D_Node* node);
5304void deleteProtoDefinition(struct ProtoDefinition *ret);
5305void freePublicBuiltinNodeFields(struct X3D_Node* node);
5306void **shaderFields(struct X3D_Node* node);
5307void deep_copy_node(struct X3D_Node** source, struct X3D_Node** dest, struct Vector *p2p, Stack *instancedScripts,
5308 struct X3D_Proto* ctx)
5309{
5310 struct pointer2pointer pair;
5311 struct X3D_Node* parent;
5312 void **shaderfield = NULL;
5313 if(*source == NULL){
5314 *dest = NULL;
5315 return;
5316 }
5317 *dest = inPointerTable(*source,p2p);
5318 if(*dest)
5319 return; //already created and we're likely at what would be a USE in the original ProtoDeclare body
5320 //create new Node
5321 //problem with both brotoInstance and createNewX3DNode in deep_copy:
5322 // default field values are malloced, but we don't need or use them, -we copy below- so we need to gc them
5323 // solution - in copy_field or shallow_copy_field, call deleteMallocedFieldValue(type,unionAnyvrml)
5324 if((*source)->_nodeType == NODE_Proto){
5325 *dest = X3D_NODE(brotoInstance(X3D_PROTO(X3D_PROTO(*source)->__prototype),ciflag_get(ctx->__protoFlags,0)));
5326 }else{
5327 *dest=X3D_NODE(createNewX3DNode( (*source)->_nodeType)); //will register sensors and viewpionts
5328 }
5329 add_node_to_broto_context(ctx,(*dest));
5330
5331 parent = *dest;
5332 if((*source)->_nodeType == NODE_Script)
5333 stack_push(struct X3D_Node*,instancedScripts,*dest);
5334 //register in pointer lookup table
5335 //pair = MALLOC(struct pointer2pointer*,sizeof(struct pointer2pointer));
5336 pair.pp = *source;
5337 pair.pn = *dest;
5338 vector_pushBack(struct pointer2pointer, p2p, pair);
5339 shaderfield = shaderFields(*source);
5340 //copy fields
5341 {
5342 //typedef struct field_info{
5343 // int nameIndex;
5344 // int offset;
5345 // int typeIndex;
5346 // int ioType;
5347 // int version;
5348 // int unca;
5349 //} *finfo;
5350 fieldinfo offsets;
5351 fieldinfo field;
5352 int ifield;
5353
5354 offsets = (fieldinfo)NODE_OFFSETS[(*source)->_nodeType];
5355 ifield = 0;
5356 field = &offsets[ifield];
5357 //printf("\n");
5358 while( field->nameIndex > -1)
5359 {
5360 int is_source;
5361 struct brotoIS * isrecord;
5362 //printf(" %s",FIELDNAMES[field->nameIndex]); //[0]]);
5363 //printf(" (%s)\n",FIELDTYPES[field->typeIndex]); //field[2]]);
5364 isrecord = NULL;
5365 is_source = 0; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
5366 isrecord = in_IStable(*source,ifield,(Stack *)ctx->__IS, is_source);
5367 if (isrecord != NULL)
5368 {
5369 //do something to change from:
5370 // copy *source to *dest, to
5371 // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
5372 union anyVrml *source_field, *dest_field;
5373 struct ProtoDefinition *sp;
5374 struct ProtoFieldDecl *sdecl;
5375 sp = ctx->__protoDef;
5376 sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
5377
5378 //source_field = (union anyVrml*)&((char*)*source)[field->offset];
5379 source_field = (union anyVrml*)&(sdecl->defaultVal);
5380 dest_field = (union anyVrml*)&((char*)*dest )[field->offset];
5381 //copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx);
5382 shallow_copy_field(field->typeIndex, source_field, dest_field);
5383 registerParentIfManagedField(field->typeIndex,PKW_from_KW(field->ioType),1, dest_field, *dest);
5384
5385 // similarly below when processing ISs on user fields in script and broto fields.
5386 // istable could include a hint on the type of field to be looking for:
5387 // ie builtin offset vs scriptfield/brotofield/userfield index
5388 // while remembering some node types could have either ie Script{ url IS protofield_URL SFString hemoglobin IS protofield_blood...
5389 }
5390 //in general we don't generically copy private fields starting with '_'
5391 //that's because usually its the compile_(nodetype)() function that populates those private fields,
5392 //and compile_ will get a shot at the node later, if/when its compiled.
5393 //except user field list pointers for proto, script etc we need to deep copy here
5394 else if((*source)->_nodeType == NODE_Proto && !strcmp(FIELDNAMES[field->nameIndex],"__protoDef") )
5395 {
5396 int k;
5397 //struct X3D_Proto *prototype, *p;
5398 struct ProtoDefinition *sp, *dp;
5399 struct ProtoFieldDecl *sdecl,*ddecl;
5400 struct X3D_Proto *s, *d;
5401
5402 s = (struct X3D_Proto*)*source;
5403 d = (struct X3D_Proto*)*dest;
5404 sp = s->__protoDef;
5405 dp = d->__protoDef; //Jan 2015 = NULL; May 2015 not null, default broto field values
5406
5407 if(sp){ //are there any Proto fields? Not for the Scene - this may not be malloced for the scene
5408 //dp = MALLOC(struct ProtoDefinition*,sizeof(struct ProtoDefinition));
5409 if(dp == NULL) //Jan 2015
5410 dp = newProtoDefinition();
5411 //memcpy(dp,sp,sizeof(struct ProtoDefinition));
5412 //usually brotoInstance or newProtoDefinition creates iface
5413 //however brotoInstance populates with default initializeOnly values
5414 //and here we are going to copy over the/any non-default brotoInstance over-ride values
5415 if(!dp->iface) //may 2015 should not be null
5416 dp->iface = newVector(struct ProtoFieldDecl *, sp->iface->n);
5417 //dp->protoName = STRDUP(sp->protoName);
5418 dp->isCopy = TRUE;
5419 for(k=0;k<sp->iface->n;k++)
5420 {
5421 sdecl = protoDefinition_getFieldByNum(sp, k);
5422 ddecl = protoDefinition_getFieldByNum(dp, k);
5423 //ddecl=newProtoFieldDecl(sdecl->mode, sdecl->type, sdecl->name);
5424 //memcpy(ndecl,pdecl,sizeof(struct ProtoFieldDecl *)); //not just the pointer
5425 //ddecl->cname = STRDUP(sdecl->cname);
5426 is_source = 3; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
5427
5428
5429 isrecord = in_IStable(*source,k,(Stack *)ctx->__IS, is_source);
5430 if (isrecord != NULL)
5431 {
5432 //do something to change from:
5433 // copy *source to *dest, to
5434 // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
5435 union anyVrml *source_field, *dest_field;
5436 struct ProtoDefinition *sp;
5437 struct ProtoFieldDecl *sdecl;
5438 sp = ctx->__protoDef;
5439 sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
5440
5441 //source_field = (union anyVrml*)&((char*)*source)[field->offset];
5442 source_field = (union anyVrml*)&(sdecl->defaultVal);
5443 dest_field = (union anyVrml*)&(ddecl->defaultVal);
5444 //copy_field(sdecl->type,source_field,dest_field,p2p,instancedScripts,ctx);
5445 //shallow copy means if its an SFNode or MFNode field, don't
5446 //deep copy - just copy the pointers. That's because the SFNodes involved
5447 //are already instanced/memoryTable malloced for the live scene: they were
5448 //done for the current proto interface
5449 shallow_copy_field(sdecl->type, source_field, dest_field);
5450 registerParentIfManagedField(sdecl->type,sdecl->mode,1, dest_field, *dest);
5451 ddecl->alreadySet = sdecl->alreadySet;
5452 }else{
5453 if(0) //shallow copy for testing
5454 memcpy(ddecl,sdecl,sizeof(struct ProtoFieldDecl)); //.. the whole struct
5455 /* proper deep copy we must do to get value-holding SFNode fields
5456 (event fields will have uninitialized junk)*/
5457 if(sdecl->mode == PKW_initializeOnly || sdecl->mode == PKW_inputOutput){
5458 //if(1){
5459 union anyVrml *source_field, *dest_field;
5460 source_field = (union anyVrml*)&(sdecl->defaultVal);
5461 dest_field = (union anyVrml*)&(ddecl->defaultVal);
5462 copy_field(sdecl->type,source_field,dest_field,p2p,instancedScripts,ctx,parent);
5463 ddecl->alreadySet = sdecl->alreadySet;
5464 }
5465 }
5466 //protoDefinition_addIfaceField(dp, ddecl);
5467 }
5468 d->__protoDef = dp;
5469 }
5470 }
5471 else if((*source)->_nodeType == NODE_Script && !strcmp(FIELDNAMES[field->nameIndex],"__scriptObj") )
5472 {
5473 /*deep copy script user fields */
5474 int k;
5475 struct Vector *sfields;
5476 struct ScriptFieldDecl *sfield, *dfield;
5477 struct Shader_Script *sp, *dp;
5478 struct X3D_Script *s, *d;
5479
5480 s = (struct X3D_Script*)*source;
5481 d = (struct X3D_Script*)*dest;
5482 sp = s->__scriptObj;
5483 dp = d->__scriptObj = new_Shader_ScriptB(*dest);
5484 dp->loaded = sp->loaded; //s.b. FALSE
5485 dp->num = sp->num; //s.b. -1
5486 sfields = sp->fields;
5487 for(k=0;k<sfields->n;k++)
5488 {
5489 BOOL isInitialize;
5490 dfield = MALLOC(struct ScriptFieldDecl*,sizeof(struct ScriptFieldDecl));
5491 bzero(dfield,sizeof(struct ScriptFieldDecl));
5492 dfield->fieldDecl = MALLOC(struct FieldDecl *,sizeof(struct FieldDecl));
5493 bzero(dfield->fieldDecl,sizeof(struct FieldDecl));
5494 is_source = 1; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
5495 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
5496
5497 isrecord = in_IStable(*source,k,(Stack *)ctx->__IS, is_source);
5498 isInitialize = isrecord && (isrecord->mode == PKW_initializeOnly || isrecord->mode == PKW_inputOutput);
5499 if( isInitialize )
5500 {
5501 //do something to change from:
5502 // copy *source to *dest, to
5503 // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
5504 union anyVrml *source_field, *dest_field;
5505 struct ProtoDefinition *sp;
5506 struct ProtoFieldDecl *sdecl;
5507
5508 sp = ctx->__protoDef;
5509 sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
5510 if(sdecl->fieldString)
5511 dfield->ASCIIvalue = STRDUP(sdecl->fieldString);
5512 memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
5513 //ddecl = dfield->fieldDecl;
5514 //ddecl->fieldType = sdecl->type;
5515 //ddecl->JSparamNameIndex = sfield->fieldDecl->;
5516 //ddecl->lexerNameIndex = sdecl->name;
5517 //ddecl->PKWmode = sdecl->mode;
5518 //ddecl->shaderVariableID = 0;
5519 //source_field = (union anyVrml*)&((char*)*source)[field->offset];
5520 source_field = (union anyVrml*)&(sdecl->defaultVal);
5521 dest_field = (union anyVrml*)&(dfield->value);
5522 //copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx);
5523 shallow_copy_field(sdecl->type, source_field, dest_field);
5524 registerParentIfManagedField(sdecl->type, sdecl->mode, 1, dest_field, *dest);
5525
5526 }else{
5527 if(sfield->ASCIIvalue)
5528 dfield->ASCIIvalue = STRDUP(sfield->ASCIIvalue);
5529 //*(output->fieldDecl) = *(sfield->fieldDecl);
5530 memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
5531 /* shallow copy for testing some scenarios*/
5532 if(0){
5533 dfield->value = sfield->value;
5534 }
5535 /* proper deep copy we must do to get value-holding SFNode fields
5536 (event fields will have uninitialized junk)*/
5537 if(sfield->fieldDecl->PKWmode == PKW_initializeOnly || sfield->fieldDecl->PKWmode == PKW_inputOutput){
5538 union anyVrml *source_field, *dest_field;
5539 source_field = (union anyVrml*)&(sfield->value);
5540 dest_field = (union anyVrml*)&(dfield->value);
5541 copy_field(dfield->fieldDecl->fieldType,source_field,dest_field,p2p,instancedScripts,ctx,parent);
5542 }
5543 dfield->valueSet = sfield->valueSet;
5544 }
5545 vector_pushBack(struct ScriptFieldDecl *, dp->fields, dfield);
5546 }
5547 }
5548 else if(shaderfield && !strcmp(FIELDNAMES[field->nameIndex],"_shaderUserDefinedFields") )
5549 {
5550 /*copied block above for Script, and hacked a few lines to abstract
5551 the __scriptObj vs _shaderUserDefinedFields
5552 Applies to:
5553 ComposedShader
5554 Effect
5555 ShaderProgram
5556 PackagedShader
5557 see function shaderFields in X3DParser.c
5558
5559 */
5560 /*deep copy script user fields */
5561 int k;
5562 struct Vector *sfields;
5563 struct ScriptFieldDecl *sfield, *dfield;
5564 struct Shader_Script *sp, *dp;
5565 void **dshaderfield;
5566 //struct X3D_Script *s, *d;
5567
5568 //s = (struct X3D_Script*)*source;
5569 //d = (struct X3D_Script*)*dest;
5570 dshaderfield = shaderFields(*dest);
5571 sp = *shaderfield; //s->__scriptObj;
5572 dp = new_Shader_ScriptB(*dest);
5573 (*dshaderfield) = (void*) dp;
5574 dp->loaded = sp->loaded; //s.b. FALSE
5575 dp->num = sp->num; //s.b. -1
5576 sfields = sp->fields;
5577 for(k=0;k<sfields->n;k++)
5578 {
5579 BOOL isInitialize;
5580 dfield = MALLOC(struct ScriptFieldDecl*,sizeof(struct ScriptFieldDecl));
5581 bzero(dfield,sizeof(struct ScriptFieldDecl));
5582 dfield->fieldDecl = MALLOC(struct FieldDecl *,sizeof(struct FieldDecl));
5583 bzero(dfield->fieldDecl,sizeof(struct FieldDecl));
5584 is_source = 2; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
5585 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
5586
5587 isrecord = in_IStable(*source,k,(Stack *)ctx->__IS, is_source);
5588 isInitialize = isrecord && (isrecord->mode == PKW_initializeOnly || isrecord->mode == PKW_inputOutput);
5589 if( isInitialize )
5590 {
5591 //do something to change from:
5592 // copy *source to *dest, to
5593 // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
5594 union anyVrml *source_field, *dest_field;
5595 struct ProtoDefinition *sp;
5596 struct ProtoFieldDecl *sdecl;
5597
5598 sp = ctx->__protoDef;
5599 sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
5600 if(sdecl->fieldString)
5601 dfield->ASCIIvalue = STRDUP(sdecl->fieldString);
5602 memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
5603 //ddecl = dfield->fieldDecl;
5604 //ddecl->fieldType = sdecl->type;
5605 //ddecl->JSparamNameIndex = sfield->fieldDecl->;
5606 //ddecl->lexerNameIndex = sdecl->name;
5607 //ddecl->PKWmode = sdecl->mode;
5608 //ddecl->shaderVariableID = 0;
5609 //source_field = (union anyVrml*)&((char*)*source)[field->offset];
5610 source_field = (union anyVrml*)&(sdecl->defaultVal);
5611 dest_field = (union anyVrml*)&(dfield->value);
5612 //copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx);
5613 shallow_copy_field(sdecl->type, source_field, dest_field);
5614 registerParentIfManagedField(sdecl->type, sdecl->mode, 1, dest_field, *dest);
5615
5616 }else{
5617 if(sfield->ASCIIvalue)
5618 dfield->ASCIIvalue = STRDUP(sfield->ASCIIvalue);
5619 //*(output->fieldDecl) = *(sfield->fieldDecl);
5620 memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
5621 /* shallow copy for testing some scenarios*/
5622 if(0){
5623 dfield->value = sfield->value;
5624 }
5625 /* proper deep copy we must do to get value-holding SFNode fields
5626 (event fields will have uninitialized junk)*/
5627 if(sfield->fieldDecl->PKWmode == PKW_initializeOnly || sfield->fieldDecl->PKWmode == PKW_inputOutput){
5628 union anyVrml *source_field, *dest_field;
5629 source_field = (union anyVrml*)&(sfield->value);
5630 dest_field = (union anyVrml*)&(dfield->value);
5631 copy_field(dfield->fieldDecl->fieldType,source_field,dest_field,p2p,instancedScripts,ctx,parent);
5632 }
5633 dfield->valueSet = sfield->valueSet;
5634 }
5635 vector_pushBack(struct ScriptFieldDecl *, dp->fields, dfield);
5636 }
5637 }
5638 else
5639 {
5640 if( FIELDNAMES[field->nameIndex][0] != '_'){ //Q. should we ignor private fields?
5641 union anyVrml *source_field, *dest_field;
5642 source_field = (union anyVrml*)&((char*)*source)[field->offset];
5643 dest_field = (union anyVrml*)&((char*)*dest )[field->offset];
5644 //if(!strcmp(FIELDNAMES[field->nameIndex],"appearance"))
5645 //{
5646 // struct X3D_Shape* shp1, *shp2;
5647 // shp1 = (struct X3D_Shape*)source;
5648 // shp2 = (struct X3D_Shape*)(*source);
5649 // printf("appearance shp1= %d shp2= %d\n",(int)shp1,(int)shp2);
5650 //}
5651 copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx,parent);
5652 }
5653 }
5654 ifield++;
5655 field = &offsets[ifield];
5656 }
5657 }
5658 if((*source)->_nodeType == NODE_Proto)
5659 {
5660 /* deep copy the body/context/_prototype from the Proto:
5661 - defnames, ISes, Routes, body nodes from _prototype upgraded by ISes
5662 */
5663 struct X3D_Proto *pdest;
5664 unsigned char pdepthflag;
5665 pdest = X3D_PROTO(*dest);
5666 if(0){
5667 //Jan 2015 - depth is upgraded in brotoInstance above
5668 pdepthflag = ciflag_get(ctx->__protoFlags,0);
5669 pdest->__protoFlags = ciflag_set(pdest->__protoFlags,pdepthflag,0); //upgrade depth flag to that of containing context ie deep == 1 live scenery (vs 0 for still protodeclare)
5670 }
5671 deep_copy_broto_body2((struct X3D_Proto**)source,(struct X3D_Proto**)dest);
5672 }
5673}
5674int nextScriptHandle (void);
5675
5676void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url){
5677 struct ScriptFieldDecl* field;
5678 int j;
5679
5680 //printf("script node %p \n",sn);
5681 ss->num = nextScriptHandle();
5682 //printf(" num=%d \n",ss->num);
5683 JSInit(ss); //ss->num);
5684 // 2)init each field
5685 for(j=0;j<ss->fields->n;j++)
5686 {
5687 //printf("initializing field %d of %d \n",j,ss->fields->n);
5688 field = vector_get(struct ScriptFieldDecl*,ss->fields,j);
5689 //script_addField(ss,field);
5690
5691 //scriptFieldDecl_jsFieldInit(field, ss->num); //saves it for initializeOnly work
5692 field->script = ss;
5693 //printf("\t field index %d JSparamnameIndex %d name %s\n",
5694 // j,field->fieldDecl->JSparamNameIndex,JSparamnames[field->fieldDecl->JSparamNameIndex].name);
5695 //Q. do I need this: - it mallocs something. Or is this just for initializeOnly?
5696 //void SaveScriptField (int num, indexT kind, indexT type, const char* field, union anyVrml value) {
5697
5698 }
5699 // 3)init from URI
5700 script_initCodeFromMFUri(ss, url);
5701}
5702
5703void initialize_scripts(Stack *instancedScripts)
5704{
5705 /*
5706 Old (pre-2013) Script special handling during Parsing:
5707 1. new script node? get a num for it
5708 ret->num=nextScriptHandle(); JSInit(ret->num);
5709 2. new script field? add it and initailize its value:
5710 script_addField > scriptFieldDecl_jsFieldInit(field, me->num);
5711 3. after all fields of a script node have been added, try initializing the URL field
5712 script_initCodeFromUri > script_initCode
5713
5714 New (2013 BROTO era) Script Special handling:
5715 Parsing: don't do any of the above 3
5716 Instancing: in sceneInstance():
5717 - instance all nodes generically, including script nodes,
5718 except for each script node instanced put it in a special node* list
5719 - after all nodes have been instanced, call this initializeScripts() function:
5720 -- go through the special node* list of instanced scripts and for each (script) node*:
5721 1)get a script num 2)init each field 3)init from URI (like the above 3)
5722
5723 */
5724 //int n, i,j;
5725 //struct X3D_Node* p;
5726 //struct X3D_Script* sn;
5727 //struct Shader_Script* ss; //)X3D_SCRIPT(node)->__scriptObj)->num
5728 //struct ScriptFieldDecl* field;
5729 //JSObject *eventInFunction;
5730
5731
5732 if(instancedScripts)
5733 {
5734 int n, i,j;
5735 struct X3D_Node* p;
5736 struct X3D_Script* sn;
5737 struct Shader_Script* ss; //)X3D_SCRIPT(node)->__scriptObj)->num
5738 struct ScriptFieldDecl* field;
5739
5740
5741 n = instancedScripts->n;
5742 for(i=0;i<n;i++)
5743 {
5744 p = vector_get(struct X3D_Node*,instancedScripts,i);
5745 sn = (struct X3D_Script*)p;
5746 // 1)get a script num
5747 ss = sn->__scriptObj;
5748 if(1){
5749 initialize_one_script(ss,&sn->url);
5750 }else{
5751
5752 //printf("script node %p \n",sn);
5753 //printf("in initialize_scripts i=%d __scriptObj =%p ",i,ss);
5754 ss->num = nextScriptHandle();
5755 //printf(" num=%d \n",ss->num);
5756 JSInit(ss); //ss->num);
5757 // 2)init each field
5758 for(j=0;j<ss->fields->n;j++)
5759 {
5760 //printf("initializing field %d of %d \n",j,ss->fields->n);
5761 field = vector_get(struct ScriptFieldDecl*,ss->fields,j);
5762 //script_addField(ss,field);
5763
5764 scriptFieldDecl_jsFieldInit(field, ss->num); //saves it for initializeOnly work
5765 //printf("\t field index %d JSparamnameIndex %d name %s\n",
5766 // j,field->fieldDecl->JSparamNameIndex,JSparamnames[field->fieldDecl->JSparamNameIndex].name);
5767 //Q. do I need this: - it mallocs something. Or is this just for initializeOnly?
5768 //void SaveScriptField (int num, indexT kind, indexT type, const char* field, union anyVrml value) {
5769
5770 }
5771 // 3)init from URI
5772 script_initCodeFromMFUri(ss, &sn->url);
5773 }
5774 }
5775 }
5776
5777}
5778void sceneInstance(struct X3D_Proto* sceneProto, struct X3D_Node *sceneInstance)
5779{
5780 //deprecated Sept 2014 by dug9: we now instance as we parse a scene (or if we did parse a scene as a sceneDeclare
5781 // we could call brotoInstance() and deep_copy_broto_body2() to instance the scene)
5782
5783 //sceneProto - cParse results in new X3D_Proto format
5784 //sceneInstance - pass in a Group node to accept scene rootNodes
5785 // - (ROUTES, sensors, viewpoints will be directly registered in global/main scene structs)
5786 //converts from binary proto/broto format to old scene format:
5787 // - ROUTES are registered in global ROUTE registry
5788 // - nodes are instanced and registered in memoryTable for startOfLoopNodesUpdate and killNode access
5789 // - sensors, viewpoints etc are registered
5790 //what will appear different in the scene:
5791 // old: PROTO instances appear as Group nodes with metaSF nodes for interface routing, mangled DEFnames
5792 // new: PROTO instances will appear as X3DProto nodes with userfields for interface routing, local DEFnames
5793
5794 //DEEP COPYING start here
5795 //we're instancing for the final scene, so go deep
5796 //0. setup pointer lookup table proto to instance
5797 //1. copy nodes, recursing on MFNode,SFnode fields
5798 // to copy, instance a new node of the same type and save (new pointer, old pointer) in lookup table
5799 // iterate over proto's node's fields, copying, and recursing on MFNode, SFNode
5800 // if node is a ProtoInstance, deepcopy it
5801 //2. copy ROUTE table, looking up new_pointers in pointer lookup table
5802 //3. copy IS table, looking up new_pointers in pointer lookup table
5803 //4. copy DEFname table, looking up new pointers in pointer lookup table
5804 //
5805
5806
5807 struct X3D_Proto *scenePlaceholderProto;
5808 struct X3D_Node *parent;
5809 struct Multi_Node *children;
5810 struct Vector *p2p = newVector(struct pointer2pointer,10);
5811 Stack *instancedScripts = newStack(struct X3D_Node*);
5812 children = childrenField(sceneInstance);
5813 children->n = 0;
5814 children->p = NULL;
5815 parent = (struct X3D_Node*)sceneInstance;
5816 scenePlaceholderProto = createNewX3DNode0(NODE_Proto);
5817 //if(0){
5818 // prototype = (struct X3D_Proto*)sceneProto->__prototype;
5819 // //copy rootnodes
5820 // copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(prototype->children),(union anyVrml*)&(sceneInstance->children),p2p);
5821 //}else{
5822 //I think the sceneProto being passed in is already the prototype -with body- and not an interface/instance
5823 //copy rootnodes
5824 copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(sceneProto->__children),(union anyVrml*)children,
5825 p2p,instancedScripts,scenePlaceholderProto,parent);
5826 //}
5827 //copy sceneProto routes (child protoInstance routes copied elsewhere)
5828 copy_routes(sceneProto->__ROUTES, NULL, p2p);
5829 //shouldn't be any IS-table in main scene (child protoInstance IS-tables copied elsewhere)
5830 copy_IS(sceneProto->__IS, NULL, p2p);
5831 //copy sceneProto defnames (child protoInstance defnames copied elsewhere - will duplicate)
5832 copy_defnames(sceneProto->__DEFnames, NULL, p2p);
5833
5834 initialize_scripts(instancedScripts);
5835
5836 return;
5837}
5838
5839
5840/* added Jan 15, 2013:
5841 parse an IS statement:
5842 - test if it's an IS, if not backup and return lexer's original position
5843 - register IS in ProtoDeclare's IS-table.
5844 - swallow the the nodeFieldName, IS and protoFieldName tokens.
5845 - set the value of the field in the node, if appropriate.
5846
5847 Background:
5848 Goal: allow IS in the main scene, or more precisely,
5849 to parse ProtoDeclare Bodies with main scene parsing code for new style protos.
5850 That means we need IS handling in the main scene parsing code.
5851 This seems like a nice place to put the handler.
5852 I'm expecting everything else already handled except IS:
5853 ----------------------------
5854 WRL Parsing Fields on Nodes
5855 when parsing a node we expect to see
5856 A. For built-in fields and user fields on protoInstances where mode and fieldtype are known in advance:
5857 (optional DEF name) nodeType ({ list of fields } or USE name)
5858 And for each field mentioned, one of:
5859 fieldname <fieldvalue> where <fieldvalue> is one of:
5860* IS protoFieldName #on any type & mode that jives^ with protoField type & mode
5861 1 2 3 #just for SF modes: field/initializeOnly, exposedField/inputOutput
5862 [1 2 3, 4 5 6] #just for MF modes: field/initializeOnly, exposedField/inputOutput
5863 USE nodename #just for SFNode modes: field/initializOnly, exposedField/inputOutput
5864 DEF nodename type{} #just for SFNode modes: field/initializOnly, exposedField/inputOutput
5865 type{} #just for SFNode modes: field/initializOnly, exposedField/inputOutput
5866 where type{} is any builtin or user node type
5867 B. for user fields on scripts and protoDeclares:
5868 mode fieldtype fieldname <fieldvalue>
5869 where:
5870 mode is one of field, eventIn, eventOut, exposedField
5871 fieldtype is one of SF*,MF* where * is one of Color,Vec3f,Node,...
5872 <fieldvalue> can be one of the above combinations as for builtin fields
5873
5874 ^See the IS mode-jive table here:
5875 http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#PROTOdefinitionsemantics
5876 where:
5877 'Prototype Declaration' means the Interface of a ProtoDeclare/PROTO
5878 'Prototype Definition' means the Body of a ProtoDeclare/PROTO
5879 ---------------------------------
5880
5881*/
5882BOOL nodeTypeSupportsUserFields(struct X3D_Node *node)
5883{
5884 BOOL user = FALSE;
5885 user = node->_nodeType == NODE_Proto || node->_nodeType == NODE_Script ||
5886 node->_nodeType == NODE_ComposedShader || node->_nodeType == NODE_ShaderProgram ||
5887 node->_nodeType == NODE_PackagedShader || node->_nodeType == NODE_Effect ? TRUE : FALSE;
5888 return user;
5889}
5890
5891
5892const char *rootFieldName(const char* fieldname, int* len, int *has_changed, int *has_set)
5893{
5894 /*
5895 given a fieldname wholename "set_amazing_changed"
5896 it returns: s="amazing_changed", len = 7, has_changed 1, has_set 1
5897 you can use s and len in strncmp to test against the rootname
5898 */
5899 static char* str_changed = "_changed";
5900
5901 static int len_changed = 8;
5902 static int len_set = 4;
5903
5904 int ln;
5905 const char* s;
5906
5907 ln = (int) strlen(fieldname);
5908
5909 *has_changed = ln > len_changed ? !strncmp(&fieldname[ln-len_changed],str_changed,len_changed) : FALSE;
5910 *has_set = ln > len_set ? !strncmp(fieldname,"set_",len_set) : FALSE;
5911 s = *has_set ? &fieldname[len_set] : fieldname;
5912 *len = *has_changed? (int)(&fieldname[ln - len_changed] - s) : (int)(&fieldname[ln] - s);
5913 return s;
5914}
5915BOOL fieldSynonymCompare(const char *routeFieldName, const char* nodeFieldName) //, int nodeFieldMode)
5916{
5917 // like strcmp, it returns false if there's no difference / a match
5918 // except it compares rootnames if there is a set_ or _changed on either
5919 // ie (set_amazing, amazing_changed) returns FALSE (a match of rootname).
5920 int lr,hsr,hcr,ln,hsn,hcn;
5921 const char *rf, *nf;
5922
5923 if(!strcmp(routeFieldName,nodeFieldName) )return FALSE; //easy match of wholenames
5924
5925 //get rootnames with set_ and _changed stripped off
5926 rf = rootFieldName(routeFieldName,&lr,&hsr,&hcr);
5927 nf = rootFieldName(nodeFieldName, &ln,&hsn,&hcn);
5928
5929 if(lr != ln) return TRUE; //rootname lengths are different so no hope of match
5930 if(strncmp(rf,nf,lr)) return TRUE; //rootnames are different so no hope of match
5931 //the rootnames are equal
5932 //Q. are there some special conditions for matching, with nodeFieldMode or route/IS field mode
5933 //a) for routes you know a-priori/beforehand 'ROUTE from TO to' and on the
5934 // from node you want either eventOut/outputOnly (_changed) or exposedField/inputOutput (rootname)
5935 // to node you want either eventIn/inputOnly or (set_) or exposedField/inputOutput (rootname)
5936 //b) for IS there is a "mode-jive table" that says
5937 // - if your node is inputOutput the protofield can be any mode.
5938 // - otherwise the nodefield and protofield modes must match.
5939 // in both cases you would want to try to match wholenames first ie trust the scene author.
5940 return FALSE; //a match
5941}
5942
5943
5944//#define WRLMODE(val) (((val) % 4)+4) //jan 2013 codegen PROTOKEYWORDS[] was ordered with x3d synonyms first, wrl last
5945
5946//#define X3DMODE(val) ((val) % 4)
5947//#define X3DMODE(##val) PKW_from_KW((##val)
5948int X3DMODE(int val)
5949{
5950 int iret = 0;
5951 switch(val){
5952 case PKW_field:
5953 case PKW_initializeOnly:
5954 iret = PKW_initializeOnly; break;
5955 case PKW_exposedField:
5956 case PKW_inputOutput:
5957 iret = PKW_inputOutput; break;
5958 case PKW_eventIn:
5959 case PKW_inputOnly:
5960 iret = PKW_inputOnly; break;
5961 case PKW_eventOut:
5962 case PKW_outputOnly:
5963 iret = PKW_outputOnly; break;
5964 default:
5965 printf("ouch from X3DMODE\n");
5966 }
5967 return iret;
5968}
5969
5970#ifndef DISABLER
5971BOOL walk_fields(struct X3D_Node* node, int (*callbackFunc)(), void* callbackData);
5972#else
5973BOOL walk_fields(struct X3D_Node* node, BOOL (*callbackFunc)(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,
5974 const char *fieldName, indexT mode, indexT type,int isource,BOOL publicfield), void* callbackData);
5975#endif
5976//=========== find any field by name via walk_fields
5977typedef struct cbDataExactName {
5978 const char *fname;
5979 union anyVrml* fieldValue;
5980 int mode;
5981 int type;
5982 int jfield;
5983 int source;
5984 BOOL publicfield;
5985} s_cbDataExactName;
5986BOOL cbExactName(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
5987{
5988 BOOL found;
5989 s_cbDataExactName *cbd = (s_cbDataExactName*)callbackData;
5990 found = !strcmp(fieldName,cbd->fname);
5991 if(found){
5992 cbd->fieldValue = fieldPtr;
5993 cbd->fname = fieldName;
5994 cbd->jfield = jfield;
5995 cbd->mode = mode;
5996 cbd->type = type;
5997 cbd->publicfield = publicfield;
5998 cbd->source = source;
5999 }
6000 return found; //returning true continues field walk, returning false breaks out.
6001}
6002BOOL find_anyfield_by_name(struct VRMLLexer* lexer, struct X3D_Node* node, union anyVrml **anyptr,
6003 int *imode, int *itype, char* nodeFieldName, int *isource, void** fdecl, int *ifield)
6004{
6005 int found, prototest11_x3dv;
6006 prototest11_x3dv = TRUE;
6007 s_cbDataExactName cbd;
6008 cbd.fname = nodeFieldName;
6009 found = walk_fields(node,cbExactName,&cbd);
6010 if(found){
6011 *anyptr = cbd.fieldValue;
6012 *imode = cbd.mode;
6013 *itype = cbd.type;
6014 *isource = cbd.source;
6015 *ifield = cbd.jfield;
6016 }else if(prototest11_x3dv){
6017 int ln, hsn, hcn;
6018 const char *nf;
6019 nf = rootFieldName(nodeFieldName, &ln,&hcn,&hsn);
6020
6021 if(hsn){
6022 //set_ prefix
6023 cbd.fname = nf;
6024 found = walk_fields(node,cbExactName,&cbd);
6025 if(found){
6026 *anyptr = cbd.fieldValue;
6027 *imode = cbd.mode;
6028 *itype = cbd.type;
6029 *isource = cbd.source;
6030 *ifield = cbd.jfield;
6031 }
6032 }
6033 ln++;
6034 if(hcn) {
6035 //_changed suffix
6036 char rootname[MAXJSVARIABLELENGTH];
6037 strncpy(rootname,nodeFieldName,ln);
6038 rootname[ln] = '\0';
6039 cbd.fname = rootname;
6040 found = walk_fields(node,cbExactName,&cbd);
6041 if(found){
6042 *anyptr = cbd.fieldValue;
6043 *imode = cbd.mode;
6044 *itype = cbd.type;
6045 *isource = cbd.source;
6046 *ifield = cbd.jfield;
6047 }
6048 }
6049 }
6050 if(!found){
6051 //printf("didn't find exact match for field name %s\n",nodeFieldName);
6052 }
6053 return found;
6054}
6055//========== find any field by name and route direction via walk_fields
6057 char *fname;
6058 int PKW_eventType;
6059 union anyVrml* fieldValue;
6060 int mode;
6061 int type;
6062 int jfield;
6063 int builtIn;
6064 int source;
6065 BOOL publicfield;
6066} s_cbDataRootNameAndRouteDir;
6067
6068BOOL cbRootNameAndRouteDir(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
6069{
6070
6071 BOOL found;
6072 s_cbDataRootNameAndRouteDir *cbd = (s_cbDataRootNameAndRouteDir*)callbackData;
6073 found = !fieldSynonymCompare(fieldName,cbd->fname) ? TRUE : FALSE;
6074 found = found && (mode == cbd->PKW_eventType || mode == PKW_inputOutput);
6075 if(found){
6076 cbd->fname = fieldName;
6077 cbd->jfield = jfield;
6078 cbd->mode = mode;
6079 cbd->type = type;
6080 cbd->publicfield = publicfield;
6081 cbd->source = source;
6082 }
6083 return found;
6084}
6085BOOL cbExactNameAndRouteDir(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
6086{
6087
6088 BOOL found;
6089 s_cbDataRootNameAndRouteDir *cbd = (s_cbDataRootNameAndRouteDir*)callbackData;
6090 found = !strcmp(fieldName,cbd->fname) ? TRUE : FALSE;
6091 found = found && (mode == cbd->PKW_eventType || mode == PKW_inputOutput);
6092 if(found){
6093 cbd->fname = fieldName;
6094 cbd->jfield = jfield;
6095 cbd->mode = mode;
6096 cbd->type = type;
6097 cbd->publicfield = publicfield;
6098 cbd->source = source;
6099 }
6100 return found;
6101}
6102BOOL find_anyfield_by_nameAndRouteDir(struct X3D_Node* node, union anyVrml **anyptr,
6103 int *imode, int *itype, char* nodeFieldName, int *isource, void** fdecl, int *ifield, int PKW_eventType)
6104{
6105 int found;
6106 s_cbDataRootNameAndRouteDir cbd;
6107 cbd.fname = nodeFieldName;
6108 cbd.PKW_eventType = PKW_eventType;
6109 found = walk_fields(node,cbExactNameAndRouteDir,&cbd);
6110 if(!found)
6111 found = walk_fields(node,cbRootNameAndRouteDir,&cbd);
6112 if(found){
6113 *anyptr = cbd.fieldValue;
6114 *imode = cbd.mode;
6115 *itype = cbd.type;
6116 *isource = cbd.source;
6117 *ifield = cbd.jfield;
6118 }
6119 return found;
6120}
6121//========== count public fields via walk_fields, used by js fieldDefinitionArray
6122
6123BOOL cbCountFields(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
6124{
6125 int found = FALSE;
6126 int *count = (int*)callbackData;
6127 (*count)++;
6128 return found;
6129}
6130int count_fields(struct X3D_Node* node)
6131{
6132 //int found;
6133 int count = 0;
6134 //found =
6135 walk_fields(node,cbCountFields,&count);
6136 return count;
6137}
6138//========
6139void **shaderFields(struct X3D_Node* node);
6140//convenience wrappers to get details for built-in fields and -on script and protoInstance- dynamic fields
6141int getFieldFromNodeAndName0(struct X3D_Node* node,const char *fieldname, int *type, int *kind,
6142 int *iifield, int *builtIn, union anyVrml **value, int *iunca, const char **cname){
6143 void **shaderfield;
6144 *type = 0;
6145 *kind = 0;
6146 *iifield = -1;
6147 *value = NULL;
6148 *iunca = UNCA_NONE;
6149 *cname = NULL;
6150 *builtIn = TRUE;
6151 shaderfield = shaderFields(node);
6152 //Q. what about shader script?
6153
6154 if(node->_nodeType == NODE_Script)
6155 {
6156 int k;
6157 struct Vector *sfields;
6158 struct ScriptFieldDecl *sfield;
6159 struct FieldDecl *fdecl;
6160 struct Shader_Script *sp;
6161 struct CRjsnameStruct *JSparamnames = getJSparamnames();
6162 struct X3D_Script *snode;
6163
6164 snode = (struct X3D_Script*)node;
6165 sp = (struct Shader_Script *)snode->__scriptObj;
6166 sfields = sp->fields;
6167 for(k=0;k<sfields->n;k++)
6168 {
6169 char *fieldName;
6170 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
6171 //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
6172 fdecl = sfield->fieldDecl;
6173 fieldName = fieldDecl_getShaderScriptName(fdecl);
6174 if(!strcmp(fieldName,fieldname)){
6175 *type = fdecl->fieldType;
6176 *kind = fdecl->PKWmode;
6177 *value = &(sfield->value);
6178 *iifield = k;
6179 *builtIn = FALSE;
6180 *cname = fieldName;
6181 return 1;
6182 }
6183 }
6184 }
6185 else if(shaderfield)
6186 {
6187 int k;
6188 struct Vector *sfields;
6189 struct ScriptFieldDecl *sfield;
6190 struct FieldDecl *fdecl;
6191 struct Shader_Script *sp;
6192 struct CRjsnameStruct *JSparamnames = getJSparamnames();
6193
6194 sp = (struct Shader_Script *)(*shaderfield);
6195 sfields = sp->fields;
6196 for(k=0;k<sfields->n;k++)
6197 {
6198 char *fieldName;
6199 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
6200 //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
6201 fdecl = sfield->fieldDecl;
6202 fieldName = fieldDecl_getShaderScriptName(fdecl);
6203 if(!strcmp(fieldName,fieldname)){
6204 *type = fdecl->fieldType;
6205 *kind = fdecl->PKWmode;
6206 *value = &(sfield->value);
6207 *iifield = k;
6208 *builtIn = FALSE;
6209 *cname = fieldName;
6210 return 1;
6211 }
6212 }
6213 }else if(node->_nodeType == NODE_Proto) {
6214 int k; //, mode;
6215 struct ProtoFieldDecl* pfield;
6216 struct X3D_Proto* pnode = (struct X3D_Proto*)node;
6217 struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
6218 if(pstruct){
6219 if(pstruct->iface)
6220 for(k=0; k!=vectorSize(pstruct->iface); ++k)
6221 {
6222 const char *fieldName;
6223 pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, k);
6224 //mode = pfield->mode;
6225 fieldName = pfield->cname;
6226 if(!strcmp(fieldName,fieldname)){
6227 *type = pfield->type;
6228 *kind = pfield->mode;
6229 // if(pfield->mode == PKW_initializeOnly || pfield->mode == PKW_inputOutput)
6230 *value = &(pfield->defaultVal);
6231 *iifield = k;
6232 *builtIn = FALSE;
6233 *cname = fieldName;
6234 return 1;
6235 }
6236 }
6237 }
6238 }
6239 //builtins on non-script, non-proto nodes (and also builtin fields like url on Script, metadata on Proto)
6240 //june 2018 problem: iifield index returned for Script.url and Proto.metadata doesn't discriminate
6241 // between builtin here and authored list above.
6242 {
6243 //typedef struct field_info{
6244 // int nameIndex;
6245 // int offset;
6246 // int typeIndex;
6247 // int ioType;
6248 // int version;
6249 // int unca;
6250 //} *finfo;
6251
6252 fieldinfo offsets;
6253 fieldinfo field;
6254 int ifield;
6255 offsets = (fieldinfo)NODE_OFFSETS[node->_nodeType];
6256 ifield = 0;
6257 field = &offsets[ifield];
6258 while( field->nameIndex > -1) //<< generalized for scripts and builtins?
6259 {
6260 if(!strcmp(FIELDNAMES[field->nameIndex],fieldname)){
6261 int kkind;
6262 *type = field->typeIndex;
6263 kkind = -1;
6264 switch(field->ioType){
6265 case KW_initializeOnly: kkind = PKW_initializeOnly; break;
6266 case KW_inputOnly: kkind = PKW_inputOnly; break;
6267 case KW_outputOnly: kkind = PKW_outputOnly; break;
6268 case KW_inputOutput: kkind = PKW_inputOutput; break;
6269 }
6270 *kind = kkind;
6271 *iifield = ifield;
6272 *builtIn = TRUE;
6273 *value = (union anyVrml*)&((char*)node)[field->offset];
6274 *iunca = field->unca;
6275 *cname = FIELDNAMES[field->nameIndex];
6276 return 1;
6277 }
6278 ifield++;
6279 field = &offsets[ifield];
6280 }
6281 }
6282 return 0;
6283}
6284int getFieldFromNodeAndNameU(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, int* builtIn, union anyVrml **value, int *iunca, const char **cname){
6285 int ifound = 0;
6286 ifound = getFieldFromNodeAndName0(node,fieldname,type,kind,iifield,builtIn,value,iunca,cname);
6287 if(!ifound){
6288 int ln, hsn, hcn;
6289 const char *nf;
6290 nf = rootFieldName(fieldname, &ln,&hcn,&hsn);
6291
6292 if(hsn){
6293 //set_ prefix
6294 ifound = getFieldFromNodeAndName0(node,nf,type,kind,iifield,builtIn,value,iunca,cname);
6295 }
6296 ln++;
6297 if(hcn) {
6298 //_changed suffix
6299 char rootname[MAXJSVARIABLELENGTH];
6300 memcpy(rootname,fieldname,ln);
6301 rootname[ln] = '\0';
6302 ifound = getFieldFromNodeAndName0(node,rootname,type,kind,iifield,builtIn,value,iunca,cname);
6303 }
6304 }
6305 return ifound;
6306}
6307int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value){
6308 int iunca;
6309 int ifound;
6310 int builtIn;
6311 const char *cname = NULL;
6312 ifound = getFieldFromNodeAndNameU(node,fieldname,type,kind,iifield,&builtIn,value,&iunca,&cname); //waste iunca
6313 return ifound;
6314}
6315int getFieldFromNodeAndNameC(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, int *builtIn, union anyVrml **value, const char **cname){
6316 int iunca;
6317 int ifound;
6318 ifound = getFieldFromNodeAndNameU(node,fieldname,type,kind,iifield,builtIn,value,&iunca,cname); //waste iunca
6319 return ifound;
6320}
6321
6322int getFieldFromNodeAndIndex(struct X3D_Node* node, int ifield, const char **fieldname, int *type, int *kind, union anyVrml **value){
6323 int iret = 0;
6324 *type = 0;
6325 *kind = 0;
6326 *fieldname = NULL;
6327 *value = NULL;
6328 if(node->_nodeType == NODE_Script )
6329 {
6330 int k;
6331 struct Vector *sfields;
6332 struct ScriptFieldDecl *sfield;
6333 struct FieldDecl *fdecl;
6334 struct Shader_Script *sp;
6335 struct CRjsnameStruct *JSparamnames = getJSparamnames();
6336 struct X3D_Script *snode;
6337
6338 snode = (struct X3D_Script*)node;
6339
6340 //sp = *(struct Shader_Script **)&((char*)node)[field->offset];
6341 sp = (struct Shader_Script *)snode->__scriptObj;
6342 sfields = sp->fields;
6343 //fprintf(fp,"sp->fields->n = %d\n",sp->fields->n);
6344 k = ifield;
6345 if(k > -1 && k < sfields->n)
6346 {
6347 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
6348 //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
6349 fdecl = sfield->fieldDecl;
6350 *fieldname = fieldDecl_getShaderScriptName(fdecl);
6351 *type = fdecl->fieldType;
6352 *kind = fdecl->PKWmode;
6353 *value = &(sfield->value);
6354 iret = 1;
6355 }
6356 return iret;
6357 }else if(node->_nodeType == NODE_Proto ) {
6358 int k; //, mode;
6359 struct ProtoFieldDecl* pfield;
6360 struct X3D_Proto* pnode = (struct X3D_Proto*)node;
6361 struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
6362 if(pstruct){
6363 if(pstruct->iface){
6364 k = ifield;
6365 if(k > -1 && k < vectorSize(pstruct->iface))
6366 {
6367 pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, k);
6368 //mode = pfield->mode;
6369 *fieldname = pfield->cname;
6370 *type = pfield->type;
6371 *kind = pfield->mode;
6372 if(pfield->mode == PKW_initializeOnly || pfield->mode == PKW_inputOutput)
6373 *value = &(pfield->defaultVal);
6374 iret = 1;
6375 }
6376 }
6377 }
6378 return iret;
6379 }
6380 //builtins on non-script, non-proto nodes (and also builtin fields like url on Script)
6381 {
6382 //typedef struct field_info{
6383 // int nameIndex;
6384 // int offset;
6385 // int typeIndex;
6386 // int ioType;
6387 // int version;
6388 // int unca;
6389 //} *finfo;
6390
6391 fieldinfo offsets;
6392 int k, kkind;
6393 int kfield;
6394
6395
6396 offsets = (fieldinfo)NODE_OFFSETS[node->_nodeType];
6397 kfield = ifield;
6398 //convert to index if in absolute offset
6399 if(kfield >= offsets[0].offset){
6400 int k = 0;
6401 while(offsets[k].nameIndex > -1){
6402 if(ifield == offsets[k].offset){
6403 kfield = k;
6404 break;
6405 }
6406 k++;
6407 }
6408 }
6409 for(k=0;k<=kfield;k++)
6410 if(offsets[k].nameIndex == -1) return 0;
6411 *fieldname = FIELDNAMES[offsets[kfield].nameIndex];
6412 *type = offsets[kfield].typeIndex;
6413 kkind = -1;
6414 switch(offsets[kfield].ioType){
6415 case KW_initializeOnly: kkind = PKW_initializeOnly; break;
6416 case KW_inputOnly: kkind = PKW_inputOnly; break;
6417 case KW_outputOnly: kkind = PKW_outputOnly; break;
6418 case KW_inputOutput: kkind = PKW_inputOutput; break;
6419 }
6420 *kind = kkind;
6421 *value = (union anyVrml*)&((char*)node)[offsets[kfield].offset];
6422 return 1;
6423 }
6424}
6425
6426int getFieldFromNodeAndIterator(struct X3D_Node* node, int ifield, const char **fieldname, int *type, int *kind, union anyVrml **value, int *builtIn){
6427 int iret = 0;
6428 int nuser = 0;
6429 *type = 0;
6430 *kind = 0;
6431 *fieldname = NULL;
6432 *value = NULL;
6433 if(node->_nodeType == NODE_Script )
6434 {
6435 int k;
6436 struct Vector *sfields;
6437 struct ScriptFieldDecl *sfield;
6438 struct FieldDecl *fdecl;
6439 struct Shader_Script *sp;
6440 struct CRjsnameStruct *JSparamnames = getJSparamnames();
6441 struct X3D_Script *snode;
6442
6443 snode = (struct X3D_Script*)node;
6444
6445 //sp = *(struct Shader_Script **)&((char*)node)[field->offset];
6446 sp = (struct Shader_Script *)snode->__scriptObj;
6447 sfields = sp->fields;
6448 //fprintf(fp,"sp->fields->n = %d\n",sp->fields->n);
6449 k = ifield;
6450 nuser = sfields->n;
6451 if(k > -1 && k < nuser)
6452 {
6453 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
6454 //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
6455 fdecl = sfield->fieldDecl;
6456 *fieldname = fieldDecl_getShaderScriptName(fdecl);
6457 *type = fdecl->fieldType;
6458 *kind = fdecl->PKWmode;
6459 *value = &(sfield->value);
6460 *builtIn = FALSE;
6461 iret = 1;
6462 return iret;
6463 }
6464 //return iret;
6465 }else if(node->_nodeType == NODE_Proto ) {
6466 int k; //, mode;
6467 struct ProtoFieldDecl* pfield;
6468 struct X3D_Proto* pnode = (struct X3D_Proto*)node;
6469 struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
6470 if(pstruct){
6471 if(pstruct->iface){
6472 k = ifield;
6473 nuser = vectorSize(pstruct->iface);
6474 if(k > -1 && k < nuser)
6475 {
6476 pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, k);
6477 //mode = pfield->mode;
6478 *fieldname = pfield->cname;
6479 *type = pfield->type;
6480 *kind = pfield->mode;
6481 *builtIn = FALSE;
6482// if(pfield->mode == PKW_initializeOnly || pfield->mode == PKW_inputOutput)
6483 *value = &(pfield->defaultVal);
6484 iret = 1;
6485 return iret;
6486 }
6487 }
6488 }
6489 //return iret;
6490 }
6491 //builtins on non-script, non-proto nodes (and also builtin fields like url on Script)
6492 {
6493 //typedef struct field_info{
6494 // int nameIndex;
6495 // int offset;
6496 // int typeIndex;
6497 // int ioType;
6498 // int version;
6499 // int unca;
6500 //} *finfo;
6501
6502 fieldinfo offsets;
6503 int k, kkind;
6504 int kfield, nbuiltin;
6505
6506
6507 offsets = (fieldinfo)NODE_OFFSETS[node->_nodeType];
6508 nbuiltin = 0;
6509
6510 kfield = ifield - nuser;
6511 for(k=0;k<=kfield;k++)
6512 if(offsets[k].nameIndex == -1) return -1; //end of iteration
6513 *fieldname = FIELDNAMES[offsets[kfield].nameIndex];
6514 *type = offsets[kfield].typeIndex;
6515 *builtIn = TRUE;
6516 kkind = -1;
6517 switch(offsets[kfield].ioType){
6518 case KW_initializeOnly: kkind = PKW_initializeOnly; break;
6519 case KW_inputOnly: kkind = PKW_inputOnly; break;
6520 case KW_outputOnly: kkind = PKW_outputOnly; break;
6521 case KW_inputOutput: kkind = PKW_inputOutput; break;
6522 }
6523 *kind = kkind;
6524 *value = (union anyVrml*)&((char*)node)[offsets[kfield].offset];
6525 return 1;
6526 }
6527 return 0; //not found, but not end of iteration
6528}
6529
6530int getFieldFromNodeAndIndexSource(struct X3D_Node* node, int ifield, int builtIn, const char **fieldname, int *type, int *kind, union anyVrml **value){
6531 int iret = 0;
6532 int nuser = 0;
6533 *type = 0;
6534 *kind = 0;
6535 *fieldname = NULL;
6536 *value = NULL;
6537 if(node->_nodeType == NODE_Script && !builtIn)
6538 {
6539 int k;
6540 struct Vector *sfields;
6541 struct ScriptFieldDecl *sfield;
6542 struct FieldDecl *fdecl;
6543 struct Shader_Script *sp;
6544 struct CRjsnameStruct *JSparamnames = getJSparamnames();
6545 struct X3D_Script *snode;
6546
6547 snode = (struct X3D_Script*)node;
6548
6549 //sp = *(struct Shader_Script **)&((char*)node)[field->offset];
6550 sp = (struct Shader_Script *)snode->__scriptObj;
6551 sfields = sp->fields;
6552 //fprintf(fp,"sp->fields->n = %d\n",sp->fields->n);
6553 k = ifield;
6554 nuser = sfields->n;
6555 if(k > -1 && k < nuser)
6556 {
6557 sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
6558 //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
6559 fdecl = sfield->fieldDecl;
6560 *fieldname = fieldDecl_getShaderScriptName(fdecl);
6561 *type = fdecl->fieldType;
6562 *kind = fdecl->PKWmode;
6563 *value = &(sfield->value);
6564 iret = 1;
6565 }
6566 return iret;
6567 }else if(node->_nodeType == NODE_Proto && !builtIn ) {
6568 int k; //, mode;
6569 struct ProtoFieldDecl* pfield;
6570 struct X3D_Proto* pnode = (struct X3D_Proto*)node;
6571 struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
6572 if(pstruct){
6573 if(pstruct->iface){
6574 k = ifield;
6575 nuser = vectorSize(pstruct->iface);
6576 if(k > -1 && k < nuser)
6577 {
6578 pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, k);
6579 //mode = pfield->mode;
6580 *fieldname = pfield->cname;
6581 *type = pfield->type;
6582 *kind = pfield->mode;
6583// if(pfield->mode == PKW_initializeOnly || pfield->mode == PKW_inputOutput)
6584 *value = &(pfield->defaultVal);
6585 iret = 1;
6586 }
6587 }
6588 }
6589 return iret;
6590 }
6591 //builtins on non-script, non-proto nodes (and also builtin fields like url on Script)
6592 if(builtIn){
6593 //typedef struct field_info{
6594 // int nameIndex;
6595 // int offset;
6596 // int typeIndex;
6597 // int ioType;
6598 // int version;
6599 // int unca;
6600 //} *finfo;
6601
6602 fieldinfo offsets;
6603 int k, kkind;
6604 int kfield;
6605
6606
6607 offsets = (fieldinfo)NODE_OFFSETS[node->_nodeType];
6608
6609 kfield = ifield;
6610 //convert to index if in absolute offset
6611 if(kfield >= offsets[0].offset){
6612 int k = 0;
6613 while(offsets[k].nameIndex > -1){
6614 if(ifield == offsets[k].offset){
6615 kfield = k;
6616 break;
6617 }
6618 k++;
6619 }
6620 }
6621 for(k=0;k<=kfield;k++)
6622 if(offsets[k].nameIndex == -1) return -1; //end of iteration
6623 *fieldname = FIELDNAMES[offsets[kfield].nameIndex];
6624 *type = offsets[kfield].typeIndex;
6625 kkind = -1;
6626 switch(offsets[kfield].ioType){
6627 case KW_initializeOnly: kkind = PKW_initializeOnly; break;
6628 case KW_inputOnly: kkind = PKW_inputOnly; break;
6629 case KW_outputOnly: kkind = PKW_outputOnly; break;
6630 case KW_inputOutput: kkind = PKW_inputOutput; break;
6631 }
6632 *kind = kkind;
6633 *value = (union anyVrml*)&((char*)node)[offsets[kfield].offset];
6634 return 1;
6635 }
6636 return 0; //not found, but not end of iteration
6637}
6638
6639
6640void broto_store_IS(struct X3D_Proto *proto,char *protofieldname,int pmode, int iprotofield, int pBuiltIn, int type,
6641 struct X3D_Node *node, char* nodefieldname, int mode, int ifield, int nBuiltIn, int source)
6642{
6643 Stack* ISs;
6644 struct brotoIS* is;
6645
6646 is = MALLOC(struct brotoIS*,sizeof(struct brotoIS));
6647 is->proto = proto;
6648 is->protofieldname = strdup(protofieldname);
6649 is->pmode = pmode;
6650 is->iprotofield = iprotofield;
6651 is->pBuiltIn = pBuiltIn;
6652 is->type = type;
6653 is->node = node;
6654 is->nodefieldname = strdup(nodefieldname);
6655 is->mode = mode;
6656 is->ifield = ifield;
6657 is->builtIn = nBuiltIn;
6658 is->source = source;
6659
6660 ISs = proto->__IS;
6661 if( ISs == NULL){
6662 ISs = newStack(struct brotoIS *);
6663 proto->__IS = ISs;
6664 }
6665 stack_push(struct brotoIS *, ISs, is);
6666 return;
6667}
6668
6669BOOL found_IS_field(struct VRMLParser* me, struct X3D_Node *node)
6670{
6671 /* if IS found, then
6672 if field/exposedfield/initializeOnly/inputOutput
6673 copy value
6674 register IS in IS-table
6675 */
6676 int i;
6677 int type, mode;
6678 int ptype, pmode;
6679 int source, builtIn, pbuiltIn;
6680 int ifield, iprotofield;
6681 struct ProtoDefinition* pdef=NULL;
6682 struct X3D_Proto* proto;
6683 char *protoFieldName;
6684 char *nodeFieldName;
6685 DECLAREUP
6686 BOOL foundField;
6687 BOOL foundProtoField;
6688 struct ProtoFieldDecl *f;
6689 union anyVrml *fieldPtr;
6690 union anyVrml *defaultPtr;
6691 void *fdecl;
6692 const char* pname = NULL;
6693
6694
6695
6696
6697 SAVEUP //save the lexer spot so if it's not an IS we can back up
6698 /* get nodeFieldName */
6699 if(!lexer_setCurID(me->lexer)) return FALSE;
6700 ASSERT(me->lexer->curID);
6701 nodeFieldName = STRDUP(me->lexer->curID);
6702 //BACKUP;
6703 FREE_IF_NZ(me->lexer->curID);
6704
6705 /*
6706 We want to know 5 things about the node:
6707 0. is it a user or builtin node
6708 1. does the field/event exist on the node
6709 if so then
6710 3. what's it's type - SF/MF,type - needed for compatibility check with proto field
6711 4. what's it's mode - [in][out][in/out] - ditto, IS-table routing direction and initialization
6712 5. what's its route field address: how does the is-table or route get to it:
6713 - integer Offset for builtin, integer field index for usernode
6714 - when deepcopying a protoDeclare during sceneInstance, the node address would be remapped,
6715 but these integers would stay the same
6716 */
6717 fieldPtr = NULL;
6718 foundField = find_anyfield_by_name(me->lexer, node, &fieldPtr, &mode, &type, nodeFieldName, &source, &fdecl, &ifield);
6719
6720 if(!(foundField))
6721 {
6722 BACKUP
6723 FREE_IF_NZ(nodeFieldName);
6724 return FALSE; /* not a field or event */
6725 }
6726
6727 /* got a node field or event */
6728 /* check if IS-statement? */
6729 if(!lexer_keyword(me->lexer, KW_IS)) {
6730 BACKUP
6731 FREE_IF_NZ(nodeFieldName);
6732 return FALSE; /* not an IS, maybe regular field or USE/DEF */
6733 }
6734
6735 /* got an IS, so unconditionally swallow 3 tokens: nodeFieldName IS protoFieldName */
6736
6737 /* get protoFieldName */
6738 if(!lexer_setCurID(me->lexer)) return FALSE;
6739 ASSERT(me->lexer->curID);
6740 protoFieldName = STRDUP(me->lexer->curID);
6741 FREE_IF_NZ(me->lexer->curID);
6742
6743
6744 /*Now we need to know the same things about the proto node and field:
6745 0. we know it's a user node - all X3D_Proto/Protos are, and they (should) have no public builtin fields
6746 (children should be removed)
6747 PROBLEM 2018 metadata [in/out] is builtin
6748 1. does the field/event exist on the proto
6749 if so then
6750 3. what's it's type - SF/MF,type - needed for compatibility check with node field
6751 4. what's it's mode - [in][out][in/out] - ditto, IS-table routing direction and initialization
6752 5. what's its route field address: how does the is-table or route get to it:
6753 - integer field index for usernode
6754 */
6755 proto = (struct X3D_Proto*)me->ectx;
6756 pdef = (struct ProtoDefinition*)proto->__protoDef; //__brotoObj;
6757 foundProtoField = FALSE;
6758 f = NULL;
6759 {
6760 //user field
6761 pbuiltIn = FALSE;
6762 const char* pname = NULL;
6763 iprotofield = -1;
6764
6765 if(!strcasecmp(protoFieldName,"metadata")){
6766 //builtin
6767 foundProtoField = getFieldFromNodeAndNameC(X3D_NODE(proto),protoFieldName,&ptype, &pmode, &iprotofield, &pbuiltIn, &defaultPtr, &pname);
6768 }else{
6769 for(i=0; i!=vectorSize(pdef->iface); ++i)
6770 {
6771 f=vector_get(struct ProtoFieldDecl*, pdef->iface, i);
6772 pname = f->cname;
6773
6774 foundProtoField = !strcmp(pname,protoFieldName) ? TRUE : FALSE;
6775 if(foundProtoField ) {
6776 /* printf ("protoDefinition_getField, comparing %d %d and %d %d\n", f->name, ind, f->mode, mode); */
6777 //return f;
6778 iprotofield = i;
6779 ptype = f->type;
6780 pmode = f->mode;
6781 pname = f->cname;
6782 defaultPtr = &f->defaultVal;
6783 break;
6784 }
6785 }
6786 }
6787 if( !foundProtoField ){
6788 ConsoleMessage("Parser error: no matching protoField for %s IS %s\n",
6789 nodeFieldName,protoFieldName);
6790 FREE_IF_NZ(me->lexer->curID);
6791 FREEUP
6792 FREE_IF_NZ(nodeFieldName);
6793 FREE_IF_NZ(protoFieldName);
6794 return TRUE;
6795 }
6796 //check its type
6797 if(ptype != type){
6798 if(!pname) pname = "";
6799 ConsoleMessage("Parser error: IS - we have a name match: %s IS %s found protofield %s\n",
6800 nodeFieldName,protoFieldName,pname);
6801 ConsoleMessage("...But the types don't match: nodefield %s protofield %s\n",
6802 FIELDTYPES[type],FIELDTYPES[ptype]);
6803 FREE_IF_NZ(me->lexer->curID);
6804 FREEUP
6805 FREE_IF_NZ(nodeFieldName);
6806 FREE_IF_NZ(protoFieldName);
6807 return TRUE;
6808 }
6809 //check its mode
6810 // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#t-RulesmappingPROTOTYPEdecl
6811 // there's what I call a mode-jive table
6812 // proto interface
6813 // inputOutput initializeOnly inputOnly outputOnly
6814 // node inputOutput jives jives jives jives
6815 // initializeOnly jives
6816 // inputOnly jives
6817 // outputOnly jives
6818 //
6819 // so if our nodefield's mode is inputOutput/exposedField then we are covered for all protoField modes
6820 // otherwise, the nodefield's mode must be the same as the protofield's mode
6821 if(X3DMODE(mode) != PKW_inputOutput && X3DMODE(mode) != X3DMODE(pmode)){
6822 if(X3DMODE(pmode) != PKW_inputOutput){
6823 ConsoleMessage("Parser Error: IS - we have a name match: %s IS %s found protofield %s\n",
6824 nodeFieldName,protoFieldName,f->fieldString);
6825 ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
6826 PROTOKEYWORDS[mode],PROTOKEYWORDS[pmode]);
6827 FREE_IF_NZ(me->lexer->curID);
6828 FREEUP
6829 FREE_IF_NZ(nodeFieldName);
6830 FREE_IF_NZ(protoFieldName);
6831 return TRUE;
6832 }else{
6833 ConsoleMessage("Parser Warning: IS - we have a name match: %s IS %s found protofield %s\n",
6834 nodeFieldName,protoFieldName,pname);
6835 ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
6836 PROTOKEYWORDS[mode],PROTOKEYWORDS[pmode]);
6837 ConsoleMessage("...will thunk\n");
6838 }
6839 }
6840 }
6841
6842 //we have an IS that's compatible/jives
6843 //a) copy the value if it's an initializeOnly or inputOutput
6844 if(X3DMODE(pmode) == PKW_initializeOnly || X3DMODE(pmode) == PKW_inputOutput)
6845 {
6846
6847 //Q. how do I do this? Just a memcpy on anyVrml or ???
6848 //printf("size of anyVrml=%d\n",sizeof(union anyVrml));
6849 //printf("f->mode=%d f->type=%d fieldptr mode=%d type=%d\n",f->mode,f->type,mode,type);
6850 //heapdump();
6851 //isMF = type % 2;
6852 //sftype = type - isMF;
6853 //from EAI_C_CommonFunctions.c
6854 //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
6855 shallow_copy_field(type, defaultPtr , fieldPtr);
6856 //memcpy(fieldPtr,&(f->defaultVal),isize); //sizeof(union anyVrml));
6857 //heapdump();
6858 //if(0)//should probably only do this for the final deep_copy sceneInstance, not here during parsing
6859 //if(source==1)
6860 //{
6861 // scriptFieldDecl_jsFieldInit(
6862 // (struct ScriptFieldDecl*) fdecl,
6863 // ((struct Shader_Script*)X3D_SCRIPT(node)->__scriptObj)->num);
6864 //}
6865
6866 }
6867 //b) register it in the IS-table for our context
6868 builtIn = source ? FALSE : TRUE;
6869 broto_store_IS(proto,protoFieldName,X3DMODE(f->mode),iprotofield,pbuiltIn,type,
6870 node,nodeFieldName,X3DMODE(mode),ifield,builtIn,source);
6871 /* Add this scriptfielddecl to the list of script fields mapped to this proto field */
6872 //sfield = newScriptFieldInstanceInfo(sdecl, script);
6873 //vector_pushBack(struct ScriptFieldInstanceInfo*, pField->scriptDests, sfield);
6874 //we need an IS-table for builtin node targets - what did CProto do?
6875 //defaultVal = &(f->defaultVal);
6876
6877 //
6878 FREEUP
6879 FREE_IF_NZ(nodeFieldName);
6880 FREE_IF_NZ(protoFieldName);
6881
6882 return TRUE;
6883
6884}
6885
6886/* note that we get the resources in a couple of steps; this tries to keep the scenegraph running
6887 copied from load_Inline
6888
6889*/
6890
6891resource_item_t * resLibraryAlreadyRequested(resource_item_t *res){
6892 /* for externProto libraries, check if there's already a resitem launched for the library
6893 and if so, return the associated resitem, else return null.
6894 - compare the absolutized (resource-identified) before-#
6895 - exampe for hddp://something.com/mylibrary.wrl#myProto1 we'll compare hddp://something.com/mylibrary.wrl
6896 */
6897 void3 *ulr;
6898 ulr = librarySearch(res->URLrequest);
6899 if(ulr) return ulr->three; //resource
6900 return NULL;
6901}
6902
6903
6904/* EXTERNPROTO library status */
6905#define LOAD_INITIAL_STATE 0
6906#define LOAD_REQUEST_RESOURCE 1
6907#define LOAD_FETCHING_RESOURCE 2
6908//#define LOAD_PARSING 3
6909#define LOAD_STABLE 10
6910/* dug9 Sept 2014 wrapper technique for externProto for useBrotos:
6911 PD - proto declare - a type declaration (shallow copies of contained protos; allocated nodes not registered)
6912 PI - proto insstance - a node for the scenegraph to render (deep copies of contained protos; nodes registered)
6913 EPD - extern PD
6914 EPI - extern PI
6915 Wrapper technique:
6916 EPD { url, resource, loadstatus, PD once loaded }
6917 EPI { *EPD, PI once loaded }
6918 1. during parsing, when an ExternProtoDeclare is encountered, an empty X3D_Proto is created
6919 to represent the ExternProtoDeclare EPD as a type, and fields as declared are added, along
6920 with the url. No body. A flag is set saying it's not loaded.
6921 2. parsing continues. When an instance of that type is encountered, a copy of the EPD is
6922 created as an externProtoInstance EPI -also empty, and with a pointer back to EPD. Parsing
6923 continues, including routing to the EPI
6924 3. during rendering when the EPI is visited (currently in startofloopnodeupdates()) it
6925 checks itself to see if its been instanced yet, and
6926 a) if not loaded:- checks to see if the EPD has been loaded yet,
6927 i) if not, gives a time slice to the EPD when visiting it, see #4
6928 ii) if yes, then instances itself, and generates routes between the wrapper EPI and contained PI
6929 b) if loaded, renders or whatever its supposed to be doing as a normal node
6930 4. EPD when visited
6931 a) checks to see if the resource has been created, if not creates it.
6932 It checks to see if another EPD has already requested the URL (in the case of a proto library)
6933 and if so, uses that EPD's resource, else submits a new resource for fetching
6934 b) if resource is loaded, then i) if its in a proto library, fetches the #name else ii) takes the first proto
6935 and sets it in its __protoDeclare list, and marks itself loaded
6936*/
6937
6938void load_externProtoDeclare (struct X3D_Proto *node) {
6939 resource_item_t *res, *res2;
6940 // printf ("load_externProto %u, loadStatus %d loadResource %u\n",node, node->__loadstatus, node->__loadResource);
6941
6942 //printf ("load_externProto, node %p loadStatus %d\n",node,node->load);
6943 char flagInstance, flagExtern;
6944 flagInstance = ciflag_get(node->__protoFlags,2);
6945 flagExtern = ciflag_get(node->__protoFlags,3);
6946 if(flagInstance == 0 && flagExtern == 1) {
6947 /* printf ("loading externProtoDeclare\n"); */
6948
6949 switch (node->__loadstatus) {
6950 case LOAD_INITIAL_STATE: /* nothing happened yet */
6951
6952 if (node->url.n == 0) {
6953 node->__loadstatus = LOAD_STABLE; /* a "do-nothing" approach */
6954 break;
6955 } else {
6956 res = resource_create_multi(&(node->url));
6957 res->media_type = resm_unknown;
6958 node->__loadstatus = LOAD_REQUEST_RESOURCE;
6959 node->__loadResource = res;
6960 }
6961 break;
6962
6963 case LOAD_REQUEST_RESOURCE:
6964 res = node->__loadResource;
6965 resource_identify(node->_parentResource, res);
6966 node->__afterPound = (void*)res->afterPoundCharacters;
6967 //check if this is a library request, and if so has it already been requested
6968 res2 = NULL;
6969 if(node->__afterPound)
6970 res2 = resLibraryAlreadyRequested(res);
6971 if(res2){
6972 node->__loadResource = res2;
6973 }else{
6974 struct X3D_Proto *libraryScene;
6975 /* printf ("load_Inline, we have type %s status %s\n",
6976 resourceTypeToString(res->type), resourceStatusToString(res->status)); */
6977 res->actions = resa_download | resa_load; //not resa_parse which we do below
6978 pushInputResource(res);
6979 libraryScene = createNewX3DNode0(NODE_Proto);
6980 popInputResource();
6981 res->ectx = (void*)libraryScene;
6982 res->whereToPlaceData = X3D_NODE(libraryScene);
6983 res->offsetFromWhereToPlaceData = offsetof (struct X3D_Proto, __children);
6984 addLibrary(res->URLrequest,libraryScene,res);
6985 resitem_enqueue(ml_new(res));
6986 }
6987 node->__loadstatus = LOAD_FETCHING_RESOURCE;
6988 break;
6989
6990 case LOAD_FETCHING_RESOURCE:
6991 res = node->__loadResource;
6992 /* printf ("load_Inline, we have type %s status %s\n",
6993 resourceTypeToString(res->type), resourceStatusToString(res->status)); */
6994 if(res->complete){
6995 if (res->status == ress_loaded) {
6996 res->actions = resa_process;
6997 res->complete = FALSE;
6998 resitem_enqueue(ml_new(res));
6999 } else if ((res->status == ress_failed) || (res->status == ress_invalid)) {
7000 //no hope left
7001 printf ("resource failed to load\n");
7002 node->__loadstatus = LOAD_STABLE; // a "do-nothing" approach
7003 } else if (res->status == ress_parsed) {
7004 //fetch the particular desired PROTO from the libraryScene, and place in _protoDeclares
7005 //or in _prototype
7006 struct X3D_Proto *libraryScene = res->whereToPlaceData; //from above
7007 if(node->__externProtoDeclares == NULL)
7008 node->__externProtoDeclares = newVector(struct X3D_Proto*,1);
7009 vector_pushBack(struct X3D_Proto*,node->__externProtoDeclares,libraryScene);
7010
7011 if(node->__externProtoDeclares){
7012 int n = vectorSize(node->__externProtoDeclares);
7013 if(n){
7014 struct X3D_Proto *libraryScene = vector_get(struct X3D_Proto*,node->__externProtoDeclares,0);
7015 if(libraryScene->__protoDeclares){
7016 int m = vectorSize(libraryScene->__protoDeclares);
7017 if(m){
7018 int k;
7019 struct X3D_Proto* pDefinition;
7020 /* the specs say if there's no # in the url, take the first PROTO definition in the library file
7021 else match #name (afterpound in resitem)
7022 */
7023 if(node->__afterPound){
7024 for(k=0;k<m;k++){
7025 char *typename, *matchstring;
7026 //matchstring = node->__typename; //specs don't say this
7027 matchstring = node->__afterPound;
7028 pDefinition = vector_get(struct X3D_Proto*,libraryScene->__protoDeclares,k);
7029 typename = (char *)pDefinition->__typename;
7030 if(typename)
7031 if(!strcmp(matchstring,typename)){
7032 //found it - the library proto's user type name matches this extern proto's #name (afterPound)
7033 //now add this protoDeclare to our externProto's protoDeclare list in 1st position
7034 node->__protoDeclares = newVector(struct X3D_Proto*,1);
7035 vector_pushBack(struct X3D_Proto*,node->__protoDeclares,pDefinition);
7036 break;
7037 }
7038 } //for k
7039 }else{
7040 //no afterPound, so according to specs: take the first proto in the file
7041 pDefinition = vector_get(struct X3D_Proto*,libraryScene->__protoDeclares,0);
7042 node->__protoDeclares = newVector(struct X3D_Proto*,1);
7043 vector_pushBack(struct X3D_Proto*,node->__protoDeclares,pDefinition);
7044 } //else no afterPound
7045 } //if(m)
7046 } //if(libraryScene->__protoDeclares)
7047 } //if(n)
7048 } //if(node->__externProtoDeclares)
7049 node->__loadstatus = LOAD_STABLE;
7050 } //if (res->status == ress_parsed)
7051 } //if(res->complete)
7052 //end case LOAD_FETCHING_RESOURCE
7053 break;
7054
7055 case LOAD_STABLE:
7056 break;
7057 }
7058
7059 }
7060}
7061void load_externProtoInstance (struct X3D_Proto *node) {
7062 //resource_item_t *res;
7063 // printf ("load_externProto %u, loadStatus %d loadResource %u\n",node, node->__loadstatus, node->__loadResource);
7064
7065 //printf ("load_externProto, node %p loadStatus %d\n",node,node->load);
7066 char flagInstance, flagExtern;
7067 flagInstance = ciflag_get(node->__protoFlags,2);
7068 flagExtern = ciflag_get(node->__protoFlags,3);
7069 if(flagInstance == 1 && flagExtern == 1) { //if protoInstance and extern
7070 struct X3D_Proto *pnode = NULL;
7071 if(node->__children.n) return; //externProtoInstance body node already instanced
7072 pnode = (struct X3D_Proto*)node->__prototype;
7073 if(pnode) {
7074 if(pnode->__loadstatus != LOAD_STABLE){
7075 // extern proto declare not loaded yet, give it a time slice to check its resource
7076 load_externProtoDeclare(pnode);
7077 }
7078 if(pnode->__loadstatus == LOAD_STABLE){
7079 // externProtoDeclare may already be loaded, if so, we just need to instance it
7080 if(pnode->__protoDeclares){
7081 int n = vectorSize(pnode->__protoDeclares);
7082 if(n){
7083 struct X3D_Proto *pdeclare, *pinstance;
7084 struct X3D_Node *nnode;
7085 pdeclare = vector_get(struct X3D_Proto*,pnode->__protoDeclares,0);
7086 pinstance = brotoInstance(pdeclare,1);
7087 if (pinstance != NULL) {
7088 struct ProtoDefinition *ed, *pd;
7089 struct Vector *ei, *pi;
7090 struct ProtoFieldDecl *ef, *pf;
7091
7092 pushInputResource(pinstance->_parentResource);
7093 ed = node->__protoDef;
7094 ei = ed->iface;
7095 pd = pinstance->__protoDef;
7096 pi = pd->iface;
7097 add_node_to_broto_context(node,X3D_NODE(pinstance));
7098
7099 //inject IS routes
7100 {
7101 int i,j;
7102 char *ename, *pname;
7103 struct Vector *p2p;
7104 struct pointer2pointer p2pentry;
7105
7106 //match fields to create IStable
7107 for(i=0;i<ei->n;i++){
7108 ef = protoDefinition_getFieldByNum(ed, i);
7109 ename = ef->cname;
7110 for(j=0;j<pi->n;j++){
7111 pf = protoDefinition_getFieldByNum(pd, j);
7112 pname = pf->cname;
7113 if(!strcmp(ename,pname) || !fieldSynonymCompare(ename,pname)){
7114 //name match
7115 //printf("ename = %s pname = %s\n",ename,pname);
7116 if(ef->type == pf->type){
7117 //type match
7118 //printf("etype = %d ptype = %d\n",ef->type, pf->type);
7119 //add IS
7120 broto_store_IS(node,ef->cname,ef->mode, i, FALSE, ef->type, X3D_NODE(pinstance), pf->cname, pf->mode, j, FALSE, 3);
7121 }
7122 }
7123 }
7124 }
7125 //convert IStable to browser routes
7126 p2p = newVector(struct pointer2pointer,1);
7127 //p2pentry = MALLOCV(sizeof(struct pointer2pointer));
7128 //nothing to look up, nuisance to re-use copy_IS
7129 p2pentry.pp = X3D_NODE(pinstance);
7130 p2pentry.pn = X3D_NODE(pinstance);
7131 vector_pushBack(struct pointer2pointer,p2p,p2pentry);
7132 copy_IS(node->__IS, node, p2p);
7133 deleteVector(struct pointer2pointer,p2p);
7134 }
7135 //copy EPI field initial values to contained PI
7136 {
7137 int i;
7138
7139 Stack *istable = (Stack*) node->__IS;
7140 if(istable != NULL)
7141 for(i=0;i<istable->n;i++)
7142 {
7143 struct brotoIS* is;
7144 //int ifield, iprotofield;
7145 is = vector_get(struct brotoIS*, istable, i);
7146 if(is->pmode == PKW_inputOutput || is->pmode == PKW_initializeOnly){
7147 ef = protoDefinition_getFieldByNum(ed, is->iprotofield);
7148 pf = protoDefinition_getFieldByNum(pd, is->ifield);
7149 if(ef->alreadySet ){
7150 // too shallow, crashes on exit during free: memcpy(&pf->defaultVal,&ef->defaultVal, sizeof(union anyVrml));
7151 shallow_copy_field(is->type, &ef->defaultVal, &pf->defaultVal);
7152 pf->alreadySet = TRUE; //in KelpForest scene, there's a CircleFish that gets its skin texture from a few levels of EPIs, and if this isn't set it doesn't go down both levels
7153 }
7154 }
7155 }
7156 }
7157 //now copy broto body, which should cascade inital values down
7158 deep_copy_broto_body2(&pdeclare,&pinstance);
7159 nnode = X3D_NODE(pinstance);
7160 AddRemoveChildren(X3D_NODE(node), &node->__children, &nnode, 1, 1,__FILE__,__LINE__);
7161 //add_parent(X3D_NODE(pinstance),X3D_NODE(node),__FILE__,__LINE__);
7162 popInputResource();
7163 } //if (pinstance != NULL)
7164 }
7165 }
7166 }
7167 }
7168 }
7169}
7170
7171void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node){
7172 /* Adds node* to 2 lists:
7173 __nodes -for unregistering and freeing the body of an inline, scene or broto/protoInstance
7174 __subcontexts - for recursive unregistering of routes, scripts, sensors and nodes
7175 (nodes being registered in createNewX3DNode() in table used by startofloopnodeupdates())
7176 these lists need to be maintained whenever adding/removing nodes to/from a context
7177 - wrl and x3d scene parsing
7178 - EAI
7179 - javascript SAI addNode, removeNode, addProto, removeProto ...
7180 */
7181 if(context && hasContext(X3D_NODE(context))){
7182 Stack *__nodes;
7183 if(!context->__nodes)
7184 context->__nodes = newVector(struct X3D_Node*,4);
7185 __nodes = context->__nodes;
7186 node->_executionContext = (struct X3D_Node*)context;
7187 stack_push(struct X3D_Node*,__nodes,node);
7188 if(hasContext(node)){
7189 Stack *__subctxs;
7190 if(!context->__subcontexts)
7191 context->__subcontexts = newVector(struct X3D_Node*,4);
7192 __subctxs = context->__subcontexts;
7193 stack_push(struct X3D_Node*,__subctxs,node);
7194 }
7195 }
7196}
7197void remove_node_from_broto_context(struct X3D_Proto *context,struct X3D_Node *node){
7198 /* removes node* from a few lists (but does not free() node memory or otherwise alter node)
7199 __nodes
7200 __subcontexts (if its an inline, scene or protoinstance
7201 these lists need to be maintained whenever adding/removing nodes to/from a context
7202 - EAI
7203 - javascript SAI addNode, removeNode, addProto, removeProto ...
7204 (for unloading a whole inline body or scene body, see unload_broto
7205
7206 */
7207 if(context && hasContext(X3D_NODE(context))){
7208 if(context->__nodes){
7209 int i;
7210 for(i=0;i<vectorSize(context->__nodes);i++){
7211 struct X3D_Node *ns = vector_get(struct X3D_Node*,context->__nodes,i);
7212 if(ns == node){
7213 vector_remove_elem(struct X3D_Node*,context->__nodes,i);
7214 break; //assumes its not added twice or more.
7215 }
7216 }
7217 }
7218 if(context->__subcontexts && hasContext(node) ){
7219 int i;
7220 for(i=0;i<vectorSize(context->__subcontexts);i++){
7221 struct X3D_Node *ns = vector_get(struct X3D_Node*,context->__subcontexts,i);
7222 if(ns == node){
7223 vector_remove_elem(struct X3D_Node*,context->__subcontexts,i);
7224 break;
7225 }
7226 }
7227 }
7228 }
7229}
7230void lock_and_do_routes_register();
7231int unregister_broutes(struct X3D_Proto * node){
7232 //unregister regular routes from broto context
7233 int iret = FALSE;
7234 if(node && hasContext(X3D_NODE(node))){
7235 unsigned char depthflag = ciflag_get(node->__protoFlags,0);
7236 if(depthflag){
7237 //live scenery
7238 if(node->__ROUTES){
7239 int i;
7240 struct brotoRoute *route;
7241 for(i=0;i<vectorSize(node->__ROUTES);i++){
7242 route = vector_get(struct brotoRoute*,node->__ROUTES,i);
7243 if(route && route->lastCommand){
7244 CRoutes_RemoveSimpleB(route->from.node,route->from.ifield,route->from.builtIn,route->to.node,route->to.ifield,route->to.builtIn,route->ft);
7245 route->lastCommand = 0;
7246 }
7247 }
7248 iret = TRUE;
7249 }
7250 }
7251 }
7252 lock_and_do_routes_register();
7253 return iret;
7254}
7255//int unregister_bscripts(node){
7256// //unregister scripts
7257//
7258//}
7259
7260
7261void unRegisterTexture(struct X3D_Node *tmp);
7262void unRegisterBindable (struct X3D_Node *node);
7263void remove_OSCsensor(struct X3D_Node * node);
7264void remove_picksensor(struct X3D_Node * node);
7265void delete_first(struct X3D_Node *node);
7266void removeNodeFromKeySensorList(struct X3D_Node* node);
7267int unInitializeScript(struct X3D_Node *node);
7268void delete_geomrep(struct X3D_Node* node);
7269void delete_glbuffers(struct X3D_Node *node);
7270void unRegisterGeoElevationGrid(struct X3D_Node *node);
7271
7272int unRegisterX3DAnyNode(struct X3D_Node *node){
7273 //this is for 'live' scenery, not protoDeclarations or proto library scenes
7274 //web3d has a concept of a browser. A browser contains and renders a scene.
7275 //as of early 2015, freewrl's browser consists of scattered 'tables' -simple flat arrays or vectors
7276 // scattered around global instance. During rendering, it does not 'recurse into sub-contexts' for
7277 // things like sensors, routes, node updating. Rather during parsing, live scenery is 'registered'
7278 // in the browser tables, and later/here unregisterd, for example when unloading an inline or scene
7279
7280 /* Undo any node registration(s)
7281 From GeneratedCode.c createNewX3DNode():
7282 // is this a texture holding node?
7283 registerTexture(tmp);
7284 // Node Tracking
7285 registerX3DNode(tmp);
7286 // is this a bindable node?
7287 registerBindable(tmp);
7288 // is this a OSC sensor node?
7289 add_OSCsensor(tmp); // WANT_OSC
7290 // is this a pick sensor node?
7291 add_picksensor(tmp); // DJTRACK_PICKSENSORS
7292 // is this a time tick node?
7293 add_first(tmp);
7294 // possibly a KeySensor node?
7295 addNodeToKeySensorList(X3D_NODE(tmp));
7296 */
7297
7298 //unRegisterPolyRep(node); //attn Disabler
7299 // is this a texture holding node?
7300 unRegisterTexture(node);
7301 // Node Tracking
7302 unRegisterX3DNode(node);
7303 // is this a bindable node?
7304 unRegisterBindable(node);
7305 // is this a geoElevationGrid?
7306 unRegisterGeoElevationGrid(node);
7307 // is this a OSC sensor node?
7308 remove_OSCsensor(node); // WANT_OSC
7309 // is this a pick sensor node?
7310 remove_picksensor(node); // DJTRACK_PICKSENSORS
7311 // is this a time tick node?
7312 delete_first(node);
7313 // possibly a KeySensor node?
7314 removeNodeFromKeySensorList(X3D_NODE(node));
7315
7316 //as with kill_nodes, disable scripts
7317 unInitializeScript(node);
7318
7319 //only live scenery has polyreps prepared, remove the polyrep
7320 delete_geomrep(node);
7321 delete_glbuffers(node);
7322 return TRUE;
7323}
7324int print_broto_stats(int level, struct X3D_Proto *node){
7325 char spaces[256];
7326 int i,nr,nn,nc;
7327 for(i=0;i<level;i++)
7328 spaces[i] = ' ';
7329 spaces[level] = '\0';
7330 nr = node->__ROUTES ? vectorSize(node->__ROUTES) : 0;
7331 nn = node->__nodes ? vectorSize(node->__nodes) : 0;
7332 nc = node->__subcontexts ? vectorSize(node->__subcontexts) : 0;
7333
7334 printf("%sctx=%p routes=%d nodes=%d subcontexts=%d\n",spaces,node,nr,nn,nc);
7335 if(nc){
7336 int nextlevel = level + 1;
7337 for(i=0;i<nc;i++){
7338 struct X3D_Proto* sc = vector_get(struct X3D_Proto*,node->__subcontexts,i);
7339 print_broto_stats(nextlevel,sc);
7340 }
7341 }
7342 return 0;
7343
7344}
7345int unregister_broto_instance(struct X3D_Proto* node){
7346 /* Nov 2014: during broto parsing, if it's live/instanced scenery, createNewX3DNode()
7347 is called instead of createNewX3DNode0() to register the node type in global/browser tables.
7348 Here we try to undo those registrations.
7349 Call this when anchoring to a new scene, cleaning up on exit, or unloading an Inline.
7350 A. unregister items registered in global/browser structs
7351
7352 a remove registered sensors -need a __sensors array?
7353 b. remove registered scripts -see __scripts
7354 c. remove registered routes:
7355 c.i regular routes -from __ROUTES table
7356 c.ii IS construction routes - from __IStable - a function was developed but not yet tested: unregister_IStableRoutes
7357 d unregister nodes from table used by startofloopnodeupdates - see createNewX3DNode vs createNewX3DNode0 in generatedCode.c
7358
7359
7360 */
7361 int retval = 1; //TRUE;
7362 if(node && hasContext(X3D_NODE(node))){
7363 unsigned char depthflag = ciflag_get(node->__protoFlags,0);
7364 if(depthflag){
7365 /* live scenery, registered */
7366 //recurse to subcontexts
7367 if(node->__subcontexts){
7368 int i;
7369 for(i=0;i<vectorSize(node->__subcontexts);i++){
7370 struct X3D_Proto* subcontext = vector_get(struct X3D_Proto*,node->__subcontexts,i);
7371 unregister_broto_instance(subcontext);
7372 }
7373 }
7374 //unregister IS construction routes
7375 unregister_IStableRoutes((Stack*)node->__IS, node);
7376 //unregister regular routes
7377 unregister_broutes(node);
7378 //unregister scripts
7379 //unregister_bscripts(node);
7380 //unregister sensors and nodes
7381 if(node->__nodes){
7382 //printf("unregister size of __nodes=%d\n",vectorSize(node->__nodes));
7383 int i;
7384 for(i=0;i<vectorSize(node->__nodes);i++){
7385 struct X3D_Node* ns = vector_get(struct X3D_Node*,node->__nodes,i);
7386 unRegisterX3DAnyNode(ns);
7387 broto_clear_DEF_by_node(node,ns);
7388 }
7389 }
7390 }
7391 }
7392 return retval;
7393}
7394
7395int gc_broto_instance(struct X3D_Proto* node){
7396 int i, iret = TRUE;
7397 //used for both live scenery -after unregistered from browser- and for protodeclarations and proto library scenes
7398 //does not free the __protoDef outward facing fields of a protoInstance, protoDeclare, nor the node itself
7399 // -- you do that generically from the containing context
7400 //recurse to free subcontexts: protoInstances, externProtoInstances, Inlines (which may instance this context's protoDeclares)
7401 //free protodeclares (recursive)
7402 //free externprotodeclares (recursive)
7403 //some of the following could be in a general GC malloc table per-context
7404 //in that case, still set the vector pointer to null because Inline re-uses itself on subsequent Inline.load = true
7405 //free routes
7406 if(node && hasContext(X3D_NODE(node))){
7407 node->__children.n = 0; //hide from other threads
7408 node->_sortedChildren.n = 0;
7409 if(node->__subcontexts){
7410 struct X3D_Proto *subctx;
7411 for(i=0;i<vectorSize(node->__subcontexts);i++){
7412 subctx = vector_get(struct X3D_Proto*,node->__subcontexts,i);
7413 gc_broto_instance(subctx);
7414 }
7415 deleteVector(struct X3D_Proto*,node->__subcontexts);
7416 }
7417
7418 if(node->__ROUTES){
7419 for(i=0;i<vectorSize(node->__ROUTES);i++){
7420 struct brotoRoute* route = vector_get(struct brotoRoute*,node->__ROUTES,i);
7421 free_broute(route);
7422 FREE_IF_NZ(route);
7423 }
7424 deleteVector(struct brotoRoute *, node->__ROUTES);
7425 }
7426 //free scipts
7427 if(node->__scripts)
7428 deleteVector(struct X3D_Node *,node->__scripts);
7429 //free IStable
7430 if(node->__IS){
7431 for(i=0;i<vectorSize(node->__IS);i++) {
7432 struct brotoIS * bi = vector_get(struct brotoIS*,node->__IS,i);
7433 FREE_IF_NZ(bi);
7434 }
7435 deleteVector(struct brotoIS *,node->__IS);
7436 }
7437 //free DEFnames
7438 if(node->__DEFnames) {
7439 for(i=0;i<vectorSize(node->__DEFnames);i++) {
7440 struct brotoDefpair def = vector_get(struct brotoDefpair,node->__DEFnames,i);
7441 FREE_IF_NZ(def.name);
7442 }
7443 deleteVector(struct brotoDefpair,node->__DEFnames);
7444 }
7445 //free IMPORTS
7446 if(node->__IMPORTS)
7447 deleteVector(struct EXIMPORT *,node->__IMPORTS);
7448 //free EXPORTS
7449 if(node->__EXPORTS)
7450 deleteVector(struct EXIMPORT *,node->__EXPORTS);
7451 //free nodes
7452 if(node->__nodes){
7453 int i;
7454 struct X3D_Node* nx;
7455 //have we cleaned up all references to these nodes?
7456 //if not, and we free() them, freewrl browser will crash - in routing,
7457 //in startofloopnodeupdates, with binding stacks - anywhere we didn't deregister/clean up
7458 //which is a good test to make sure we cleaned up.
7459 //Apr 2015 also crashes if the same node is listed multiple times in the __nodes list, 2nd free(node) bombs
7460 int crash_challenge = 1;
7461 if(crash_challenge) {
7462 for(i=0;i<vectorSize(node->__nodes);i++){
7463 nx = vector_get(struct X3D_Node*,node->__nodes,i);
7464 freeMallocedNodeFields(nx);
7465 FREE_IF_NZ(nx);
7466 }
7467 }
7468 deleteVector(struct X3D_Node *,node->__nodes);
7469 }
7470 if(node->__protoDeclares){
7471 int i;
7472 struct X3D_Proto *subctx;
7473 char flagInstance, flagExtern;
7474 flagInstance = ciflag_get(node->__protoFlags,2);
7475 flagExtern = ciflag_get(node->__protoFlags,3);
7476 if(!(flagExtern && !flagInstance)) //don't delete library protos - we'll get them when we delete the library
7477 for(i=0;i<vectorSize(node->__protoDeclares);i++){
7478 subctx = vector_get(struct X3D_Proto*,node->__protoDeclares,i);
7479 //
7480 gc_broto_instance(subctx);
7481 freeMallocedNodeFields(X3D_NODE(subctx));
7482 FREE_IF_NZ(subctx);
7483 }
7484 deleteVector(void*,node->__protoDeclares);
7485 }
7486 if(node->__externProtoDeclares){
7487 int i;
7488 struct X3D_Proto *subctx;
7489 char flagInstance, flagExtern;
7490 flagInstance = ciflag_get(node->__protoFlags,2);
7491 flagExtern = ciflag_get(node->__protoFlags,3);
7492 if(!(flagExtern && !flagInstance)) //don't delete library protos - we'll get them when we delete the library
7493 for(i=0;i<vectorSize(node->__externProtoDeclares);i++){
7494 //Q. wait - what if its in a shared libararyScene?
7495 //Those persist beyond the coming and going of scenes and inlines and protoinstances
7496 //A. externProto is a local scene proxy for a libraryscene protodeclare
7497 subctx = vector_get(struct X3D_Proto*,node->__externProtoDeclares,i);
7498 gc_broto_instance(subctx);
7499 freeMallocedNodeFields(X3D_NODE(subctx));
7500 FREE_IF_NZ(subctx);
7501 }
7502 deleteVector(void*,node->__externProtoDeclares);
7503 }
7504 iret = TRUE;
7505 }
7506 return iret;
7507}
7508int unload_broto(struct X3D_Proto* node){
7509 /* code to unload a scene, inline, or protoInstance (a per-broto-context, recursive version of kill_nodes)
7510 the garbage collection part can be used on protoDeclares, externProtoDeclares,
7511 and extern proto library scenes. All these use X3D_Proto or X3D_Inline struct
7512 with a few .__protoFlags distinguishing their type at runtime.
7513 A. unregister items registered in global/browser structs
7514 a remove registered sensors -need a __sensors array?
7515 b. remove registered scripts -see __scripts
7516 c. remove registered routes:
7517 c.i regular routes -from __ROUTES table
7518 c.ii IS construction routes - from __IStable - a function was developed but not yet tested: unregister_IStableRoutes
7519 d unregister nodes from table used by startofloopnodeupdates - see createNewX3DNode vs createNewX3DNode0 in generatedCode.c
7520 B. deallocate context-specific heap:
7521 a nodes allocated -need a context-specific nodes heap
7522 a.0 recursively unload sub-contexts: inlines and protoInstances
7523 a.1 builtin nodes
7524 b. context vectors: __ROUTES, __IMPORTS, __EXPORTS, __DEFnames, __scripts, addChildren, removeChildren, _children
7525 c prototypes declared: __protoDeclares, __externProtoDeclares - use same recursive unload
7526 d string heap -need a string heap
7527 e malloc heap used for elements of __ vectors - need a context-specific malloc and heap ie fmalloc(context,sizeof)
7528 C. clear/reset scalar values so Inline can be re-used/re-loaded: (not sure, likely none to worry about)
7529 */
7530 int retval = FALSE;
7531 if(node && hasContext(X3D_NODE(node))){
7532 //print_broto_stats(0, node);
7533 unregister_broto_instance(node);
7534 gc_broto_instance(node);
7535 retval = TRUE;
7536 }
7537 return retval;
7538}
7539int unRegisterNodeRoutes(struct X3D_Proto *context, struct X3D_Node* node){
7540 //unregister any routes that are to/from a particular node
7541 int iret = 0;
7542 if(context && hasContext(X3D_NODE(context))){
7543 if(context->__ROUTES){
7544 int i,ii,nr;
7545 nr = vectorSize(context->__ROUTES);
7546 for(i=0;i<nr;i++){
7547 struct brotoRoute *route;
7548 ii = nr - i - 1; //start at end so we can pack without losing our index
7549 route = vector_get(struct brotoRoute*,context->__ROUTES,ii);
7550 if(route->from.node == node || route->to.node == node){
7551 if( route->lastCommand){
7552 CRoutes_RemoveSimpleB(route->from.node,route->from.ifield,route->from.builtIn, route->to.node,route->to.ifield,route->to.builtIn,route->ft);
7553 route->lastCommand = 0;
7554 }
7555 vector_remove_elem(struct X3D_Node*,context->__ROUTES,ii);
7556 iret++;
7557 }
7558 }
7559 }
7560 }
7561 return iret;
7562}
7563int remove_broto_node(struct X3D_Proto *context, struct X3D_Node* node){
7564 // used by js/SAI > executionContext.removeNamedNode(DEF)
7565 // to zap a node out of existence
7566 int iret = 0;
7567 if(context && hasContext(X3D_NODE(context))){
7568 if(node && hasContext(node))
7569 unload_broto(X3D_PROTO(node)); //cleanup its guts if its an inline or protoInstance
7570 unRegisterX3DAnyNode(node); //unregister from browser stacks and lists
7571 unRegisterNodeRoutes(context,node); //unregister any routes that are to/from the deleted node
7572 remove_node_from_broto_context(context,node); //remove from context.__nodes and __subcontexts
7573 FREE_IF_NZ(node);
7574 iret = 1;
7575 }
7576 return iret;
7577}
7578
7579
7580//void *createNewX3DNodeB(int nt, int intable, void *executionContext){
7581// struct X3D_Node *node;
7582// if(intable)
7583// node = createNewX3DNode(nt);
7584// else
7585// node = createNewX3DNode0(nt);
7586// if(node && executionContext)
7587// node->_executionContext = executionContext;
7588// return node;
7589//}