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