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