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