FreeWRL / FreeX3D 4.3.0
ProdCon.c
1/*
2
3 Main functions II (how to define the purpose of this file?).
4*/
5
6
7/****************************************************************************
8 This file is part of the FreeWRL/FreeX3D Distribution.
9
10 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
11
12 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
13 it under the terms of the GNU Lesser Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
24****************************************************************************/
25
26
27#include <config.h>
28#include <system.h>
29#include <system_threads.h>
30#include <display.h>
31#include <internal.h>
32
33#include <libFreeWRL.h>
34#include <list.h>
35
36#include <io_files.h>
37#include <io_http.h>
38
39
40#include <threads.h>
41
42#include "../vrml_parser/Structs.h"
43#include "headers.h"
44#include "../vrml_parser/CParseGeneral.h"
45#include "../scenegraph/Vector.h"
46#include "../vrml_parser/CFieldDecls.h"
47#include "../world_script/JScript.h"
48#include "../world_script/CScripts.h"
49#include "../vrml_parser/CParseParser.h"
50#include "../vrml_parser/CParseLexer.h"
51#include "../vrml_parser/CParse.h"
52#include "Snapshot.h"
53#include "../scenegraph/Collision.h"
54#include "../scenegraph/Component_KeyDevice.h"
55#include "../opengl/Frustum.h"
56#include "../opengl/OpenGL_Utils.h"
57
58#if defined(INCLUDE_NON_WEB3D_FORMATS)
59#include "../non_web3d_formats/ColladaParser.h"
60#endif //INCLUDE_NON_WEB3D_FORMATS
61
62#if defined (INCLUDE_STL_FILES)
63#include "../input/convertSTL.h"
64#endif //INCLUDE_STL_FILES
65
66#include "../scenegraph/quaternion.h"
67#include "../scenegraph/Viewer.h"
68#include "../input/SensInterps.h"
69#include "../x3d_parser/Bindable.h"
70#include "../input/InputFunctions.h"
71#ifndef DISABLER
72#include "../plugin/pluginUtils.h"
73#include "../plugin/PluginSocket.h"
74#endif
75#include "../ui/common.h"
76#include "../opengl/OpenGL_Utils.h"
77#include "../opengl/Textures.h"
78#include "../opengl/LoadTextures.h"
79
80
81#include "MainLoop.h"
82#include "ProdCon.h"
83
84
85
86/* used by the paser to call back the lexer for EXTERNPROTO */
87void embedEXTERNPROTO(struct VRMLLexer *me, char *myName, char *buffer, char *pound);
88
89//true statics:
90char *EAI_Flag = "From the EAI bootcamp of life ";
91char* PluginPath = "/private/tmp";
92int PluginLength = 12;
93
94//I think these are Aqua - I'll leave them static pending Aqua guru plugin review:
95int _fw_browser_plugin = 0;
96int _fw_pipe = 0;
97uintptr_t _fw_instance = 0;
98
99
100/*******************************/
101
102
103struct PSStruct {
104 unsigned type; /* what is this task? */
105 char *inp; /* data for task (eg, vrml text) */
106 void *ptr; /* address (node) to put data */
107 unsigned ofs; /* offset in node for data */
108 int zeroBind; /* should we dispose Bindables? */
109 int bind; /* should we issue a bind? */
110 char *path; /* path of parent URL */
111 int *comp; /* pointer to complete flag */
112
113 char *fieldname; /* pointer to a static field name */
114 int jparamcount; /* number of parameters for this one */
115 struct Uni_String *sv; /* the SV for javascript */
116};
117
118static bool parser_do_parse_string(const char *input, const int len, struct X3D_Node *ectx, struct X3D_Node *nRn);
119
120/* Bindables */
121typedef struct pProdCon {
122 //these bindable lists store all bindable nodes as parsed
123 struct Vector *viewpointNodes;
124 struct Vector *fogNodes;
125 struct Vector *backgroundNodes;
126 struct Vector *navigationNodes;
127
128 /* thread synchronization issues */
129 int _P_LOCK_VAR;// = 0;
130 s_list_t *resource_list_to_parse; // = NULL;
131 s_list_t *frontend_list_to_get; // = NULL;
132 int frontend_gets_files;
133 /* psp is the data structure that holds parameters for the parsing thread */
134 struct PSStruct psp;
135 /* is the inputParse thread created? */
136 //int inputParseInitialized; //=FALSE;
137
138 /* is the parsing thread active? this is read-only, used as a "flag" by other tasks */
139 int inputThreadParsing; //=FALSE;
140 int haveParsedCParsed; // = FALSE; /* used to tell when we need to call destroyCParserData as destroyCParserData can segfault otherwise */
141 int frontend_res_count;
142#if defined (INCLUDE_STL_FILES)
143 /* stl files have no implicit scale. This scale will make it fit into a reasonable boundingBox */
144 float lastSTLScaling;
145#endif
146
147}* ppProdCon;
148void *ProdCon_constructor(){
149 void *v = MALLOCV(sizeof(struct pProdCon));
150 memset(v,0,sizeof(struct pProdCon));
151 return v;
152}
153void ProdCon_init(struct tProdCon *t)
154{
155 //public
156 t->currboundvpno=0;
157
158 /* bind nodes in display loop, NOT in parsing threadthread */
159 t->setViewpointBindInRender = NULL;
160 t->setFogBindInRender = NULL;
161 t->setBackgroundBindInRender = NULL;
162 t->setNavigationBindInRender = NULL;
163 /* make up a new parser for parsing from createVrmlFromURL and createVrmlFromString */
164 t->savedParser = NULL; //struct VRMLParser* savedParser;
165
166 //private
167 t->prv = ProdCon_constructor();
168 {
169 ppProdCon p = (ppProdCon)t->prv;
170 //stores all bindable viewpoints as parsed
171 p->viewpointNodes = newVector(struct X3D_Node *,8);
172 t->viewpointNodes = p->viewpointNodes;
173 p->fogNodes = newVector(struct X3D_Node *, 2);
174 p->backgroundNodes = newVector(struct X3D_Node *, 2);
175 p->navigationNodes = newVector(struct X3D_Node *, 2);
176 //printf ("created new navigationNodes of %p, at A\n",p->navigationNodes);
177
178
179 /* thread synchronization issues */
180 p->_P_LOCK_VAR = 0;
181 p->resource_list_to_parse = NULL;
182 p->frontend_list_to_get = NULL;
183#ifndef DISABLER
184 p->frontend_gets_files = 2; //dug9 Sep 1, 2013 used to test new fgf method in win32; July2014 we're back, for Async 1=main.c 2=_displayThread
185#else
186 p->frontend_gets_files = 0; //Disabler
187#endif
188 /* psp is the data structure that holds parameters for the parsing thread */
189 //p->psp;
190 /* is the inputParse thread created? */
191 //p->inputParseInitialized=FALSE;
192 /* is the parsing thread active? this is read-only, used as a "flag" by other tasks */
193 p->inputThreadParsing=FALSE;
194 p->haveParsedCParsed = FALSE; /* used to tell when we need to call destroyCParserData
195 as destroyCParserData can segfault otherwise */
196 p->frontend_res_count = 0;
197#if defined (INCLUDE_STL_FILES)
198 /* stl files have no implicit scale. This scale will make it fit into a reasonable boundingBox */
199 p->lastSTLScaling = 0.1;
200#endif
201
202 }
203}
204void ProdCon_clear(struct tProdCon *t){
205 if(t->prv)
206 {
207 ppProdCon p = (ppProdCon)t->prv;
208 deleteVector(struct X3D_Node *, p->viewpointNodes);
209 deleteVector(struct X3D_Node *, p->fogNodes);
210 deleteVector(struct X3D_Node *, p->backgroundNodes);
211 deleteVector(struct X3D_Node *, p->navigationNodes);
212 }
213}
215//static int inputParseInitialized=FALSE;
216//
218//int inputThreadParsing=FALSE;
219
220/* /\* Is the initial URL loaded ? Robert Sim *\/ */
221/* int URLLoaded = FALSE; */
222/* int isURLLoaded() { return (URLLoaded && !inputThreadParsing); } */
223
225//struct PSStruct psp;
226
227//static int haveParsedCParsed = FALSE; /* used to tell when we need to call destroyCParserData
228// as destroyCParserData can segfault otherwise */
229
230
231
232#if defined (INCLUDE_STL_FILES)
233/* stl files have no implicit scale. This scale will make it fit into a reasonable boundingBox */
234float fwl_getLastSTLScaling() {
235 ppProdCon p = (ppProdCon)gglobal()->ProdCon.prv;
236 if (p!=NULL) return p->lastSTLScaling;
237 return 1.0;
238}
239#endif
240
241
242/* is a parser running? this is a function, because if we need to mutex lock, we
243 can do all locking in this file */
244int fwl_isInputThreadInitialized() {
245 //ppProdCon p = (ppProdCon)gglobal()->ProdCon.prv;
246 //return p->inputParseInitialized;
247 return gglobal()->threads.ResourceThreadRunning;
248}
249
250/* statusbar uses this to tell user that we are still loading */
251int fwl_isinputThreadParsing() {
252 ppProdCon p = (ppProdCon)gglobal()->ProdCon.prv;
253 return(p->inputThreadParsing);
254}
255void sceneInstance(struct X3D_Proto* proto, struct X3D_Group *scene);
256void dump_scene2(FILE *fp, int level, struct X3D_Node* node, int recurse, Stack *DEFedNodes) ;
257
258int indexChildrenName(struct X3D_Node *node){
259 int index = -1; //we'll have it work like a bool too, and I don't think any of our children field are at 0
260 if(node)
261 switch(node->_nodeType){
262 case NODE_Group:
263 index = FIELDNAMES_children;
264 break;
265 case NODE_Transform:
266 index = FIELDNAMES_children;
267 break;
268 case NODE_Switch:
269 index = FIELDNAMES_children;
270 break;
271 case NODE_Billboard:
272 index = FIELDNAMES_children;
273 break;
274 case NODE_Proto:
275 index = FIELDNAMES___children;
276 break;
277 case NODE_Inline: //Q. do I need this in here? Saw code in x3dparser.
278 index = FIELDNAMES___children;
279 break;
280 case NODE_GeoLOD: //Q. do I need this in here? A. No - leave null and the correct field is found for geoOrigin (otherwise it puts it in rootNode which is a kind of parent node field -sick - see glod1/b.x3d)
281 index = FIELDNAMES_rootNode;
282 break;
283 //switch?
284 }
285 return index;
286
287}
288struct Multi_Node *childrenField(struct X3D_Node *node){
289 struct Multi_Node *childs = NULL;
290 if(node)
291 switch(node->_nodeType){
292 case NODE_Group:
293 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_Group,children));
294 break;
295 case NODE_Transform:
296 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_Transform,children));
297 break;
298 case NODE_Switch:
299 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_Switch,children));
300 break;
301 case NODE_Billboard:
302 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_Billboard,children));
303 break;
304 case NODE_Proto:
305 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_Proto,__children));
306 break;
307 case NODE_Inline: //Q. do I need this in here? Saw code in x3dparser.
308 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_Inline,__children));
309 break;
310 case NODE_GeoLOD: //Q. do I need this in here?
311 childs = offsetPointer_deref(void*, node, offsetof(struct X3D_GeoLOD,rootNode));
312 break;
313 }
314 return childs;
315}
316int offsetofChildren(struct X3D_Node *node){
317 int offs = 0; //we'll have it work like a bool too, and I don't think any of our children field are at 0
318 if(node)
319 switch(node->_nodeType){
320 case NODE_Group:
321 offs = offsetof(struct X3D_Group,children);
322 break;
323 case NODE_Transform:
324 offs = offsetof(struct X3D_Transform,children);
325 break;
326 case NODE_Switch:
327 offs = offsetof(struct X3D_Switch,children);
328 break;
329 case NODE_Billboard:
330 offs = offsetof(struct X3D_Billboard,children);
331 break;
332 case NODE_Proto:
333 //offs = offsetof(struct X3D_Proto,__children); //addRemoveChildren reallocs p, so mfnode .p field not stable enough for rendering thread
334 offs = offsetof(struct X3D_Proto,__children); //addChildren); //this is the designed way to add
335 break;
336 case NODE_Inline: //Q. do I need this in here? Saw code in x3dparser.
337 offs = offsetof(struct X3D_Inline,__children); //addChildren); //__children);
338 break;
339 case NODE_GeoLOD: //Q. do I need this in here? Saw code in x3dparser.
340 offs = offsetof(struct X3D_GeoLOD,rootNode);
341 break;
342 }
343 return offs;
344}
345
349static bool parser_do_parse_string(const char *input, const int len, struct X3D_Node *ectx, struct X3D_Node *nRn)
350{
351 bool ret;
352 int kids;
353 ppProdCon p = (ppProdCon)gglobal()->ProdCon.prv;
354
355
356#if defined (INCLUDE_STL_FILES)
357 /* stl files have no implicit scale. This scale will make it fit into a reasonable boundingBox */
358 p->lastSTLScaling = 0.1;
359#endif
360
361
362 ret = FALSE;
363
364 inputFileType = determineFileType(input,len);
365 DEBUG_MSG("PARSE STRING, ft %d, fv %d.%d.%d\n",
366 inputFileType, inputFileVersion[0], inputFileVersion[1], inputFileVersion[2]);
367 kids = offsetofChildren(nRn);
368
369 switch (inputFileType) {
370 case IS_TYPE_XML_X3D:
371 if(kids){
372 //if(nRn->_nodeType == NODE_Group || nRn->_nodeType == NODE_Proto){
373 ret = X3DParse(ectx, X3D_NODE(nRn), (const char*)input);
374 }
375 break;
376 case IS_TYPE_VRML:
377 if(kids){
378 ret = cParse(ectx, nRn, kids, (const char*)input);
379 p->haveParsedCParsed = TRUE;
380 }
381 break;
382 case IS_TYPE_VRML1: {
383 char *newData = STRDUP("#VRML V2.0 utf8\n\
384 Shape {appearance Appearance {material Material {diffuseColor 0.0 1.0 1.0}}\
385 geometry Text {\
386 string [\"This build\" \"is not made with\" \"VRML1 support\"]\
387 fontStyle FontStyle{\
388 justify [\"MIDDLE\",\"MIDDLE\"]\
389 size 0.5\
390 }\
391 }}\
392 ");
393
394 //ret = cParse (nRn,(int) offsetof (struct X3D_Proto, children), newData);
395 FREE_IF_NZ(newData);
396 break;
397 }
398
399#if defined (INCLUDE_NON_WEB3D_FORMATS)
400 case IS_TYPE_COLLADA:
401 ConsoleMessage ("Collada not supported yet");
402 ret = ColladaParse (nRn, (const char*)input);
403 break;
404 case IS_TYPE_SKETCHUP:
405 ConsoleMessage ("Google Sketchup format not supported yet");
406 break;
407 case IS_TYPE_KML:
408 ConsoleMessage ("KML-KMZ format not supported yet");
409 break;
410#endif //INCLUDE_NON_WEB3D_FORMATS
411
412#if defined (INCLUDE_STL_FILES)
413 case IS_TYPE_ASCII_STL: {
414 char *newData = convertAsciiSTL(input);
415 p->lastSTLScaling = getLastSTLScale();
416
417 //ConsoleMessage("IS_TYPE_ASCII_STL, now file is :%s:",newData);
418
419 ret = cParse (ectx,nRn,(int) offsetof (struct X3D_Group, children), newData);
420 FREE_IF_NZ(newData);
421 break;
422 }
423 case IS_TYPE_BINARY_STL: {
424 char *newData = convertBinarySTL((const unsigned char *)input);
425 p->lastSTLScaling = getLastSTLScale();
426
427 ret = cParse (ectx,nRn,(int) offsetof (struct X3D_Group, children), newData);
428 FREE_IF_NZ(newData);
429 break;
430 }
431#endif //INCLUDE_STL_FILES
432
433 default: {
434 if (gglobal()->internalc.global_strictParsing) {
435 ConsoleMessage("unknown text as input");
436 } else {
437 inputFileType = IS_TYPE_VRML;
438 inputFileVersion[0] = 2; /* try VRML V2 */
439 cParse (ectx,nRn,(int) offsetof (struct X3D_Proto, __children), (const char*)input);
440 p->haveParsedCParsed = TRUE; }
441 }
442 }
443
444
445 if (!ret) {
446 ConsoleMessage ("Parser Unsuccessful");
447 }
448
449 return ret;
450}
451
452/* interface for telling the parser side to forget about everything... */
453void EAI_killBindables (void) {
454 int complete;
455 ttglobal tg = gglobal();
456 ppProdCon p = (ppProdCon)tg->ProdCon.prv;
457
458 complete=0;
459 p->psp.comp = &complete;
460 p->psp.type = ZEROBINDABLES;
461 p->psp.ofs = 0;
462 p->psp.ptr = NULL;
463 p->psp.path = NULL;
464 p->psp.zeroBind = FALSE;
465 p->psp.bind = FALSE; /* should we issue a set_bind? */
466 p->psp.inp = NULL;
467 p->psp.fieldname = NULL;
468
469}
470
471void new_root(){
472 //clean up before loading a new scene
473 int i;
474 //ConsoleMessage ("SHOULD CALL KILL_OLDWORLD HERE\n");
475
476 //struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
477
478 /* get rid of sensor events */
479 resetSensorEvents();
480
481
482 /* close the Console Message system, if required. */
483 closeConsoleMessage();
484
485 /* occlusion testing - zero total count, but keep MALLOC'd memory around */
486 zeroOcclusion();
487
488 /* clock events - stop them from ticking */
489 kill_clockEvents();
490
491
492 /* kill DEFS, handles */
493 EAI_killBindables();
494 kill_bindables();
495 killKeySensorNodeList();
496
497
498 /* stop routing */
499 kill_routing();
500
501 /* tell the statusbar that it needs to reinitialize */
502 //kill_status();
503 setMenuStatusVP(NULL);
504
505 /* free textures */
506/*
507 kill_openGLTextures();
508*/
509
510 /* free scripts */
511
512 kill_javascript();
513
514
515
516#ifdef DO_NOT_KNOW
517 /* free EAI */
518 if (kill_EAI) {
519 /* shutdown_EAI(); */
520 fwlio_RxTx_control(CHANNEL_EAI, RxTx_STOP) ;
521 }
522#endif
523
524 /* reset any VRML Parser data */
525/*
526 if (globalParser != NULL) {
527 parser_destroyData(globalParser);
528 //globalParser = NULL;
529 gglobal()->CParse.globalParser = NULL;
530 }
531*/
532 kill_X3DDefs();
533
534 /* tell statusbar that we have none */
535 viewer_default();
536 setMenuStatusVP("NONE");
537
538 //ConsoleMessage ("new_root, right now rootNode has %d children\n",rootNode()->children.n);
539
540 //ConsoleMessage("send_resource_to_parser, new_root\n");
541 /* mark all rootNode children for Dispose */
542 {
543 struct Multi_Node *children;
544 children = childrenField(rootNode());
545 for (i = 0; i < children->n; i++) {
546 markForDispose(children->p[i], TRUE);
547 }
548
549 // force rootNode to have 0 children, compile_Group will make
550 // the _sortedChildren field mimic the children field.
551 children->n = 0;
552 rootNode()->_change++;
553 }
554 // set the extents back to initial
555 {
556 struct X3D_Node *node = rootNode();
557 INITIALIZE_EXTENT
558 ;
559 }
560
561 //printf ("send_resource_to_parser, rootnode children count set to 0\n");
562
563}
564void resitem_enqueue(s_list_t* item);
565
566//void send_resource_to_parser(resource_item_t *res)
567//{
568// ppProdCon p;
569// ttglobal tg;
570//
571// //ConsoleMessage ("send_resource_to_parser, res->new_root %s",BOOL_STR(res->new_root));
572//
573// if (res->new_root) {
574// new_root();
575// }
576//
577//
578// /* We are not in parser thread, most likely
579// in main or display thread, and we successfully
580// parsed a resource request.
581//
582// We send it to parser.
583// */
584// tg = gglobal();
585// p = tg->ProdCon.prv;
586//
587// /* Wait for display thread to be fully initialized */
588// while (IS_DISPLAY_INITIALIZED == FALSE) {
589// usleep(50);
590// }
591//
592// ///* wait for the parser thread to come up to speed */
593// //while (!p->inputParseInitialized)
594// // usleep(50);
595//
596// resitem_enqueue(ml_new(res));
597//}
598
599
600
601//bool send_resource_to_parser_if_available(resource_item_t *res)
602//{
603// /* We are not in parser thread, most likely
604// in main or display thread, and we successfully
605// parsed a resource request.
606//
607// We send it to parser.
608// */
609// ppProdCon p;
610// ttglobal tg = gglobal();
611// p = (ppProdCon)tg->ProdCon.prv;
612//
613// /* Wait for display thread to be fully initialized */
614// /* dug9 Aug 24, 2013 - don't wait (it seems to hang apartment-threaded apps) and see what happens.
615// display_initialized flag is set in a worker thread.
616// H: perhaps the usleep and pthread_create compete in an apartment thread, causing deadlock
617// */
618// //while (IS_DISPLAY_INITIALIZED == FALSE) {
619// // usleep(50);
620// //}
621//
622// /* wait for the parser thread to come up to speed */
623// //while (!p->inputParseInitialized) usleep(50);
624//
625// resitem_enqueue(ml_new(res));
626// return TRUE;
627//}
628
629void dump_resource_waiting(resource_item_t* res)
630{
631#ifdef FW_DEBUG
632 printf("%s\t%s\n",( res->complete ? "<finished>" : "<waiting>" ), res->URLrequest);
633#endif
634}
635
636void send_resource_to_parser_async(resource_item_t *res){
637
638 resitem_enqueue(ml_new(res));
639}
640
641
642void dump_parser_wait_queue()
643{
644#ifdef FW_DEBUG
645 ppProdCon p;
646 struct tProdCon *t = &gglobal()->ProdCon;
647 p = (ppProdCon)t->prv;
648 printf("Parser wait queue:\n");
649 ml_foreach(p->resource_list_to_parse, dump_resource_waiting((resource_item_t*)ml_elem(__l)));
650 printf(".\n");
651#endif
652}
653
654void post_parse_set_activeLayer(); //Component_Layering.c
655void zeroUnits(); //UNITS keyword parse-time processing
659// = spare mutex for testing parse/render thread clash theories, assumes one freewrl instance in process
660static pthread_mutex_t mutex_test = PTHREAD_MUTEX_INITIALIZER;
661void fwl_lockTestMutex()
662{
663 pthread_mutex_lock(&mutex_test);
664 //printf(",");
665}
666void fwl_unlockTestMutex()
667{
668 pthread_mutex_unlock(&mutex_test);
669}
670
671
672
673bool parser_process_res_VRML_X3D(resource_item_t *res)
674{
675 //s_list_t *l;
676 openned_file_t *of;
677 struct X3D_Node *nRn;
678 struct X3D_Node *nRnfree;
679 struct X3D_Node *ectx;
680 struct X3D_Node *insert_node;
681 //int i;
682 int offsetInNode;
683 int shouldBind;
684 //int shouldUnBind;
685 int parsedOk = FALSE; // results from parser
686 bool fromEAI_SAI = FALSE;
687 /* we only bind to new nodes, if we are adding via Inlines, etc */
688 //int origFogNodes, origBackgroundNodes, origNavigationNodes, origViewpointNodes;
689 struct X3D_Node *oldFogBindInRender, *oldBackgroundBindInRender, *oldNavigationBindInRender, *oldViewpointBindInRender;
690
691 ppProdCon p;
692 struct tProdCon *t;
693 ttglobal tg = gglobal();
694 t = &tg->ProdCon;
695 p = (ppProdCon)t->prv;
696
697 UNUSED(parsedOk); // compiler warning mitigation
698
699 //printf ("entering parser_process_res_VRML_X3D\n");
700 //fwl_lockTestMutex();
701
702 /* printf("processing VRML/X3D resource: %s\n", res->URLrequest); */
703 offsetInNode = 0;
704 insert_node = NULL;
705 nRnfree = NULL;
706 shouldBind = TRUE; //FALSE aug 2016
707 //shouldUnBind = FALSE;
708
709 oldFogBindInRender = oldBackgroundBindInRender = oldNavigationBindInRender = oldViewpointBindInRender = NULL;
710 if(vectorSize(p->fogNodes))
711 oldFogBindInRender = vector_get(struct X3D_Node*, p->fogNodes,0);
712 if (vectorSize(p->backgroundNodes))
713 oldBackgroundBindInRender = vector_get(struct X3D_Node*, p->backgroundNodes,0);
714 if (vectorSize(p->navigationNodes))
715 oldNavigationBindInRender = vector_get(struct X3D_Node*, p->navigationNodes,0);
716 if (vectorSize(t->viewpointNodes) )
717 // dont take vp from inline
718 oldViewpointBindInRender = vector_get(struct X3D_Node*, t->viewpointNodes,0);
719
720
721 //ConsoleMessage ("parser_process_res_VRML_X3D, url %s",res->parsed_request);
722 /* save the current URL so that any local-url gets are relative to this */
723 if (res->parsed_request != NULL)
724 if (strncmp(res->parsed_request,EAI_Flag,strlen(EAI_Flag)) == 0) {
725 //ConsoleMessage("parser_process_res_VRML_X3D, from EAI, ignoring");
726 fromEAI_SAI = TRUE;
727 }
728
729 if (!fromEAI_SAI){
730 pushInputResource(res);
731 zeroUnits();
732 }
733
734 ectx = res->ectx;
735 /* OK Boyz - here we go... if this if from the EAI, just parse it, as it will be a simple string */
736 if (res->parsed_request != NULL && strcmp(res->parsed_request, EAI_Flag) == 0) {
737
738 /* EAI/SAI parsing */
739 /* printf ("have the actual text here \n"); */
740 /* create a container so that the parser has a place to put the nodes */
741 nRn = (struct X3D_Node *) createNewX3DNode0(NODE_Group);
742 nRnfree = nRn;
743 insert_node = X3D_NODE(res->whereToPlaceData); /* casting here for compiler */
744 offsetInNode = res->offsetFromWhereToPlaceData;
745 if(res->media_type == resm_gltf || res->media_type == resm_glb)
746 parsedOk = parser_do_parse_gltf((const char *)res->URLrequest,(const int)strlen(res->URLrequest), ectx, nRn);
747 else
748 parsedOk = parser_do_parse_string((const char *)res->URLrequest,(const int)strlen(res->URLrequest), ectx, nRn);
749 //printf("after parse_string in EAI/SAI parsing\n");
750 } else {
751 /* standard file parsing */
752 //l = (s_list_t *) res->openned_files;
753 //if (!l) {
754 // /* error */
755 // return FALSE;
756 //}
757
758 //of = ml_elem(l);
759 of = res->openned_files;
760 if (!of) {
761 /* error */
762 //fwl_unlockTestMutex();
763 return FALSE;
764 }
765
766
767 if (!of->fileData) {
768 /* error */
769 //fwl_unlockTestMutex();
770 return FALSE;
771 }
772
773 /*
774 printf ("res %p root_res %p\n",res,gglobal()->resources.root_res);
775 ConsoleMessage ("pc - res %p root_res %p\n",res,gglobal()->resources.root_res);
776 */
777
778 /* bind ONLY in main - do not bind for Inlines, etc */
779 if (res->treat_as_root || res == (resource_item_t*) gglobal()->resources.root_res) {
780 kill_bindables();
781 //kill_oldWorld(TRUE, TRUE, TRUE, __FILE__, __LINE__);
782 shouldBind = TRUE;
783 //ConsoleMessage ("pc - shouldBind");
784 } else {
785 if (!((resource_item_t*)tg->resources.root_res)->complete) {
786 /* Push the parser state : re-entrance here */
787 /* "save" the old classic parser state, so that names do not cross-pollute */
788 t->savedParser = (void *)tg->CParse.globalParser;
789 tg->CParse.globalParser = NULL;
790 }
791 }
792
793 /* create a container so that the parser has a place to put the nodes */
794 if(res->whereToPlaceData){
795 nRn = X3D_NODE(res->whereToPlaceData);
796 if(nRn->_nodeType == NODE_Inline){
797 // Problem: - PULL technique of downloading nearly empty main scene with Inline to big scene
798 // as a way to fix the problem of browsers downloading rather than running plugin,
799 // and losing the http in the process
800 // but specs say "bindables from Inlines are not eligible to be the first node bound'
801 // Solutions:
802 // 1. Component Networking > Browser Options has something about allowing Inlines to bind bindables
803 // - we could add a browser option on commandline (Launcher in win32)
804 // 2. we could detect if the main scene found any of its own bindables, and for
805 // the bindable types it doesn't have, use the Inlines'
806 // In freewrl, the main scene is completely parsed first
807 // Then ExternProtos and Inlines are parsed. So if we are in here, in theory we already
808 // know what bindables the main scene has.
809 // 3. above, if treat_as_root, always unbind everything there so nothing on bindables stacks
810 // Then after parsing, always bind to first one in each bindable list, if exists
811 // - #3 IMPLEMENTED AUG 22, 2016
812 shouldBind = TRUE; //TRUE;
813 // OLDCODE shouldUnBind = FALSE; //brotos > Inlines > additively bind (not sure about other things like externProto 17.wrl)
814 X3D_INLINE(nRn)->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
815 }
816 }else{
817 // we do a kind of hot-swap: we parse into a new broto,
818 // then delete the old rootnode broto, then register the new one
819 // assumes uload_broto(old root node) has already been done elsewhere
820 struct X3D_Proto *sceneProto;
821 struct X3D_Node *rn;
822 sceneProto = (struct X3D_Proto *) createNewX3DNode(NODE_Proto);
823 sceneProto->__protoFlags = ciflag_set(sceneProto->__protoFlags,1,0);
824 sceneProto->__protoFlags = ciflag_set(sceneProto->__protoFlags,2,2);
825
826 nRn = X3D_NODE(sceneProto);
827 sceneProto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
828 ectx = nRn;
829 rn = rootNode(); //save a pointer to old rootnode
830 setRootNode(X3D_NODE(sceneProto)); //set new rootnode
831 if(rn){
832 //old root node cleanup
833 deleteVector(sizeof(void*),rn->_parentVector); //perhaps unlink first
834 freeMallocedNodeFields(rn);
835 unRegisterX3DNode(rn);
836 FREE_IF_NZ(rn);
837 }
838 }
839
840 /* ACTUALLY CALLS THE PARSER */
841 if(res->media_type == resm_gltf || res->media_type == resm_glb)
842 parsedOk = parser_do_parse_gltf(of->fileData, of->fileDataSize, ectx, nRn);
843 else
844 parsedOk = parser_do_parse_string(of->fileData, of->fileDataSize, ectx, nRn);
845 //printf("after parse_string in standard file parsing\n");
846 if ((res != (resource_item_t*)tg->resources.root_res) && ((!tg->resources.root_res) ||(!((resource_item_t*)tg->resources.root_res)->complete))) {
847 tg->CParse.globalParser = t->savedParser;
848 }
849
850 if (shouldBind) {
851 /* Aug 22, 2016
852 New theory of operation of parsing and binding stacks:
853 1. when parsing, add to end of binding lists
854 2. when determining which is bound, use the start of the binding list
855 ie top-of-stack is p[0], bottom is p[n-1]
856 Vector add and Stack push both add to the end of the vector, so new functions are needed
857 to work from the start
858 3. after parsing anything, bind to the first in each list
859 since freewrl parses the main scene completely before parsing inlines,
860 main scene bindables will be at the start of the list if they exist
861 and if mainscene has none then the first Inline will be bound
862 How (I think) Layers and binding stacks work (dug9):
863 A layer is conceptually like a scene, and has its own binding stacks
864 on each draw, we may draw the main scene and a number of layers
865 the scene is treated like a layer for the purpose of switching binding stacks
866 when switching layers, the bstacks[layerId] are pointer-copied to p-> and t-> viewpointNodes,
867 navigationNodes, backgroundNodes, fogNodes (called xxxNodes) so old code can run against these
868 arrays without knowing about layers. Therefore its possible to read from bstacks or xxxNodes,
869 and -due to being pointer copies of the Vectors- we and read and write to eihter xxxNodes
870 or bstacks[layerId] when in the current layer, which is normal
871 */
872 //Aug 22, 2016 new interpretation: always rebind to first bindable
873 struct X3D_Node *stacktop;
874 if(vectorSize(p->fogNodes)){
875 stacktop = vector_get(struct X3D_Node*, p->fogNodes,0);
876 if(stacktop != oldFogBindInRender)
877 t->setFogBindInRender = stacktop;
878 }
879 if (vectorSize(p->backgroundNodes)){
880 stacktop = vector_get(struct X3D_Node*, p->backgroundNodes,0);
881 if(stacktop != oldBackgroundBindInRender)
882 t->setBackgroundBindInRender = stacktop;
883 }
884 if (vectorSize(p->navigationNodes)){
885 stacktop = vector_get(struct X3D_Node*, p->navigationNodes,0);
886 if(stacktop != oldNavigationBindInRender)
887 t->setNavigationBindInRender = stacktop;
888 }
889 if (vectorSize(t->viewpointNodes) ){
890 // dont take vp from inline
891 stacktop = vector_get(struct X3D_Node*, t->viewpointNodes,0);
892 if(stacktop != oldViewpointBindInRender){
893 t->setViewpointBindInRender = stacktop;
894 if (res->afterPoundCharacters)
895 fwl_gotoViewpoint(res->afterPoundCharacters);
896 }
897 }
898
899
900
901 }
902
903 /* we either put things at the rootNode (ie, a new world) or we put them as a children to another node */
904 if (res->whereToPlaceData == NULL) {
905 //brotos have to maintain various lists, which is done in the parser.
906 //therefore pass the rootnode / executioncontext into the parser
907 } else {
908 insert_node = X3D_NODE(res->whereToPlaceData); /* casting here for compiler */
909 offsetInNode = res->offsetFromWhereToPlaceData;
910 }
911
912 }
913
914 /* printf ("parser_process_res_VRML_X3D, res->where %u, insert_node %u, rootNode %u\n",res->where, insert_node, rootNode); */
915
916 /* now that we have the VRML/X3D file, load it into the scene. */
917 /* add the new nodes to wherever the caller wanted */
918
919 /* take the nodes from the nRn node, and put them into the place where we have decided to put them */
920 if(X3D_NODE(nRn)->_nodeType == NODE_Group){
921 struct X3D_Group *nRng = X3D_GROUP(nRn);
922 AddRemoveChildren(X3D_NODE(insert_node),
923 offsetPointer_deref(void*, insert_node, offsetInNode),
924 (struct X3D_Node * *)nRng->children.p,
925 nRng->children.n, 1, __FILE__,__LINE__);
926
927 /* and, remove them from this nRn node, so that they are not multi-parented */
928 AddRemoveChildren(X3D_NODE(nRng),
929 (struct Multi_Node *)((char *)nRng + offsetof (struct X3D_Group, children)),
930 (struct X3D_Node* *)nRng->children.p,nRng->children.n,2,__FILE__,__LINE__);
931 }
932
933 res->complete = TRUE;
934
935 if(nRnfree){
936 deleteVector(sizeof(void*),nRnfree->_parentVector); //perhaps unlink first
937 freeMallocedNodeFields(nRnfree);
938 FREE_IF_NZ(nRnfree);
939 }
940
941 /* remove this resource from the stack */
942 if (!fromEAI_SAI){
943 popInputResource();
944 zeroUnits();
945 }
946
947 //printf ("exiting praser_process_res_VRML_X3D\n");
948 //fwl_unlockTestMutex();
949 return TRUE;
950}
951
952/* interface for creating VRML for EAI */
953int EAI_CreateVrml(const char *tp, const char *inputstring,
954 struct X3D_Node *ectx, struct X3D_Group *where) {
955 resource_item_t *res;
956 char *newString;
957 bool retval = FALSE;
958
959 newString = NULL;
960
961 if (strncmp(tp, "URL", 3) == 0) {
962
963 res = resource_create_single(inputstring);
964 res->ectx = ectx;
965 res->whereToPlaceData = where;
966 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
967 /* printf ("EAI_CreateVrml, res->where is %u, root is %u parameter where %u\n",res->where, rootNode, where); */
968
969 } else { // all other cases are inline code to parse... let the parser do the job ;P...
970
971 const char *sendIn;
972
973 if (strncmp(inputstring,"#VRML V2.0", 6) == 0) {
974 sendIn = inputstring;
975 } else {
976 newString = MALLOC (char *, strlen(inputstring) + strlen ("#VRML V2.0 utf8\n") + 3);
977 strcpy (newString,"#VRML V2.0 utf8\n");
978 strcat (newString,inputstring);
979 sendIn = newString;
980 /* printf ("EAI_Create, had to append, now :%s:\n",newString); */
981 }
982
983 res = resource_create_from_string(sendIn);
984 res->media_type=resm_vrml;
985 res->parsed_request = EAI_Flag;
986 res->ectx = ectx;
987 res->whereToPlaceData = where;
988 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
989 }
990 retval = parser_process_res_VRML_X3D(res);
991 FREE_IF_NZ(newString);
992 return retval;
993 //send_resource_to_parser(res);
994 //resource_wait(res);
995 //FREE_IF_NZ(newString);
996 //return (res->status == ress_parsed);
997}
998
999/* interface for creating X3D for EAI - like above except x3d */
1000int EAI_CreateX3d(const char *tp, const char *inputstring, struct X3D_Node *ectx, struct X3D_Group *where)
1001{
1002 //int retval;
1003 resource_item_t *res;
1004 char *newString;
1005
1006 newString = NULL;
1007
1008 if (strncmp(tp, "URL", 3) == 0) {
1009
1010 res = resource_create_single(inputstring);
1011 res->ectx = ectx;
1012 res->whereToPlaceData = where;
1013 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
1014 /* printf ("EAI_CreateVrml, res->where is %u, root is %u parameter where %u\n",res->where, rootNode, where); */
1015
1016 } else { // all other cases are inline code to parse... let the parser do the job ;P...
1017
1018 const char *sendIn;
1019 // the x3dparser doesn't like multiple root xml elements
1020 // and it doesn't seem to hurt to give it an extra wrapping in <x3d>
1021 // that way you can have multiple root elements and they all get
1022 // put into the target children[] field
1023 newString = MALLOC (char *, strlen(inputstring) + strlen ("<X3D>\n\n</X3D>\n") + 3);
1024 strcpy(newString,"<X3D>\n");
1025 strcat(newString,inputstring);
1026 strcat(newString,"\n</X3D>\n");
1027 sendIn = newString;
1028 //printf("EAI_createX3d string[%s]\n",sendIn);
1029 res = resource_create_from_string(sendIn);
1030 res->media_type=resm_x3d; //**different than vrml
1031 res->parsed_request = EAI_Flag;
1032 res->ectx = ectx;
1033 res->whereToPlaceData = where;
1034 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
1035 }
1036 return parser_process_res_VRML_X3D(res);
1037
1038 //send_resource_to_parser(res);
1039 //resource_wait(res);
1040 //FREE_IF_NZ(newString);
1041 //return (res->status == ress_parsed);
1042}
1043
1044
1048static bool parser_process_res_SCRIPT(resource_item_t *res)
1049{
1050 //s_list_t *l;
1051 openned_file_t *of;
1052 struct Shader_Script* ss;
1053 const char *buffer;
1054
1055 buffer = NULL;
1056
1057 switch (res->type) {
1058 case rest_invalid:
1059 return FALSE;
1060 break;
1061
1062 case rest_string:
1063 buffer = res->URLrequest;
1064 break;
1065 case rest_url:
1066 case rest_file:
1067 case rest_multi:
1068 //l = (s_list_t *) res->openned_files;
1069 //if (!l) {
1070 // /* error */
1071 // return FALSE;
1072 //}
1073
1074 //of = ml_elem(l);
1075 of = res->openned_files;
1076 if (!of) {
1077 /* error */
1078 return FALSE;
1079 }
1080
1081 buffer = (const char*)of->fileData;
1082 break;
1083 }
1084
1085 ss = (struct Shader_Script *) res->whereToPlaceData;
1086
1087 return script_initCode(ss, buffer);
1088}
1089
1090
1091#if !defined(HAVE_PTHREAD_CANCEL)
1092void Parser_thread_exit_handler(int sig) {
1093 ConsoleMessage("Parser_thread_exit_handler: parserThread exiting");
1094 pthread_exit(0);
1095}
1096#endif //HAVE_PTHREAD_CANCEL
1097
1098
1102
1103
1104/*
1105 QUEUE method uses DesignPatterns: CommandPattern + ThreadsafeQueue + SingleThread_ThreadPool/MonoThreading
1106 It doesn't block the queue while processing/doing_work. That allows the involked
1107 commands to chain new commands into the queue without deadlocking.
1108
1109*/
1110//recently added list functions:
1111//void ml_enqueue(s_list_t **list, s_list_t *item);
1112//s_list_t *ml_dequeue(s_list_t **list);
1113
1114
1115
1116void *getProdConQueueContentStatus() {
1117
1118 /*void resitem_enqueue(s_list_t *item){ */
1119 ppProdCon p;
1120 ttglobal tg = gglobal();
1121 p = (ppProdCon) tg->ProdCon.prv;
1122
1123 return (p->resource_list_to_parse);
1124}
1125
1126
1127void threadsafe_enqueue_item_signal(s_list_t *item, s_list_t** queue, pthread_mutex_t* queue_lock, pthread_cond_t *queue_nonzero)
1128{
1129 pthread_mutex_lock(queue_lock);
1130 if (*queue == NULL)
1131 pthread_cond_signal(queue_nonzero);
1132 ml_enqueue(queue,item);
1133 pthread_mutex_unlock(queue_lock);
1134}
1135
1136s_list_t* threadsafe_dequeue_item_wait(s_list_t** queue, pthread_mutex_t *queue_lock, pthread_cond_t *queue_nonzero, BOOL *waiting )
1137{
1138 s_list_t *item = NULL;
1139 pthread_mutex_lock(queue_lock);
1140 while (*queue == NULL){
1141 *waiting = TRUE;
1142 pthread_cond_wait(queue_nonzero, queue_lock);
1143 *waiting = FALSE;
1144 }
1145 item = ml_dequeue(queue);
1146 pthread_mutex_unlock(queue_lock);
1147 return item;
1148}
1149void resitem_enqueue(s_list_t *item){
1150 ppProdCon p;
1151 ttglobal tg = gglobal();
1152 p = (ppProdCon)tg->ProdCon.prv;
1153
1154 threadsafe_enqueue_item_signal(item,&p->resource_list_to_parse, &tg->threads.mutex_resource_list, &tg->threads.resource_list_condition );
1155}
1156void resitem_enqueue_tg(s_list_t *item, void* tg){
1157 fwl_setCurrentHandle(tg, __FILE__, __LINE__);
1158 resitem_enqueue(item);
1159 fwl_clearCurrentHandle();
1160}
1161s_list_t *resitem_dequeue(){
1162 ppProdCon p;
1163 ttglobal tg = gglobal();
1164 p = (ppProdCon)tg->ProdCon.prv;
1165
1166 return threadsafe_dequeue_item_wait(&p->resource_list_to_parse, &tg->threads.mutex_resource_list, &tg->threads.resource_list_condition, &tg->threads.ResourceThreadWaiting );
1167}
1168
1169
1170
1171void threadsafe_enqueue_item(s_list_t *item, s_list_t** queue, pthread_mutex_t* queue_lock)
1172{
1173 pthread_mutex_lock(queue_lock);
1174 ml_enqueue(queue,item);
1175 pthread_mutex_unlock(queue_lock);
1176}
1177
1178s_list_t* threadsafe_dequeue_item(s_list_t** queue, pthread_mutex_t *queue_lock )
1179{
1180 s_list_t *item = NULL;
1181 pthread_mutex_lock(queue_lock);
1182 item = ml_dequeue(queue);
1183 pthread_mutex_unlock(queue_lock);
1184 return item;
1185}
1186
1187void frontenditem_enqueue(s_list_t *item){
1188 ppProdCon p;
1189 ttglobal tg = gglobal();
1190 p = (ppProdCon)tg->ProdCon.prv;
1191 threadsafe_enqueue_item(item,&p->frontend_list_to_get, &tg->threads.mutex_frontend_list );
1192}
1193void frontenditem_enqueue_tg(s_list_t *item, void *tg){
1194 fwl_setCurrentHandle(tg, __FILE__, __LINE__);
1195 frontenditem_enqueue(item);
1196 fwl_clearCurrentHandle();
1197}
1198s_list_t *frontenditem_dequeue(){
1199 ppProdCon p;
1200 ttglobal tg = gglobal();
1201 p = (ppProdCon)tg->ProdCon.prv;
1202
1203 return threadsafe_dequeue_item(&p->frontend_list_to_get, &tg->threads.mutex_frontend_list );
1204}
1205s_list_t *frontenditem_dequeue_tg(void *tg){
1206 s_list_t *item;
1207 fwl_setCurrentHandle(tg, __FILE__, __LINE__);
1208 item = frontenditem_dequeue();
1209 fwl_clearCurrentHandle();
1210 return item;
1211}
1212void *fwl_frontenditem_dequeue(){
1213 void *res = NULL;
1214 s_list_t *item = frontenditem_dequeue();
1215 if (item){
1216 res = item->elem;
1217 FREE(item);
1218 }
1219 return res;
1220}
1221void fwl_resitem_enqueue(void *res){
1222 resitem_enqueue(ml_new(res));
1223}
1224
1225int frontendGetsFiles(){
1226 return ((ppProdCon)(gglobal()->ProdCon.prv))->frontend_gets_files;
1227}
1228
1229void process_res_texitem(resource_item_t *res);
1230bool parser_process_res_SHADER(resource_item_t *res);
1231bool process_res_audio(resource_item_t *res);
1232bool process_res_movie(resource_item_t *res);
1233int parser_process_res_gltf(resource_item_t *res);
1239static bool parser_process_res(s_list_t *item)
1240{
1241 int more_multi;
1242 bool remove_it = FALSE;
1243 // OLDCODE bool destroy_it = FALSE;
1244 bool retval = TRUE;
1245 resource_item_t *res;
1246 //ppProdCon p;
1247 //ttglobal tg = gglobal();
1248 //p = (ppProdCon)tg->ProdCon.prv;
1249
1250 if (!item || !item->elem)
1251 return retval;
1252
1253 res = ml_elem(item);
1254 //printf("%s ",res->URLrequest);
1255 //printf("\nprocessing resource: type %s, status %s\n", resourceTypeToString(res->type), resourceStatusToString(res->status));
1256 switch (res->status) {
1257
1258 case ress_invalid:
1259 case ress_none:
1260 retval = FALSE;
1261 if(!res->actions || (res->actions & resa_identify)){
1262 resource_identify(res->parent, res);
1263 if (res->type == rest_invalid) {
1264 remove_it = TRUE;
1265 res->complete = TRUE; //J30
1266 }
1267 }
1268 break;
1269
1270 case ress_starts_good:
1271 if(!res->actions || (res->actions & resa_download)){
1272#ifndef DISABLER
1273 //if(p->frontend_gets_files){
1274 frontenditem_enqueue(ml_new(res));
1275 remove_it = TRUE;
1276 //}else{
1277 // resource_fetch(res);
1278 //}
1279#else
1280 if(p->frontend_gets_files){
1281 frontenditem_enqueue(ml_new(res));
1282 remove_it = TRUE;
1283 }else{
1284 resource_fetch(res);
1285 }
1286#endif
1287 }
1288 break;
1289
1290 case ress_downloaded:
1291 if(!res->actions || (res->actions & resa_load))
1292 /* Here we may want to delegate loading into another thread ... */
1293 //if (!resource_load(res)) {
1294 if(res->_loadFunc){
1295 if(!res->_loadFunc(res)){
1296 ERROR_MSG("failure when trying to load resource: %s\n", res->URLrequest);
1297 remove_it = TRUE;
1298 res->complete = TRUE; //J30
1299 retval = FALSE;
1300 }
1301 }
1302 break;
1303
1304 case ress_failed:
1305 more_multi = (res->status == ress_failed) && (res->m_request != NULL);
1306 if(more_multi){
1307 //still some hope via multi_string url, perhaps next one
1308 res->status = ress_invalid; //downgrade ress_fail to ress_invalid
1309 res->type = rest_multi; //should already be flagged
1310 //must consult BE to convert relativeURL to absoluteURL via baseURL
1311 //(or could we absolutize in a batch in resource_create_multi0()?)
1312 resource_identify(res->parent, res); //should increment multi pointer/iterator
1313 frontenditem_enqueue(ml_new(res));
1314 }else{
1315 ConsoleMessage("url not found: %s\n",res->parsed_request);
1316 retval = FALSE;
1317 res->complete = TRUE; //J30
1318 // OLDCODE destroy_it = TRUE;
1319 }
1320 remove_it = TRUE;
1321 break;
1322
1323 case ress_loaded:
1324 // printf("processing resource, media_type %s\n",resourceMediaTypeToString(res->media_type));
1325 if(!res->actions || (res->actions & resa_process))
1326 switch (res->media_type) {
1327 case resm_unknown:
1328 ConsoleMessage ("deciphering file: 404 file not found or unknown file type encountered.");
1329 remove_it = TRUE;
1330 res->complete=TRUE; /* not going to do anything else with this one */
1331 res->status = ress_not_loaded;
1332 break;
1333 case resm_vrml:
1334 case resm_x3d:
1335 if (parser_process_res_VRML_X3D(res)) {
1336 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1337 res->status = ress_parsed;
1338
1339 } else {
1340 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1341 retval = FALSE;
1342 }
1343 break;
1344 case resm_script:
1345 if (parser_process_res_SCRIPT(res)) {
1346 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1347 res->status = ress_parsed;
1348 } else {
1349 retval = FALSE;
1350 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1351 }
1352 break;
1353 case resm_pshader:
1354 case resm_fshader:
1355 if (parser_process_res_SHADER(res)) {
1356 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1357 res->status = ress_parsed;
1358 } else {
1359 retval = FALSE;
1360 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1361 }
1362 break;
1363 case resm_image:
1364 /* Texture file has been loaded into memory
1365 the node could be updated ... i.e. texture created */
1366 res->complete = TRUE; /* small hack */
1367 process_res_texitem(res);
1368 break;
1369 case resm_movie:
1370 res->complete = TRUE;
1371 if(process_res_movie(res)){
1372 res->status = ress_parsed;
1373 }else{
1374 retval = FALSE;
1375 res->status = ress_failed;
1376 }
1377 break;
1378 case resm_audio:
1379 res->complete = TRUE;
1380 if(process_res_audio(res)){
1381 res->status = ress_parsed;
1382 }else{
1383 retval = FALSE;
1384 res->status = ress_failed;
1385 }
1386 break;
1387 case resm_x3z:
1388 process_x3z(res);
1389 printf("processed x3z\n");
1390 break;
1391 case resm_mocap:
1392 process_mocap(res);
1393 break;
1394 //Khronos gltf and derivitives
1395 case resm_gltf:
1396 case resm_glb:
1397 case resm_bin:
1398 //cesium derivitives related to gltf
1399 case resm_json:
1400 case resm_b3dm:
1401 case resm_i3dm:
1402 case resm_pnts:
1403 case resm_cmpt:
1404 if (parser_process_res_gltf(res)) {
1405 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1406 res->status = ress_parsed;
1407
1408 } else {
1409 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1410 retval = FALSE;
1411 }
1412 break;
1413 case resm_external:
1414 // JAS - resm_external is part of this enum, but not handled here,
1415 // so we get compiler warnings.
1416 printf ("dont know anything about resm_external at this point\n");
1417 break;
1418 }
1419 /* Parse only once ! */
1420 res->complete = TRUE; //J30
1421 remove_it = TRUE;
1422 break;
1423
1424 case ress_not_loaded:
1425 remove_it = TRUE;
1426 res->complete = TRUE; //J30
1427 retval = FALSE;
1428 break;
1429
1430 case ress_parsed:
1431 res->complete = TRUE; //J30
1432 remove_it = TRUE;
1433 break;
1434
1435 case ress_not_parsed:
1436 res->complete = TRUE; //J30
1437 retval = FALSE;
1438 remove_it = TRUE;
1439 break;
1440 }
1441
1442 if (remove_it) {
1443 /* Remove the parsed resource from the list */
1444 if(res->status == ress_parsed){
1445 //just x3d and vrml. if you clear images nothing shows up
1446 if(res->openned_files){
1447 openned_file_t *of = res->openned_files;
1448 //remove BLOB
1449 FREE_IF_NZ(of->fileData);
1450 }
1451 }
1452 FREE_IF_NZ(item);
1453 }else{
1454 // chain command by adding it back into the queue
1455 resitem_enqueue(item);
1456 }
1457 dump_parser_wait_queue();
1458
1459 // printf ("end of process resource\n");
1460
1461 return retval;
1462}
1463//we want the void* addresses of the following, so the int value doesn't matter
1464static const int res_command_exit;
1465
1466void resitem_queue_exit(){
1467 resitem_enqueue(ml_new(&res_command_exit));
1468}
1469void _inputParseThread(void *globalcontext)
1470{
1471 ttglobal tg = (ttglobal)globalcontext;
1472
1473 #if !defined (HAVE_PTHREAD_CANCEL)
1474 struct sigaction actions;
1475 int rc;
1476 memset(&actions, 0, sizeof(actions));
1477 sigemptyset(&actions.sa_mask);
1478 actions.sa_flags = 0;
1479 actions.sa_handler = Parser_thread_exit_handler;
1480 rc = sigaction(SIGUSR2,&actions,NULL);
1481 // ConsoleMessage ("for parserThread, have defined exit handler");
1482 #endif //HAVE_PTHREAD_CANCEL
1483
1484 {
1485 ppProdCon p = (ppProdCon)tg->ProdCon.prv;
1486 tg->threads.PCthread = pthread_self();
1487 //set_thread2global(tg, tg->threads.PCthread ,"parse thread");
1488 fwl_setCurrentHandle(tg,__FILE__,__LINE__);
1489
1490 //p->inputParseInitialized = TRUE;
1491 tg->threads.ResourceThreadRunning = TRUE;
1492 ENTER_THREAD("input parser");
1493
1494 //viewer_default();
1495
1496 /* now, loop here forever, waiting for instructions and obeying them */
1497
1498 for (;;) {
1499 void *elem;
1500 //bool result = TRUE;
1501 s_list_t* item = resitem_dequeue();
1502 elem = ml_elem(item);
1503 if (elem == &res_command_exit){
1504 FREE_IF_NZ(item);
1505 break;
1506 }
1507 //printf ("thread hit, flushing %d, tg %p, resource thread\n",tg->threads.flushing, tg);
1508
1509 if (tg->threads.flushing){
1510 FREE_IF_NZ(item);
1511 continue;
1512 }
1513 p->inputThreadParsing = TRUE;
1514 //result =
1515 parser_process_res(item); //,&p->resource_list_to_parse);
1516 p->inputThreadParsing = FALSE;
1517 }
1518
1519 tg->threads.ResourceThreadRunning = FALSE;
1520
1521
1522 }
1523}
1524
1525
1526
1527void kill_bindables (void) {
1528 int i, ib;
1529 struct X3D_Node *tmp;
1530 ppProdCon p;
1531 ttglobal tg = gglobal();
1532
1533 struct tProdCon *t = &gglobal()->ProdCon;
1534 p = (ppProdCon)t->prv;
1535
1536 //H: we have per-layer binding stacks, and when we switch to a layer
1537 // we copy from bstack to the old-style p-> or t-> viewpointNodes, backgroundNodes ...
1538 // so if unbinding all layers ie new scene, we can do it from bstack,
1539 // but don't forget to zero the oldstyle copy.
1540 //printf ("kill_bindables called\n");
1541 ib = 0; //unbind
1542 for(i=0;i<vectorSize(tg->Bindable.bstacks);i++){
1543 bindablestack *bstack = getBindableStacksByLayer(tg,i);
1544 if (vectorSize(bstack->navigation) > 0) {
1545 for (i=0; i < vectorSize(bstack->navigation);i++){
1546 tmp = vector_get(struct X3D_Node*,bstack->navigation,i);
1547 send_bind_to(tmp, ib);
1548 }
1549 }
1550 if (vectorSize(bstack->background) > 0) {
1551 for (i=0; i < vectorSize(bstack->background);i++){
1552 tmp = vector_get(struct X3D_Node*,bstack->background,i);
1553 send_bind_to(tmp, ib);
1554 }
1555 }
1556 if (vectorSize(bstack->viewpoint) > 0) {
1557 for (i=0; i < vectorSize(bstack->viewpoint);i++){
1558 tmp = vector_get(struct X3D_Node*,bstack->viewpoint,i);
1559 send_bind_to(tmp, ib);
1560 }
1561 }
1562 if (vectorSize(bstack->fog) > 0) {
1563 for (i=0; i < vectorSize(bstack->fog);i++){
1564 tmp = vector_get(struct X3D_Node*,bstack->fog,i);
1565 send_bind_to(tmp, ib);
1566 }
1567 }
1568 ((struct Vector *)bstack->navigation)->n=0;
1569 ((struct Vector *)bstack->background)->n=0;
1570 ((struct Vector *)bstack->viewpoint)->n=0;
1571 ((struct Vector *)bstack->fog)->n=0;
1572 }
1573 //do we still use these?
1574 ((struct Vector *)t->viewpointNodes)->n=0;
1575 p->backgroundNodes->n=0;
1576 p->navigationNodes->n=0;
1577 p->fogNodes->n=0;
1578
1579 return;
1580
1581 /*
1582 printf ("before tvp %p ",t->viewpointNodes);
1583 KILL_BINDABLE(t->viewpointNodes);
1584 printf ("after, tvp %p\n",t->viewpointNodes);
1585
1586 KILL_BINDABLE(p->backgroundNodes);
1587 printf ("calling KILL_BINDABLE on navigationNodes %p at B\n",p->navigationNodes);
1588
1589 KILL_BINDABLE(p->navigationNodes);
1590 KILL_BINDABLE(p->fogNodes);
1591
1592 printf ("calling KILL_BINDABLE on the global navigation stack\n");
1593 KILL_BINDABLE(tg->Bindable.navigation_stack);
1594 KILL_BINDABLE(tg->Bindable.background_stack);
1595 KILL_BINDABLE(tg->Bindable.viewpoint_stack);
1596 KILL_BINDABLE(tg->Bindable.fog_stack);
1597 */
1598 /*
1599 struct Vector *background_stack;
1600 struct Vector *viewpoint_stack;
1601 struct Vector *navigation_stack;
1602 struct Vector *fog_stack;
1603
1604 ttglobal tg = gglobal();
1605 if (node->set_bind < 100) {
1606 if (node->set_bind == 1) set_naviinfo(node);
1607 bind_node (X3D_NODE(node), tg->Bindable.navigation_stack,"Component_Navigation");
1608*/
1609
1610
1611}
1612
1613
1614void registerBindable (struct X3D_Node *node) {
1615 int layerId;
1616 ppProdCon p;
1617 ttglobal tg;
1618 struct tProdCon *t;
1619 tg = gglobal();
1620 t = &tg->ProdCon;
1621 p = (ppProdCon)t->prv;
1622
1623 layerId = tg->Bindable.activeLayer;
1624
1625 switch (node->_nodeType) {
1626 case NODE_Viewpoint:
1627 X3D_VIEWPOINT(node)->set_bind = 100;
1628 X3D_VIEWPOINT(node)->isBound = 0;
1629 X3D_VIEWPOINT(node)->_layerId = layerId;
1630 vector_pushBack (struct X3D_Node*,t->viewpointNodes, node);
1631 break;
1632 case NODE_OrthoViewpoint:
1633 X3D_ORTHOVIEWPOINT(node)->set_bind = 100;
1634 X3D_ORTHOVIEWPOINT(node)->isBound = 0;
1635 X3D_ORTHOVIEWPOINT(node)->_layerId = layerId;
1636 vector_pushBack (struct X3D_Node*,t->viewpointNodes, node);
1637 break;
1638 case NODE_GeoViewpoint:
1639 X3D_GEOVIEWPOINT(node)->set_bind = 100;
1640 X3D_GEOVIEWPOINT(node)->isBound = 0;
1641 X3D_GEOVIEWPOINT(node)->_layerId = layerId;
1642 vector_pushBack (struct X3D_Node*,t->viewpointNodes, node);
1643 break;
1644 case NODE_Background:
1645 X3D_BACKGROUND(node)->set_bind = 100;
1646 X3D_BACKGROUND(node)->isBound = 0;
1647 X3D_BACKGROUND(node)->_layerId = layerId;
1648 vector_pushBack (struct X3D_Node*,p->backgroundNodes, node);
1649 break;
1650 case NODE_TextureBackground:
1651 X3D_TEXTUREBACKGROUND(node)->set_bind = 100;
1652 X3D_TEXTUREBACKGROUND(node)->isBound = 0;
1653 X3D_TEXTUREBACKGROUND(node)->_layerId = layerId;
1654 vector_pushBack (struct X3D_Node*,p->backgroundNodes, node);
1655 break;
1656 case NODE_NavigationInfo:
1657 X3D_NAVIGATIONINFO(node)->set_bind = 100;
1658 X3D_NAVIGATIONINFO(node)->isBound = 0;
1659 X3D_NAVIGATIONINFO(node)->_layerId = layerId;
1660 vector_pushBack (struct X3D_Node*,p->navigationNodes, node);
1661 break;
1662 case NODE_Fog:
1663 X3D_FOG(node)->set_bind = 100;
1664 X3D_FOG(node)->isBound = 0;
1665 X3D_FOG(node)->_layerId = layerId;
1666 vector_pushBack (struct X3D_Node*,p->fogNodes, node);
1667 break;
1668 default: {
1669 /* do nothing with this node */
1670 /* printf ("got a registerBind on a node of type %s - ignoring\n",
1671 stringNodeType(node->_nodeType));
1672 */
1673 return;
1674 }
1675
1676 }
1677}
1678int removeNodeFromVector(int iaction, struct Vector *v, struct X3D_Node *node){
1679 //iaction = 0 pack vector
1680 //iaction = 1 set NULL
1681 int noisy, iret = FALSE;
1682 noisy = FALSE;
1683 if(v && node){
1684 struct X3D_Node *tn;
1685 int i, ii, n; //idx,
1686 //idx = -1;
1687 n = vectorSize(v);
1688 for(i=0;i<n;i++){
1689 ii = n - i - 1; //reverse walk, so we can remove without losing our loop counter
1690 tn = vector_get(struct X3D_Node*,v,ii);
1691 if(tn == node){
1692 iret++;
1693 if(iaction == 1){
1694 vector_set(struct X3D_Node*,v,ii,NULL);
1695 if(noisy) printf("NULLing %d %p\n",ii,node);
1696 }else if(iaction == 0){
1697 if(noisy) printf("REMOVing %d %p\n",ii,node);
1698 vector_remove_elem(struct X3D_Node*,v,ii);
1699 }
1700 }
1701 }
1702 }
1703 if(!iret && noisy){
1704 int i;
1705 printf("not found in stack node=%p stack.n=%d:\n",node,vectorSize(v));
1706 for(i=0;i<vectorSize(v);i++){
1707 printf(" %p",vector_get(struct X3D_Node*,v,i));
1708 }
1709 printf("\n");
1710 }
1711 return iret;
1712}
1713void unRegisterBindable (struct X3D_Node *node) {
1714 ppProdCon p;
1715 struct tProdCon *t = &gglobal()->ProdCon;
1716 p = (ppProdCon)t->prv;
1717
1718
1719 switch (node->_nodeType) {
1720 case NODE_Viewpoint:
1721 X3D_VIEWPOINT(node)->set_bind = 100;
1722 X3D_VIEWPOINT(node)->isBound = 0;
1723 //printf ("unRegisterBindable %p Viewpoint, description :%s:\n",node,X3D_VIEWPOINT(node)->description->strptr);
1724 send_bind_to(node,0);
1725 removeNodeFromVector(0, t->viewpointNodes, node);
1726 break;
1727 case NODE_OrthoViewpoint:
1728 X3D_ORTHOVIEWPOINT(node)->set_bind = 100;
1729 X3D_ORTHOVIEWPOINT(node)->isBound = 0;
1730 send_bind_to(node,0);
1731 removeNodeFromVector(0, t->viewpointNodes, node);
1732 break;
1733 case NODE_GeoViewpoint:
1734 X3D_GEOVIEWPOINT(node)->set_bind = 100;
1735 X3D_GEOVIEWPOINT(node)->isBound = 0;
1736 send_bind_to(node,0);
1737 removeNodeFromVector(0, t->viewpointNodes, node);
1738 break;
1739 case NODE_Background:
1740 X3D_BACKGROUND(node)->set_bind = 100;
1741 X3D_BACKGROUND(node)->isBound = 0;
1742 send_bind_to(node,0);
1743 removeNodeFromVector(0, p->backgroundNodes, node);
1744 break;
1745 case NODE_TextureBackground:
1746 X3D_TEXTUREBACKGROUND(node)->set_bind = 100;
1747 X3D_TEXTUREBACKGROUND(node)->isBound = 0;
1748 removeNodeFromVector(0, p->backgroundNodes, node);
1749 break;
1750 case NODE_NavigationInfo:
1751 X3D_NAVIGATIONINFO(node)->set_bind = 100;
1752 X3D_NAVIGATIONINFO(node)->isBound = 0;
1753 send_bind_to(node,0);
1754 removeNodeFromVector(0, p->navigationNodes, node);
1755 break;
1756 case NODE_Fog:
1757 X3D_FOG(node)->set_bind = 100;
1758 X3D_FOG(node)->isBound = 0;
1759 send_bind_to(node,0);
1760 removeNodeFromVector(0, p->fogNodes, node);
1761 break;
1762 default: {
1763 /* do nothing with this node */
1764 /* printf ("got a registerBind on a node of type %s - ignoring\n",
1765 stringNodeType(node->_nodeType));
1766 */
1767 return;
1768 }
1769
1770 }
1771}