FreeWRL/FreeX3D  3.0.0
RenderFuncs.c
1 /*
2 
3  FreeWRL support library.
4  Scenegraph rendering.
5 
6 */
7 
8 /****************************************************************************
9  This file is part of the FreeWRL/FreeX3D Distribution.
10 
11  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12 
13  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14  it under the terms of the GNU Lesser Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25 ****************************************************************************/
26 
27 
28 
29 #include <config.h>
30 #include <system.h>
31 #include <display.h>
32 #include <internal.h>
33 
34 #include <libFreeWRL.h>
35 
36 #include "../vrml_parser/Structs.h"
37 #include "../main/headers.h"
38 #include "../scenegraph/Component_ProgrammableShaders.h"
39 
40 #include "Polyrep.h"
41 #include "Collision.h"
42 #include "../scenegraph/quaternion.h"
43 #include "Viewer.h"
44 #include "LinearAlgebra.h"
45 #include "../input/SensInterps.h"
46 #include "system_threads.h"
47 #include "threads.h"
48 
49 #include "../opengl/OpenGL_Utils.h"
50 #include "../opengl/Textures.h"
51 #include "../scenegraph/Component_Shape.h"
52 #include "RenderFuncs.h"
53 
54 
55 typedef float shaderVec4[4];
56 
57 
58 struct profile_entry {
59  char *name;
60  double start;
61  double accum;
62  int hits;
63 };
64 
65 struct point_XYZ3 {
66  struct point_XYZ p1;
67  struct point_XYZ p2;
68  struct point_XYZ p3;
69 };
70 
71 typedef struct {
72 int calltype;
73 union {
74  struct arrays {
75  int arrays_mode;
76  int arrays_count;
77  int arrays_first;
78  } arrays;
79  struct elements {
80  int elements_mode;
81  int elements_count;
82  //GLenum elements_type;
83  ushort *elements_indices;
84  } elements;
85 };
87 
88 typedef struct pRenderFuncs{
89  int profile_entry_count;
90  struct profile_entry profile_entries[100];
91  int profiling_on;
92  float light_linAtten[MAX_LIGHT_STACK];
93  float light_constAtten[MAX_LIGHT_STACK];
94  float light_quadAtten[MAX_LIGHT_STACK];
95  float light_spotCutoffAngle[MAX_LIGHT_STACK];
96  float light_spotBeamWidth[MAX_LIGHT_STACK];
97  shaderVec4 light_amb[MAX_LIGHT_STACK];
98  shaderVec4 light_dif[MAX_LIGHT_STACK];
99  shaderVec4 light_pos[MAX_LIGHT_STACK];
100  shaderVec4 light_spec[MAX_LIGHT_STACK];
101  shaderVec4 light_spotDir[MAX_LIGHT_STACK];
102  float light_radius[MAX_LIGHT_STACK];
103  GLint lightType[MAX_LIGHT_STACK]; //0=point 1=spot 2=directional
104  /* Rearrange to take advantage of headlight when off */
105  int nextFreeLight;// = 0;
106  int refreshLightUniforms;
107  unsigned int currentLoop;
108  unsigned int lastLoop;
109  unsigned int sendCount;
110  //int firstLight;//=0;
111  /* lights status. Light HEADLIGHT_LIGHT is the headlight */
112  GLint lightOnOff[MAX_LIGHT_STACK];
113  GLint lightChanged[MAX_LIGHT_STACK]; //optimization
114  GLint lastShader;
115  //int cur_hits;//=0;
116  void *empty_group;//=0;
117  //struct point_XYZ ht1, ht2; not used
118  struct point_XYZ hyper_r1,hyper_r2; /* Transformed ray for the hypersensitive node */
119  struct currayhit rayph;
120  struct X3D_Node *rootNode;//=NULL; /* scene graph root node */
121  struct Vector *libraries; //vector of extern proto library scenes in X3D_Proto format that are parsed shallow (not instanced scenes) - the library protos will be in X3D_Proto->protoDeclares vector
122  struct X3D_Anchor *AnchorsAnchor;// = NULL;
123  struct currayhit rayHit; //,rayHitHyper;
124  struct trenderstate renderstate;
125  int renderLevel;
126 
127  // which Shader is currently in use?
128  GLint currentShader;
129  Stack *render_geom_stack;
130  Stack *sensor_stack;
131  Stack *ray_stack;
132  Stack *shaderflags_stack;
133  Stack *fog_stack;
134  Stack *localLight_stack;
135 
136  //struct point_XYZ t_r1,t_r2,t_r3; /* transformed ray */
137  struct point_XYZ3 t_r123;
138  struct point_XYZ hp;
139  Stack *usehits_stack;
140  Stack *usehitsB_stack;
141  Stack *pickablegroupdata_stack;
142  Stack *draw_call_params_stack;
143 }* ppRenderFuncs;
144 void *RenderFuncs_constructor(){
145  void *v = MALLOCV(sizeof(struct pRenderFuncs));
146  memset(v,0,sizeof(struct pRenderFuncs));
147  return v;
148 }
149 void RenderFuncs_init(struct tRenderFuncs *t){
150  //public
151 
152  t->BrowserAction = FALSE;
153  // t->hitPointDist; /* distance in ray: 0 = r1, 1 = r2, 2 = 2*r2-r1... */
155  //t->hyp_save_posn;
156  //t->hyp_save_norm;t->ray_save_posn;
157  t->hypersensitive = 0;
158  t->hyperhit = 0;
159  t->have_transparency=FALSE;/* did any Shape have transparent material? */
160  /* material node usage depends on texture depth; if rgb (depth1) we blend color field
161  and diffusecolor with texture, else, we dont bother with material colors */
162  t->last_texture_type = NOTEXTURE;
163 
164  //private
165  t->prv = RenderFuncs_constructor();
166  {
167  ppRenderFuncs p = (ppRenderFuncs)t->prv;
168  p->profile_entry_count = 0;
169  p->profiling_on = 0; //toggle on with '.' on keyboard
170  /* which arrays are enabled, and defaults for each array */
171  /* Rearrange to take advantage of headlight when off */
172  p->nextFreeLight = 0;
173  p->refreshLightUniforms = 0;
174  //p->firstLight = 0;
175  //p->cur_hits=0;
176  p->empty_group=0;
177  p->rootNode=NULL; /* scene graph root node */
178  p->libraries=newVector(void3 *,1);
179  p->AnchorsAnchor = NULL;
180  t->rayHit = (void *)&p->rayHit;
181  //t->rayHitHyper = (void *)&p->rayHitHyper;
182  p->renderLevel = 0;
183  p->lastShader = -1;
184  p->currentLoop = 0;
185  p->lastLoop = 10000000;
186  p->sendCount = 0;
187  p->render_geom_stack = newStack(int);
188  p->sensor_stack = newStack(struct currayhit);
189  p->ray_stack = newStack(struct point_XYZ3);
190  p->usehits_stack = newStack(usehit);
191  p->usehitsB_stack = newStack(usehit);
192  p->pickablegroupdata_stack = newStack(void*);
193  p->shaderflags_stack = newStack(shaderflagsstruct); //newStack(unsigned int);
194  p->fog_stack = newStack(struct X3D_Node*);
195  p->localLight_stack = newStack(int);
196  p->draw_call_params_stack = newStack(draw_call_params);
197  //t->t_r123 = (void *)&p->t_r123;
198  t->hp = (void *)&p->hp;
199  }
200 
201  //setLightType(HEADLIGHT_LIGHT,2); // ensure that this is a DirectionalLight.
202 }
203 //the following usehit functions are for node-node scenarios such as picksensor and transformsensor
204 //more precisely for node_USE-node_USE aka USE_USE scenarios
205 //when a node is 'rendered' if its VF_USE flag is set, then we call usehit_add(self,modelviewmatrix)
206 //then in do_first() > do_activity() the use-use combinations are each applied.
207 //at least one in the use-use pair needs to hold a pointer to the other node to use as a lookup
208 void usehit_add(struct X3D_Node * node, double *modelviewmatrix){
209  //called from render_hier when/each-use-time a VF_USE node is hit
210  usehit uhit;
211  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
212  uhit.node = node;
213  memcpy(uhit.mvm,modelviewmatrix,16*sizeof(double)); //deep copy
214  uhit.userdata = NULL;
215  vector_pushBack(usehit,p->usehits_stack,uhit); //fat elements do another deep copy
216 }
217 void usehit_add2(struct X3D_Node * node, double *modelviewmatrix, void *userdata){
218  //called from render_hier when/each-use-time a VF_USE node is hit
219  usehit uhit;
220  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
221  uhit.node = node;
222  memcpy(uhit.mvm,modelviewmatrix,16*sizeof(double)); //deep copy
223  uhit.userdata = userdata;
224  vector_pushBack(usehit,p->usehits_stack,uhit); //fat elements do another deep copy
225 }
226 usehit * usehit_next(struct X3D_Node *node, usehit *lasthit){
227  //called from do_first() > do_activity() when one of the use-use pair is searching for another of its mates
228  //call with lasthit = NULL the first time, and otherwise the previous hit to continue searching
229  int i, istart;
230  usehit *ret, *item;
231  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
232  ret = NULL;
233  if(vectorSize(p->usehits_stack)>0){
234  //find lasthit
235  istart = 0;
236  if(lasthit) {
237  //size_t size;
238  //ptrdiff_t delta;
239  //void *start;
240  //size = sizeof(usehit);
241  //start = (char*)vector_get_ptr(usehit,p->usehits_stack,0);
242  //delta = (char*)lasthit - (char*)start;
243  //istart = delta/size + 1;
244  istart = ((char*)lasthit - (char*)vector_get_ptr(usehit,p->usehits_stack,0))/sizeof(usehit) + 1;
245  }
246  //search starting at lasthit+1
247  for(i=istart;i<p->usehits_stack->n;i++){
248  item = vector_get_ptr(usehit,p->usehits_stack,i);
249  if(item->node == node){
250  ret = item;
251  break;
252  }
253  }
254  }
255  return ret; //returing pointer to p->usehits fat element
256 }
257 void usehit_clear(){
258  //called at the end of do_first (once per frame, after USE_USE pairing and action, and before rendering)
259  //to clear all the USE hits from last frame
260  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
261  p->usehits_stack->n = 0;
262 }
263 
264 //USEHITB - for Component_Picking.c when traversing the sub-scenegraph
265 // to get geometry nodes, and their transform, and any more PickingGroup userdata
266 // (sorry - I just copied the useHit functions above, normally I refactor but short on time -dug9 dec31,2016)
267 void usehitB_add(struct X3D_Node * node, double *modelviewmatrix){
268  //called from render_hier when/each-use-time a VF_USE node is hit
269  usehit uhit;
270  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
271  uhit.node = node;
272  memcpy(uhit.mvm,modelviewmatrix,16*sizeof(double)); //deep copy
273  uhit.userdata = NULL;
274  vector_pushBack(usehit,p->usehitsB_stack,uhit); //fat elements do another deep copy
275 }
276 void usehitB_add2(struct X3D_Node * node, double *modelviewmatrix, void *userdata){
277  //called from render_hier when/each-use-time a VF_USE node is hit
278  usehit uhit;
279  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
280  uhit.node = node;
281  memcpy(uhit.mvm,modelviewmatrix,16*sizeof(double)); //deep copy
282  uhit.userdata = userdata;
283  vector_pushBack(usehit,p->usehitsB_stack,uhit); //fat elements do another deep copy
284 }
285 usehit * usehitB_next(struct X3D_Node *node, usehit *lasthit){
286  //called from do_first() > do_activity() when one of the use-use pair is searching for another of its mates
287  //call with lasthit = NULL the first time, and otherwise the previous hit to continue searching
288  int i, istart;
289  usehit *ret, *item;
290  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
291  ret = NULL;
292  if(vectorSize(p->usehitsB_stack)>0){
293  //find lasthit
294  istart = 0;
295  if(lasthit) {
296  //size_t size;
297  //ptrdiff_t delta;
298  //void *start;
299  //size = sizeof(usehit);
300  //start = (char*)vector_get_ptr(usehit,p->usehits_stack,0);
301  //delta = (char*)lasthit - (char*)start;
302  //istart = delta/size + 1;
303  istart = ((char*)lasthit - (char*)vector_get_ptr(usehit,p->usehitsB_stack,0))/sizeof(usehit) + 1;
304  }
305  //search starting at lasthit+1
306  for(i=istart;i<p->usehitsB_stack->n;i++){
307  item = vector_get_ptr(usehit,p->usehitsB_stack,i);
308  if(item->node == node){
309  ret = item;
310  break;
311  }
312  }
313  }
314  return ret; //returing pointer to p->usehits fat element
315 }
316 void usehitB_clear(){
317  //called at the end of do_first (once per frame, after USE_USE pairing and action, and before rendering)
318  //to clear all the USE hits from last frame
319  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
320  p->usehitsB_stack->n = 0;
321 }
322 Stack *getUseHitBStack(){
323  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
324  return p->usehitsB_stack;
325 }
326 
327 //PickableGroup can be several parents above a usehit picktarget node
328 //see prep_PickableGroup, fin_PickableGroup for push and pop,
329 //see below for call to getpickablegroupdata() in render
330 void push_pickablegroupdata(void *userdata){
331  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
332  stack_push(void*,p->pickablegroupdata_stack,userdata);
333 }
334 void pop_pickablegroupdata(){
335  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
336  stack_pop(void*,p->pickablegroupdata_stack);
337 }
338 void *getpickablegroupdata(){
339  void *ret;
340  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
341  ret = NULL;
342  if(vectorSize(p->pickablegroupdata_stack)>0)
343  ret = stack_top(void*,p->pickablegroupdata_stack);
344  return ret;
345 }
346 
347 
348 void unload_libraryscenes();
349 int gc_broto_instance(struct X3D_Proto* node);
350 void RenderFuncs_clear(struct tRenderFuncs *t){
351  ppRenderFuncs p = (ppRenderFuncs)t->prv;
352  unload_libraryscenes();
353  deleteVector(void3 *,p->libraries);
354  deleteVector(int,p->render_geom_stack);
355  deleteVector(struct currayhit,p->sensor_stack);
356  deleteVector(struct point_XYZ3,p->ray_stack);
357  deleteVector(usehit,p->usehits_stack);
358  //deleteVector(unsigned int,p->shaderflags_stack);
359  deleteVector(shaderflagsstruct,p->shaderflags_stack);
360  deleteVector(struct X3D_Node*,p->fog_stack);
361  deleteVector(int,p->localLight_stack);
362  deleteVector(draw_call_params,p->draw_call_params_stack);
363 }
364 void unload_libraryscenes(){
365  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
366  //freeing these library scenes should be done during exit procedures before gglobal gc, perhaps in
367  // finalizeRenderSceneUpdateScene
368  // or perhaps when changing scenes. Perhaps libraries should be in a Scene context.
369  // One old idea not implemented: all scenes should first be parsed to libraryScene (nothing registered, empty protoInstance bodies)
370  // then scene instanced like a proto. That would speed up Anchoring between scene files ie between rooms.
371  // (Avatar state would be carried between scenes in browser key,value attributes like metadata
372  if(p->libraries){
373  int i;
374  for(i=0;i<vectorSize(p->libraries);i++){
375  struct X3D_Proto *libscn;
376  char *url;
377  void3 *ul;
378  ul = vector_get(struct void3*,p->libraries,i);
379  if(ul){
380  url = (char *)ul->one;
381  libscn = (struct X3D_Proto*) ul->two;
382  //unload_broto(libscn); //nothing to un-register - library scenes aren't registered
383  gc_broto_instance(libscn);
384  deleteVector(struct X3D_Node*,libscn->_parentVector);
385  freeMallocedNodeFields((struct X3D_Node*)libscn);
386  FREE_IF_NZ(libscn);
387  FREE_IF_NZ(url);
388  FREE_IF_NZ(ul);
389  //FREE_IF_NZ(res);
390  vector_set(struct void3*,p->libraries,i,NULL);
391  }
392  }
393  p->libraries->n = 0;
394  }
395 }
396 void clearLightTable(){ //unsigned int loop_count){
397  //int i;
398  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
399  p->nextFreeLight = 0;
400  //p->currentLoop = loop_count;
401  p->sendCount = 0;
402  //for(i=0;i<MAX_LIGHT_STACK;i++){
403  // p->lightChanged[i] = 0;
404  //}
405 }
406 /* we assume max MAX_LIGHTS lights. The max light is the Headlight, so we go through 0-HEADLIGHT_LIGHT for Lights */
407 int nextlight() {
408  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
409  int rv = p->nextFreeLight;
410  if(rv == HEADLIGHT_LIGHT) {
411  return -1;
412  }
413  p->lightChanged[rv] = 0;
414  p->nextFreeLight ++;
415  return rv;
416 }
417 
418 /* lightType 0=point 1=spot 2=directional */
419 void setLightType(GLint light, int type) {
420  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
421  p->lightType[light] = type;
422 }
423 void setLightChangedFlag(GLint light) {
424  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
425  p->lightChanged[light] = 1;
426 }
427 
428 /* keep track of lighting */
429 void setLightState(GLint light, int status) {
430  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
431  //ConsoleMessage ("start lightState, light %d, status %d\n",light,status);
432 
433 
434  PRINT_GL_ERROR_IF_ANY("start lightState");
435 
436  if (light<0) return; /* nextlight will return -1 if too many lights */
437  p->lightOnOff[light] = status;
438  PRINT_GL_ERROR_IF_ANY("end lightState");
439 }
440 
441 /* for local lights, we keep track of what is on and off */
442 void saveLightState2(int *last) {
443  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
444  *last = p->nextFreeLight;
445 }
446 
447 void restoreLightState2(int last) {
448  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
449  p->nextFreeLight = last;
450 }
451 void refreshLightUniforms(){
452  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
453  p->refreshLightUniforms = TRUE;
454 }
455 int numberOfLights(){
456  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
457  int rv = p->nextFreeLight;
458  return rv;
459 }
460 
461 int getLocalLight(){
462  //return top-of-stack Fog or LocalFog
463  int retval = 0;
464  ttglobal tg = gglobal();
465  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
466  if(p->localLight_stack->n)
467  retval = stack_top(int,p->localLight_stack);
468  return retval;
469 }
470 void pushLocalLight(int lastlight){
471  //at root level, before render_hier, any bound Fog node
472  //and pop after render_hier
473  //for prep_LocalFog you would call this to push (and pop in fin_LocalFog)
474  ttglobal tg = gglobal();
475  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
476  stack_push(int,p->localLight_stack,lastlight);
477 }
478 void popLocalLight(){
479  //
480  ttglobal tg = gglobal();
481  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
482  stack_pop(int,p->localLight_stack);
483 }
484 
485 
486 void transformLightToEye(float *pos, float* dir)
487 {
488  int i;
489  GLDOUBLE modelMatrix[16], *b;
490  float *a;
491  shaderVec4 aux, auxt;
492  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
493 
494 /*
495 ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[0],modelMatrix[1],modelMatrix[2],modelMatrix[3]);
496 ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[4],modelMatrix[5],modelMatrix[6],modelMatrix[7]);
497 ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[8],modelMatrix[9],modelMatrix[10],modelMatrix[11]);
498 ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[12],modelMatrix[13],modelMatrix[14],modelMatrix[15]);
499 */
500 
501  /* pre-multiply the light position, as per the orange book, page 216,
502  "OpenGL specifies that light positions are transformed by the modelview
503  matrix when they are provided to OpenGL..." */
504  /* DirectionalLight? PointLight, SpotLight? */
505 
506  // assumes pos[3] = 0.0; only use first 3 of these numbers
507  transformf(auxt,pos,modelMatrix);
508  auxt[3] = 0.0;
509 
510 /*
511 ConsoleMessage("LightToEye, after transformf, auxt %4.2f %4.2f %4.2f %4.2f, pos %4.2f %4.2f %4.2f %4.2f",
512 auxt[0],auxt[1],auxt[2],auxt[3],
513 pos[0],pos[1],pos[2],pos[3]);
514 */
515 
516  for(i=0;i<4;i++){
517  pos[i] = auxt[i];
518  }
519  b = modelMatrix;
520  a = dir;
521  aux[0] = (float) (b[0]*a[0] +b[4]*a[1] +b[8]*a[2] );
522  aux[1] = (float) (b[1]*a[0] +b[5]*a[1] +b[9]*a[2] );
523  aux[2] = (float) (b[2]*a[0] +b[6]*a[1] +b[10]*a[2]);
524  for(i=0;i<3;i++)
525  dir[i] = aux[i];
526 
527  // just initialize this to 0.0
528  dir[3] = 0.0;
529 
530 }
531 
532 void fwglLightfv (int light, int pname, GLfloat *params) {
533  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
534  /*printf ("fwglLightfv light: %d ",light);
535  switch (pname) {
536  case GL_AMBIENT: printf ("GL_AMBIENT"); break;
537  case GL_DIFFUSE: printf ("GL_DIFFUSE"); break;
538  case GL_POSITION: printf ("GL_POSITION"); break;
539  case GL_SPECULAR: printf ("GL_SPECULAR"); break;
540  case GL_SPOT_DIRECTION: printf ("GL_SPOT_DIRECTION"); break;
541  case GL_LIGHT_RADIUS: printf ("GL_LIGHT_RADIUS"); break;
542  }
543  printf (" %f %f %f %f\n",params[0], params[1],params[2],params[3]);
544  */
545 
546  //printLTDebug(__FILE__,__LINE__);
547 
548 
549  switch (pname) {
550  case GL_AMBIENT:
551  memcpy ((void *)p->light_amb[light],(void *)params,sizeof(shaderVec4));
552  break;
553  case GL_DIFFUSE:
554  memcpy ((void *)p->light_dif[light],(void *)params,sizeof(shaderVec4));
555  break;
556  case GL_POSITION:
557  memcpy ((void *)p->light_pos[light],(void *)params,sizeof(shaderVec4));
558  //the following function call assumes spotdir has already been set - set it first from render_light
559 
560 /*
561 ConsoleMessage("fwglLightfv - NOT transforming pos %3.2f %3.2f %3.2f %3.2f spd %3.2f %3.2f %3.2f %3.2f",
562  p->light_pos[light][0],
563  p->light_pos[light][1],
564  p->light_pos[light][2],
565  p->light_pos[light][3],
566  p->light_spotDir[light][0],
567  p->light_spotDir[light][1],
568  p->light_spotDir[light][2],
569  p->light_spotDir[light][3]);
570 */
571  if (light != HEADLIGHT_LIGHT) transformLightToEye(p->light_pos[light], p->light_spotDir[light]);
572  break;
573  case GL_SPECULAR:
574  memcpy ((void *)p->light_spec[light],(void *)params,sizeof(shaderVec4));
575  break;
576  case GL_SPOT_DIRECTION:
577  //call spot_direction before spot_position, so direction gets transformed above in spot position
578  memcpy ((void *)p->light_spotDir[light],(void *)params,sizeof(shaderVec4));
579  break;
580  default: {printf ("help, unknown fwgllightfv param %d\n",pname);}
581  }
582 }
583 
584 void fwglLightf (int light, int pname, GLfloat param) {
585  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
586 
587 #ifdef RENDERVERBOSE
588  printf ("fwglLightf light: %d ",light);
589  switch (pname) {
590  case GL_CONSTANT_ATTENUATION: printf ("GL_CONSTANT_ATTENUATION"); break;
591  case GL_LINEAR_ATTENUATION: printf ("GL_LINEAR_ATTENUATION"); break;
592  case GL_QUADRATIC_ATTENUATION: printf ("GL_QUADRATIC_ATTENUATION"); break;
593  case GL_SPOT_CUTOFF: printf ("GL_SPOT_CUTOFF"); break;
594  case GL_SPOT_BEAMWIDTH: printf ("GL_SPOT_BEAMWIDTH"); break;
595  }
596  printf (" %f\n",param);
597 #endif
598 
599 
600  switch (pname) {
601  case GL_CONSTANT_ATTENUATION:
602  p->light_constAtten[light] = param;
603  break;
604  case GL_LINEAR_ATTENUATION:
605  p->light_linAtten[light] = param;
606  break;
607  case GL_QUADRATIC_ATTENUATION:
608  p->light_quadAtten[light] = param;
609  break;
610  case GL_SPOT_CUTOFF:
611  p->light_spotCutoffAngle[light] = param;
612  //ConsoleMessage ("setting light_spotCutoffAngle for %d to %f\n",light,param);
613  break;
614  case GL_SPOT_BEAMWIDTH:
615  p->light_spotBeamWidth[light] = param;
616  //ConsoleMessage ("setting light_spotBeamWidth for %d to %f\n",light,param);
617 
618  break;
619  case GL_LIGHT_RADIUS:
620  p->light_radius[light] = param;
621  break;
622 
623  default: {printf ("help, unknown fwgllightfv param %d\n",pname);}
624  }
625 }
626 
627 
628 /* send light info into Shader. if OSX gets glGetUniformBlockIndex calls, we can do this with 1 call
629  On old pentium with old board in old PCI slot, 8 lights take 1050bytes and 12% of mainloop load
630  3 optimizations reduce the light sending traffic:
631  1. send only active lights
632  -Android had a problem on startup with this, I changed the flavor a bit - lets see if it works now
633  -cuts from 12% of loop to 4%
634  2. for an active light, send only parameters that light type needs in the shader calc
635  -cuts from 4% of loop to 3%
636  3. if the active light set and shader haven't changed since last shape, don't resend any lights.
637  (active light sets can change during scene graph traversal. But a light itself doesn't change
638  settings during traversal. Just during routing and scripting. So in render_heir
639  lastShader is set to -1 to trigger a fresh send.
640  - cuts from 3% of loop to .5%
641 
642 */
643 void sendLightInfo (s_shader_capabilities_t *me) {
644  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
645  int i,j, lightcount, lightsChanged;
646  int lightIndexesToSend[MAX_LIGHTS];
647 
648  // in case we are trying to render a node that has just been killed...
649  if (me==NULL) return;
650 
651  PRINT_GL_ERROR_IF_ANY("BEGIN sendLightInfo");
652  /* if one of these are equal to -1, we had an error in the shaders... */
653  //Optimization 3>> if the shader and lights haven't changed since the last shape,
654  //then don't resend the lights to the shader
655  if(0){
656  lightsChanged = FALSE;
657  for(i=0;i<MAX_LIGHT_STACK;i++){
658  if(p->lightChanged[i]) lightsChanged = TRUE;
659  }
660  if(!lightsChanged && (p->currentShader == p->lastShader))
661  return;
662  p->lastShader = p->currentShader;
663  //p->lastLoop = p->currentLoop;
664  //p->sendCount++;
665  }
666  //<<end optimization 3
667  profile_start("sendlight");
668  //GLUNIFORM1I(me->lightcount,lightcount);
669  //GLUNIFORM1IV(me->lightState,MAX_LIGHTS,p->lightOnOff); //don't need with lightcount
670  //GLUNIFORM1IV(me->lightType,MAX_LIGHTS,p->lightType); //need to pack into light struct
671  //GLUNIFORM1FV(me->lightRadius,MAX_LIGHTS,p->light_radius); //need to pack into lightstruct
672  PRINT_GL_ERROR_IF_ANY("MIDDLE1 sendLightInfo");
673 
674  // send in lighting info, but only for lights that are "on"
675  // reason: at 1100+ bytes per shape for 8 lights, it takes up 11.2% of mainloop activity on an old pentium
676  // so this cuts it down to about 200 bytes per shape if you have a headlight and another light.
677 
678  lightcount = 0;
679  lightsChanged = FALSE;
680  //by looping from the top down, we'll give headlight first chance,
681  //then local lights pushed onto the stack
682  //then global lights last chance
683  for(i=MAX_LIGHT_STACK-1;i>-1;i--){
684  if(i==HEADLIGHT_LIGHT || i<p->nextFreeLight){
685  if (p->lightOnOff[i]){
686  lightIndexesToSend[lightcount] = i;
687  lightcount++;
688  lightsChanged = lightsChanged || p->lightChanged[i];
689  if(lightcount >= MAX_LIGHTS) break;
690  }
691  }
692  }
693  if(!lightsChanged && (p->currentShader == p->lastShader) && !p->refreshLightUniforms)
694  return;
695  p->refreshLightUniforms = FALSE;
696  p->lastShader = p->currentShader;
697  for (j=0;j<lightcount; j++) {
698  i = lightIndexesToSend[j];
699  p->lightChanged[i] = 0;
700  // this causes initial screen on Android to fail.
701  // dug9 - I added another parameter lightcount above and in ADSL shader
702  // and pack the lights ie. moving headlight up here so its at
703  // lightcount-1 instead of MAX_LIGHTS-1 on the GPU.
704  // LMK if breaks android
705  //0 - pointlight
706  //1 - spotlight
707  //2 - directionlight
708  //save a bit of bandwidth by not sending unused parameters for a light type
709  if(p->lightType[i]<2 ){ //not direction
710  shaderVec4 light_Attenuations;
711  light_Attenuations[0] = p->light_constAtten[i];
712  light_Attenuations[1] = p->light_linAtten[i];
713  light_Attenuations[2] = p->light_quadAtten[i];
714  GLUNIFORM3FV(me->lightAtten[j],1,light_Attenuations);
715  //GLUNIFORM1F (me->lightConstAtten[j], p->light_constAtten[i]);
716  //GLUNIFORM1F (me->lightLinAtten[j], p->light_linAtten[i]);
717  //GLUNIFORM1F(me->lightQuadAtten[j], p->light_quadAtten[i]);
718  }
719  if(p->lightType[i]==1 ){ //spot
720  GLUNIFORM1F(me->lightSpotCutoffAngle[j], p->light_spotCutoffAngle[i]);
721  GLUNIFORM1F(me->lightSpotBeamWidth[j], p->light_spotBeamWidth[i]);
722  }
723  if(p->lightType[i]==0){ //point
724  GLUNIFORM1F(me->lightRadius[j],p->light_radius[i]);
725  }
726  GLUNIFORM4FV(me->lightSpotDir[j],1, p->light_spotDir[i]);
727  GLUNIFORM4FV(me->lightPosition[j],1,p->light_pos[i]);
728  GLUNIFORM4FV(me->lightAmbient[j],1,p->light_amb[i]);
729  GLUNIFORM4FV(me->lightDiffuse[j],1,p->light_dif[i]);
730  GLUNIFORM4FV(me->lightSpecular[j],1,p->light_spec[i]);
731  GLUNIFORM1I(me->lightType[j],p->lightType[i]);
732  }
733  GLUNIFORM1I(me->lightcount,lightcount);
734 
735  profile_end("sendlight");
736  PRINT_GL_ERROR_IF_ANY("END sendLightInfo");
737 }
738 
739 /* finished rendering thisshape. */
740 void finishedWithGlobalShader(void) {
741  //printf ("finishedWithGlobalShader\n");
742 
743 
744  /* get rid of the shader */
745  getAppearanceProperties()->currentShaderProperties = NULL;
746 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
747 
748 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
749 
750 }
751 
752 
753 /* should the system need to rebuild the OpenGL system (eg, Android,
754 on restore of screen, iPhone?? Blackberry???) we ensure that the system
755 state is such that new information will get cached */
756 
757 void resetGlobalShader() {
758  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
759 
760  //ConsoleMessage ("resetGlobalShader called");
761 
762  /* no shader currently active */
763  p->currentShader = 0;
764 }
765 
766 void restoreGlobalShader(){
767  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
768  if (p->currentShader)
769  USE_SHADER(p->currentShader);
770 }
771 /* choose and turn on a shader for this geometry */
772 
773 void enableGlobalShader(s_shader_capabilities_t *myShader) {
774  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
775 
776  //ConsoleMessage ("enableGlobalShader, have myShader %d",myShader->myShaderProgram);
777  if (myShader == NULL) {
778  finishedWithGlobalShader();
779  return;
780  };
781 
782 
783  getAppearanceProperties()->currentShaderProperties = myShader;
784  if (myShader->myShaderProgram != p->currentShader) {
785  USE_SHADER(myShader->myShaderProgram);
786  p->currentShader = myShader->myShaderProgram;
787  }
788 }
789 
790 
791 /* send in vertices, normals, etc, etc... to either a shader or via older opengl methods */
792 void sendAttribToGPU(int myType, int dataSize, int dataType, int normalized, int stride, float *pointer, int texID, char *file, int line){
793 
794  s_shader_capabilities_t *me = getAppearanceProperties()->currentShaderProperties;
795 
796  // checking to see that we really have the data
797  if (me==NULL) return;
798 
799 #ifdef RENDERVERBOSE
800 
801 ConsoleMessage ("sendAttribToGPU, getAppearanceProperties()->currentShaderProperties %p\n",getAppearanceProperties()->currentShaderProperties);
802 ConsoleMessage ("myType %d, dataSize %d, dataType %d, stride %d\n",myType,dataSize,dataType,stride);
803  if (me != NULL) {
804  switch (myType) {
805  case FW_NORMAL_POINTER_TYPE:
806  ConsoleMessage ("glVertexAttribPointer Normals %d at %s:%d\n",me->Normals,file,line);
807  break;
808  case FW_VERTEX_POINTER_TYPE:
809  ConsoleMessage ("glVertexAttribPointer Vertexs %d at %s:%d\n",me->Vertices,file,line);
810  break;
811  case FW_COLOR_POINTER_TYPE:
812  ConsoleMessage ("glVertexAttribPointer Colours %d at %s:%d\n",me->Colours,file,line);
813  break;
814  case FW_TEXCOORD_POINTER_TYPE:
815  ConsoleMessage ("glVertexAttribPointer TexCoords %d at %s:%d\n",me->TexCoords,file,line);
816  break;
817 
818  default : {ConsoleMessage ("sendAttribToGPU, unknown type in shader\n");}
819  }
820  }
821 #endif
822 #undef RENDERVERBOSE
823 
824  switch (myType) {
825  case FW_NORMAL_POINTER_TYPE:
826  if (me->Normals != -1) {
827  glEnableVertexAttribArray(me->Normals);
828  glVertexAttribPointer(me->Normals, 3, dataType, normalized, stride, pointer);
829  }
830  break;
831  case FW_FOG_POINTER_TYPE:
832  if (me->FogCoords != -1) {
833  glEnableVertexAttribArray(me->FogCoords);
834  glVertexAttribPointer(me->FogCoords, 1, dataType, normalized, stride, pointer);
835  }
836  break;
837 
838  case FW_VERTEX_POINTER_TYPE:
839  if (me->Vertices != -1) {
840  glEnableVertexAttribArray(me->Vertices);
841  glVertexAttribPointer(me->Vertices, dataSize, dataType, normalized, stride, pointer);
842  }
843  break;
844  case FW_COLOR_POINTER_TYPE:
845  if (me->Colours != -1) {
846  glEnableVertexAttribArray(me->Colours);
847  glVertexAttribPointer(me->Colours, dataSize, dataType, normalized, stride, pointer);
848  }
849  break;
850  case FW_TEXCOORD_POINTER_TYPE:
851  if (me->TexCoords[texID] != -1) {
852  glEnableVertexAttribArray(me->TexCoords[texID]);
853  glVertexAttribPointer(me->TexCoords[texID], dataSize, dataType, normalized, stride, pointer);
854 
855  }
856  break;
857 
858  default : {printf ("sendAttribToGPU, unknown type in shader\n");}
859  }
860 }
861 
862 
863 void sendBindBufferToGPU (GLenum target, GLuint buffer, char *file, int line) {
864 
865 
866 /*
867  if (target == GL_ARRAY_BUFFER_BINDING) printf ("glBindBuffer, GL_ARRAY_BUFFER_BINDING %d at %s:%d\n",buffer,file,line);
868  else if (target == GL_ARRAY_BUFFER) printf ("glBindBuffer, GL_ARRAY_BUFFER %d at %s:%d\n",buffer,file,line);
869  else if (target == GL_ELEMENT_ARRAY_BUFFER) printf ("glBindBuffer, GL_ELEMENT_ARRAY_BUFFER %d at %s:%d\n",buffer,file,line);
870  else printf ("glBindBuffer, %d %d at %s:%d\n",target,buffer,file,line);
871 
872 */
873 
874  glBindBuffer(target,buffer);
875 }
876 
877 
878 bool setupShader() {
879  return true;
880 }
881 void sendFogToShader(s_shader_capabilities_t *me);
882 void sendClipplanesToShader(s_shader_capabilities_t *me);
883 bool setupShaderB() {
884 
885  s_shader_capabilities_t *mysp = getAppearanceProperties()->currentShaderProperties;
886 
887 PRINT_GL_ERROR_IF_ANY("BEGIN setupShader");
888  if (mysp == NULL)
889  return FALSE;
890 
891  /* if we had a shader compile problem, do not draw */
892  if (!(mysp->compiledOK)) {
893 #ifdef RENDERVERBOSE
894  printf ("shader compile error\n");
895 #endif
896  PRINT_GL_ERROR_IF_ANY("EXIT(false) setupShader");
897  return false;
898  }
899 
900 #ifdef RENDERVERBOSE
901  printf ("setupShader, we have Normals %d Vertices %d Colours %d TexCoords %d \n",
902  mysp->Normals,
903  mysp->Vertices,
904  mysp->Colours,
905  mysp->TexCoords);
906 #endif
907 
908  /* send along lighting, material, other visible properties */
909  sendFogToShader(mysp);
910  sendClipplanesToShader(mysp);
911  sendMaterialsToShader(mysp);
912  sendMatriciesToShader(mysp);
913 
914  return true;
915 }
916 
917 // for particlephysics component we want to be able to do:
918 // send vbos to shader/gpu
919 // foreach liveparticle
920 // send particle-specific age-related color, texcoords, position to gpu
921 // drawOnce()
922 // clearDraw()
923 void saveArraysForGPU(int mode, int first, int count){
924  draw_call_params params;
925  ppRenderFuncs p;
926  ttglobal tg = gglobal();
927  p = (ppRenderFuncs)tg->RenderFuncs.prv;
928 
929  params.calltype = 1;
930  params.arrays.arrays_mode = mode;
931  params.arrays.arrays_count = count;
932  params.arrays.arrays_first = first;
933  stack_push(draw_call_params,p->draw_call_params_stack,params);
934 }
935 
936 
937 void saveElementsForGPU(int mode, int count, ushort *indices){
938  //we use a vector/stack because IndexedLineSet and LineSet call several times
939  // for one polyline vbo
940  draw_call_params params;
941  ppRenderFuncs p;
942  ttglobal tg = gglobal();
943  p = (ppRenderFuncs)tg->RenderFuncs.prv;
944 
945  params.calltype = 2;
946  params.elements.elements_count = count;
947  params.elements.elements_mode = mode;
948  params.elements.elements_indices = indices;
949  stack_push(draw_call_params,p->draw_call_params_stack,params);
950 }
951 
952 void reallyDrawOnce(){
953  //particle system will call this
954  int i;
955  draw_call_params params;
956  ppRenderFuncs p;
957  ttglobal tg = gglobal();
958  p = (ppRenderFuncs)tg->RenderFuncs.prv;
959 
960  for(i=0;i<vectorSize(p->draw_call_params_stack);i++){
961  params = vector_get(draw_call_params,p->draw_call_params_stack,i);
962  if(params.calltype == 1)
963  glDrawArrays(params.arrays.arrays_mode,params.arrays.arrays_first,params.arrays.arrays_count);
964  else if(params.calltype == 2)
965  glDrawElements(params.elements.elements_mode,params.elements.elements_count,GL_UNSIGNED_SHORT,params.elements.elements_indices);
966  }
967  //p->draw_call_params_stack->n = 0;
968 }
969 void clearDraw(){
970  // particlesystem will call this
971  ppRenderFuncs p;
972  ttglobal tg = gglobal();
973  p = (ppRenderFuncs)tg->RenderFuncs.prv;
974  p->draw_call_params_stack->n = 0;
975 }
976 void reallyDraw(){
977  //child_Shape will call this
978  reallyDrawOnce();
979  clearDraw();
980 }
981 void sendArraysToGPU (int mode, int first, int count) {
982  #ifdef RENDERVERBOSE
983  printf ("sendArraysToGPU start\n");
984  #endif
985 
986  // when glDrawArrays bombs it's usually some function left an array
987  // enabled that's not supposed to be - try disabling something
988  //glDisableClientState(GL_VERTEX_ARRAY);
989  //glDisableClientState(GL_NORMAL_ARRAY);
990  //glDisableClientState(GL_INDEX_ARRAY);
991  //glDisableClientState(GL_COLOR_ARRAY);
992  //glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
993  //glDisableClientState(GL_FOG_COORDINATE_ARRAY);
994  //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
995  //glDisableClientState(GL_EDGE_FLAG_ARRAY);
996 
997  if (setupShader()){
998  profile_start("draw_arr");
999 // glDrawArrays(mode,first,count);
1000  saveArraysForGPU(mode,first,count);
1001  profile_end("draw_arr");
1002  }
1003  #ifdef RENDERVERBOSE
1004  printf ("sendArraysToGPU end\n");
1005  #endif
1006 }
1007 
1008 
1009 
1010 void sendElementsToGPU (int mode, int count, ushort *indices) {
1011  #ifdef RENDERVERBOSE
1012  printf ("sendElementsToGPU start\n");
1013  #endif
1014 
1015  if (setupShader()){
1016  profile_start("draw_el");
1017 // glDrawElements(mode,count,GL_UNSIGNED_SHORT,indices);
1018  saveElementsForGPU(mode,count,indices);
1019  profile_end("draw_el");
1020  }
1021 
1022  #ifdef RENDERVERBOSE
1023  printf ("sendElementsToGPU finish\n");
1024  #endif
1025 }
1026 
1027 
1028 void initializeLightTables() {
1029  int i;
1030  float pos[] = { 0.0f, 0.0f, 1.0f, 0.0f };
1031  float dif[] = { 1.0f, 1.0f, 1.0f, 1.0f };
1032  float shin[] = { 0.0f, 0.0f, 0.0f, 1.0f }; /* light defaults - headlight is here, too */
1033  float As[] = { 0.0f, 0.0f, 0.0f, 1.0f };
1034  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1035 
1036  PRINT_GL_ERROR_IF_ANY("start of initializeightTables");
1037 
1038  for(i=0; i<MAX_LIGHT_STACK; i++) {
1039  p->lightOnOff[i] = TRUE;
1040  setLightState(i,FALSE);
1041 
1042  FW_GL_LIGHTFV(i, GL_SPOT_DIRECTION, pos);
1043  FW_GL_LIGHTFV(i, GL_POSITION, pos);
1044  FW_GL_LIGHTFV(i, GL_AMBIENT, As);
1045  FW_GL_LIGHTFV(i, GL_DIFFUSE, dif);
1046  FW_GL_LIGHTFV(i, GL_SPECULAR, shin);
1047  FW_GL_LIGHTF(i, GL_CONSTANT_ATTENUATION,1.0f);
1048  FW_GL_LIGHTF(i, GL_LINEAR_ATTENUATION,0.0f);
1049  FW_GL_LIGHTF(i, GL_QUADRATIC_ATTENUATION,0.0f);
1050  FW_GL_LIGHTF(i, GL_SPOT_CUTOFF,0.0f);
1051  FW_GL_LIGHTF(i, GL_SPOT_BEAMWIDTH,0.0f);
1052  FW_GL_LIGHTF(i, GL_LIGHT_RADIUS, 100000.0); /* just make it large for now*/
1053 
1054  PRINT_GL_ERROR_IF_ANY("initizlizeLight2.10");
1055  }
1056  setLightState(HEADLIGHT_LIGHT, TRUE);
1057 
1058  LIGHTING_INITIALIZE
1059 
1060 
1061  PRINT_GL_ERROR_IF_ANY("end initializeLightTables");
1062 }
1063 
1064 
1065 ttrenderstate renderstate()
1066 {
1067  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1068  return &p->renderstate;
1069 }
1070 
1071 
1072 //true statics:
1073 GLint viewport[4] = {-1,-1,2,2}; //pseudo-viewport - doesn't change, used in glu unprojects
1074 /* These two points (r2,r1) define a ray in pick-veiwport window coordinates
1075  r2=viewpoint
1076  r1=ray from center of pick-viewport in viewport coordinates
1077  - in setup_pickray(pick=TRUE,,) the projMatrix is modified for the pick-ray-viewport
1078  - when unprojecting geometry-local xyz to bearing-local/pick-viewport-local, use pseudo-viewport defined above
1079 */
1080 struct point_XYZ r1 = {0,0,-1}, r2 = {0,0,0}, r3 = {0,1,0}; //r3 y direction in case needed for testing
1081 
1082 
1083 struct X3D_Anchor *AnchorsAnchor()
1084 {
1085  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1086  return p->AnchorsAnchor;
1087 }
1088 void setAnchorsAnchor(struct X3D_Anchor* anchor)
1089 {
1090  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1091  p->AnchorsAnchor = anchor;
1092 }
1093 
1094 
1095 //static struct currayhit rayph;
1096 //struct currayhit rayHit,rayHitHyper;
1097 /* used to test new hits */
1098 
1099 
1100 
1101 //struct X3D_Group *_rootNode=NULL; /* scene graph root node */
1102 struct X3D_Node *rootNode()
1103 {
1104  // ConsoleMessage ("rootNode called");
1105  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1106  if (p==NULL) {
1107  ConsoleMessage ("rootNode, p null");
1108  return NULL;
1109  }
1110  return p->rootNode;
1111 }
1112 void setRootNode(struct X3D_Node *rn)
1113 {
1114  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1115  p->rootNode = rn;
1116 }
1117 //struct Vector *libraries(){
1118 // ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1119 // if(!p->libraries) p->libraries = newVector(void3 *,1) ;
1120 // return p->libraries;
1121 //}
1122 //void setLibraries(struct Vector *libvector){
1123 // //might use this in KILL_oldWorld to NULL the library vector?
1124 // ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1125 // p->libraries = libvector;
1126 //}
1127 void addLibrary(char *url, struct X3D_Proto *library, void *res){
1128  void3 *ul = MALLOC(void3 *,sizeof(void3));
1129  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1130  ul->one = (void *)STRDUP(url);
1131  ul->two = (void *)library;
1132  ul->three = res;
1133  vector_pushBack(void3 *,p->libraries,ul);
1134 }
1135 void3 *librarySearch(char *absoluteUniUrlNoPound){
1136  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1137  void3 *ul;
1138  struct Vector* libs;
1139  int n, i;
1140  libs = p->libraries;
1141  n = vectorSize(libs);
1142  for(i=0;i<n;i++){
1143  ul = vector_get(void3 *,libs,i);
1144  if(ul)
1145  if(!strcmp(absoluteUniUrlNoPound,ul->one)){
1146  return ul; //return res
1147  }
1148  }
1149  return NULL;
1150 }
1151 
1152 //void *empty_group=0;
1153 
1154 /*******************************************************************************/
1155 
1156 
1157 
1158 void prepare_model_view_pickmatrix0(GLDOUBLE *modelMatrix, GLDOUBLE *mvp){
1159  //prepares a matrix that will transform a point in geometry-local coordintes
1160  //into eye/pickray/bearing coordinates ie along the pickray 0,0,1
1161  GLDOUBLE *pickMatrixi;
1162 
1163  pickMatrixi = getPickrayMatrix(1);
1164 
1165  //pickMatrix is inverted in setup_pickray
1166  matmultiplyAFFINE(mvp,modelMatrix,pickMatrixi);
1167 
1168 }
1169 void prepare_model_view_pickmatrix_inverse0(GLDOUBLE *modelMatrix, GLDOUBLE *mvpi){
1170  //prepares a matrix that will transform a point in eye/pickray/bearing coords ie 0,0,1
1171  //into geometry-local coordinates, given the modelMatrix to transform
1172  // eye/pickray -> geometry-local
1173  GLDOUBLE mvi[16];
1174  GLDOUBLE *pickMatrix;
1175 
1176  pickMatrix = getPickrayMatrix(0);
1177 
1178  //pickMatrix is not inverted in setup_pickray
1179  matinverseAFFINE(mvi,modelMatrix);
1180  matmultiplyAFFINE(mvpi,pickMatrix,mvi);
1181 }
1182 
1183 
1184 /* rayhit
1185  For PointingDeviceSensor component work, called from virt->rendray_<Shape> on VF_Sensitive pass
1186  - tests if this ray-geometry intersection is closer to the viewpoint than the closest one so far
1187  - if not it means it is occluded, do nothing
1188  - if so
1189  -- updates the closest distance to intersection of pick-ray/bearing with scene geometry so far
1190  How:
1191  - the calling rendray_<geometry> function already has the pickray/bearing in its geometry-local
1192  coordinates, and computes the distance from A as rat and passes it in here.
1193  - this makes sure its on the B side of A (otherwise its behind the pickray/viewpoint)
1194  - if its the closest intersection of pickray with scene geometry so far:
1195  1.records the point, in bearing-local coordinates
1196  a) for non-sensitive geometry: the point is used to occlude picksensors by being closer to the viewpoint/bearing A
1197  b) for <Drag>Sensor and TouchSensor, if the point succeeds as the closest point
1198  at end of VF_Sensitive pass, the point will be transformed from bearing-local to sensor-local
1199  to generate eventOuts in do_<>Sensor in sensor-local coordinates
1200  2.snapshots the sensor's modelview matrix for later use
1201 
1202  */
1203 void rayhit(float rat, float cx,float cy,float cz, float nx,float ny,float nz,
1204  float tx,float ty, char *descr) {
1205  GLDOUBLE modelMatrix[16];
1206  ppRenderFuncs p;
1207  ttglobal tg = gglobal();
1208  p = (ppRenderFuncs)tg->RenderFuncs.prv;
1209 
1210  /* Real rat-testing */
1211 #ifdef RENDERVERBOSE
1212  //printf("RAY HIT %s! %f (%f %f %f) (%f %f %f)\n\tR: (%f %f %f) (%f %f %f)\n",
1213  // descr, rat,cx,cy,cz,nx,ny,nz,
1214  // t_r1.x, t_r1.y, t_r1.z,
1215  // t_r2.x, t_r2.y, t_r2.z
1216  // );
1217 #endif
1218 
1219  if(rat<0 || (rat>tg->RenderFuncs.hitPointDist && tg->RenderFuncs.hitPointDist >= 0)) {
1220  return;
1221  }
1222  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix); //snapshot of geometry's modelview matrix
1223  {
1224  GLDOUBLE mvp[16];
1225  struct point_XYZ tp; //note viewpoint/avatar Z=1 behind the viewer, to match the glu_unproject method WinZ = -1
1226  tp.x = cx; tp.y = cy; tp.z = cz;
1227  prepare_model_view_pickmatrix0(modelMatrix,mvp);
1228  transform(&tp,&tp,mvp);
1229  p->hp = tp;
1230  }
1231  tg->RenderFuncs.hitPointDist = rat;
1232  p->rayHit=p->rayph;
1233 #ifdef RENDERVERBOSE
1234 // printf ("Rayhit, hp.x y z: - %f %f %f rat %f hitPointDist %f\n",hp.x,hp.y,hp.z, rat, tg->RenderFuncs.hitPointDist);
1235 #endif
1236 }
1237 
1238 /* Call this when modelview and projection modified
1239  keeps bearing/pick-ray transformed into current geometry-local
1240  for use in virt->rendray_<geometry> calculations, on VF_Sensitive pass
1241  bearing-local == pick-viewport-local
1242 */
1243 void upd_ray0(struct point_XYZ *t_r1, struct point_XYZ *t_r2, struct point_XYZ *t_r3) {
1244  //struct point_XYZ t_r1,t_r2,t_r3;
1245  GLDOUBLE modelMatrix[16];
1246  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1247 /*
1248 {int i; printf ("\n");
1249 printf ("upd_ray, pm %p\n",projMatrix);
1250 for (i=0; i<16; i++) printf ("%4.3lf ",modelMatrix[i]); printf ("\n");
1251 for (i=0; i<16; i++) printf ("%4.3lf ",projMatrix[i]); printf ("\n");
1252 }
1253 */
1254 
1255  {
1256  //feature-AFFINE_GLU_UNPROJECT
1257  //FLOPs 112 double: matmultiplyAFFINE 36, matinverseAFFINE 49, 3x transform (affine) 9 =27
1258  GLDOUBLE mvpi[16]; //mvp[16],
1259  struct point_XYZ r11 = {0.0,0.0,1.0}; //note viewpoint/avatar Z=1 behind the viewer, to match the glu_unproject method WinZ = -1
1260 
1261  prepare_model_view_pickmatrix_inverse0(modelMatrix, mvpi);
1262  transform(t_r1,&r11,mvpi);
1263  transform(t_r2,&r2,mvpi);
1264  transform(t_r3,&r3,mvpi);
1265  //r2 is A, r1 is B relative to A in pickray [A,B)
1266  //we prove it here by moving B along the ray, to distance 1.0 from A, and no change to picking
1267  //if(0){
1268  // vecdiff(t_r1,t_r1,t_r2);
1269  // vecnormal(t_r1,t_r1);
1270  // vecadd(t_r1,t_r1,t_r2);
1271  //}
1272  //printf("Upd_ray new: (%f %f %f) (%f %f %f) \n", t_r1.x,t_r1.y,t_r1.z,t_r2.x,t_r2.y,t_r2.z);
1273  }
1274 }
1275 void setup_pickray0();
1276 void upd_ray() {
1277  ppRenderFuncs p;
1278  ttglobal tg = gglobal();
1279  p = (ppRenderFuncs)tg->RenderFuncs.prv;
1280 
1281  setup_pickray0();
1282  upd_ray0(&p->t_r123.p1,&p->t_r123.p2,&p->t_r123.p3);
1283  /*
1284  printf("Upd_ray: (%f %f %f)->(%f %f %f) == (%f %f %f)->(%f %f %f)\n",
1285  r1.x,r1.y,r1.z,r2.x,r2.y,r2.z,
1286  t_r1.x,t_r1.y,t_r1.z,t_r2.x,t_r2.y,t_r2.z);
1287  */
1288 
1289 }
1290 void transformMBB(GLDOUBLE *rMBBmin, GLDOUBLE *rMBBmax, GLDOUBLE *matTransform, GLDOUBLE* inMBBmin, GLDOUBLE* inMBBmax);
1291 int pickrayHitsMBB(struct X3D_Node *node){
1292  //GOAL: on a render_hier(VF_sensitive) (touch sensor) pass, before checking the ray against geometry, check first if the
1293  //ray goes through the extent / minimum-bounding-box (MBB) of the shape. If not, no need to check the ray
1294  //against all the shape's triangles, speeding up the VF_Sensitive pass.
1295  //FLOPs 156 double: matmultiplyAffine 36, matInversAffine 48, transformAffine 8 pts x 12= 72
1296  GLDOUBLE modelMatrix[16];
1297  int i, isIn;
1298  //if using new Sept 2014 pickmatrix, we can test the pickray against the shape node's bounding box
1299  //and if no hit, then no need to run through rendray testing all triangles
1300  //feature-AFFINE_GLU_UNPROJECT
1301  //FLOPs 112 double: matmultiplyAFFINE 36, matinverseAFFINE 49, 3x transform (affine) 9 =27
1302  GLDOUBLE mvp[16]; //, mvpi[16];
1303  GLDOUBLE smin[3], smax[3], shapeMBBmin[3], shapeMBBmax[3];
1304  int retval;
1305  retval = TRUE;
1306 
1307  //struct point_XYZ r11 = {0.0,0.0,-1.0}; //note viewpoint/avatar Z=1 behind the viewer, to match the glu_unproject method WinZ = -1
1308  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1309 
1310  prepare_model_view_pickmatrix0(modelMatrix, mvp);
1311  /* generate mins and maxes for avatar cylinder in avatar space to represent the avatar collision volume */
1312  for(i=0;i<3;i++)
1313  {
1314  shapeMBBmin[i] = node->_extent[i*2 + 1];
1315  shapeMBBmax[i] = node->_extent[i*2];
1316  }
1317  transformMBB(smin,smax,mvp,shapeMBBmin,shapeMBBmax); //transform shape's MBB into pickray space
1318  // the pickray is now at 0,0,x
1319  isIn = TRUE;
1320  for(i=0;i<2;i++)
1321  isIn = isIn && (smin[i] <= 0.0 && smax[i] >= 0.0);
1322  retval = isIn;
1323  //printf("%d x %f %f y %f %f\n",isIn,smin[0],smax[0],smin[1],smax[1]);
1324  //retval = 1;
1325 
1326  return retval;
1327 }
1328 
1329 
1330 
1331 
1332 /* if a node changes, void the display lists */
1333 /* Courtesy of Jochen Hoenicke */
1334 
1335 void update_node(struct X3D_Node *node) {
1336  int i;
1337 
1338 #ifdef VERBOSE
1339  printf ("update_node for %d %s nparents %d renderflags %x\n",node, stringNodeType(node->_nodeType),node->_nparents, node->_renderFlags);
1340  if (node->_nparents == 0) {
1341  if (node == rootNode) printf ("...no parents, this IS the rootNode\n");
1342  else printf ("...no parents, this IS NOT the rootNode\n");
1343  }
1344 
1345 
1346 
1347  for (i = 0; i < node->_nparents; i++) {
1348  struct X3D_Node *n = X3D_NODE(node->_parents[i]);
1349  if( n != 0 ) {
1350  printf (" parent %u is %s\n",n,stringNodeType(n->_nodeType));
1351  } else {
1352  printf (" parent %d is NULL\n",i);
1353  }
1354  }
1355 #endif
1356 
1357  node->_change ++;
1358 
1359  /* parentVector here yet?? */
1360  if (node->_parentVector == NULL) {
1361  return;
1362  }
1363 
1364  for (i = 0; i < vectorSize(node->_parentVector); i++) {
1365  struct X3D_Node *n = vector_get(struct X3D_Node *, node->_parentVector,i);
1366  if(n == node) {
1367  fprintf(stderr, "Error: self-referential node structure! (node:'%s')\n", stringNodeType(node->_nodeType));
1368  vector_set(struct X3D_Node*, node->_parentVector, i,NULL);
1369  } else if( n != 0 ) {
1370  update_node(n);
1371  }
1372  }
1373 }
1374 
1375 /*********************************************************************
1376  *********************************************************************
1377  *
1378  * render_node : call the correct virtual functions to render the node
1379  * depending on what we are doing right now.
1380  */
1381 
1382 //#ifdef RENDERVERBOSE
1383 //static int renderLevel = 0;
1384 //#endif
1385 
1386 #define PRINT_NODE(_node, _v) do { \
1387  if (gglobal()->internalc.global_print_opengl_errors && (gglobal()->display._global_gl_err != GL_NO_ERROR)) { \
1388  printf("Render_node_v %p (%s) PREP: %p REND: %p CH: %p FIN: %p RAY: %p HYP: %p\n",_v, \
1389  stringNodeType(_node->_nodeType), \
1390  _v->prep, \
1391  _v->rend, \
1392  _v->children, \
1393  _v->fin, \
1394  _v->rendray, \
1395  gglobal()->RenderFuncs.hypersensitive); \
1396  printf("Render_state geom %d light %d sens %d\n", \
1397  renderstate()->render_geom, \
1398  renderstate()->render_light, \
1399  renderstate()->render_sensitive); \
1400  printf("pchange %d pichange %d \n", _node->_change, _node->_ichange); \
1401  } \
1402  } while (0)
1403 
1404 //static int renderLevel = 0;
1405 //#define RENDERVERBOSE
1406 
1407 
1408 /* poor-man's performance profiler:
1409  wrap a section of code like this
1410  profile_start("section1");
1411  ...code...
1412  profile_end("section1");
1413  then let the browser loop for 10 seconds
1414  and hit period '.' on the keyboard to get a printout
1415 */
1416 
1417 void profile_start(char *name){
1418  ppRenderFuncs p;
1419  struct profile_entry *pe;
1420  int i, ifound = -1;
1421  ttglobal tg = gglobal();
1422  p = (ppRenderFuncs)tg->RenderFuncs.prv;
1423 
1424  if (!p->profiling_on) return;
1425  pe = p->profile_entries;
1426 
1427  for(i=0;i<p->profile_entry_count;i++){
1428  if(!strcmp(name,pe[i].name)){
1429  ifound = i;
1430  break;
1431  }
1432  }
1433  if(ifound == -1){
1434  pe[p->profile_entry_count].name = name;
1435  pe[p->profile_entry_count].hits = 0;
1436  ifound = p->profile_entry_count;
1437  p->profile_entry_count++;
1438  }
1439  pe[ifound].start = Time1970sec();
1440 }
1441 void profile_end(char *name){
1442  ppRenderFuncs p;
1443  struct profile_entry *pe;
1444  int i, ifound = -1;
1445  ttglobal tg = gglobal();
1446  p = (ppRenderFuncs)tg->RenderFuncs.prv;
1447 
1448  if (!p->profiling_on) return;
1449  pe = p->profile_entries;
1450  for(i=0;i<p->profile_entry_count;i++){
1451  if(!strcmp(name,pe[i].name)){
1452  ifound = i;
1453  break;
1454  }
1455  }
1456  if(ifound > -1){
1457  pe[ifound].accum += Time1970sec() - pe[ifound].start;
1458  pe[ifound].hits++;
1459  }
1460 }
1461 void profile_print_all(){
1462  //hit '.' in the graphics window to get here
1463  ppRenderFuncs p;
1464  struct profile_entry *pe;
1465  ttglobal tg = gglobal();
1466  p = (ppRenderFuncs)tg->RenderFuncs.prv;
1467  if (!p->profiling_on){
1468  p->profiling_on = 1;
1469  ConsoleMessage("turning profiling on\n");
1470  }else{
1471  int i;
1472  pe = p->profile_entries;
1473  ConsoleMessage("frame rate: %9.3f number of items tracked: %d\n", gglobal()->Mainloop.BrowserFPS,p->profile_entry_count);
1474  ConsoleMessage("%15s %10s %15s %10s\n", "profile name", "hits", "time(sec)", "% of 1st");
1475  for (i = 0; i < p->profile_entry_count; i++){
1476  ConsoleMessage("%15s %10d %15.3f %10.2f\n", pe[i].name, pe[i].hits, pe[i].accum, pe[i].accum / pe[0].accum*100.0);
1477  }
1478  }
1479 }
1480 
1481 
1482 //unsigned int getShaderFlags(){
1483 shaderflagsstruct getShaderFlags(){
1484  //return top-of-stack global shaderflags
1485  //unsigned int retval;
1486  shaderflagsstruct retval;
1487  ttglobal tg = gglobal();
1488  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1489  //retval = stack_top(unsigned int,p->shaderflags_stack);
1490  retval = stack_top(shaderflagsstruct,p->shaderflags_stack);
1491  return retval;
1492 }
1493 void pushShaderFlags(shaderflagsstruct flags){ //unsigned int flags){
1494  //at root level, before render_hier, you would push 0000000
1495  //and pop after render_hier
1496  //for prep_LocalFog you would call this to push (and pop in fin_LocalFog)
1497  //these flags are for non-leaf-node shader influencers
1498  //localLights, localFog, clipPlane
1499  //and will be |= with shape->_shaderTableEntry flags in child_shape
1500  ttglobal tg = gglobal();
1501  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1502  //stack_push(unsigned int,p->shaderflags_stack,flags);
1503  stack_push(shaderflagsstruct,p->shaderflags_stack,flags);
1504 
1505 }
1506 void popShaderFlags(){
1507  //
1508  ttglobal tg = gglobal();
1509  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1510  //stack_pop(unsigned int,p->shaderflags_stack);
1511  stack_pop(shaderflagsstruct,p->shaderflags_stack);
1512 
1513 }
1514 struct X3D_Node *getFogParams(){
1515  //return top-of-stack Fog or LocalFog
1516  struct X3D_Node *retval = NULL;
1517  ttglobal tg = gglobal();
1518  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1519  if(p->fog_stack->n)
1520  retval = stack_top(struct X3D_Node*,p->fog_stack);
1521  return retval;
1522 }
1523 void pushFogParams(struct X3D_Node *fogparams){
1524  //at root level, before render_hier, any bound Fog node
1525  //and pop after render_hier
1526  //for prep_LocalFog you would call this to push (and pop in fin_LocalFog)
1527  ttglobal tg = gglobal();
1528  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1529  stack_push(struct X3D_Node*,p->fog_stack,fogparams);
1530 
1531 }
1532 void popFogParams(){
1533  //
1534  ttglobal tg = gglobal();
1535  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1536  stack_pop(struct X3D_Node*,p->fog_stack);
1537 
1538 }
1539 //struct point_XYZ3 {
1540 // struct point_XYZ p1;
1541 // struct point_XYZ p2;
1542 // struct point_XYZ p3;
1543 //};
1544 void push_ray(){
1545  //upd_ray();
1546  //struct point_XYZ t_r1,t_r2,t_r3;
1547  //struct point_XYZ3 r123;
1548  ttglobal tg = gglobal();
1549  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1550  //r123.p1 = tg->RenderFuncs.t_r1;
1551  //r123.p2 = tg->RenderFuncs.t_r2;
1552  //r123.p3 = tg->RenderFuncs.t_r3;
1553 
1554  //stack_push(struct point_XYZ3,p->ray_stack,r123);
1555  stack_push(struct point_XYZ3,p->ray_stack,p->t_r123);
1556 
1557  //upd_ray0(&t_r1,&t_r2,&t_r3);
1558  //VECCOPY(tg->RenderFuncs.t_r1,t_r1);
1559  //VECCOPY(tg->RenderFuncs.t_r2,t_r2);
1560  //VECCOPY(tg->RenderFuncs.t_r3,t_r3);
1561  upd_ray0(&p->t_r123.p1,&p->t_r123.p2,&p->t_r123.p3);
1562 
1563 }
1564 void pop_ray(){
1565  //struct point_XYZ t_r1,t_r2,t_r3;
1566  //struct point_XYZ3 r123;
1567  ttglobal tg = gglobal();
1568  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1569  //upd_ray();
1570  //r123 = stack_top(struct point_XYZ3,p->ray_stack);
1571  stack_pop(struct point_XYZ3,p->ray_stack);
1572  p->t_r123 = stack_top(struct point_XYZ3,p->ray_stack);
1573  //stack_pop(struct point_XYZ3,p->ray_stack);
1574  //tg->RenderFuncs.t_r1 = r123.p1;
1575  //tg->RenderFuncs.t_r2 = r123.p2;
1576  //tg->RenderFuncs.t_r3 = r123.p3;
1577 
1578 }
1579 void get_current_ray(struct point_XYZ* p1, struct point_XYZ* p2){
1580  ttglobal tg = gglobal();
1581  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1582  *p1 = p->t_r123.p1;
1583  *p2 = p->t_r123.p2;
1584 }
1585 void push_render_geom(int igeom){
1586  ttglobal tg = gglobal();
1587  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1588  stack_push(int,p->render_geom_stack,p->renderstate.render_geom);
1589  p->renderstate.render_geom = igeom;
1590 }
1591 void pop_render_geom(){
1592  int igeom;
1593  ttglobal tg = gglobal();
1594  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1595  igeom = stack_top(int,p->render_geom_stack);
1596  stack_pop(int,p->render_geom_stack);
1597  p->renderstate.render_geom = igeom;
1598 }
1599 void push_sensor(struct X3D_Node *node){
1600  ttglobal tg = gglobal();
1601  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1602 
1603  push_render_geom(1);
1604  stack_push(struct currayhit,p->sensor_stack,p->rayph);
1605  //srh = MALLOC(struct currayhit *,sizeof(struct currayhit));
1607  //memcpy(srh,&p->rayph,sizeof(struct currayhit));
1608  p->rayph.hitNode = node; //will be the parent Transform or Group to a PointingDevice (Touch,Drag) Sensor node
1609  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, p->rayph.modelMatrix); //snapshot of sensor's modelview matrix
1610  FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, p->rayph.projMatrix);
1611  //PRINT_GL_ERROR_IF_ANY("render_sensitive"); PRINT_NODE(node,virt);
1612 }
1613 void pop_sensor(){
1614  ttglobal tg = gglobal();
1615  ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1616 
1617  //memcpy(&p->rayph,srh,sizeof(struct currayhit));
1618  //FREE_IF_NZ(srh);
1619  p->rayph = stack_top(struct currayhit,p->sensor_stack);
1620  stack_pop(struct currayhit,p->sensor_stack);
1621  pop_render_geom();
1622 
1623 }
1624 int getWindex();
1625 int render_foundLayerViewpoint();
1626 void render_node(struct X3D_Node *node) {
1627  struct X3D_Virt *virt;
1628 
1629  //int srg = 0;
1630  //int sch = 0;
1631  int justGeom = 0;
1632  int pushed_ray;
1633  int pushed_sensor;
1634  //struct currayhit *srh = NULL;
1635  ppRenderFuncs p;
1636  ttglobal tg = gglobal();
1637  p = (ppRenderFuncs)tg->RenderFuncs.prv;
1638 
1639  X3D_NODE_CHECK(node);
1640 //#define RENDERVERBOSE 1
1641 #ifdef RENDERVERBOSE
1642  p->renderLevel ++;
1643 #endif
1644 
1645  if(!node) {
1646 #ifdef RENDERVERBOSE
1647  DEBUG_RENDER("%d no node, quick return\n", renderLevel);
1648  p->renderLevel--;
1649 #endif
1650  return;
1651  }
1652 
1653  virt = virtTable[node->_nodeType];
1654 
1655 #ifdef RENDERVERBOSE
1656  //printf("%d =========================================NODE RENDERED===================================================\n",renderLevel);
1657  {
1658  int i;
1659  for(i=0;i<p->renderLevel;i++) printf(" ");
1660  }
1661  printf("%d node %u (%s) , v %u renderFlags %x ",p->renderLevel, node,stringNodeType(node->_nodeType),virt,node->_renderFlags);
1662 
1663  if ((node->_renderFlags & VF_Viewpoint) == VF_Viewpoint) printf (" VF_Viewpoint");
1664  if ((node->_renderFlags & VF_Geom )== VF_Geom) printf (" VF_Geom");
1665  if ((node->_renderFlags & VF_localLight )== VF_localLight) printf (" VF_localLight");
1666  if ((node->_renderFlags & VF_Sensitive) == VF_Sensitive) printf (" VF_Sensitive");
1667  if ((node->_renderFlags & VF_Blend) == VF_Blend) printf (" VF_Blend");
1668  if ((node->_renderFlags & VF_Proximity) == VF_Proximity) printf (" VF_Proximity");
1669  if ((node->_renderFlags & VF_Collision) == VF_Collision) printf (" VF_Collision");
1670  if ((node->_renderFlags & VF_globalLight) == VF_globalLight) printf (" VF_globalLight");
1671  if ((node->_renderFlags & VF_hasVisibleChildren) == VF_hasVisibleChildren) printf (" VF_hasVisibleChildren");
1672  if ((node->_renderFlags & VF_shouldSortChildren) == VF_shouldSortChildren) printf (" VF_shouldSortChildren");
1673  if ((node->_renderFlags & VF_Other) == VF_Other) printf (" VF_Other");
1674  /*
1675  if ((node->_renderFlags & VF_inPickableGroup == VF_inPickableGroup) printf (" VF_inPickableGroup");
1676  if ((node->_renderFlags & VF_PickingSensor == VF_PickingSensor) printf (" VF_PickingSensor");
1677  */
1678  printf ("\n");
1679 
1680  //printf("PREP: %d REND: %d CH: %d FIN: %d RAY: %d HYP: %d\n",virt->prep, virt->rend, virt->children, virt->fin,
1681  // virt->rendray, hypersensitive);
1682  //printf("%d state: vp %d geom %d light %d sens %d blend %d prox %d col %d ", renderLevel,
1683  // render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision);
1684  //printf("change %d ichange %d \n",node->_change, node->_ichange);
1685 #endif
1686 
1687 
1688 
1689  // leaf-node filtering (we still do the transform-children stack)
1690  // if we are doing Viewpoints, and we don't have a Viewpoint, don't bother doing anything here *
1691  //if (renderstate()->render_vp == VF_Viewpoint) {
1692  if (p->renderstate.render_vp == VF_Viewpoint) {
1693  //if(tg->Bindable.activeLayer == 0) //no Layerset nodes
1694  if ((node->_renderFlags & VF_Viewpoint) != VF_Viewpoint) {
1695  #ifdef RENDERVERBOSE
1696  printf ("doing Viewpoint, but this node is not for us - just returning\n");
1697  p->renderLevel--;
1698  #endif
1699  return;
1700  }
1701  if(p->renderstate.render_vp == VF_Viewpoint && render_foundLayerViewpoint()){
1702  //on vp pass, just find first DEF/USE of bound viewpoint
1703  return;
1704  }
1705  }
1706 
1707  /* are we working through global PointLights, DirectionalLights or SpotLights, but none exist from here on down? */
1708  if (p->renderstate.render_light ) {
1709  if((node->_renderFlags & VF_globalLight) != VF_globalLight) {
1710  #ifdef RENDERVERBOSE
1711  printf ("doing globalLight, but this node is not for us - just returning\n");
1712  p->renderLevel--;
1713  #endif
1714  return;
1715  }
1716  }
1717  justGeom = p->renderstate.render_geom && !p->renderstate.render_sensitive && !p->renderstate.render_blend;
1718  pushed_ray = FALSE;
1719  pushed_sensor = FALSE;
1720 
1721  if(virt->prep) {
1722  //transform types will pushmatrix and multiply in their translation.rotation,scale here (and popmatrix in virt->fin)
1723  DEBUG_RENDER("rs 2\n");
1724  profile_start("prep");
1725  if(justGeom)
1726  profile_start("prepgeom");
1727  virt->prep(node);
1728  profile_end("prep");
1729  if(justGeom)
1730  profile_end("prepgeom");
1731  //if(p->renderstate.render_sensitive && !tg->RenderFuncs.hypersensitive) {
1732  // push_ray(); //upd_ray();
1733  // pushed_ray = TRUE;
1734  //}
1735  PRINT_GL_ERROR_IF_ANY("prep"); PRINT_NODE(node,virt);
1736  }
1737  if(p->renderstate.render_sensitive && !tg->RenderFuncs.hypersensitive) {
1738  push_ray(); //upd_ray();
1739  pushed_ray = TRUE;
1740  }
1741  if(p->renderstate.render_proximity && virt->proximity) {
1742  DEBUG_RENDER("rs 2a\n");
1743  profile_start("proximity");
1744  virt->proximity(node);
1745  profile_end("proximity");
1746  PRINT_GL_ERROR_IF_ANY("render_proximity"); PRINT_NODE(node,virt);
1747  }
1748  if(p->renderstate.render_geom && ((node->_renderFlags & VF_USE) == VF_USE) && !p->renderstate.render_picking){
1749  //picking sensor, transform sensor and generally any USE_NODE-USE_NODE scenario
1750  //ideally we would come in here once per scenegraph USE per frame, even when stereo or quad views
1751  //because we want to work in world coordinates (not view coordinates) so by the time
1752  //we strip off the view matrix we would have duplicate entries with stereo
1753  if(getWindex() == 0){
1754  //just on first window of stereo or quad
1755  //we don't do this in VF_Proximity because that pass doesn't go all the way to all geom nodes
1756  //we could give it its own pass, but doing just the first window is a simple hack.
1757  double modelviewMatrix[16];
1758  //IF VIEW == 0
1759  //GL_GET_MODELVIEWMATRIX
1760  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1761  //strip viewmatrix - will happen when we invert one of the USEUSE pair, and multiply
1762  usehit_add2(node,modelviewMatrix,getpickablegroupdata());
1763  }
1764  }
1765  if(p->renderstate.render_picking && node->_nodeType == NODE_Shape ){
1766  //this is for when called from Component_Picking.c on a partial scenegraph,
1767  //to get geometry nodes in the usehitB list
1768  //I put vrit->rendray as a way to detect if its geometry, is there a better way?
1769  double modelviewMatrix[16];
1770  struct X3D_Shape *shapenode = (struct X3D_Shape*)node;
1771  if(shapenode->geometry){
1772  //IF VIEW == 0
1773  //GL_GET_MODELVIEWMATRIX
1774  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1775  //strip viewmatrix - will happen when we invert one of the USEUSE pair, and multiply
1776  usehitB_add2(shapenode->geometry,modelviewMatrix,getpickablegroupdata());
1777  }
1778  }
1779 
1780  if(p->renderstate.render_collision && virt->collision) {
1781  DEBUG_RENDER("rs 2b\n");
1782  profile_start("collision");
1783  virt->collision(node);
1784  profile_end("collision");
1785  PRINT_GL_ERROR_IF_ANY("render_collision"); PRINT_NODE(node,virt);
1786  }
1787 
1788  if(p->renderstate.render_geom && !p->renderstate.render_sensitive && !p->renderstate.render_picking && virt->rend) {
1789  DEBUG_RENDER("rs 3\n");
1790  PRINT_GL_ERROR_IF_ANY("BEFORE render_geom"); PRINT_NODE(node,virt);
1791  profile_start("rend");
1792  virt->rend(node);
1793  profile_end("rend");
1794  PRINT_GL_ERROR_IF_ANY("render_geom"); PRINT_NODE(node,virt);
1795  }
1796  if(p->renderstate.render_other && virt->other )
1797  {
1798  virt->other(node);
1799  } //other
1800 
1801  if(p->renderstate.render_sensitive && ((node->_renderFlags & VF_Sensitive)|| Viewer()->LookatMode ==2)) {
1802  DEBUG_RENDER("rs 5\n");
1803  profile_start("sensitive");
1804  push_sensor(node);
1805  pushed_sensor = TRUE;
1806  profile_end("sensitive");
1807  }
1808  if(p->renderstate.render_geom && p->renderstate.render_sensitive && !tg->RenderFuncs.hypersensitive && virt->rendray) {
1809  DEBUG_RENDER("rs 6\n");
1810  profile_start("rendray");
1811  if(pickrayHitsMBB(node))
1812  virt->rendray(node);
1813  profile_end("rendray");
1814  PRINT_GL_ERROR_IF_ANY("rs 6"); PRINT_NODE(node,virt);
1815  }
1816 
1817  /* May 16 2016: now we don't come into render_hier on hypersensitive
1818  if((p->renderstate.render_sensitive) && (tg->RenderFuncs.hypersensitive == node)) {
1819  DEBUG_RENDER("rs 7\n");
1820  p->hyper_r1 = p->t_r123.p1; //tg->RenderFuncs.t_r1;
1821  p->hyper_r2 = p->t_r123.p2; //tg->RenderFuncs.t_r2;
1822  tg->RenderFuncs.hyperhit = 1;
1823  }
1824  */
1825 
1826  /* start recursive section */
1827  if(virt->children) {
1828  DEBUG_RENDER("rs 8 - has valid child node pointer\n");
1829  //if(! (p->renderstate.render_vp == VF_Viewpoint && render_foundLayerViewpoint())){ //on vp pass, just find first DEF/USE of bound viewpoint
1830  //printf("children ");
1831  virt->children(node);
1832  //}
1833  //}else{
1834  // printf("skipping ");
1835  //}
1836  PRINT_GL_ERROR_IF_ANY("children"); PRINT_NODE(node,virt);
1837  }
1838  /* end recursive section */
1839 
1840  if(p->renderstate.render_other && virt->other)
1841  {
1842  }
1843 
1844  if(pushed_sensor)
1845  pop_sensor();
1846 
1847  if(virt->fin) {
1848  DEBUG_RENDER("rs A\n");
1849  profile_start("fin");
1850  if(justGeom)
1851  profile_start("fingeom");
1852 
1853  virt->fin(node);
1854  profile_end("fin");
1855  if(justGeom)
1856  profile_end("fingeom");
1857  //if(p->renderstate.render_sensitive && virt == &virt_Transform) {
1858  // upd_ray();
1859  //}
1860  PRINT_GL_ERROR_IF_ANY("fin"); PRINT_NODE(node,virt);
1861  }
1862  if(pushed_ray)
1863  pop_ray();
1864 
1865 #ifdef RENDERVERBOSE
1866  {
1867  int i;
1868  for(i=0;i<p->renderLevel;i++)printf(" ");
1869  }
1870  printf("%d (end render_node)\n",p->renderLevel);
1871  p->renderLevel--;
1872 #endif
1873 }
1874 //#undef RENDERVERBOSE
1875 
1876 /*
1877  * The following code handles keeping track of the parents of a given
1878  * node. This enables us to traverse the scene on C level for optimizations.
1879  *
1880  * We use this array code because VRML nodes usually don't have
1881  * hundreds of children and don't usually shuffle them too much.
1882  */
1883 //dug9 dec 13 >>
1884 struct X3D_Node* getTypeNode(struct X3D_Node *node);
1885 
1886 void add_parent(struct X3D_Node *node, struct X3D_Node *parent, char *file, int line) {
1887  struct X3D_Node* itype;
1888  if(!node) return;
1889  //if(node->_nodeType == NODE_PlaneSensor)
1890  // printf("hi from add_parent, have a Planesensor");
1891 #ifdef CHILDVERBOSE
1892  printf ("add_parent; adding node %u ,to parent %u at %s:%d\n",node, parent,file,line);
1893  printf ("add_parent; adding node %x ,to parent %x (hex) at %s:%d\n",node, parent,file,line);
1894  printf ("add_parent; adding node %p ,to parent %p (ptr) at %s:%d\n",node, parent,file,line);
1895 
1896 
1897  printf ("add_parent; adding node %u (%s) to parent %u (%s) at %s:%d\n",node, stringNodeType(node->_nodeType),
1898  parent, stringNodeType(parent->_nodeType),file,line);
1899 #endif
1900 
1901  parent->_renderFlags = parent->_renderFlags | node->_renderFlags;
1902 
1903  /* add it to the parents list */
1904  vector_pushBack (struct X3D_Node*,node->_parentVector, parent);
1905  /* tie in sensitive nodes */
1906  itype = getTypeNode(node);
1907  if(itype)
1908  setSensitive (parent, itype );
1909 }
1910 
1911 void remove_parent(struct X3D_Node *child, struct X3D_Node *parent) {
1912  int i;
1913  int pi;
1914 
1915  if(!child) return;
1916  if(!parent) return;
1917 
1918  //JAS printf ("remove_parent, parent %p (%s) , child %p (%s)\n",parent, stringNodeType(parent->_nodeType),
1919  //JAS child, stringNodeType(child->_nodeType));
1920 
1921  //JAS printf ("remove_parent, parent vector size %d\n",vectorSize(child->_parentVector));
1922 
1923  pi = -1;
1924  for (i=0; i<vectorSize(child->_parentVector); i++) {
1925  struct X3D_Node *n = vector_get(struct X3D_Node *, child->_parentVector,i);
1926  //JAS printf ("remPar, ele %d was %p\n",i,n);
1927  if (n==parent) pi = i;
1928  }
1929 
1930  if (pi >=0) {
1931  //JAS printf ("remove parent, pi %d\n",pi);
1932 
1933  struct X3D_Node *n = vector_get(struct X3D_Node *, child->_parentVector,vectorSize(child->_parentVector)-1);
1934 
1935  /* get the last entry, and overwrite the entry found */
1936  vector_set(struct X3D_Node*, child->_parentVector, pi,n);
1937 
1938  /* take that last entry off the vector */
1939  vector_popBack(struct X3D_Node*, child->_parentVector);
1940  }
1941 
1942  //JAS - verification that parent was indeed removed.
1943  //JAS printf ("remove_parent, after parent vector size %d\n",vectorSize(child->_parentVector));
1944  //JAS for (i=0; i<vectorSize(child->_parentVector); i++) {
1945  //JAS struct X3D_Node *n = vector_get(struct X3D_Node *, child->_parentVector,i);
1946  //JAS printf ("remPar, ele %d was %p\n",i,n);
1947  //JAS }
1948 }
1949 
1950 
1951 #include "../x3d_parser/Bindable.h"
1952 int fwl_getShadingStyle();
1953 void push_globalRenderFlags(){
1954  //call in render_hier for geom or blend passes
1955  //unsigned int shaderflags;
1956  shaderflagsstruct shaderflags;
1957  ttglobal tg = gglobal();
1958  shaderflags = getShaderFlags(); //take a copy (which should be 0000000 at root level)
1959  memset(&shaderflags,0,sizeof(shaderflagsstruct));
1960  //modify copy
1961  //A. if there's a bound (non local) fog, copy its state to fog_state
1962  if(vectorSize(getActiveBindableStacks(tg)->fog) > 0){
1963  //there's a bound fog, bound fogs are enabled
1964  struct X3D_Fog *fog = stack_top(struct X3D_Fog*,getActiveBindableStacks(tg)->fog);
1965  if(fog->visibilityRange > 0.0f){
1966  //enabled
1967  //set fog bit in renderflags
1968  shaderflags.base |= FOG_APPEARANCE_SHADER;
1969  //push fogparams
1970  pushFogParams((struct X3D_Node*)fog);
1971  }
1972  }
1973  //B. Anaglyph?
1974  if(Viewer()->anaglyph || Viewer()->anaglyphB)
1975  shaderflags.base |= WANT_ANAGLYPH;
1976 
1977  //C. ShadingStyle ie 0 flat, 1 gouraud, 2 phong, 3 wire
1978  switch(fwl_getShadingStyle()){
1979  case 0: shaderflags.base |= SHADINGSTYLE_FLAT; break;
1980  case 1: shaderflags.base |= SHADINGSTYLE_GOURAUD; break;
1981  case 2: shaderflags.base |= SHADINGSTYLE_PHONG; break;
1982  case 3: shaderflags.base |= SHADINGSTYLE_WIRE; break;
1983  default:
1984  shaderflags.base |= SHADINGSTYLE_GOURAUD; break;
1985  }
1986 
1987  pushShaderFlags(shaderflags); //push nodified copy
1988 }
1989 void pop_globalRenderFlags(){
1990  //call after render_hier for geom or blend passes
1991  ttglobal tg = gglobal();
1992 
1993  popShaderFlags(); //pop modified copy
1994 
1995  //A. Fog, pop its stack only if it was pushed in push_globalRenderFlags
1996  if(vectorSize(getActiveBindableStacks(tg)->fog) > 0){
1997  struct X3D_Fog *fog = stack_top(struct X3D_Fog*,getActiveBindableStacks(tg)->fog);
1998  if(fog->visibilityRange > 0.0f){
1999  //enabled
2000  //pop fogParms
2001  popFogParams();
2002  }
2003  }
2004 }
2005 void render_hier(struct X3D_Node *g, int rwhat) {
2008 
2009  ppRenderFuncs p;
2010  shaderflagsstruct shaderflags;
2011  ttglobal tg = gglobal();
2012  ttrenderstate rs;
2013  p = (ppRenderFuncs)tg->RenderFuncs.prv;
2014  rs = renderstate();
2015  memset(&shaderflags,0,sizeof(shaderflagsstruct));
2016  pushShaderFlags(shaderflags);
2017 
2018  rs->render_vp = rwhat & VF_Viewpoint;
2019  rs->render_geom = rwhat & VF_Geom;
2020  rs->render_light = rwhat & VF_globalLight;
2021  rs->render_sensitive = rwhat & VF_Sensitive;
2022  rs->render_picking = rwhat & VF_Picking;
2023  rs->render_blend = rwhat & VF_Blend;
2024  rs->render_proximity = rwhat & VF_Proximity;
2025  rs->render_collision = rwhat & VF_Collision;
2026  rs->render_other = rwhat & VF_Other;
2027  rs->render_cube = rwhat & VF_Cube;
2028  //p->nextFreeLight = 0;
2029  p->lastShader = -1; //in sendLights,and optimization
2030  tg->RenderFuncs.hitPointDist = -1;
2031 
2032 
2033 #ifdef RENDERVERBOSE
2034  printf ("render_hier vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
2035  rs->render_vp,rs->render_geom,rs->render_light,rs->render_sensitive,rs->render_blend,rs->render_proximity,rs->render_collision);
2036 #endif
2037 
2038  if (!g) {
2039  /* we have no geometry yet, sleep for a tiny bit */
2040  usleep(1000);
2041  return;
2042  }
2043 
2044 #ifdef RENDERVERBOSE
2045  printf("Render_hier node=%d what=%d\n", g, rwhat);
2046 #endif
2047 
2048 
2049  if (rs->render_sensitive) {
2050  upd_ray();
2051  }
2052  if(rs->render_blend || rs->render_geom){
2053  push_globalRenderFlags();
2054 
2055  }
2056  profile_start("render_hier");
2057  render_node(X3D_NODE(g));
2058  profile_end("render_hier");
2059  if(rs->render_blend || rs->render_geom){
2060  pop_globalRenderFlags();
2061  }
2062  popShaderFlags();
2063 
2064 
2065 }
2066 
2067 
2068 /******************************************************************************
2069  *
2070  * shape compiler "thread"
2071  *
2072  ******************************************************************************/
2073 
2074 void compileNode (void (*nodefn)(void *, void *, void *, void *, void *, void *), void *node, void *Icoord, void *IfogCoord, void *Icolor, void *Inormal, void *ItexCoord) {
2075  void *coord; void *fogCoord; void *color; void *normal; void *texCoord;
2076 
2077  /* are any of these SFNodes PROTOS? If so, get the underlying real node, as PROTOS are handled like Groups. */
2078  POSSIBLE_PROTO_EXPANSION(void *, Icoord,coord)
2079  POSSIBLE_PROTO_EXPANSION(void *, IfogCoord,fogCoord)
2080  POSSIBLE_PROTO_EXPANSION(void *, Icolor,color)
2081  POSSIBLE_PROTO_EXPANSION(void *, Inormal,normal)
2082  POSSIBLE_PROTO_EXPANSION(void *, ItexCoord,texCoord)
2083 
2084  nodefn(node, coord, fogCoord, color, normal, texCoord);
2085 }
2086 
2087 void do_NurbsPositionInterpolator (void *node);
2088 void do_NurbsOrientationInterpolator (void *node);
2089 void do_NurbsSurfaceInterpolator (void *node);
2090 /* for CRoutes, we need to have a function pointer to an interpolator to run, if we
2091  route TO an interpolator */
2092 void *returnInterpolatorPointer (int nodeType) {
2093  void (*do_interp)(void *);
2094 
2095  do_interp = NULL;
2096  switch(nodeType){
2097  case NODE_OrientationInterpolator: do_interp = do_Oint4; break;
2098  case NODE_CoordinateInterpolator2D: do_interp = do_OintCoord2D; break;
2099  case NODE_PositionInterpolator2D: do_interp = do_OintPos2D; break;
2100  case NODE_ScalarInterpolator: do_interp = do_OintScalar; break;
2101  case NODE_ColorInterpolator: do_interp = do_ColorInterpolator; break;
2102  case NODE_PositionInterpolator: do_interp = do_PositionInterpolator; break;
2103  case NODE_CoordinateInterpolator: do_interp = do_OintCoord; break;
2104  case NODE_NormalInterpolator: do_interp = do_OintNormal; break;
2105  case NODE_EaseInEaseOut: do_interp = do_EaseInEaseOut; break;
2106  case NODE_SplinePositionInterpolator: do_interp = do_SplinePositionInterpolator; break;
2107  case NODE_SplinePositionInterpolator2D: do_interp = do_SplinePositionInterpolator2D; break;
2108  case NODE_SplineScalarInterpolator: do_interp = do_SplineScalarInterpolator; break;
2109  case NODE_SquadOrientationInterpolator: do_interp = do_SquadOrientationInterpolator; break;
2110  case NODE_GeoPositionInterpolator: do_interp = do_GeoPositionInterpolator; break;
2111  case NODE_NurbsPositionInterpolator: do_interp = do_NurbsPositionInterpolator; break;
2112  case NODE_NurbsOrientationInterpolator: do_interp = do_NurbsOrientationInterpolator; break;
2113  case NODE_NurbsSurfaceInterpolator: do_interp = do_NurbsSurfaceInterpolator; break;
2114  case NODE_BooleanFilter: do_interp = do_BooleanFilter; break;
2115  case NODE_BooleanSequencer: do_interp = do_BooleanSequencer; break;
2116  case NODE_BooleanToggle: do_interp = do_BooleanToggle; break;
2117  case NODE_BooleanTrigger: do_interp = do_BooleanTrigger; break;
2118  case NODE_IntegerTrigger: do_interp = do_IntegerTrigger; break;
2119  case NODE_IntegerSequencer: do_interp = do_IntegerSequencer; break;
2120  case NODE_TimeTrigger: do_interp = do_TimeTrigger; break;
2121  default:
2122  do_interp = NULL;
2123  }
2124  return (void *)do_interp;
2125 }
2126 /*
2127 void *returnInterpolatorPointer (const char *x) {
2128  if (strcmp("OrientationInterpolator",x)==0) { return (void *)do_Oint4;
2129  } else if (strcmp("CoordinateInterpolator2D",x)==0) { return (void *)do_OintCoord2D;
2130  } else if (strcmp("PositionInterpolator2D",x)==0) { return (void *)do_OintPos2D;
2131  } else if (strcmp("ScalarInterpolator",x)==0) { return (void *)do_OintScalar;
2132  } else if (strcmp("ColorInterpolator",x)==0) { return (void *)do_ColorInterpolator;
2133  } else if (strcmp("PositionInterpolator",x)==0) { return (void *)do_PositionInterpolator;
2134  } else if (strcmp("CoordinateInterpolator",x)==0) { return (void *)do_OintCoord;
2135  } else if (strcmp("NormalInterpolator",x)==0) { return (void *)do_OintNormal;
2136  } else if (strcmp("GeoPositionInterpolator",x)==0) { return (void *)do_GeoPositionInterpolator;
2137  } else if (strcmp("NurbsPositionInterpolator",x)==0) { return (void *)do_NurbsPositionInterpolator;
2138  } else if (strcmp("NurbsOrientationInterpolator",x)==0) { return (void *)do_NurbsOrienatationInterpolator;
2139  } else if (strcmp("NurbsSurfaceInterpolator",x)==0) { return (void *)do_NurbsSurfaceInterpolator;
2140  } else if (strcmp("BooleanFilter",x)==0) { return (void *)do_BooleanFilter;
2141  } else if (strcmp("BooleanSequencer",x)==0) { return (void *)do_BooleanSequencer;
2142  } else if (strcmp("BooleanToggle",x)==0) { return (void *)do_BooleanToggle;
2143  } else if (strcmp("BooleanTrigger",x)==0) { return (void *)do_BooleanTrigger;
2144  } else if (strcmp("IntegerTrigger",x)==0) { return (void *)do_IntegerTrigger;
2145  } else if (strcmp("IntegerSequencer",x)==0) { return (void *)do_IntegerSequencer;
2146  } else if (strcmp("TimeTrigger",x)==0) { return (void *)do_TimeTrigger;
2147 
2148  } else {
2149  return 0;
2150  }
2151 }
2152 */
2153 
2154 
2155 
2156 void checkParentLink (struct X3D_Node *node,struct X3D_Node *parent) {
2157  int n;
2158 
2159  int *offsetptr;
2160  char *memptr;
2161  struct Multi_Node *mfn;
2162  uintptr_t *voidptr;
2163 
2164  if (node == NULL) return;
2165 
2166  /* printf ("checkParentLink for node %u parent %u type %s\n",node,parent,stringNodeType(node->_nodeType)); */
2167 
2168  if (parent != NULL) ADD_PARENT(node, parent);
2169 
2170  if ((node->_nodeType<0) || (node->_nodeType>NODES_COUNT)) {
2171  ConsoleMessage ("checkParentLink - %d not a valid nodeType",node->_nodeType);
2172  return;
2173  }
2174 
2175  /* find all the fields of this node */
2176  offsetptr = (int *) NODE_OFFSETS[node->_nodeType];
2177 
2178  /* FIELDNAMES_bboxCenter, offsetof (struct X3D_Group, bboxCenter), FIELDTYPE_SFVec3f, KW_field, */
2179  while (*offsetptr >= 0) {
2180 
2181  /*
2182  printf (" field %s",FIELDNAMES[offsetptr[0]]);
2183  printf (" offset %d",offsetptr[1]);
2184  printf (" type %s",FIELDTYPES[offsetptr[2]]);
2185  printf (" kind %s\n",KEYWORDS[offsetptr[3]]);
2186  */
2187 
2188  /* worry about SFNodes and MFNodes */
2189  if ((offsetptr[2] == FIELDTYPE_SFNode) || (offsetptr[2] == FIELDTYPE_MFNode)) {
2190  if ((offsetptr[3] == KW_initializeOnly) || (offsetptr[3] == KW_inputOutput)) {
2191 
2192  /* create a pointer to the actual field */
2193  memptr = (char *) node;
2194  memptr += offsetptr[1];
2195 
2196  if (offsetptr[2] == FIELDTYPE_SFNode) {
2197  /* get the field as a POINTER VALUE, not just a pointer... */
2198  voidptr = (uintptr_t *) memptr;
2199  voidptr = (uintptr_t *) *voidptr;
2200 
2201  /* is there a node here? */
2202  if (voidptr != NULL) {
2203  checkParentLink(X3D_NODE(voidptr),node);
2204  }
2205  } else {
2206  mfn = (struct Multi_Node*) memptr;
2207  /* printf ("MFNode has %d children\n",mfn->n); */
2208  for (n=0; n<mfn->n; n++) {
2209  checkParentLink(mfn->p[n],node);
2210  }
2211  }
2212  }
2213 
2214  }
2215  offsetptr+=5;
2216  }
2217 }
2218 
2219 #define X3D_COORD(node) ((struct X3D_Coordinate*)node)
2220 #define X3D_GEOCOORD(node) ((struct X3D_GeoCoordinate*)node)
2221 
2222 /* get a coordinate array - (SFVec3f) from either a NODE_Coordinate or NODE_GeoCoordinate */
2223 struct Multi_Vec3f *getCoordinate (struct X3D_Node *innode, char *str) {
2224  struct X3D_Coordinate * xc;
2225  struct X3D_GeoCoordinate *gxc;
2226  struct X3D_Node *node;
2227 
2228  POSSIBLE_PROTO_EXPANSION (struct X3D_Node *, innode,node)
2229 
2230  if(node){
2231  xc = X3D_COORD(node);
2232  /* printf ("getCoordinate, have a %s\n",stringNodeType(xc->_nodeType)); */
2233  if (xc->_nodeType == NODE_Coordinate) {
2234  return &(xc->point);
2235  } else if (xc->_nodeType == NODE_GeoCoordinate) {
2236  COMPILE_IF_REQUIRED_RETURN_NULL_ON_ERROR;
2237  gxc = X3D_GEOCOORD(node);
2238  return &(gxc->__movedCoords);
2239  } else {
2240  ConsoleMessage ("%s - coord expected but got %s\n", stringNodeType(xc->_nodeType));
2241  }
2242  }
2243  return NULL;
2244 }
2245 
2246 
2247 
2248 /*
2249 void printLTDebug(char * fn, int ln)
2250 {
2251  ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
2252 ConsoleMessage ("headlight pos %f %f %f %f at %s:%d",
2253 p->light_pos[HEADLIGHT_LIGHT][0],p->light_pos[HEADLIGHT_LIGHT][1],
2254  p->light_pos[HEADLIGHT_LIGHT][2],p->light_pos[HEADLIGHT_LIGHT][3],fn,ln);
2255 }
2256 */
2257 
Definition: headers.h:666
Definition: Vector.h:36
Definition: RenderFuncs.c:58