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 setMenuStatus(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 setMenuStatus("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
746 parsedOk = parser_do_parse_string((const char *)res->URLrequest,(const int)strlen(res->URLrequest), ectx, nRn);
747 //printf("after parse_string in EAI/SAI parsing\n");
748 } else {
749 /* standard file parsing */
750 //l = (s_list_t *) res->openned_files;
751 //if (!l) {
752 // /* error */
753 // return FALSE;
754 //}
755
756 //of = ml_elem(l);
757 of = res->openned_files;
758 if (!of) {
759 /* error */
760 //fwl_unlockTestMutex();
761 return FALSE;
762 }
763
764
765 if (!of->fileData) {
766 /* error */
767 //fwl_unlockTestMutex();
768 return FALSE;
769 }
770
771 /*
772 printf ("res %p root_res %p\n",res,gglobal()->resources.root_res);
773 ConsoleMessage ("pc - res %p root_res %p\n",res,gglobal()->resources.root_res);
774 */
775
776 /* bind ONLY in main - do not bind for Inlines, etc */
777 if (res->treat_as_root || res == (resource_item_t*) gglobal()->resources.root_res) {
778 kill_bindables();
779 //kill_oldWorld(TRUE, TRUE, TRUE, __FILE__, __LINE__);
780 shouldBind = TRUE;
781 //ConsoleMessage ("pc - shouldBind");
782 } else {
783 if (!((resource_item_t*)tg->resources.root_res)->complete) {
784 /* Push the parser state : re-entrance here */
785 /* "save" the old classic parser state, so that names do not cross-pollute */
786 t->savedParser = (void *)tg->CParse.globalParser;
787 tg->CParse.globalParser = NULL;
788 }
789 }
790
791 /* create a container so that the parser has a place to put the nodes */
792 if(res->whereToPlaceData){
793 nRn = X3D_NODE(res->whereToPlaceData);
794 if(nRn->_nodeType == NODE_Inline){
795 // Problem: - PULL technique of downloading nearly empty main scene with Inline to big scene
796 // as a way to fix the problem of browsers downloading rather than running plugin,
797 // and losing the http in the process
798 // but specs say "bindables from Inlines are not eligible to be the first node bound'
799 // Solutions:
800 // 1. Component Networking > Browser Options has something about allowing Inlines to bind bindables
801 // - we could add a browser option on commandline (Launcher in win32)
802 // 2. we could detect if the main scene found any of its own bindables, and for
803 // the bindable types it doesn't have, use the Inlines'
804 // In freewrl, the main scene is completely parsed first
805 // Then ExternProtos and Inlines are parsed. So if we are in here, in theory we already
806 // know what bindables the main scene has.
807 // 3. above, if treat_as_root, always unbind everything there so nothing on bindables stacks
808 // Then after parsing, always bind to first one in each bindable list, if exists
809 // - #3 IMPLEMENTED AUG 22, 2016
810 shouldBind = TRUE; //TRUE;
811 // OLDCODE shouldUnBind = FALSE; //brotos > Inlines > additively bind (not sure about other things like externProto 17.wrl)
812 X3D_INLINE(nRn)->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
813 }
814 }else{
815 // we do a kind of hot-swap: we parse into a new broto,
816 // then delete the old rootnode broto, then register the new one
817 // assumes uload_broto(old root node) has already been done elsewhere
818 struct X3D_Proto *sceneProto;
819 struct X3D_Node *rn;
820 sceneProto = (struct X3D_Proto *) createNewX3DNode(NODE_Proto);
821 sceneProto->__protoFlags = ciflag_set(sceneProto->__protoFlags,1,0);
822 sceneProto->__protoFlags = ciflag_set(sceneProto->__protoFlags,2,2);
823
824 nRn = X3D_NODE(sceneProto);
825 sceneProto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
826 ectx = nRn;
827 rn = rootNode(); //save a pointer to old rootnode
828 setRootNode(X3D_NODE(sceneProto)); //set new rootnode
829 if(rn){
830 //old root node cleanup
831 deleteVector(sizeof(void*),rn->_parentVector); //perhaps unlink first
832 freeMallocedNodeFields(rn);
833 unRegisterX3DNode(rn);
834 FREE_IF_NZ(rn);
835 }
836 }
837
838 /* ACTUALLY CALLS THE PARSER */
839 parsedOk = parser_do_parse_string(of->fileData, of->fileDataSize, ectx, nRn);
840 //printf("after parse_string in standard file parsing\n");
841 if ((res != (resource_item_t*)tg->resources.root_res) && ((!tg->resources.root_res) ||(!((resource_item_t*)tg->resources.root_res)->complete))) {
842 tg->CParse.globalParser = t->savedParser;
843 }
844
845 if (shouldBind) {
846 /* Aug 22, 2016
847 New theory of operation of parsing and binding stacks:
848 1. when parsing, add to end of binding lists
849 2. when determining which is bound, use the start of the binding list
850 ie top-of-stack is p[0], bottom is p[n-1]
851 Vector add and Stack push both add to the end of the vector, so new functions are needed
852 to work from the start
853 3. after parsing anything, bind to the first in each list
854 since freewrl parses the main scene completely before parsing inlines,
855 main scene bindables will be at the start of the list if they exist
856 and if mainscene has none then the first Inline will be bound
857 How (I think) Layers and binding stacks work (dug9):
858 A layer is conceptually like a scene, and has its own binding stacks
859 on each draw, we may draw the main scene and a number of layers
860 the scene is treated like a layer for the purpose of switching binding stacks
861 when switching layers, the bstacks[layerId] are pointer-copied to p-> and t-> viewpointNodes,
862 navigationNodes, backgroundNodes, fogNodes (called xxxNodes) so old code can run against these
863 arrays without knowing about layers. Therefore its possible to read from bstacks or xxxNodes,
864 and -due to being pointer copies of the Vectors- we and read and write to eihter xxxNodes
865 or bstacks[layerId] when in the current layer, which is normal
866 */
867 //Aug 22, 2016 new interpretation: always rebind to first bindable
868 struct X3D_Node *stacktop;
869 if(vectorSize(p->fogNodes)){
870 stacktop = vector_get(struct X3D_Node*, p->fogNodes,0);
871 if(stacktop != oldFogBindInRender)
872 t->setFogBindInRender = stacktop;
873 }
874 if (vectorSize(p->backgroundNodes)){
875 stacktop = vector_get(struct X3D_Node*, p->backgroundNodes,0);
876 if(stacktop != oldBackgroundBindInRender)
877 t->setBackgroundBindInRender = stacktop;
878 }
879 if (vectorSize(p->navigationNodes)){
880 stacktop = vector_get(struct X3D_Node*, p->navigationNodes,0);
881 if(stacktop != oldNavigationBindInRender)
882 t->setNavigationBindInRender = stacktop;
883 }
884 if (vectorSize(t->viewpointNodes) ){
885 // dont take vp from inline
886 stacktop = vector_get(struct X3D_Node*, t->viewpointNodes,0);
887 if(stacktop != oldViewpointBindInRender){
888 t->setViewpointBindInRender = stacktop;
889 if (res->afterPoundCharacters)
890 fwl_gotoViewpoint(res->afterPoundCharacters);
891 }
892 }
893
894
895
896 }
897
898 /* we either put things at the rootNode (ie, a new world) or we put them as a children to another node */
899 if (res->whereToPlaceData == NULL) {
900 //brotos have to maintain various lists, which is done in the parser.
901 //therefore pass the rootnode / executioncontext into the parser
902 } else {
903 insert_node = X3D_NODE(res->whereToPlaceData); /* casting here for compiler */
904 offsetInNode = res->offsetFromWhereToPlaceData;
905 }
906
907 }
908
909 /* printf ("parser_process_res_VRML_X3D, res->where %u, insert_node %u, rootNode %u\n",res->where, insert_node, rootNode); */
910
911 /* now that we have the VRML/X3D file, load it into the scene. */
912 /* add the new nodes to wherever the caller wanted */
913
914 /* take the nodes from the nRn node, and put them into the place where we have decided to put them */
915 if(X3D_NODE(nRn)->_nodeType == NODE_Group){
916 struct X3D_Group *nRng = X3D_GROUP(nRn);
917 AddRemoveChildren(X3D_NODE(insert_node),
918 offsetPointer_deref(void*, insert_node, offsetInNode),
919 (struct X3D_Node * *)nRng->children.p,
920 nRng->children.n, 1, __FILE__,__LINE__);
921
922 /* and, remove them from this nRn node, so that they are not multi-parented */
923 AddRemoveChildren(X3D_NODE(nRng),
924 (struct Multi_Node *)((char *)nRng + offsetof (struct X3D_Group, children)),
925 (struct X3D_Node* *)nRng->children.p,nRng->children.n,2,__FILE__,__LINE__);
926 }
927
928 res->complete = TRUE;
929
930 if(nRnfree){
931 deleteVector(sizeof(void*),nRnfree->_parentVector); //perhaps unlink first
932 freeMallocedNodeFields(nRnfree);
933 FREE_IF_NZ(nRnfree);
934 }
935
936 /* remove this resource from the stack */
937 if (!fromEAI_SAI){
938 popInputResource();
939 zeroUnits();
940 }
941
942 //printf ("exiting praser_process_res_VRML_X3D\n");
943 //fwl_unlockTestMutex();
944 return TRUE;
945}
946
947/* interface for creating VRML for EAI */
948int EAI_CreateVrml(const char *tp, const char *inputstring,
949 struct X3D_Node *ectx, struct X3D_Group *where) {
950 resource_item_t *res;
951 char *newString;
952 bool retval = FALSE;
953
954 newString = NULL;
955
956 if (strncmp(tp, "URL", 3) == 0) {
957
958 res = resource_create_single(inputstring);
959 res->ectx = ectx;
960 res->whereToPlaceData = where;
961 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
962 /* printf ("EAI_CreateVrml, res->where is %u, root is %u parameter where %u\n",res->where, rootNode, where); */
963
964 } else { // all other cases are inline code to parse... let the parser do the job ;P...
965
966 const char *sendIn;
967
968 if (strncmp(inputstring,"#VRML V2.0", 6) == 0) {
969 sendIn = inputstring;
970 } else {
971 newString = MALLOC (char *, strlen(inputstring) + strlen ("#VRML V2.0 utf8\n") + 3);
972 strcpy (newString,"#VRML V2.0 utf8\n");
973 strcat (newString,inputstring);
974 sendIn = newString;
975 /* printf ("EAI_Create, had to append, now :%s:\n",newString); */
976 }
977
978 res = resource_create_from_string(sendIn);
979 res->media_type=resm_vrml;
980 res->parsed_request = EAI_Flag;
981 res->ectx = ectx;
982 res->whereToPlaceData = where;
983 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
984 }
985 retval = parser_process_res_VRML_X3D(res);
986 FREE_IF_NZ(newString);
987 return retval;
988 //send_resource_to_parser(res);
989 //resource_wait(res);
990 //FREE_IF_NZ(newString);
991 //return (res->status == ress_parsed);
992}
993
994/* interface for creating X3D for EAI - like above except x3d */
995int EAI_CreateX3d(const char *tp, const char *inputstring, struct X3D_Node *ectx, struct X3D_Group *where)
996{
997 //int retval;
998 resource_item_t *res;
999 char *newString;
1000
1001 newString = NULL;
1002
1003 if (strncmp(tp, "URL", 3) == 0) {
1004
1005 res = resource_create_single(inputstring);
1006 res->ectx = ectx;
1007 res->whereToPlaceData = where;
1008 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
1009 /* printf ("EAI_CreateVrml, res->where is %u, root is %u parameter where %u\n",res->where, rootNode, where); */
1010
1011 } else { // all other cases are inline code to parse... let the parser do the job ;P...
1012
1013 const char *sendIn;
1014 // the x3dparser doesn't like multiple root xml elements
1015 // and it doesn't seem to hurt to give it an extra wrapping in <x3d>
1016 // that way you can have multiple root elements and they all get
1017 // put into the target children[] field
1018 newString = MALLOC (char *, strlen(inputstring) + strlen ("<X3D>\n\n</X3D>\n") + 3);
1019 strcpy(newString,"<X3D>\n");
1020 strcat(newString,inputstring);
1021 strcat(newString,"\n</X3D>\n");
1022 sendIn = newString;
1023 //printf("EAI_createX3d string[%s]\n",sendIn);
1024 res = resource_create_from_string(sendIn);
1025 res->media_type=resm_x3d; //**different than vrml
1026 res->parsed_request = EAI_Flag;
1027 res->ectx = ectx;
1028 res->whereToPlaceData = where;
1029 res->offsetFromWhereToPlaceData = (int) offsetof (struct X3D_Group, children);
1030 }
1031 return parser_process_res_VRML_X3D(res);
1032
1033 //send_resource_to_parser(res);
1034 //resource_wait(res);
1035 //FREE_IF_NZ(newString);
1036 //return (res->status == ress_parsed);
1037}
1038
1039
1043static bool parser_process_res_SCRIPT(resource_item_t *res)
1044{
1045 //s_list_t *l;
1046 openned_file_t *of;
1047 struct Shader_Script* ss;
1048 const char *buffer;
1049
1050 buffer = NULL;
1051
1052 switch (res->type) {
1053 case rest_invalid:
1054 return FALSE;
1055 break;
1056
1057 case rest_string:
1058 buffer = res->URLrequest;
1059 break;
1060 case rest_url:
1061 case rest_file:
1062 case rest_multi:
1063 //l = (s_list_t *) res->openned_files;
1064 //if (!l) {
1065 // /* error */
1066 // return FALSE;
1067 //}
1068
1069 //of = ml_elem(l);
1070 of = res->openned_files;
1071 if (!of) {
1072 /* error */
1073 return FALSE;
1074 }
1075
1076 buffer = (const char*)of->fileData;
1077 break;
1078 }
1079
1080 ss = (struct Shader_Script *) res->whereToPlaceData;
1081
1082 return script_initCode(ss, buffer);
1083}
1084
1085
1086#if !defined(HAVE_PTHREAD_CANCEL)
1087void Parser_thread_exit_handler(int sig) {
1088 ConsoleMessage("Parser_thread_exit_handler: parserThread exiting");
1089 pthread_exit(0);
1090}
1091#endif //HAVE_PTHREAD_CANCEL
1092
1093
1099/*
1100 QUEUE method uses DesignPatterns: CommandPattern + ThreadsafeQueue + SingleThread_ThreadPool/MonoThreading
1101 It doesn't block the queue while processing/doing_work. That allows the involked
1102 commands to chain new commands into the queue without deadlocking.
1103
1104*/
1105//recently added list functions:
1106//void ml_enqueue(s_list_t **list, s_list_t *item);
1107//s_list_t *ml_dequeue(s_list_t **list);
1108
1109
1110
1111void *getProdConQueueContentStatus() {
1112
1113 /*void resitem_enqueue(s_list_t *item){ */
1114 ppProdCon p;
1115 ttglobal tg = gglobal();
1116 p = (ppProdCon) tg->ProdCon.prv;
1117
1118 return (p->resource_list_to_parse);
1119}
1120
1121
1122void threadsafe_enqueue_item_signal(s_list_t *item, s_list_t** queue, pthread_mutex_t* queue_lock, pthread_cond_t *queue_nonzero)
1123{
1124 pthread_mutex_lock(queue_lock);
1125 if (*queue == NULL)
1126 pthread_cond_signal(queue_nonzero);
1127 ml_enqueue(queue,item);
1128 pthread_mutex_unlock(queue_lock);
1129}
1130
1131s_list_t* threadsafe_dequeue_item_wait(s_list_t** queue, pthread_mutex_t *queue_lock, pthread_cond_t *queue_nonzero, BOOL *waiting )
1132{
1133 s_list_t *item = NULL;
1134 pthread_mutex_lock(queue_lock);
1135 while (*queue == NULL){
1136 *waiting = TRUE;
1137 pthread_cond_wait(queue_nonzero, queue_lock);
1138 *waiting = FALSE;
1139 }
1140 item = ml_dequeue(queue);
1141 pthread_mutex_unlock(queue_lock);
1142 return item;
1143}
1144void resitem_enqueue(s_list_t *item){
1145 ppProdCon p;
1146 ttglobal tg = gglobal();
1147 p = (ppProdCon)tg->ProdCon.prv;
1148
1149 threadsafe_enqueue_item_signal(item,&p->resource_list_to_parse, &tg->threads.mutex_resource_list, &tg->threads.resource_list_condition );
1150}
1151void resitem_enqueue_tg(s_list_t *item, void* tg){
1152 fwl_setCurrentHandle(tg, __FILE__, __LINE__);
1153 resitem_enqueue(item);
1154 fwl_clearCurrentHandle();
1155}
1156s_list_t *resitem_dequeue(){
1157 ppProdCon p;
1158 ttglobal tg = gglobal();
1159 p = (ppProdCon)tg->ProdCon.prv;
1160
1161 return threadsafe_dequeue_item_wait(&p->resource_list_to_parse, &tg->threads.mutex_resource_list, &tg->threads.resource_list_condition, &tg->threads.ResourceThreadWaiting );
1162}
1163
1164
1165
1166void threadsafe_enqueue_item(s_list_t *item, s_list_t** queue, pthread_mutex_t* queue_lock)
1167{
1168 pthread_mutex_lock(queue_lock);
1169 ml_enqueue(queue,item);
1170 pthread_mutex_unlock(queue_lock);
1171}
1172
1173s_list_t* threadsafe_dequeue_item(s_list_t** queue, pthread_mutex_t *queue_lock )
1174{
1175 s_list_t *item = NULL;
1176 pthread_mutex_lock(queue_lock);
1177 item = ml_dequeue(queue);
1178 pthread_mutex_unlock(queue_lock);
1179 return item;
1180}
1181
1182void frontenditem_enqueue(s_list_t *item){
1183 ppProdCon p;
1184 ttglobal tg = gglobal();
1185 p = (ppProdCon)tg->ProdCon.prv;
1186 threadsafe_enqueue_item(item,&p->frontend_list_to_get, &tg->threads.mutex_frontend_list );
1187}
1188void frontenditem_enqueue_tg(s_list_t *item, void *tg){
1189 fwl_setCurrentHandle(tg, __FILE__, __LINE__);
1190 frontenditem_enqueue(item);
1191 fwl_clearCurrentHandle();
1192}
1193s_list_t *frontenditem_dequeue(){
1194 ppProdCon p;
1195 ttglobal tg = gglobal();
1196 p = (ppProdCon)tg->ProdCon.prv;
1197
1198 return threadsafe_dequeue_item(&p->frontend_list_to_get, &tg->threads.mutex_frontend_list );
1199}
1200s_list_t *frontenditem_dequeue_tg(void *tg){
1201 s_list_t *item;
1202 fwl_setCurrentHandle(tg, __FILE__, __LINE__);
1203 item = frontenditem_dequeue();
1204 fwl_clearCurrentHandle();
1205 return item;
1206}
1207void *fwl_frontenditem_dequeue(){
1208 void *res = NULL;
1209 s_list_t *item = frontenditem_dequeue();
1210 if (item){
1211 res = item->elem;
1212 FREE(item);
1213 }
1214 return res;
1215}
1216void fwl_resitem_enqueue(void *res){
1217 resitem_enqueue(ml_new(res));
1218}
1219
1220int frontendGetsFiles(){
1221 return ((ppProdCon)(gglobal()->ProdCon.prv))->frontend_gets_files;
1222}
1223
1224void process_res_texitem(resource_item_t *res);
1225bool parser_process_res_SHADER(resource_item_t *res);
1226bool process_res_audio(resource_item_t *res);
1227bool process_res_movie(resource_item_t *res);
1233static bool parser_process_res(s_list_t *item)
1234{
1235 int more_multi;
1236 bool remove_it = FALSE;
1237 // OLDCODE bool destroy_it = FALSE;
1238 bool retval = TRUE;
1239 resource_item_t *res;
1240 //ppProdCon p;
1241 //ttglobal tg = gglobal();
1242 //p = (ppProdCon)tg->ProdCon.prv;
1243
1244 if (!item || !item->elem)
1245 return retval;
1246
1247 res = ml_elem(item);
1248
1249 //printf("\nprocessing resource: type %s, status %s\n", resourceTypeToString(res->type), resourceStatusToString(res->status));
1250 switch (res->status) {
1251
1252 case ress_invalid:
1253 case ress_none:
1254 retval = FALSE;
1255 if(!res->actions || (res->actions & resa_identify)){
1256 resource_identify(res->parent, res);
1257 if (res->type == rest_invalid) {
1258 remove_it = TRUE;
1259 res->complete = TRUE; //J30
1260 }
1261 }
1262 break;
1263
1264 case ress_starts_good:
1265 if(!res->actions || (res->actions & resa_download)){
1266#ifndef DISABLER
1267 //if(p->frontend_gets_files){
1268 frontenditem_enqueue(ml_new(res));
1269 remove_it = TRUE;
1270 //}else{
1271 // resource_fetch(res);
1272 //}
1273#else
1274 if(p->frontend_gets_files){
1275 frontenditem_enqueue(ml_new(res));
1276 remove_it = TRUE;
1277 }else{
1278 resource_fetch(res);
1279 }
1280#endif
1281 }
1282 break;
1283
1284 case ress_downloaded:
1285 if(!res->actions || (res->actions & resa_load))
1286 /* Here we may want to delegate loading into another thread ... */
1287 //if (!resource_load(res)) {
1288 if(res->_loadFunc){
1289 if(!res->_loadFunc(res)){
1290 ERROR_MSG("failure when trying to load resource: %s\n", res->URLrequest);
1291 remove_it = TRUE;
1292 res->complete = TRUE; //J30
1293 retval = FALSE;
1294 }
1295 }
1296 break;
1297
1298 case ress_failed:
1299 more_multi = (res->status == ress_failed) && (res->m_request != NULL);
1300 if(more_multi){
1301 //still some hope via multi_string url, perhaps next one
1302 res->status = ress_invalid; //downgrade ress_fail to ress_invalid
1303 res->type = rest_multi; //should already be flagged
1304 //must consult BE to convert relativeURL to absoluteURL via baseURL
1305 //(or could we absolutize in a batch in resource_create_multi0()?)
1306 resource_identify(res->parent, res); //should increment multi pointer/iterator
1307 frontenditem_enqueue(ml_new(res));
1308 }else{
1309 ConsoleMessage("url not found: %s\n",res->parsed_request);
1310 retval = FALSE;
1311 res->complete = TRUE; //J30
1312 // OLDCODE destroy_it = TRUE;
1313 }
1314 remove_it = TRUE;
1315 break;
1316
1317 case ress_loaded:
1318 // printf("processing resource, media_type %s\n",resourceMediaTypeToString(res->media_type));
1319 if(!res->actions || (res->actions & resa_process))
1320 switch (res->media_type) {
1321 case resm_unknown:
1322 ConsoleMessage ("deciphering file: 404 file not found or unknown file type encountered.");
1323 remove_it = TRUE;
1324 res->complete=TRUE; /* not going to do anything else with this one */
1325 res->status = ress_not_loaded;
1326 break;
1327 case resm_vrml:
1328 case resm_x3d:
1329 if (parser_process_res_VRML_X3D(res)) {
1330 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1331 res->status = ress_parsed;
1332
1333 } else {
1334 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1335 retval = FALSE;
1336 }
1337 break;
1338 case resm_script:
1339 if (parser_process_res_SCRIPT(res)) {
1340 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1341 res->status = ress_parsed;
1342 } else {
1343 retval = FALSE;
1344 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1345 }
1346 break;
1347 case resm_pshader:
1348 case resm_fshader:
1349 if (parser_process_res_SHADER(res)) {
1350 DEBUG_MSG("parser successfull: %s\n", res->URLrequest);
1351 res->status = ress_parsed;
1352 } else {
1353 retval = FALSE;
1354 ERROR_MSG("parser failed for resource: %s\n", res->URLrequest);
1355 }
1356 break;
1357 case resm_image:
1358 /* Texture file has been loaded into memory
1359 the node could be updated ... i.e. texture created */
1360 res->complete = TRUE; /* small hack */
1361 process_res_texitem(res);
1362 break;
1363 case resm_movie:
1364 res->complete = TRUE;
1365 if(process_res_movie(res)){
1366 res->status = ress_parsed;
1367 }else{
1368 retval = FALSE;
1369 res->status = ress_failed;
1370 }
1371 break;
1372 case resm_audio:
1373 res->complete = TRUE;
1374 if(process_res_audio(res)){
1375 res->status = ress_parsed;
1376 }else{
1377 retval = FALSE;
1378 res->status = ress_failed;
1379 }
1380 break;
1381 case resm_x3z:
1382 process_x3z(res);
1383 printf("processed x3z\n");
1384 break;
1385 case resm_external:
1386 // JAS - resm_external is part of this enum, but not handled here,
1387 // so we get compiler warnings.
1388 printf ("dont know anything about resm_external at this point\n");
1389 break;
1390 }
1391 /* Parse only once ! */
1392 res->complete = TRUE; //J30
1393 remove_it = TRUE;
1394 break;
1395
1396 case ress_not_loaded:
1397 remove_it = TRUE;
1398 res->complete = TRUE; //J30
1399 retval = FALSE;
1400 break;
1401
1402 case ress_parsed:
1403 res->complete = TRUE; //J30
1404 remove_it = TRUE;
1405 break;
1406
1407 case ress_not_parsed:
1408 res->complete = TRUE; //J30
1409 retval = FALSE;
1410 remove_it = TRUE;
1411 break;
1412 }
1413
1414 if (remove_it) {
1415 /* Remove the parsed resource from the list */
1416 if(res->status == ress_parsed){
1417 //just x3d and vrml. if you clear images nothing shows up
1418 if(res->openned_files){
1419 openned_file_t *of = res->openned_files;
1420 //remove BLOB
1421 FREE_IF_NZ(of->fileData);
1422 }
1423 }
1424 FREE_IF_NZ(item);
1425 }else{
1426 // chain command by adding it back into the queue
1427 resitem_enqueue(item);
1428 }
1429 dump_parser_wait_queue();
1430
1431 // printf ("end of process resource\n");
1432
1433 return retval;
1434}
1435//we want the void* addresses of the following, so the int value doesn't matter
1436static const int res_command_exit;
1437
1438void resitem_queue_exit(){
1439 resitem_enqueue(ml_new(&res_command_exit));
1440}
1441void _inputParseThread(void *globalcontext)
1442{
1443 ttglobal tg = (ttglobal)globalcontext;
1444
1445 #if !defined (HAVE_PTHREAD_CANCEL)
1446 struct sigaction actions;
1447 int rc;
1448 memset(&actions, 0, sizeof(actions));
1449 sigemptyset(&actions.sa_mask);
1450 actions.sa_flags = 0;
1451 actions.sa_handler = Parser_thread_exit_handler;
1452 rc = sigaction(SIGUSR2,&actions,NULL);
1453 // ConsoleMessage ("for parserThread, have defined exit handler");
1454 #endif //HAVE_PTHREAD_CANCEL
1455
1456 {
1457 ppProdCon p = (ppProdCon)tg->ProdCon.prv;
1458 tg->threads.PCthread = pthread_self();
1459 //set_thread2global(tg, tg->threads.PCthread ,"parse thread");
1460 fwl_setCurrentHandle(tg,__FILE__,__LINE__);
1461
1462 //p->inputParseInitialized = TRUE;
1463 tg->threads.ResourceThreadRunning = TRUE;
1464 ENTER_THREAD("input parser");
1465
1466 //viewer_default();
1467
1468 /* now, loop here forever, waiting for instructions and obeying them */
1469
1470 for (;;) {
1471 void *elem;
1472 //bool result = TRUE;
1473 s_list_t* item = resitem_dequeue();
1474 elem = ml_elem(item);
1475 if (elem == &res_command_exit){
1476 FREE_IF_NZ(item);
1477 break;
1478 }
1479 //printf ("thread hit, flushing %d, tg %p, resource thread\n",tg->threads.flushing, tg);
1480
1481 if (tg->threads.flushing){
1482 FREE_IF_NZ(item);
1483 continue;
1484 }
1485 p->inputThreadParsing = TRUE;
1486 //result =
1487 parser_process_res(item); //,&p->resource_list_to_parse);
1488 p->inputThreadParsing = FALSE;
1489 }
1490
1491 tg->threads.ResourceThreadRunning = FALSE;
1492
1493
1494 }
1495}
1496
1497
1498
1499void kill_bindables (void) {
1500 int i, ib;
1501 struct X3D_Node *tmp;
1502 ppProdCon p;
1503 ttglobal tg = gglobal();
1504
1505 struct tProdCon *t = &gglobal()->ProdCon;
1506 p = (ppProdCon)t->prv;
1507
1508 //H: we have per-layer binding stacks, and when we switch to a layer
1509 // we copy from bstack to the old-style p-> or t-> viewpointNodes, backgroundNodes ...
1510 // so if unbinding all layers ie new scene, we can do it from bstack,
1511 // but don't forget to zero the oldstyle copy.
1512 //printf ("kill_bindables called\n");
1513 ib = 0; //unbind
1514 for(i=0;i<vectorSize(tg->Bindable.bstacks);i++){
1515 bindablestack *bstack = getBindableStacksByLayer(tg,i);
1516 if (vectorSize(bstack->navigation) > 0) {
1517 for (i=0; i < vectorSize(bstack->navigation);i++){
1518 tmp = vector_get(struct X3D_Node*,bstack->navigation,i);
1519 send_bind_to(tmp, ib);
1520 }
1521 }
1522 if (vectorSize(bstack->background) > 0) {
1523 for (i=0; i < vectorSize(bstack->background);i++){
1524 tmp = vector_get(struct X3D_Node*,bstack->background,i);
1525 send_bind_to(tmp, ib);
1526 }
1527 }
1528 if (vectorSize(bstack->viewpoint) > 0) {
1529 for (i=0; i < vectorSize(bstack->viewpoint);i++){
1530 tmp = vector_get(struct X3D_Node*,bstack->viewpoint,i);
1531 send_bind_to(tmp, ib);
1532 }
1533 }
1534 if (vectorSize(bstack->fog) > 0) {
1535 for (i=0; i < vectorSize(bstack->fog);i++){
1536 tmp = vector_get(struct X3D_Node*,bstack->fog,i);
1537 send_bind_to(tmp, ib);
1538 }
1539 }
1540 ((struct Vector *)bstack->navigation)->n=0;
1541 ((struct Vector *)bstack->background)->n=0;
1542 ((struct Vector *)bstack->viewpoint)->n=0;
1543 ((struct Vector *)bstack->fog)->n=0;
1544 }
1545 //do we still use these?
1546 ((struct Vector *)t->viewpointNodes)->n=0;
1547 p->backgroundNodes->n=0;
1548 p->navigationNodes->n=0;
1549 p->fogNodes->n=0;
1550
1551 return;
1552
1553 /*
1554 printf ("before tvp %p ",t->viewpointNodes);
1555 KILL_BINDABLE(t->viewpointNodes);
1556 printf ("after, tvp %p\n",t->viewpointNodes);
1557
1558 KILL_BINDABLE(p->backgroundNodes);
1559 printf ("calling KILL_BINDABLE on navigationNodes %p at B\n",p->navigationNodes);
1560
1561 KILL_BINDABLE(p->navigationNodes);
1562 KILL_BINDABLE(p->fogNodes);
1563
1564 printf ("calling KILL_BINDABLE on the global navigation stack\n");
1565 KILL_BINDABLE(tg->Bindable.navigation_stack);
1566 KILL_BINDABLE(tg->Bindable.background_stack);
1567 KILL_BINDABLE(tg->Bindable.viewpoint_stack);
1568 KILL_BINDABLE(tg->Bindable.fog_stack);
1569 */
1570 /*
1571 struct Vector *background_stack;
1572 struct Vector *viewpoint_stack;
1573 struct Vector *navigation_stack;
1574 struct Vector *fog_stack;
1575
1576 ttglobal tg = gglobal();
1577 if (node->set_bind < 100) {
1578 if (node->set_bind == 1) set_naviinfo(node);
1579 bind_node (X3D_NODE(node), tg->Bindable.navigation_stack,"Component_Navigation");
1580*/
1581
1582
1583}
1584
1585
1586void registerBindable (struct X3D_Node *node) {
1587 int layerId;
1588 ppProdCon p;
1589 ttglobal tg;
1590 struct tProdCon *t;
1591 tg = gglobal();
1592 t = &tg->ProdCon;
1593 p = (ppProdCon)t->prv;
1594
1595 layerId = tg->Bindable.activeLayer;
1596
1597 switch (node->_nodeType) {
1598 case NODE_Viewpoint:
1599 X3D_VIEWPOINT(node)->set_bind = 100;
1600 X3D_VIEWPOINT(node)->isBound = 0;
1601 X3D_VIEWPOINT(node)->_layerId = layerId;
1602 vector_pushBack (struct X3D_Node*,t->viewpointNodes, node);
1603 break;
1604 case NODE_OrthoViewpoint:
1605 X3D_ORTHOVIEWPOINT(node)->set_bind = 100;
1606 X3D_ORTHOVIEWPOINT(node)->isBound = 0;
1607 X3D_ORTHOVIEWPOINT(node)->_layerId = layerId;
1608 vector_pushBack (struct X3D_Node*,t->viewpointNodes, node);
1609 break;
1610 case NODE_GeoViewpoint:
1611 X3D_GEOVIEWPOINT(node)->set_bind = 100;
1612 X3D_GEOVIEWPOINT(node)->isBound = 0;
1613 X3D_GEOVIEWPOINT(node)->_layerId = layerId;
1614 vector_pushBack (struct X3D_Node*,t->viewpointNodes, node);
1615 break;
1616 case NODE_Background:
1617 X3D_BACKGROUND(node)->set_bind = 100;
1618 X3D_BACKGROUND(node)->isBound = 0;
1619 X3D_BACKGROUND(node)->_layerId = layerId;
1620 vector_pushBack (struct X3D_Node*,p->backgroundNodes, node);
1621 break;
1622 case NODE_TextureBackground:
1623 X3D_TEXTUREBACKGROUND(node)->set_bind = 100;
1624 X3D_TEXTUREBACKGROUND(node)->isBound = 0;
1625 X3D_TEXTUREBACKGROUND(node)->_layerId = layerId;
1626 vector_pushBack (struct X3D_Node*,p->backgroundNodes, node);
1627 break;
1628 case NODE_NavigationInfo:
1629 X3D_NAVIGATIONINFO(node)->set_bind = 100;
1630 X3D_NAVIGATIONINFO(node)->isBound = 0;
1631 X3D_NAVIGATIONINFO(node)->_layerId = layerId;
1632 vector_pushBack (struct X3D_Node*,p->navigationNodes, node);
1633 break;
1634 case NODE_Fog:
1635 X3D_FOG(node)->set_bind = 100;
1636 X3D_FOG(node)->isBound = 0;
1637 X3D_FOG(node)->_layerId = layerId;
1638 vector_pushBack (struct X3D_Node*,p->fogNodes, node);
1639 break;
1640 default: {
1641 /* do nothing with this node */
1642 /* printf ("got a registerBind on a node of type %s - ignoring\n",
1643 stringNodeType(node->_nodeType));
1644 */
1645 return;
1646 }
1647
1648 }
1649}
1650int removeNodeFromVector(int iaction, struct Vector *v, struct X3D_Node *node){
1651 //iaction = 0 pack vector
1652 //iaction = 1 set NULL
1653 int noisy, iret = FALSE;
1654 noisy = FALSE;
1655 if(v && node){
1656 struct X3D_Node *tn;
1657 int i, ii, n; //idx,
1658 //idx = -1;
1659 n = vectorSize(v);
1660 for(i=0;i<n;i++){
1661 ii = n - i - 1; //reverse walk, so we can remove without losing our loop counter
1662 tn = vector_get(struct X3D_Node*,v,ii);
1663 if(tn == node){
1664 iret++;
1665 if(iaction == 1){
1666 vector_set(struct X3D_Node*,v,ii,NULL);
1667 if(noisy) printf("NULLing %d %p\n",ii,node);
1668 }else if(iaction == 0){
1669 if(noisy) printf("REMOVing %d %p\n",ii,node);
1670 vector_remove_elem(struct X3D_Node*,v,ii);
1671 }
1672 }
1673 }
1674 }
1675 if(!iret && noisy){
1676 int i;
1677 printf("not found in stack node=%p stack.n=%d:\n",node,vectorSize(v));
1678 for(i=0;i<vectorSize(v);i++){
1679 printf(" %p",vector_get(struct X3D_Node*,v,i));
1680 }
1681 printf("\n");
1682 }
1683 return iret;
1684}
1685void unRegisterBindable (struct X3D_Node *node) {
1686 ppProdCon p;
1687 struct tProdCon *t = &gglobal()->ProdCon;
1688 p = (ppProdCon)t->prv;
1689
1690
1691 switch (node->_nodeType) {
1692 case NODE_Viewpoint:
1693 X3D_VIEWPOINT(node)->set_bind = 100;
1694 X3D_VIEWPOINT(node)->isBound = 0;
1695 //printf ("unRegisterBindable %p Viewpoint, description :%s:\n",node,X3D_VIEWPOINT(node)->description->strptr);
1696 send_bind_to(node,0);
1697 removeNodeFromVector(0, t->viewpointNodes, node);
1698 break;
1699 case NODE_OrthoViewpoint:
1700 X3D_ORTHOVIEWPOINT(node)->set_bind = 100;
1701 X3D_ORTHOVIEWPOINT(node)->isBound = 0;
1702 send_bind_to(node,0);
1703 removeNodeFromVector(0, t->viewpointNodes, node);
1704 break;
1705 case NODE_GeoViewpoint:
1706 X3D_GEOVIEWPOINT(node)->set_bind = 100;
1707 X3D_GEOVIEWPOINT(node)->isBound = 0;
1708 send_bind_to(node,0);
1709 removeNodeFromVector(0, t->viewpointNodes, node);
1710 break;
1711 case NODE_Background:
1712 X3D_BACKGROUND(node)->set_bind = 100;
1713 X3D_BACKGROUND(node)->isBound = 0;
1714 send_bind_to(node,0);
1715 removeNodeFromVector(0, p->backgroundNodes, node);
1716 break;
1717 case NODE_TextureBackground:
1718 X3D_TEXTUREBACKGROUND(node)->set_bind = 100;
1719 X3D_TEXTUREBACKGROUND(node)->isBound = 0;
1720 removeNodeFromVector(0, p->backgroundNodes, node);
1721 break;
1722 case NODE_NavigationInfo:
1723 X3D_NAVIGATIONINFO(node)->set_bind = 100;
1724 X3D_NAVIGATIONINFO(node)->isBound = 0;
1725 send_bind_to(node,0);
1726 removeNodeFromVector(0, p->navigationNodes, node);
1727 break;
1728 case NODE_Fog:
1729 X3D_FOG(node)->set_bind = 100;
1730 X3D_FOG(node)->isBound = 0;
1731 send_bind_to(node,0);
1732 removeNodeFromVector(0, p->fogNodes, node);
1733 break;
1734 default: {
1735 /* do nothing with this node */
1736 /* printf ("got a registerBind on a node of type %s - ignoring\n",
1737 stringNodeType(node->_nodeType));
1738 */
1739 return;
1740 }
1741
1742 }
1743}