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 ushort *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 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;
144void *RenderFuncs_constructor(){
145 void *v = MALLOCV(sizeof(struct pRenderFuncs));
146 memset(v,0,sizeof(struct pRenderFuncs));
147 return v;
148}
149void 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
208void 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}
217void 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}
226usehit * 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}
257void 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)
267void 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}
276void 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}
285usehit * 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}
316void 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}
322Stack *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
330void push_pickablegroupdata(void *userdata){
331 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
332 stack_push(void*,p->pickablegroupdata_stack,userdata);
333}
334void pop_pickablegroupdata(){
335 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
336 stack_pop(void*,p->pickablegroupdata_stack);
337}
338void *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
348void unload_libraryscenes();
349int gc_broto_instance(struct X3D_Proto* node);
350void 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}
364void 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}
396void 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 */
407int 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 */
419void setLightType(GLint light, int type) {
420 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
421 p->lightType[light] = type;
422}
423void setLightChangedFlag(GLint light) {
424 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
425 p->lightChanged[light] = 1;
426}
427
428/* keep track of lighting */
429void 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 */
442void saveLightState2(int *last) {
443 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
444 *last = p->nextFreeLight;
445}
446
447void restoreLightState2(int last) {
448 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
449 p->nextFreeLight = last;
450}
451void refreshLightUniforms(){
452 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
453 p->refreshLightUniforms = TRUE;
454}
455int numberOfLights(){
456 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
457 int rv = p->nextFreeLight;
458 return rv;
459}
460
461int 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}
470void 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}
478void popLocalLight(){
479 //
480 ttglobal tg = gglobal();
481 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
482 stack_pop(int,p->localLight_stack);
483}
484
485
486void 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/*
495ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[0],modelMatrix[1],modelMatrix[2],modelMatrix[3]);
496ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[4],modelMatrix[5],modelMatrix[6],modelMatrix[7]);
497ConsoleMessage ("nvm %4.2f %4.2f %4.2f %4.2f",modelMatrix[8],modelMatrix[9],modelMatrix[10],modelMatrix[11]);
498ConsoleMessage ("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/*
511ConsoleMessage("LightToEye, after transformf, auxt %4.2f %4.2f %4.2f %4.2f, pos %4.2f %4.2f %4.2f %4.2f",
512auxt[0],auxt[1],auxt[2],auxt[3],
513pos[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
532void 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/*
561ConsoleMessage("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
584void 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*/
643void 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. */
740void finishedWithGlobalShader(void) {
741 //printf ("finishedWithGlobalShader\n");
742
743
744 /* get rid of the shader */
745 getAppearanceProperties()->currentShaderProperties = NULL;
746FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
747
748FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
749
750}
751
752
753/* should the system need to rebuild the OpenGL system (eg, Android,
754on restore of screen, iPhone?? Blackberry???) we ensure that the system
755state is such that new information will get cached */
756
757void 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
766void 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
773void 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 */
792void 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)
798 return;
799
800#ifdef RENDERVERBOSE
801
802ConsoleMessage ("sendAttribToGPU, getAppearanceProperties()->currentShaderProperties %p\n",getAppearanceProperties()->currentShaderProperties);
803ConsoleMessage ("myType %d, dataSize %d, dataType %d, stride %d\n",myType,dataSize,dataType,stride);
804 if (me != NULL) {
805 switch (myType) {
806 case FW_NORMAL_POINTER_TYPE:
807 ConsoleMessage ("glVertexAttribPointer Normals %d at %s:%d\n",me->Normals,file,line);
808 break;
809 case FW_VERTEX_POINTER_TYPE:
810 ConsoleMessage ("glVertexAttribPointer Vertexs %d at %s:%d\n",me->Vertices,file,line);
811 break;
812 case FW_COLOR_POINTER_TYPE:
813 ConsoleMessage ("glVertexAttribPointer Colours %d at %s:%d\n",me->Colours,file,line);
814 break;
815 case FW_TEXCOORD_POINTER_TYPE:
816 ConsoleMessage ("glVertexAttribPointer TexCoords %d at %s:%d\n",me->TexCoords,file,line);
817 break;
818
819 default : {ConsoleMessage ("sendAttribToGPU, unknown type in shader\n");}
820 }
821 }
822#endif
823#undef RENDERVERBOSE
824
825 switch (myType) {
826 case FW_NORMAL_POINTER_TYPE:
827 if (me->Normals != -1) {
828 glEnableVertexAttribArray(me->Normals);
829 glVertexAttribPointer(me->Normals, 3, dataType, normalized, stride, pointer);
830 }
831 break;
832 case FW_FOG_POINTER_TYPE:
833 if (me->FogCoords != -1) {
834 glEnableVertexAttribArray(me->FogCoords);
835 glVertexAttribPointer(me->FogCoords, 1, dataType, normalized, stride, pointer);
836 }
837 break;
838
839 case FW_VERTEX_POINTER_TYPE:
840 if (me->Vertices != -1) {
841 glEnableVertexAttribArray(me->Vertices);
842 glVertexAttribPointer(me->Vertices, dataSize, dataType, normalized, stride, pointer);
843 }
844 break;
845 case FW_COLOR_POINTER_TYPE:
846 if (me->Colours != -1) {
847 glEnableVertexAttribArray(me->Colours);
848 glVertexAttribPointer(me->Colours, dataSize, dataType, normalized, stride, pointer);
849 }
850 break;
851 case FW_TEXCOORD_POINTER_TYPE:
852 if (me->TexCoords[texID] != -1) {
853 glEnableVertexAttribArray(me->TexCoords[texID]);
854 glVertexAttribPointer(me->TexCoords[texID], dataSize, dataType, normalized, stride, pointer);
855
856 }
857 break;
858
859 default : {printf ("sendAttribToGPU, unknown type in shader\n");}
860 }
861}
862
863
864void sendBindBufferToGPU (GLenum target, GLuint buffer, char *file, int line) {
865
866
867/*
868 if (target == GL_ARRAY_BUFFER_BINDING) printf ("glBindBuffer, GL_ARRAY_BUFFER_BINDING %d at %s:%d\n",buffer,file,line);
869 else if (target == GL_ARRAY_BUFFER) printf ("glBindBuffer, GL_ARRAY_BUFFER %d at %s:%d\n",buffer,file,line);
870 else if (target == GL_ELEMENT_ARRAY_BUFFER) printf ("glBindBuffer, GL_ELEMENT_ARRAY_BUFFER %d at %s:%d\n",buffer,file,line);
871 else printf ("glBindBuffer, %d %d at %s:%d\n",target,buffer,file,line);
872
873*/
874
875 glBindBuffer(target,buffer);
876}
877
878
879bool setupShader() {
880 return true;
881}
882void sendFogToShader(s_shader_capabilities_t *me);
883void sendClipplanesToShader(s_shader_capabilities_t *me);
884bool setupShaderB() {
885
886 s_shader_capabilities_t *mysp = getAppearanceProperties()->currentShaderProperties;
887
888PRINT_GL_ERROR_IF_ANY("BEGIN setupShader");
889 if (mysp == NULL)
890 return FALSE;
891
892 /* if we had a shader compile problem, do not draw */
893 if (!(mysp->compiledOK)) {
894#ifdef RENDERVERBOSE
895 printf ("shader compile error\n");
896#endif
897 PRINT_GL_ERROR_IF_ANY("EXIT(false) setupShader");
898 return false;
899 }
900
901#ifdef RENDERVERBOSE
902 printf ("setupShader, we have Normals %d Vertices %d Colours %d TexCoords %d \n",
903 mysp->Normals,
904 mysp->Vertices,
905 mysp->Colours,
906 mysp->TexCoords);
907#endif
908
909 /* send along lighting, material, other visible properties */
910 sendFogToShader(mysp);
911 sendClipplanesToShader(mysp);
912 sendMaterialsToShader(mysp);
913 sendMatriciesToShader(mysp);
914
915 return true;
916}
917
918// for particlephysics component we want to be able to do:
919// send vbos to shader/gpu
920// foreach liveparticle
921// send particle-specific age-related color, texcoords, position to gpu
922// drawOnce()
923// clearDraw()
924void saveArraysForGPU(int mode, int first, int count){
925 draw_call_params params;
927 ttglobal tg = gglobal();
928 p = (ppRenderFuncs)tg->RenderFuncs.prv;
929
930 params.calltype = 1;
931 params.arrays.arrays_mode = mode;
932 params.arrays.arrays_count = count;
933 params.arrays.arrays_first = first;
934 stack_push(draw_call_params,p->draw_call_params_stack,params);
935}
936
937
938void saveElementsForGPU(int mode, int count, ushort *indices){
939 //we use a vector/stack because IndexedLineSet and LineSet call several times
940 // for one polyline vbo
941 draw_call_params params;
943 ttglobal tg = gglobal();
944 p = (ppRenderFuncs)tg->RenderFuncs.prv;
945
946 params.calltype = 2;
947 params.elements.elements_count = count;
948 params.elements.elements_mode = mode;
949 params.elements.elements_indices = indices;
950 stack_push(draw_call_params,p->draw_call_params_stack,params);
951}
952
953void reallyDrawOnce(){
954 //particle system will call this
955 //H: this might be a bit like glDrawMultiElements - a list of more primitive triangle fans etc that would make up a 3D shape
956 int i;
957 draw_call_params *params;
959 ttglobal tg = gglobal();
960 p = (ppRenderFuncs)tg->RenderFuncs.prv;
961
962 for(i=0;i<vectorSize(p->draw_call_params_stack);i++){
963 params = vector_get_ptr(draw_call_params,p->draw_call_params_stack,i);
964 if(params->calltype == 1){
965 // in msvc you can do try catch in flat C, but not recommended in general - use c++
966 // but works when testing/debugging if the video driver is throwing c++ exceptions
967 // because we're sending it junk, to stop it from vapor-crashing
968 // https://msdn.microsoft.com/en-us/library/1deeycx5.aspx
969 #define CATCH_GLDRAWARRAYS_THROWS 1
970 #if defined(CATCH_GLDRAWARRAYS_THROWS) && defined(_MSC_VER) && defined(W_DEBUG)
971 __try {
972 glDrawArrays(params->arrays.arrays_mode,params->arrays.arrays_first,params->arrays.arrays_count);
973 }
974 __except(EXCEPTION_EXECUTE_HANDLER) {
975 printf("\n ouch from reallyDrawOnce glDrawArrays \n");
976 printf("i= %d n= %d",i,vectorSize(p->draw_call_params_stack));
977 }
978 #else
979 glDrawArrays(params->arrays.arrays_mode,params->arrays.arrays_first,params->arrays.arrays_count);
980 #endif
981 }else if(params->calltype == 2){
982 glDrawElements(params->elements.elements_mode,params->elements.elements_count,GL_UNSIGNED_SHORT,params->elements.elements_indices);
983 }
984 }
985 //p->draw_call_params_stack->n = 0;
986}
987void clearDraw(){
988 // particlesystem will call this
990 ttglobal tg = gglobal();
991 p = (ppRenderFuncs)tg->RenderFuncs.prv;
992 p->draw_call_params_stack->n = 0;
993}
994void reallyDraw(){
995 //child_Shape will call this
996 reallyDrawOnce();
997 clearDraw();
998}
999void sendArraysToGPU (int mode, int first, int count) {
1000 #ifdef RENDERVERBOSE
1001 printf ("sendArraysToGPU start\n");
1002 #endif
1003
1004
1005 // when glDrawArrays bombs it's usually some function left an array
1006 // enabled that's not supposed to be - try disabling something
1007 //glDisableClientState(GL_VERTEX_ARRAY);
1008 //glDisableClientState(GL_NORMAL_ARRAY);
1009 //glDisableClientState(GL_INDEX_ARRAY);
1010 //glDisableClientState(GL_COLOR_ARRAY);
1011 //glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
1012 //glDisableClientState(GL_FOG_COORDINATE_ARRAY);
1013 //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1014 //glDisableClientState(GL_EDGE_FLAG_ARRAY);
1015
1016 if (setupShader()){
1017 profile_start("draw_arr");
1018// glDrawArrays(mode,first,count);
1019 saveArraysForGPU(mode,first,count);
1020 profile_end("draw_arr");
1021 }
1022 #ifdef RENDERVERBOSE
1023 printf ("sendArraysToGPU end\n");
1024 #endif
1025}
1026
1027
1028
1029void sendElementsToGPU (int mode, int count, ushort *indices) {
1030 #ifdef RENDERVERBOSE
1031 printf ("sendElementsToGPU start\n");
1032 #endif
1033
1034 if (setupShader()){
1035 profile_start("draw_el");
1036// glDrawElements(mode,count,GL_UNSIGNED_SHORT,indices);
1037 saveElementsForGPU(mode,count,indices);
1038 profile_end("draw_el");
1039 }
1040
1041 #ifdef RENDERVERBOSE
1042 printf ("sendElementsToGPU finish\n");
1043 #endif
1044}
1045
1046
1047void initializeLightTables() {
1048 int i;
1049 float pos[] = { 0.0f, 0.0f, 1.0f, 0.0f };
1050 float dif[] = { 1.0f, 1.0f, 1.0f, 1.0f };
1051 float shin[] = { 0.0f, 0.0f, 0.0f, 1.0f }; /* light defaults - headlight is here, too */
1052 float As[] = { 0.0f, 0.0f, 0.0f, 1.0f };
1053 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1054
1055 PRINT_GL_ERROR_IF_ANY("start of initializeightTables");
1056
1057 for(i=0; i<MAX_LIGHT_STACK; i++) {
1058 p->lightOnOff[i] = TRUE;
1059 setLightState(i,FALSE);
1060
1061 FW_GL_LIGHTFV(i, GL_SPOT_DIRECTION, pos);
1062 FW_GL_LIGHTFV(i, GL_POSITION, pos);
1063 FW_GL_LIGHTFV(i, GL_AMBIENT, As);
1064 FW_GL_LIGHTFV(i, GL_DIFFUSE, dif);
1065 FW_GL_LIGHTFV(i, GL_SPECULAR, shin);
1066 FW_GL_LIGHTF(i, GL_CONSTANT_ATTENUATION,1.0f);
1067 FW_GL_LIGHTF(i, GL_LINEAR_ATTENUATION,0.0f);
1068 FW_GL_LIGHTF(i, GL_QUADRATIC_ATTENUATION,0.0f);
1069 FW_GL_LIGHTF(i, GL_SPOT_CUTOFF,0.0f);
1070 FW_GL_LIGHTF(i, GL_SPOT_BEAMWIDTH,0.0f);
1071 FW_GL_LIGHTF(i, GL_LIGHT_RADIUS, 100000.0); /* just make it large for now*/
1072
1073 PRINT_GL_ERROR_IF_ANY("initizlizeLight2.10");
1074 }
1075 setLightState(HEADLIGHT_LIGHT, TRUE);
1076
1077 LIGHTING_INITIALIZE
1078
1079
1080 PRINT_GL_ERROR_IF_ANY("end initializeLightTables");
1081}
1082
1083
1084ttrenderstate renderstate()
1085{
1086 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1087 return &p->renderstate;
1088}
1089
1090
1091//true statics:
1092GLint viewport[4] = {-1,-1,2,2}; //pseudo-viewport - doesn't change, used in glu unprojects
1093/* These two points (r2,r1) define a ray in pick-veiwport window coordinates
1094 r2=viewpoint
1095 r1=ray from center of pick-viewport in viewport coordinates
1096 - in setup_pickray(pick=TRUE,,) the projMatrix is modified for the pick-ray-viewport
1097 - when unprojecting geometry-local xyz to bearing-local/pick-viewport-local, use pseudo-viewport defined above
1098*/
1099struct point_XYZ r1 = {0,0,-1}, r2 = {0,0,0}, r3 = {0,1,0}; //r3 y direction in case needed for testing
1100
1101
1102struct X3D_Anchor *AnchorsAnchor()
1103{
1104 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1105 return p->AnchorsAnchor;
1106}
1107void setAnchorsAnchor(struct X3D_Anchor* anchor)
1108{
1109 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1110 p->AnchorsAnchor = anchor;
1111}
1112
1113
1114//static struct currayhit rayph;
1115//struct currayhit rayHit,rayHitHyper;
1116/* used to test new hits */
1117
1118
1119
1120//struct X3D_Group *_rootNode=NULL; /* scene graph root node */
1121struct X3D_Node *rootNode()
1122{
1123 // ConsoleMessage ("rootNode called");
1124 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1125 if (p==NULL) {
1126 ConsoleMessage ("rootNode, p null");
1127 return NULL;
1128 }
1129 return p->rootNode;
1130}
1131void setRootNode(struct X3D_Node *rn)
1132{
1133 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1134 p->rootNode = rn;
1135}
1136//struct Vector *libraries(){
1137// ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1138// if(!p->libraries) p->libraries = newVector(void3 *,1) ;
1139// return p->libraries;
1140//}
1141//void setLibraries(struct Vector *libvector){
1142// //might use this in KILL_oldWorld to NULL the library vector?
1143// ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1144// p->libraries = libvector;
1145//}
1146void addLibrary(char *url, struct X3D_Proto *library, void *res){
1147 void3 *ul = MALLOC(void3 *,sizeof(void3));
1148 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1149 ul->one = (void *)STRDUP(url);
1150 ul->two = (void *)library;
1151 ul->three = res;
1152 vector_pushBack(void3 *,p->libraries,ul);
1153}
1154void3 *librarySearch(char *absoluteUniUrlNoPound){
1155 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
1156 void3 *ul;
1157 struct Vector* libs;
1158 int n, i;
1159 libs = p->libraries;
1160 n = vectorSize(libs);
1161 for(i=0;i<n;i++){
1162 ul = vector_get(void3 *,libs,i);
1163 if(ul)
1164 if(!strcmp(absoluteUniUrlNoPound,ul->one)){
1165 return ul; //return res
1166 }
1167 }
1168 return NULL;
1169}
1170
1171//void *empty_group=0;
1172
1173/*******************************************************************************/
1174
1175
1176
1177void prepare_model_view_pickmatrix0(GLDOUBLE *modelMatrix, GLDOUBLE *mvp){
1178 //prepares a matrix that will transform a point in geometry-local coordintes
1179 //into eye/pickray/bearing coordinates ie along the pickray 0,0,1
1180 GLDOUBLE *pickMatrixi;
1181
1182 pickMatrixi = getPickrayMatrix(1);
1183
1184 //pickMatrix is inverted in setup_pickray
1185 matmultiplyAFFINE(mvp,modelMatrix,pickMatrixi);
1186
1187}
1188void prepare_model_view_pickmatrix_inverse0(GLDOUBLE *modelMatrix, GLDOUBLE *mvpi){
1189 //prepares a matrix that will transform a point in eye/pickray/bearing coords ie 0,0,1
1190 //into geometry-local coordinates, given the modelMatrix to transform
1191 // eye/pickray -> geometry-local
1192 GLDOUBLE mvi[16];
1193 GLDOUBLE *pickMatrix;
1194
1195 pickMatrix = getPickrayMatrix(0);
1196
1197 //pickMatrix is not inverted in setup_pickray
1198 matinverseAFFINE(mvi,modelMatrix);
1199 matmultiplyAFFINE(mvpi,pickMatrix,mvi);
1200}
1201
1202
1203/* rayhit
1204 For PointingDeviceSensor component work, called from virt->rendray_<Shape> on VF_Sensitive pass
1205 - tests if this ray-geometry intersection is closer to the viewpoint than the closest one so far
1206 - if not it means it is occluded, do nothing
1207 - if so
1208 -- updates the closest distance to intersection of pick-ray/bearing with scene geometry so far
1209 How:
1210 - the calling rendray_<geometry> function already has the pickray/bearing in its geometry-local
1211 coordinates, and computes the distance from A as rat and passes it in here.
1212 - this makes sure its on the B side of A (otherwise its behind the pickray/viewpoint)
1213 - if its the closest intersection of pickray with scene geometry so far:
1214 1.records the point, in bearing-local coordinates
1215 a) for non-sensitive geometry: the point is used to occlude picksensors by being closer to the viewpoint/bearing A
1216 b) for <Drag>Sensor and TouchSensor, if the point succeeds as the closest point
1217 at end of VF_Sensitive pass, the point will be transformed from bearing-local to sensor-local
1218 to generate eventOuts in do_<>Sensor in sensor-local coordinates
1219 2.snapshots the sensor's modelview matrix for later use
1220
1221 */
1222void rayhit(float rat, float cx,float cy,float cz, float nx,float ny,float nz,
1223 float tx,float ty, char *descr) {
1224 GLDOUBLE modelMatrix[16];
1225 ppRenderFuncs p;
1226 ttglobal tg = gglobal();
1227 p = (ppRenderFuncs)tg->RenderFuncs.prv;
1228
1229 /* Real rat-testing */
1230#ifdef RENDERVERBOSE
1231 //printf("RAY HIT %s! %f (%f %f %f) (%f %f %f)\n\tR: (%f %f %f) (%f %f %f)\n",
1232 // descr, rat,cx,cy,cz,nx,ny,nz,
1233 // t_r1.x, t_r1.y, t_r1.z,
1234 // t_r2.x, t_r2.y, t_r2.z
1235 // );
1236#endif
1237
1238 if(rat<0 || (rat>tg->RenderFuncs.hitPointDist && tg->RenderFuncs.hitPointDist >= 0)) {
1239 return;
1240 }
1241 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix); //snapshot of geometry's modelview matrix
1242 {
1243 GLDOUBLE mvp[16];
1244 struct point_XYZ tp; //note viewpoint/avatar Z=1 behind the viewer, to match the glu_unproject method WinZ = -1
1245 tp.x = cx; tp.y = cy; tp.z = cz;
1246 prepare_model_view_pickmatrix0(modelMatrix,mvp);
1247 transform(&tp,&tp,mvp);
1248 p->hp = tp;
1249 }
1250 tg->RenderFuncs.hitPointDist = rat;
1251 p->rayHit=p->rayph;
1252#ifdef RENDERVERBOSE
1253 printf ("Rayhit, hp.x y z: - %f %f %f hitPointDist %f %s\n",p->hp.x,p->hp.y,p->hp.z, rat, descr);
1254#endif
1255}
1256
1257/* Call this when modelview and projection modified
1258 keeps bearing/pick-ray transformed into current geometry-local
1259 for use in virt->rendray_<geometry> calculations, on VF_Sensitive pass
1260 bearing-local == pick-viewport-local
1261*/
1262void upd_ray0(struct point_XYZ *t_r1, struct point_XYZ *t_r2, struct point_XYZ *t_r3) {
1263 //struct point_XYZ t_r1,t_r2,t_r3;
1264 GLDOUBLE modelMatrix[16];
1265 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1266/*
1267{int i; printf ("\n");
1268printf ("upd_ray, pm %p\n",projMatrix);
1269for (i=0; i<16; i++) printf ("%4.3lf ",modelMatrix[i]); printf ("\n");
1270for (i=0; i<16; i++) printf ("%4.3lf ",projMatrix[i]); printf ("\n");
1271}
1272*/
1273
1274 {
1275 //feature-AFFINE_GLU_UNPROJECT
1276 //FLOPs 112 double: matmultiplyAFFINE 36, matinverseAFFINE 49, 3x transform (affine) 9 =27
1277 GLDOUBLE mvpi[16]; //mvp[16],
1278 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
1279 {
1280 //PointSensor needs an original camera axis (not modified pickray camera)
1281 // to use as a plane normal to intersect the pickray/bearing with
1282 ttglobal tg;
1283 double mvi[16];
1284 struct point_XYZ view_cam_axis, local_cam_axis;
1285 tg = gglobal();
1286 view_cam_axis.x = 0.0;
1287 view_cam_axis.y = 0.0;
1288 view_cam_axis.z = -1.0;
1289 matinverseAFFINE(mvi,modelMatrix);
1290 transformAFFINE(&local_cam_axis,&view_cam_axis,mvi);
1291 tg->RenderFuncs.camera_axis[0] = local_cam_axis.x;
1292 tg->RenderFuncs.camera_axis[1] = local_cam_axis.y;
1293 tg->RenderFuncs.camera_axis[2] = local_cam_axis.z;
1294
1295 }
1296 prepare_model_view_pickmatrix_inverse0(modelMatrix, mvpi);
1297 transform(t_r1,&r11,mvpi);
1298 transform(t_r2,&r2,mvpi);
1299 transform(t_r3,&r3,mvpi);
1300 //r2 is A, r1 is B relative to A in pickray [A,B)
1301 //we prove it here by moving B along the ray, to distance 1.0 from A, and no change to picking
1302 //if(0){
1303 // vecdiff(t_r1,t_r1,t_r2);
1304 // vecnormal(t_r1,t_r1);
1305 // vecadd(t_r1,t_r1,t_r2);
1306 //}
1307 //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);
1308 }
1309}
1310void setup_pickray0();
1311void upd_ray() {
1312 ppRenderFuncs p;
1313 ttglobal tg = gglobal();
1314 p = (ppRenderFuncs)tg->RenderFuncs.prv;
1315
1316 setup_pickray0();
1317 upd_ray0(&p->t_r123.p1,&p->t_r123.p2,&p->t_r123.p3);
1318 /*
1319 printf("Upd_ray: (%f %f %f)->(%f %f %f) == (%f %f %f)->(%f %f %f)\n",
1320 r1.x,r1.y,r1.z,r2.x,r2.y,r2.z,
1321 t_r1.x,t_r1.y,t_r1.z,t_r2.x,t_r2.y,t_r2.z);
1322 */
1323
1324}
1325void transformMBB(GLDOUBLE *rMBBmin, GLDOUBLE *rMBBmax, GLDOUBLE *matTransform, GLDOUBLE* inMBBmin, GLDOUBLE* inMBBmax);
1326int pickrayHitsMBB(struct X3D_Node *node){
1327 //GOAL: on a render_hier(VF_sensitive) (touch sensor) pass, before checking the ray against geometry, check first if the
1328 //ray goes through the extent / minimum-bounding-box (MBB) of the shape. If not, no need to check the ray
1329 //against all the shape's triangles, speeding up the VF_Sensitive pass.
1330 //FLOPs 156 double: matmultiplyAffine 36, matInversAffine 48, transformAffine 8 pts x 12= 72
1331 GLDOUBLE modelMatrix[16];
1332 int i, isIn;
1333 //if using new Sept 2014 pickmatrix, we can test the pickray against the shape node's bounding box
1334 //and if no hit, then no need to run through rendray testing all triangles
1335 //feature-AFFINE_GLU_UNPROJECT
1336 //FLOPs 112 double: matmultiplyAFFINE 36, matinverseAFFINE 49, 3x transform (affine) 9 =27
1337 GLDOUBLE mvp[16]; //, mvpi[16];
1338 GLDOUBLE smin[3], smax[3], shapeMBBmin[3], shapeMBBmax[3];
1339 int retval;
1340 retval = TRUE;
1341
1342 //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
1343 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1344
1345 prepare_model_view_pickmatrix0(modelMatrix, mvp);
1346 /* generate mins and maxes for avatar cylinder in avatar space to represent the avatar collision volume */
1347 for(i=0;i<3;i++)
1348 {
1349 shapeMBBmin[i] = node->_extent[i*2 + 1];
1350 shapeMBBmax[i] = node->_extent[i*2];
1351 }
1352 transformMBB(smin,smax,mvp,shapeMBBmin,shapeMBBmax); //transform shape's MBB into pickray space
1353 // the pickray is now at 0,0,x
1354 isIn = TRUE;
1355 for(i=0;i<2;i++)
1356 isIn = isIn && (smin[i] <= 0.0 && smax[i] >= 0.0);
1357 retval = isIn;
1358 //printf("%d x %f %f y %f %f\n",isIn,smin[0],smax[0],smin[1],smax[1]);
1359 //retval = 1;
1360
1361 return retval;
1362}
1363
1364
1365
1366
1367/* if a node changes, void the display lists */
1368/* Courtesy of Jochen Hoenicke */
1369
1370void update_node(struct X3D_Node *node) {
1371 int i;
1372
1373#ifdef VERBOSE
1374 printf ("update_node for %d %s nparents %d renderflags %x\n",node, stringNodeType(node->_nodeType),node->_nparents, node->_renderFlags);
1375 if (node->_nparents == 0) {
1376 if (node == rootNode) printf ("...no parents, this IS the rootNode\n");
1377 else printf ("...no parents, this IS NOT the rootNode\n");
1378 }
1379
1380
1381
1382 for (i = 0; i < node->_nparents; i++) {
1383 struct X3D_Node *n = X3D_NODE(node->_parents[i]);
1384 if( n != 0 ) {
1385 printf (" parent %u is %s\n",n,stringNodeType(n->_nodeType));
1386 } else {
1387 printf (" parent %d is NULL\n",i);
1388 }
1389 }
1390#endif
1391
1392 node->_change ++;
1393
1394 /* parentVector here yet?? */
1395 if (node->_parentVector == NULL) {
1396 return;
1397 }
1398
1399 for (i = 0; i < vectorSize(node->_parentVector); i++) {
1400 struct X3D_Node *n = vector_get(struct X3D_Node *, node->_parentVector,i);
1401 if(n == node) {
1402 fprintf(stderr, "Error: self-referential node structure! (node:'%s')\n", stringNodeType(node->_nodeType));
1403 vector_set(struct X3D_Node*, node->_parentVector, i,NULL);
1404 } else if( n != 0 ) {
1405 update_node(n);
1406 }
1407 }
1408}
1409
1410/*********************************************************************
1411 *********************************************************************
1412 *
1413 * render_node : call the correct virtual functions to render the node
1414 * depending on what we are doing right now.
1415 */
1416
1417//#ifdef RENDERVERBOSE
1418//static int renderLevel = 0;
1419//#endif
1420
1421#define PRINT_NODE(_node, _v) do { \
1422 if (gglobal()->internalc.global_print_opengl_errors && (gglobal()->display._global_gl_err != GL_NO_ERROR)) { \
1423 printf("Render_node_v %p (%s) PREP: %p REND: %p CH: %p FIN: %p RAY: %p HYP: %p\n",_v, \
1424 stringNodeType(_node->_nodeType), \
1425 _v->prep, \
1426 _v->rend, \
1427 _v->children, \
1428 _v->fin, \
1429 _v->rendray, \
1430 gglobal()->RenderFuncs.hypersensitive); \
1431 printf("Render_state geom %d light %d sens %d\n", \
1432 renderstate()->render_geom, \
1433 renderstate()->render_light, \
1434 renderstate()->render_sensitive); \
1435 printf("pchange %d pichange %d \n", _node->_change, _node->_ichange); \
1436 } \
1437 } while (0)
1438
1439//static int renderLevel = 0;
1440//#define RENDERVERBOSE
1441
1442
1443/* poor-man's performance profiler:
1444 wrap a section of code like this
1445 profile_start("section1");
1446 ...code...
1447 profile_end("section1");
1448 then let the browser loop for 10 seconds
1449 and hit period '.' on the keyboard to get a printout
1450*/
1451
1452void profile_start(char *name){
1453 ppRenderFuncs p;
1454 struct profile_entry *pe;
1455 int i, ifound = -1;
1456 ttglobal tg = gglobal();
1457 p = (ppRenderFuncs)tg->RenderFuncs.prv;
1458
1459 if (!p->profiling_on) return;
1460 pe = p->profile_entries;
1461
1462 for(i=0;i<p->profile_entry_count;i++){
1463 if(!strcmp(name,pe[i].name)){
1464 ifound = i;
1465 break;
1466 }
1467 }
1468 if(ifound == -1){
1469 pe[p->profile_entry_count].name = name;
1470 pe[p->profile_entry_count].hits = 0;
1471 ifound = p->profile_entry_count;
1472 p->profile_entry_count++;
1473 }
1474 pe[ifound].start = Time1970sec();
1475}
1476void profile_end(char *name){
1477 ppRenderFuncs p;
1478 struct profile_entry *pe;
1479 int i, ifound = -1;
1480 ttglobal tg = gglobal();
1481 p = (ppRenderFuncs)tg->RenderFuncs.prv;
1482
1483 if (!p->profiling_on) return;
1484 pe = p->profile_entries;
1485 for(i=0;i<p->profile_entry_count;i++){
1486 if(!strcmp(name,pe[i].name)){
1487 ifound = i;
1488 break;
1489 }
1490 }
1491 if(ifound > -1){
1492 pe[ifound].accum += Time1970sec() - pe[ifound].start;
1493 pe[ifound].hits++;
1494 }
1495}
1496void profile_print_all(){
1497 //hit '.' in the graphics window to get here
1498 ppRenderFuncs p;
1499 struct profile_entry *pe;
1500 ttglobal tg = gglobal();
1501 p = (ppRenderFuncs)tg->RenderFuncs.prv;
1502 if (!p->profiling_on){
1503 p->profiling_on = 1;
1504 ConsoleMessage("turning profiling on\n");
1505 }else{
1506 int i;
1507 pe = p->profile_entries;
1508 ConsoleMessage("frame rate: %9.3f number of items tracked: %d\n", gglobal()->Mainloop.BrowserFPS,p->profile_entry_count);
1509 ConsoleMessage("%15s %10s %15s %10s\n", "profile name", "hits", "time(sec)", "% of 1st");
1510 for (i = 0; i < p->profile_entry_count; i++){
1511 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);
1512 }
1513 }
1514}
1515
1516
1517//unsigned int getShaderFlags(){
1518shaderflagsstruct getShaderFlags(){
1519 //return top-of-stack global shaderflags
1520 //unsigned int retval;
1521 shaderflagsstruct retval;
1522 ttglobal tg = gglobal();
1523 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1524 //retval = stack_top(unsigned int,p->shaderflags_stack);
1525 retval = stack_top(shaderflagsstruct,p->shaderflags_stack);
1526 return retval;
1527}
1528void pushShaderFlags(shaderflagsstruct flags){ //unsigned int flags){
1529 //at root level, before render_hier, you would push 0000000
1530 //and pop after render_hier
1531 //for prep_LocalFog you would call this to push (and pop in fin_LocalFog)
1532 //these flags are for non-leaf-node shader influencers
1533 //localLights, localFog, clipPlane
1534 //and will be |= with shape->_shaderTableEntry flags in child_shape
1535 ttglobal tg = gglobal();
1536 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1537 //stack_push(unsigned int,p->shaderflags_stack,flags);
1538 stack_push(shaderflagsstruct,p->shaderflags_stack,flags);
1539
1540}
1541void popShaderFlags(){
1542 //
1543 ttglobal tg = gglobal();
1544 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1545 //stack_pop(unsigned int,p->shaderflags_stack);
1546 stack_pop(shaderflagsstruct,p->shaderflags_stack);
1547
1548}
1549struct X3D_Node *getFogParams(){
1550 //return top-of-stack Fog or LocalFog
1551 struct X3D_Node *retval = NULL;
1552 ttglobal tg = gglobal();
1553 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1554 if(p->fog_stack->n)
1555 retval = stack_top(struct X3D_Node*,p->fog_stack);
1556 return retval;
1557}
1558void pushFogParams(struct X3D_Node *fogparams){
1559 //at root level, before render_hier, any bound Fog node
1560 //and pop after render_hier
1561 //for prep_LocalFog you would call this to push (and pop in fin_LocalFog)
1562 ttglobal tg = gglobal();
1563 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1564 stack_push(struct X3D_Node*,p->fog_stack,fogparams);
1565
1566}
1567void popFogParams(){
1568 //
1569 ttglobal tg = gglobal();
1570 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1571 stack_pop(struct X3D_Node*,p->fog_stack);
1572
1573}
1574//struct point_XYZ3 {
1575// struct point_XYZ p1;
1576// struct point_XYZ p2;
1577// struct point_XYZ p3;
1578//};
1579void push_ray(){
1580 //upd_ray();
1581 //struct point_XYZ t_r1,t_r2,t_r3;
1582 //struct point_XYZ3 r123;
1583 ttglobal tg = gglobal();
1584 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1585 //r123.p1 = tg->RenderFuncs.t_r1;
1586 //r123.p2 = tg->RenderFuncs.t_r2;
1587 //r123.p3 = tg->RenderFuncs.t_r3;
1588
1589 //stack_push(struct point_XYZ3,p->ray_stack,r123);
1590 stack_push(struct point_XYZ3,p->ray_stack,p->t_r123);
1591
1592 //upd_ray0(&t_r1,&t_r2,&t_r3);
1593 //VECCOPY(tg->RenderFuncs.t_r1,t_r1);
1594 //VECCOPY(tg->RenderFuncs.t_r2,t_r2);
1595 //VECCOPY(tg->RenderFuncs.t_r3,t_r3);
1596 upd_ray0(&p->t_r123.p1,&p->t_r123.p2,&p->t_r123.p3);
1597
1598}
1599void pop_ray(){
1600 //struct point_XYZ t_r1,t_r2,t_r3;
1601 //struct point_XYZ3 r123;
1602 ttglobal tg = gglobal();
1603 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1604 //upd_ray();
1605 //r123 = stack_top(struct point_XYZ3,p->ray_stack);
1606 stack_pop(struct point_XYZ3,p->ray_stack);
1607 p->t_r123 = stack_top(struct point_XYZ3,p->ray_stack);
1608 //stack_pop(struct point_XYZ3,p->ray_stack);
1609 //tg->RenderFuncs.t_r1 = r123.p1;
1610 //tg->RenderFuncs.t_r2 = r123.p2;
1611 //tg->RenderFuncs.t_r3 = r123.p3;
1612
1613}
1614void get_current_ray(struct point_XYZ* p1, struct point_XYZ* p2){
1615 ttglobal tg = gglobal();
1616 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1617 *p1 = p->t_r123.p1;
1618 *p2 = p->t_r123.p2;
1619}
1620void push_render_geom(int igeom){
1621 ttglobal tg = gglobal();
1622 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1623 stack_push(int,p->render_geom_stack,p->renderstate.render_geom);
1624 p->renderstate.render_geom = igeom;
1625}
1626void pop_render_geom(){
1627 int igeom;
1628 ttglobal tg = gglobal();
1629 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1630 igeom = stack_top(int,p->render_geom_stack);
1631 stack_pop(int,p->render_geom_stack);
1632 p->renderstate.render_geom = igeom;
1633}
1634void push_sensor(struct X3D_Node *node){
1635 ttglobal tg = gglobal();
1636 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1637
1638 push_render_geom(1);
1639 stack_push(struct currayhit,p->sensor_stack,p->rayph);
1640 //srh = MALLOC(struct currayhit *,sizeof(struct currayhit));
1642 //memcpy(srh,&p->rayph,sizeof(struct currayhit));
1643 p->rayph.hitNode = node; //will be the parent Transform or Group to a PointingDevice (Touch,Drag) Sensor node
1644 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, p->rayph.modelMatrix); //snapshot of sensor's modelview matrix
1645 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, p->rayph.projMatrix);
1646 //PRINT_GL_ERROR_IF_ANY("render_sensitive"); PRINT_NODE(node,virt);
1647}
1648void pop_sensor(){
1649 ttglobal tg = gglobal();
1650 ppRenderFuncs p = (ppRenderFuncs)tg->RenderFuncs.prv;
1651
1652 //memcpy(&p->rayph,srh,sizeof(struct currayhit));
1653 //FREE_IF_NZ(srh);
1654 p->rayph = stack_top(struct currayhit,p->sensor_stack);
1655 stack_pop(struct currayhit,p->sensor_stack);
1656 pop_render_geom();
1657
1658}
1659int getWindex();
1660int render_foundLayerViewpoint();
1661void extent6f_draw(float *extent);
1662static int draw_extents = TRUE;
1663void render_node(struct X3D_Node *node) {
1664 struct X3D_Virt *virt;
1665
1666 //int srg = 0;
1667 //int sch = 0;
1668 int justGeom = 0;
1669 int pushed_ray;
1670 int pushed_sensor;
1671 //struct currayhit *srh = NULL;
1672 ppRenderFuncs p;
1673 ttglobal tg = gglobal();
1674 p = (ppRenderFuncs)tg->RenderFuncs.prv;
1675
1676 X3D_NODE_CHECK(node);
1677//#define RENDERVERBOSE 1
1678#ifdef RENDERVERBOSE
1679 p->renderLevel ++;
1680#endif
1681
1682 if(!node) {
1683#ifdef RENDERVERBOSE
1684 DEBUG_RENDER("%d no node, quick return\n", renderLevel);
1685 p->renderLevel--;
1686#endif
1687 return;
1688 }
1689 virt = virtTable[node->_nodeType];
1690
1691#ifdef RENDERVERBOSE
1692 //printf("%d =========================================NODE RENDERED===================================================\n",renderLevel);
1693 {
1694 int i;
1695 for(i=0;i<p->renderLevel;i++) printf(" ");
1696 }
1697 printf("%d node %u (%s) , v %u renderFlags %x ",p->renderLevel, node,stringNodeType(node->_nodeType),virt,node->_renderFlags);
1698
1699 if ((node->_renderFlags & VF_Viewpoint) == VF_Viewpoint) printf (" VF_Viewpoint");
1700 if ((node->_renderFlags & VF_Geom )== VF_Geom) printf (" VF_Geom");
1701 if ((node->_renderFlags & VF_localLight )== VF_localLight) printf (" VF_localLight");
1702 if ((node->_renderFlags & VF_Sensitive) == VF_Sensitive) printf (" VF_Sensitive");
1703 if ((node->_renderFlags & VF_Blend) == VF_Blend) printf (" VF_Blend");
1704 if ((node->_renderFlags & VF_Proximity) == VF_Proximity) printf (" VF_Proximity");
1705 if ((node->_renderFlags & VF_Collision) == VF_Collision) printf (" VF_Collision");
1706 if ((node->_renderFlags & VF_globalLight) == VF_globalLight) printf (" VF_globalLight");
1707 if ((node->_renderFlags & VF_hasVisibleChildren) == VF_hasVisibleChildren) printf (" VF_hasVisibleChildren");
1708 if ((node->_renderFlags & VF_shouldSortChildren) == VF_shouldSortChildren) printf (" VF_shouldSortChildren");
1709 if ((node->_renderFlags & VF_Other) == VF_Other) printf (" VF_Other");
1710 /*
1711 if ((node->_renderFlags & VF_inPickableGroup == VF_inPickableGroup) printf (" VF_inPickableGroup");
1712 if ((node->_renderFlags & VF_PickingSensor == VF_PickingSensor) printf (" VF_PickingSensor");
1713 */
1714 printf ("\n");
1715
1716 //printf("PREP: %d REND: %d CH: %d FIN: %d RAY: %d HYP: %d\n",virt->prep, virt->rend, virt->children, virt->fin,
1717 // virt->rendray, hypersensitive);
1718 //printf("%d state: vp %d geom %d light %d sens %d blend %d prox %d col %d ", renderLevel,
1719 // render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision);
1720 //printf("change %d ichange %d \n",node->_change, node->_ichange);
1721#endif
1722
1723
1724
1725 // leaf-node filtering (we still do the transform-children stack)
1726 // if we are doing Viewpoints, and we don't have a Viewpoint, don't bother doing anything here *
1727 //if (renderstate()->render_vp == VF_Viewpoint) {
1728 if (p->renderstate.render_vp == VF_Viewpoint) {
1729 //if(tg->Bindable.activeLayer == 0) //no Layerset nodes
1730 if ((node->_renderFlags & VF_Viewpoint) != VF_Viewpoint) {
1731 #ifdef RENDERVERBOSE
1732 printf ("doing Viewpoint, but this node is not for us - just returning\n");
1733 p->renderLevel--;
1734 #endif
1735 return;
1736 }
1737 if(p->renderstate.render_vp == VF_Viewpoint && render_foundLayerViewpoint()){
1738 //on vp pass, just find first DEF/USE of bound viewpoint
1739 return;
1740 }
1741 }
1742
1743 /* are we working through global PointLights, DirectionalLights or SpotLights, but none exist from here on down? */
1744 if (p->renderstate.render_light ) {
1745 if((node->_renderFlags & VF_globalLight) != VF_globalLight) {
1746 #ifdef RENDERVERBOSE
1747 printf ("doing globalLight, but this node is not for us - just returning\n");
1748 p->renderLevel--;
1749 #endif
1750 return;
1751 }
1752 }
1753 justGeom = p->renderstate.render_geom && !p->renderstate.render_sensitive && !p->renderstate.render_blend;
1754 pushed_ray = FALSE;
1755 pushed_sensor = FALSE;
1756
1757 if(virt->prep) {
1758 //transform types will pushmatrix and multiply in their translation.rotation,scale here (and popmatrix in virt->fin)
1759 DEBUG_RENDER("rs 2\n");
1760 profile_start("prep");
1761 if(justGeom)
1762 profile_start("prepgeom");
1763 virt->prep(node);
1764 profile_end("prep");
1765 if(justGeom)
1766 profile_end("prepgeom");
1767 //if(p->renderstate.render_sensitive && !tg->RenderFuncs.hypersensitive) {
1768 // push_ray(); //upd_ray();
1769 // pushed_ray = TRUE;
1770 //}
1771 PRINT_GL_ERROR_IF_ANY("prep"); PRINT_NODE(node,virt);
1772 if(p->renderstate.render_boxes) extent6f_draw(node->_extent);
1773
1774 }
1775 if(p->renderstate.render_sensitive && !tg->RenderFuncs.hypersensitive) {
1776 push_ray(); //upd_ray();
1777 pushed_ray = TRUE;
1778 }
1779 if(p->renderstate.render_proximity && virt->proximity) {
1780 DEBUG_RENDER("rs 2a\n");
1781 profile_start("proximity");
1782 virt->proximity(node);
1783 profile_end("proximity");
1784 PRINT_GL_ERROR_IF_ANY("render_proximity"); PRINT_NODE(node,virt);
1785 }
1786 if(p->renderstate.render_geom && ((node->_renderFlags & VF_USE) == VF_USE) && !p->renderstate.render_picking){
1787 //picking sensor, transform sensor and generally any USE_NODE-USE_NODE scenario
1788 //ideally we would come in here once per scenegraph USE per frame, even when stereo or quad views
1789 //because we want to work in world coordinates (not view coordinates) so by the time
1790 //we strip off the view matrix we would have duplicate entries with stereo
1791 if(getWindex() == 0){
1792 //just on first window of stereo or quad
1793 //we don't do this in VF_Proximity because that pass doesn't go all the way to all geom nodes
1794 //we could give it its own pass, but doing just the first window is a simple hack.
1795 double modelviewMatrix[16];
1796 //IF VIEW == 0
1797 //GL_GET_MODELVIEWMATRIX
1798 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1799 //strip viewmatrix - will happen when we invert one of the USEUSE pair, and multiply
1800 usehit_add2(node,modelviewMatrix,getpickablegroupdata());
1801 }
1802 }
1803 if(p->renderstate.render_picking && node->_nodeType == NODE_Shape ){
1804 //this is for when called from Component_Picking.c on a partial scenegraph,
1805 //to get geometry nodes in the usehitB list
1806 //I put vrit->rendray as a way to detect if its geometry, is there a better way?
1807 double modelviewMatrix[16];
1808 struct X3D_Shape *shapenode = (struct X3D_Shape*)node;
1809 if(shapenode->geometry){
1810 //IF VIEW == 0
1811 //GL_GET_MODELVIEWMATRIX
1812 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
1813 //strip viewmatrix - will happen when we invert one of the USEUSE pair, and multiply
1814 usehitB_add2(shapenode->geometry,modelviewMatrix,getpickablegroupdata());
1815 }
1816 }
1817
1818 if(p->renderstate.render_collision && virt->collision) {
1819 DEBUG_RENDER("rs 2b\n");
1820 profile_start("collision");
1821 virt->collision(node);
1822 profile_end("collision");
1823 PRINT_GL_ERROR_IF_ANY("render_collision"); PRINT_NODE(node,virt);
1824 }
1825
1826 if(p->renderstate.render_geom && !p->renderstate.render_sensitive && !p->renderstate.render_picking && virt->rend) {
1827 DEBUG_RENDER("rs 3\n");
1828 PRINT_GL_ERROR_IF_ANY("BEFORE render_geom"); PRINT_NODE(node,virt);
1829 profile_start("rend");
1830 virt->rend(node);
1831 profile_end("rend");
1832 PRINT_GL_ERROR_IF_ANY("render_geom"); PRINT_NODE(node,virt);
1833 }
1834 if(p->renderstate.render_other && virt->other )
1835 {
1836 virt->other(node);
1837 } //other
1838
1839 if(p->renderstate.render_sensitive && ((node->_renderFlags & VF_Sensitive)|| Viewer()->LookatMode ==2)) {
1840 DEBUG_RENDER("rs 5\n");
1841 profile_start("sensitive");
1842 push_sensor(node);
1843 pushed_sensor = TRUE;
1844 profile_end("sensitive");
1845 }
1846 if(p->renderstate.render_geom && p->renderstate.render_sensitive && !tg->RenderFuncs.hypersensitive && virt->rendray) {
1847 DEBUG_RENDER("rs 6\n");
1848 profile_start("rendray");
1849 if(pickrayHitsMBB(node))
1850 virt->rendray(node);
1851 profile_end("rendray");
1852 PRINT_GL_ERROR_IF_ANY("rs 6"); PRINT_NODE(node,virt);
1853 }
1854
1855 /* May 16 2016: now we don't come into render_hier on hypersensitive
1856 if((p->renderstate.render_sensitive) && (tg->RenderFuncs.hypersensitive == node)) {
1857 DEBUG_RENDER("rs 7\n");
1858 p->hyper_r1 = p->t_r123.p1; //tg->RenderFuncs.t_r1;
1859 p->hyper_r2 = p->t_r123.p2; //tg->RenderFuncs.t_r2;
1860 tg->RenderFuncs.hyperhit = 1;
1861 }
1862 */
1863
1864 /* start recursive section */
1865 if(virt->children) {
1866 DEBUG_RENDER("rs 8 - has valid child node pointer\n");
1867 //if(! (p->renderstate.render_vp == VF_Viewpoint && render_foundLayerViewpoint())){ //on vp pass, just find first DEF/USE of bound viewpoint
1868 //printf("children ");
1869 virt->children(node);
1870 //}
1871 //}else{
1872 // printf("skipping ");
1873 //}
1874 PRINT_GL_ERROR_IF_ANY("children"); PRINT_NODE(node,virt);
1875 }
1876 /* end recursive section */
1877
1878 if(p->renderstate.render_other && virt->other)
1879 {
1880 }
1881
1882 if(pushed_sensor)
1883 pop_sensor();
1884
1885 if(virt->fin) {
1886 DEBUG_RENDER("rs A\n");
1887 profile_start("fin");
1888 if(justGeom)
1889 profile_start("fingeom");
1890
1891 virt->fin(node);
1892 profile_end("fin");
1893 if(justGeom)
1894 profile_end("fingeom");
1895 //if(p->renderstate.render_sensitive && virt == &virt_Transform) {
1896 // upd_ray();
1897 //}
1898 PRINT_GL_ERROR_IF_ANY("fin"); PRINT_NODE(node,virt);
1899 }
1900 if(pushed_ray)
1901 pop_ray();
1902
1903#ifdef RENDERVERBOSE
1904 {
1905 int i;
1906 for(i=0;i<p->renderLevel;i++)printf(" ");
1907 }
1908 printf("%d (end render_node)\n",p->renderLevel);
1909 p->renderLevel--;
1910#endif
1911}
1912//#undef RENDERVERBOSE
1913
1914/*
1915 * The following code handles keeping track of the parents of a given
1916 * node. This enables us to traverse the scene on C level for optimizations.
1917 *
1918 * We use this array code because VRML nodes usually don't have
1919 * hundreds of children and don't usually shuffle them too much.
1920 */
1921//dug9 dec 13 >>
1922struct X3D_Node* getTypeNode(struct X3D_Node *node);
1923
1924void add_parent(struct X3D_Node *node, struct X3D_Node *parent, char *file, int line) {
1925 struct X3D_Node* itype;
1926 if(!node) return;
1927 //if(node->_nodeType == NODE_PlaneSensor)
1928 // printf("hi from add_parent, have a Planesensor");
1929#ifdef CHILDVERBOSE
1930 printf ("add_parent; adding node %u ,to parent %u at %s:%d\n",node, parent,file,line);
1931 printf ("add_parent; adding node %x ,to parent %x (hex) at %s:%d\n",node, parent,file,line);
1932 printf ("add_parent; adding node %p ,to parent %p (ptr) at %s:%d\n",node, parent,file,line);
1933
1934
1935 printf ("add_parent; adding node %u (%s) to parent %u (%s) at %s:%d\n",node, stringNodeType(node->_nodeType),
1936 parent, stringNodeType(parent->_nodeType),file,line);
1937#endif
1938
1939 parent->_renderFlags = parent->_renderFlags | node->_renderFlags;
1940
1941 /* add it to the parents list */
1942 vector_pushBack (struct X3D_Node*,node->_parentVector, parent);
1943 /* tie in sensitive nodes */
1944 itype = getTypeNode(node);
1945 if(itype)
1946 setSensitive (parent, itype );
1947}
1948
1949void remove_parent(struct X3D_Node *child, struct X3D_Node *parent) {
1950 int i;
1951 int pi;
1952
1953 if(!child) return;
1954 if(!parent) return;
1955
1956 //JAS printf ("remove_parent, parent %p (%s) , child %p (%s)\n",parent, stringNodeType(parent->_nodeType),
1957 //JAS child, stringNodeType(child->_nodeType));
1958
1959 //JAS printf ("remove_parent, parent vector size %d\n",vectorSize(child->_parentVector));
1960
1961 pi = -1;
1962 for (i=0; i<vectorSize(child->_parentVector); i++) {
1963 struct X3D_Node *n = vector_get(struct X3D_Node *, child->_parentVector,i);
1964 //JAS printf ("remPar, ele %d was %p\n",i,n);
1965 if (n==parent) pi = i;
1966 }
1967
1968 if (pi >=0) {
1969 //JAS printf ("remove parent, pi %d\n",pi);
1970
1971 struct X3D_Node *n = vector_get(struct X3D_Node *, child->_parentVector,vectorSize(child->_parentVector)-1);
1972
1973 /* get the last entry, and overwrite the entry found */
1974 vector_set(struct X3D_Node*, child->_parentVector, pi,n);
1975
1976 /* take that last entry off the vector */
1977 vector_popBack(struct X3D_Node*, child->_parentVector);
1978 }
1979
1980 //JAS - verification that parent was indeed removed.
1981 //JAS printf ("remove_parent, after parent vector size %d\n",vectorSize(child->_parentVector));
1982 //JAS for (i=0; i<vectorSize(child->_parentVector); i++) {
1983 //JAS struct X3D_Node *n = vector_get(struct X3D_Node *, child->_parentVector,i);
1984 //JAS printf ("remPar, ele %d was %p\n",i,n);
1985 //JAS }
1986}
1987
1988
1989#include "../x3d_parser/Bindable.h"
1990int fwl_getShadingStyle();
1991void push_globalRenderFlags(){
1992 //call in render_hier for geom or blend passes
1993 //unsigned int shaderflags;
1994 shaderflagsstruct shaderflags;
1995 ttglobal tg = gglobal();
1996 shaderflags = getShaderFlags(); //take a copy (which should be 0000000 at root level)
1997 memset(&shaderflags,0,sizeof(shaderflagsstruct));
1998 //modify copy
1999 //A. if there's a bound (non local) fog, copy its state to fog_state
2000 if(vectorSize(getActiveBindableStacks(tg)->fog) > 0){
2001 //there's a bound fog, bound fogs are enabled
2002 struct X3D_Fog *fog = stack_top(struct X3D_Fog*,getActiveBindableStacks(tg)->fog);
2003 if(fog->visibilityRange > 0.0f){
2004 //enabled
2005 //set fog bit in renderflags
2006 shaderflags.base |= FOG_APPEARANCE_SHADER;
2007 //push fogparams
2008 pushFogParams((struct X3D_Node*)fog);
2009 }
2010 }
2011 //B. Anaglyph?
2012 if(Viewer()->anaglyph || Viewer()->anaglyphB)
2013 shaderflags.base |= WANT_ANAGLYPH;
2014
2015 //C. ShadingStyle ie 0 flat, 1 gouraud, 2 phong, 3 wire
2016 switch(fwl_getShadingStyle()){
2017 case 0: shaderflags.base |= SHADINGSTYLE_FLAT; break;
2018 case 1: shaderflags.base |= SHADINGSTYLE_GOURAUD; break;
2019 case 2: shaderflags.base |= SHADINGSTYLE_PHONG; break;
2020 case 3: shaderflags.base |= SHADINGSTYLE_WIRE; break;
2021 default:
2022 shaderflags.base |= SHADINGSTYLE_GOURAUD; break;
2023 }
2024 if(tg->Component_PTM.globalProjector){
2025 shaderflags.base |= HAVE_PROJECTIVETEXTURE;
2026 }
2027 pushShaderFlags(shaderflags); //push nodified copy
2028}
2029void pop_globalRenderFlags(){
2030 //call after render_hier for geom or blend passes
2031 ttglobal tg = gglobal();
2032
2033 popShaderFlags(); //pop modified copy
2034
2035 //A. Fog, pop its stack only if it was pushed in push_globalRenderFlags
2036 if(vectorSize(getActiveBindableStacks(tg)->fog) > 0){
2037 struct X3D_Fog *fog = stack_top(struct X3D_Fog*,getActiveBindableStacks(tg)->fog);
2038 if(fog->visibilityRange > 0.0f){
2039 //enabled
2040 //pop fogParms
2041 popFogParams();
2042 }
2043 }
2044 tg->Component_PTM.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
2045
2046}
2047void render_hier(struct X3D_Node *g, int rwhat) {
2050
2051 ppRenderFuncs p;
2052 shaderflagsstruct shaderflags;
2053 ttglobal tg = gglobal();
2054 ttrenderstate rs;
2055 p = (ppRenderFuncs)tg->RenderFuncs.prv;
2056 rs = renderstate();
2057 memset(&shaderflags,0,sizeof(shaderflagsstruct));
2058 pushShaderFlags(shaderflags);
2059
2060 rs->render_vp = rwhat & VF_Viewpoint;
2061 rs->render_geom = rwhat & VF_Geom;
2062 rs->render_light = rwhat & VF_globalLight;
2063 rs->render_sensitive = rwhat & VF_Sensitive;
2064 rs->render_picking = rwhat & VF_Picking;
2065 rs->render_blend = rwhat & VF_Blend;
2066 rs->render_proximity = rwhat & VF_Proximity;
2067 rs->render_collision = rwhat & VF_Collision;
2068 rs->render_other = rwhat & VF_Other;
2069 rs->render_cube = rwhat & VF_Cube;
2070 rs->render_background = rwhat & VF_Background;
2071 rs->render_boxes = (rwhat & VF_Geom) && fwl_getDrawBoundingBoxes();
2072 //p->nextFreeLight = 0;
2073 p->lastShader = -1; //in sendLights,and optimization
2074 tg->RenderFuncs.hitPointDist = -1;
2075
2076
2077#ifdef RENDERVERBOSE
2078 printf ("render_hier vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
2079 rs->render_vp,rs->render_geom,rs->render_light,rs->render_sensitive,rs->render_blend,rs->render_proximity,rs->render_collision);
2080#endif
2081
2082 if (!g) {
2083 /* we have no geometry yet, sleep for a tiny bit */
2084 usleep(1000);
2085 return;
2086 }
2087
2088#ifdef RENDERVERBOSE
2089 printf("Render_hier node=%d what=%d\n", g, rwhat);
2090#endif
2091
2092
2093 if (rs->render_sensitive) {
2094 upd_ray();
2095 }
2096 if(rs->render_blend || rs->render_geom){
2097 push_globalRenderFlags();
2098
2099 }
2100 profile_start("render_hier");
2101 render_node(X3D_NODE(g));
2102 profile_end("render_hier");
2103 if(rs->render_blend || rs->render_geom){
2104 pop_globalRenderFlags();
2105 }
2106 popShaderFlags();
2107
2108
2109}
2110
2111
2112/******************************************************************************
2113 *
2114 * shape compiler "thread"
2115 *
2116 ******************************************************************************/
2117
2118void compileNode (void (*nodefn)(void *, void *, void *, void *, void *, void *), void *node, void *Icoord, void *IfogCoord, void *Icolor, void *Inormal, void *ItexCoord) {
2119 void *coord; void *fogCoord; void *color; void *normal; void *texCoord;
2120
2121 /* are any of these SFNodes PROTOS? If so, get the underlying real node, as PROTOS are handled like Groups. */
2122 POSSIBLE_PROTO_EXPANSION(void *, Icoord,coord)
2123 POSSIBLE_PROTO_EXPANSION(void *, IfogCoord,fogCoord)
2124 POSSIBLE_PROTO_EXPANSION(void *, Icolor,color)
2125 POSSIBLE_PROTO_EXPANSION(void *, Inormal,normal)
2126 POSSIBLE_PROTO_EXPANSION(void *, ItexCoord,texCoord)
2127
2128 nodefn(node, coord, fogCoord, color, normal, texCoord);
2129}
2130
2131void do_NurbsPositionInterpolator (void *node);
2132void do_NurbsOrientationInterpolator (void *node);
2133void do_NurbsSurfaceInterpolator (void *node);
2134/* for CRoutes, we need to have a function pointer to an interpolator to run, if we
2135 route TO an interpolator */
2136void *returnInterpolatorPointer (int nodeType) {
2137 void (*do_interp)(void *);
2138
2139 do_interp = NULL;
2140 switch(nodeType){
2141 case NODE_OrientationInterpolator: do_interp = do_Oint4; break;
2142 case NODE_CoordinateInterpolator2D: do_interp = do_OintCoord2D; break;
2143 case NODE_PositionInterpolator2D: do_interp = do_OintPos2D; break;
2144 case NODE_ScalarInterpolator: do_interp = do_OintScalar; break;
2145 case NODE_ColorInterpolator: do_interp = do_ColorInterpolator; break;
2146 case NODE_PositionInterpolator: do_interp = do_PositionInterpolator; break;
2147 case NODE_CoordinateInterpolator: do_interp = do_OintCoord; break;
2148 case NODE_NormalInterpolator: do_interp = do_OintNormal; break;
2149 case NODE_EaseInEaseOut: do_interp = do_EaseInEaseOut; break;
2150 case NODE_SplinePositionInterpolator: do_interp = do_SplinePositionInterpolator; break;
2151 case NODE_SplinePositionInterpolator2D: do_interp = do_SplinePositionInterpolator2D; break;
2152 case NODE_SplineScalarInterpolator: do_interp = do_SplineScalarInterpolator; break;
2153 case NODE_SquadOrientationInterpolator: do_interp = do_SquadOrientationInterpolator; break;
2154 case NODE_GeoPositionInterpolator: do_interp = do_GeoPositionInterpolator; break;
2155 case NODE_NurbsPositionInterpolator: do_interp = do_NurbsPositionInterpolator; break;
2156 case NODE_NurbsOrientationInterpolator: do_interp = do_NurbsOrientationInterpolator; break;
2157 case NODE_NurbsSurfaceInterpolator: do_interp = do_NurbsSurfaceInterpolator; break;
2158 case NODE_BooleanFilter: do_interp = do_BooleanFilter; break;
2159 case NODE_BooleanSequencer: do_interp = do_BooleanSequencer; break;
2160 case NODE_BooleanToggle: do_interp = do_BooleanToggle; break;
2161 case NODE_BooleanTrigger: do_interp = do_BooleanTrigger; break;
2162 case NODE_IntegerTrigger: do_interp = do_IntegerTrigger; break;
2163 case NODE_IntegerSequencer: do_interp = do_IntegerSequencer; break;
2164 case NODE_TimeTrigger: do_interp = do_TimeTrigger; break;
2165 case NODE_GeoConvert: do_interp = do_GeoConvert; break;
2166 default:
2167 do_interp = NULL;
2168 }
2169 return (void *)do_interp;
2170}
2171/*
2172void *returnInterpolatorPointer (const char *x) {
2173 if (strcmp("OrientationInterpolator",x)==0) { return (void *)do_Oint4;
2174 } else if (strcmp("CoordinateInterpolator2D",x)==0) { return (void *)do_OintCoord2D;
2175 } else if (strcmp("PositionInterpolator2D",x)==0) { return (void *)do_OintPos2D;
2176 } else if (strcmp("ScalarInterpolator",x)==0) { return (void *)do_OintScalar;
2177 } else if (strcmp("ColorInterpolator",x)==0) { return (void *)do_ColorInterpolator;
2178 } else if (strcmp("PositionInterpolator",x)==0) { return (void *)do_PositionInterpolator;
2179 } else if (strcmp("CoordinateInterpolator",x)==0) { return (void *)do_OintCoord;
2180 } else if (strcmp("NormalInterpolator",x)==0) { return (void *)do_OintNormal;
2181 } else if (strcmp("GeoPositionInterpolator",x)==0) { return (void *)do_GeoPositionInterpolator;
2182 } else if (strcmp("NurbsPositionInterpolator",x)==0) { return (void *)do_NurbsPositionInterpolator;
2183 } else if (strcmp("NurbsOrientationInterpolator",x)==0) { return (void *)do_NurbsOrienatationInterpolator;
2184 } else if (strcmp("NurbsSurfaceInterpolator",x)==0) { return (void *)do_NurbsSurfaceInterpolator;
2185 } else if (strcmp("BooleanFilter",x)==0) { return (void *)do_BooleanFilter;
2186 } else if (strcmp("FloatMultiply",x)==0) { return (void *)do_FloatMultiply;
2187 } else if (strcmp("BooleanSequencer",x)==0) { return (void *)do_BooleanSequencer;
2188 } else if (strcmp("BooleanToggle",x)==0) { return (void *)do_BooleanToggle;
2189 } else if (strcmp("BooleanTrigger",x)==0) { return (void *)do_BooleanTrigger;
2190 } else if (strcmp("IntegerTrigger",x)==0) { return (void *)do_IntegerTrigger;
2191 } else if (strcmp("IntegerSequencer",x)==0) { return (void *)do_IntegerSequencer;
2192 } else if (strcmp("TimeTrigger",x)==0) { return (void *)do_TimeTrigger;
2193
2194 } else {
2195 return 0;
2196 }
2197}
2198*/
2199
2200
2201
2202void checkParentLink (struct X3D_Node *node,struct X3D_Node *parent) {
2203 int n;
2204
2205 int *offsetptr;
2206 char *memptr;
2207 struct Multi_Node *mfn;
2208 uintptr_t *voidptr;
2209
2210 if (node == NULL) return;
2211
2212 /* printf ("checkParentLink for node %u parent %u type %s\n",node,parent,stringNodeType(node->_nodeType)); */
2213
2214 if (parent != NULL) ADD_PARENT(node, parent);
2215
2216 if ((node->_nodeType<0) || (node->_nodeType>NODES_COUNT)) {
2217 ConsoleMessage ("checkParentLink - %d not a valid nodeType",node->_nodeType);
2218 return;
2219 }
2220
2221 /* find all the fields of this node */
2222 offsetptr = (int *) NODE_OFFSETS[node->_nodeType];
2223
2224 /* FIELDNAMES_bboxCenter, offsetof (struct X3D_Group, bboxCenter), FIELDTYPE_SFVec3f, KW_field, */
2225 while (*offsetptr >= 0) {
2226
2227 /*
2228 printf (" field %s",FIELDNAMES[offsetptr[0]]);
2229 printf (" offset %d",offsetptr[1]);
2230 printf (" type %s",FIELDTYPES[offsetptr[2]]);
2231 printf (" kind %s\n",KEYWORDS[offsetptr[3]]);
2232 */
2233
2234 /* worry about SFNodes and MFNodes */
2235 if ((offsetptr[2] == FIELDTYPE_SFNode) || (offsetptr[2] == FIELDTYPE_MFNode)) {
2236 if ((offsetptr[3] == KW_initializeOnly) || (offsetptr[3] == KW_inputOutput)) {
2237
2238 /* create a pointer to the actual field */
2239 memptr = (char *) node;
2240 memptr += offsetptr[1];
2241
2242 if (offsetptr[2] == FIELDTYPE_SFNode) {
2243 /* get the field as a POINTER VALUE, not just a pointer... */
2244 voidptr = (uintptr_t *) memptr;
2245 voidptr = (uintptr_t *) *voidptr;
2246
2247 /* is there a node here? */
2248 if (voidptr != NULL) {
2249 checkParentLink(X3D_NODE(voidptr),node);
2250 }
2251 } else {
2252 mfn = (struct Multi_Node*) memptr;
2253 /* printf ("MFNode has %d children\n",mfn->n); */
2254 for (n=0; n<mfn->n; n++) {
2255 checkParentLink(mfn->p[n],node);
2256 }
2257 }
2258 }
2259
2260 }
2261 offsetptr += FIELDOFFSET_LENGTH;
2262 }
2263}
2264
2265#define X3D_COORD(node) ((struct X3D_Coordinate*)node)
2266#define X3D_GEOCOORD(node) ((struct X3D_GeoCoordinate*)node)
2267
2268/* get a coordinate array - (SFVec3f) from either a NODE_Coordinate or NODE_GeoCoordinate */
2269struct Multi_Vec3f *getCoordinate (struct X3D_Node *innode, char *str) {
2270 struct X3D_Coordinate * xc;
2271 struct X3D_GeoCoordinate *gxc;
2272 struct X3D_Node *node;
2273
2274 POSSIBLE_PROTO_EXPANSION (struct X3D_Node *, innode,node)
2275
2276 if(node){
2277 xc = X3D_COORD(node);
2278 /* printf ("getCoordinate, have a %s\n",stringNodeType(xc->_nodeType)); */
2279 if (xc->_nodeType == NODE_Coordinate) {
2280 return &(xc->point);
2281 } else if (xc->_nodeType == NODE_GeoCoordinate) {
2282 COMPILE_IF_REQUIRED_RETURN_NULL_ON_ERROR;
2283 gxc = X3D_GEOCOORD(node);
2284 return &(gxc->__movedCoords);
2285 } else {
2286 ConsoleMessage ("%s - coord expected but got %s\n", stringNodeType(xc->_nodeType));
2287 }
2288 }
2289 return NULL;
2290}
2291
2292
2293
2294/*
2295void printLTDebug(char * fn, int ln)
2296{
2297 ppRenderFuncs p = (ppRenderFuncs)gglobal()->RenderFuncs.prv;
2298ConsoleMessage ("headlight pos %f %f %f %f at %s:%d",
2299p->light_pos[HEADLIGHT_LIGHT][0],p->light_pos[HEADLIGHT_LIGHT][1],
2300 p->light_pos[HEADLIGHT_LIGHT][2],p->light_pos[HEADLIGHT_LIGHT][3],fn,ln);
2301}
2302*/
2303
Definition RenderFuncs.c:58