FreeWRL / FreeX3D 4.3.0
Bindable.c
1/*
2
3
4Bindable nodes - Background, TextureBackground, Fog, NavigationInfo, Viewpoint, GeoViewpoint.
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 "../vrml_parser/CParseGeneral.h"
39#include "../scenegraph/Vector.h"
40#include "../vrml_parser/CFieldDecls.h"
41#include "../vrml_parser/CParseParser.h"
42#include "../vrml_parser/CParseLexer.h"
43#include "../vrml_parser/CRoutes.h"
44#include "../opengl/OpenGL_Utils.h"
45#include "../opengl/Textures.h"
46#include "Bindable.h"
47#include "../scenegraph/quaternion.h"
48#include "../scenegraph/Viewer.h"
49#include "../scenegraph/Component_Shape.h"
50#include "../scenegraph/Component_Geospatial.h"
51#include "../scenegraph/RenderFuncs.h"
52#include "../scenegraph/Component_ProgrammableShaders.h"
53#include "../ui/common.h"
54#include "../scenegraph/LinearAlgebra.h"
55
56void setup_projection();
57
58/* for Background spheres */
59struct MyVertex
60 {
61 struct SFVec3f vert; //Vertex
62 struct SFColorRGBA col; //Colour
63 };
64
65
66
67static void saveBGVert (float *colptr, float *pt, int *vertexno, float *col, double dist, double x, double y, double z) ;
68
69void init_bindablestack(bindablestack *bstack, int layerId, int nodetype){
70 bstack->background = newVector(struct X3D_Node*, 2);
71 bstack->viewpoint = newVector(struct X3D_Node*, 2);
72 bstack->fog = newVector(struct X3D_Node*, 2);
73 bstack->navigation = newVector(struct X3D_Node*, 2);
74 bstack->layerId = layerId;
75 loadIdentityMatrix(bstack->screenorientationmatrix);
76 loadIdentityMatrix(bstack->viewtransformmatrix);
77 loadIdentityMatrix(bstack->posorimatrix);
78 loadIdentityMatrix(bstack->stereooffsetmatrix[0]);
79 loadIdentityMatrix(bstack->stereooffsetmatrix[1]);
80 bstack->isStereo = 0;
81 bstack->iside = 0;
82 bstack->viewer = NULL; //X3D_Viewer - navigation is per-layer
83 bstack->nodetype = nodetype;
84 loadIdentityMatrix(bstack->pickraymatrix[0]);
85 loadIdentityMatrix(bstack->pickraymatrix[1]);
86}
87void free_bindablestack(bindablestack *bstack){
88 deleteVector(struct X3D_Node*, bstack->background);
89 deleteVector(struct X3D_Node*, bstack->viewpoint);
90 deleteVector(struct X3D_Node*, bstack->fog);
91 deleteVector(struct X3D_Node*, bstack->navigation);
92 FREE_IF_NZ(bstack->viewer);
93}
94typedef struct pBindable{
95 struct sNaviInfo naviinfo;
96 bindablestack bstack;
97}* ppBindable;
98void *Bindable_constructor(){
99 void *v = MALLOCV(sizeof(struct pBindable));
100 memset(v,0,sizeof(struct pBindable));
101 return v;
102}
103void Bindable_init(struct tBindable *t){
104 //public
105 //these are the binding stacks as descriped in Core Component in the specs which store just the bound bindables
106 //t->background_stack = newVector(struct X3D_Node*, 2);
107 //t->viewpoint_stack = newVector(struct X3D_Node*, 2);
108 //t->fog_stack = newVector(struct X3D_Node*, 2);
109 //t->navigation_stack = newVector(struct X3D_Node*, 2);
110
111 t->prv = Bindable_constructor();
112 t->activeLayer = 0;
113 t->bstacks = newVector(bindablestack*,4);
114 {
115 ppBindable p = (ppBindable)t->prv;
116 init_bindablestack(&p->bstack,0, NODE_Viewpoint); //default binding stacks layer=0
117 vector_pushBack(bindablestack*, t->bstacks, &p->bstack);
118 p->naviinfo.width = 0.25;
119 p->naviinfo.height = 1.6;
120 p->naviinfo.step = 0.75;
121 t->naviinfo = &p->naviinfo;
122 }
123
124}
125void Bindable_clear(struct tBindable *t){
126 int i;
127 //public
128 //deleteVector(struct X3D_Node*, t->background_stack);
129 //deleteVector(struct X3D_Node*, t->viewpoint_stack);
130 //deleteVector(struct X3D_Node*, t->fog_stack);
131 //deleteVector(struct X3D_Node*, t->navigation_stack);
132 for(i=0;i<vectorSize(t->bstacks);i++){
133 bindablestack* bstack = vector_get(bindablestack*,t->bstacks,i);
134 free_bindablestack(bstack);
135 if(i>0) FREE_IF_NZ(bstack); //the first bstack is &something_not_malloced
136 }
137 deleteVector(bindablestack*,t->bstacks);
138}
139bindablestack* getBindableStacksByLayer(ttglobal tg, int layerId )
140{
141 int i;
142 bindablestack* bstack, *bstacktmp;
143 bstack = NULL; // vector_get(bindablestack*,tg->Bindable.bstacks,0); //default
144 for(i=0;i<vectorSize(tg->Bindable.bstacks);i++){
145 bstacktmp = vector_get(bindablestack*,tg->Bindable.bstacks,i);
146 if(bstacktmp->layerId == layerId){
147 bstack = bstacktmp;
148 break;
149 }
150 }
151 return bstack;
152}
153int addBindableStack(ttglobal tg, bindablestack* bstack){
154 //returns index of added bindablestack
155 //layer and layoutlayer should call this once in their lifetime to add their stack
156 int layerId = bstack->layerId;
157 while(vectorSize(tg->Bindable.bstacks)<layerId+1)
158 vector_pushBack(bindablestack*,tg->Bindable.bstacks,NULL);
159 vector_set(bindablestack*,tg->Bindable.bstacks,layerId,bstack);
160 return layerId;
161}
162bindablestack* getActiveBindableStacks(ttglobal tg )
163{
164 return getBindableStacksByLayer(tg,tg->Bindable.activeLayer);
165}
166int getBindableStacksCount(ttglobal tg){
167 return vectorSize(tg->Bindable.bstacks);
168}
169void printStatsBindingStacks()
170{
171 int i,nstacks;
172 bindablestack* bstack;
173 ttglobal tg = gglobal();
174 nstacks = getBindableStacksCount(tg);
175 for(i=0;i<nstacks;i++){
176 bstack = getBindableStacksByLayer(tg,i);
177 if(0){
178 ConsoleMessage("Layer %d",i);
179 if(i == tg->Bindable.activeLayer)
180 ConsoleMessage(" activeLayer");
181 ConsoleMessage(":\n");
182 }else{
183 char* al = " ";
184 if(i == tg->Bindable.activeLayer)
185 al = " activeLayer";
186 ConsoleMessage("Layer %d%s:\n",i,al);
187 }
188 ConsoleMessage("%25s %d\n","Background stack count", vectorSize(bstack->background));
189 ConsoleMessage("%25s %d\n","Fog stack count", vectorSize(bstack->fog));
190 ConsoleMessage("%25s %d\n","Navigation stack count", vectorSize(bstack->navigation));
191 ConsoleMessage("%25s %d\n","Viewpoint stack count", vectorSize(bstack->viewpoint));
192 }
193}
194
195/* common entry routine for setting avatar size */
196void set_naviWidthHeightStep(double wid, double hei, double step) {
197 ppBindable p;
198 ttglobal tg = gglobal();
199 p = (ppBindable)tg->Bindable.prv;
200
201 p->naviinfo.width = wid;
202 p->naviinfo.height = hei;
203 p->naviinfo.step = step;
204
205 //printf ("set_naviWdithHeightStep - width %lf height %lf step %lf speed %lf\n",wid,hei,step,Viewer()->speed);
206
207}
208
209/* called when binding NavigationInfo nodes */
210void set_naviinfo(struct X3D_NavigationInfo *node) {
211 struct Uni_String **svptr;
212 int i;
213 char *typeptr;
214 X3D_Viewer *viewer = ViewerByLayerId(node->_layerId);
215
216 viewer->speed = (double) node->speed;
217 if (node->avatarSize.n < 2) {
218 //old cosmo one-number way? kuka scene has { avatarSize 180 }
219 //printf ("set_naviinfo, avatarSize smaller than expected\n");
220 if(node->avatarSize.n == 1){
221 //take it as height, and scale width and step by it
222 // web3d v3.3 default size: 0.25 1.6 0.75
223 double avScale = (double)(node->avatarSize.p[0])/1.6;
224 set_naviWidthHeightStep (.25*avScale,1.6*avScale,.75*avScale);
225 }
226 } else {
227 set_naviWidthHeightStep ((double)(node->avatarSize.p[0]),
228 (double)(node->avatarSize.p[1]),
229 (double)((node->avatarSize.p[2]))); //dug9 Jan 6, 2010 - this is too crazy for the new gravity. * node->speed) * 2));
230 }
231
232 /* keep track of valid Navigation types. */
233 svptr = node->type.p;
234
235 /* assume "NONE" is set */
236 for (i=0; i<18; i++) viewer->oktypes[i] = FALSE;
237
238
239 /* now, find the ones that are ok */
240 for (i = 0; i < node->type.n; i++) {
241 /* get the string pointer */
242 typeptr = svptr[i]->strptr;
243
244 if (strcmp(typeptr,"WALK") == 0) {
245 viewer->oktypes[VIEWER_WALK] = TRUE;
246 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_WALK);
247 }
248 if (strcmp(typeptr,"FLY") == 0) {
249 viewer->oktypes[VIEWER_FLY] = TRUE;
250 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_FLY);
251 }
252 if (strcmp(typeptr,"EXAMINE") == 0) {
253 viewer->oktypes[VIEWER_EXAMINE] = TRUE;
254 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_EXAMINE);
255 }
256 if (strcmp(typeptr,"NONE") == 0) {
257 viewer->oktypes[VIEWER_NONE] = TRUE;
258 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_NONE);
259 }
260 if (strcmp(typeptr,"EXFLY") == 0) {
261 viewer->oktypes[VIEWER_EXFLY] = TRUE;
262 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_EXFLY);
263 }
264 if (strcmp(typeptr,"EXPLORE") == 0) {
265 viewer->oktypes[VIEWER_EXPLORE] = TRUE;
266 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_EXPLORE);
267 }
268 if (strcmp(typeptr,"LOOKAT") == 0) {
269 viewer->oktypes[VIEWER_LOOKAT] = TRUE;
270 //if (i==0) fwl_set_viewer_type(VIEWER_LOOKAT);
271 }
272 if (strcmp(typeptr,"SPHERICAL") == 0) {
273 viewer->oktypes[VIEWER_SPHERICAL] = TRUE;
274 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_SPHERICAL);
275 }
276 if (strcmp(typeptr, "TURNTABLE") == 0) {
277 viewer->oktypes[VIEWER_TURNTABLE] = TRUE;
278 if (i == 0) fwl_set_viewer_type0(viewer, VIEWER_TURNTABLE);
279 }
280 if (strcmp(typeptr, "DIST") == 0) {
281 viewer->oktypes[VIEWER_DIST] = TRUE;
282 if (i == 0) fwl_set_viewer_type0(viewer, VIEWER_DIST);
283 }
284 if (strcmp(typeptr, "PAN") == 0) {
285 viewer->oktypes[VIEWER_PAN] = TRUE;
286 if (i == 0) fwl_set_viewer_type0(viewer, VIEWER_PAN);
287 }
288 if (strcmp(typeptr, "ZOOM") == 0) {
289 viewer->oktypes[VIEWER_ZOOM] = TRUE;
290 if (i == 0) fwl_set_viewer_type0(viewer, VIEWER_ZOOM);
291 }
292
293 if (strcmp(typeptr, "ANY") == 0) {
294 viewer->oktypes[VIEWER_EXAMINE] = TRUE;
295 viewer->oktypes[VIEWER_WALK] = TRUE;
296 viewer->oktypes[VIEWER_EXFLY] = TRUE;
297 viewer->oktypes[VIEWER_FLY] = TRUE;
298 viewer->oktypes[VIEWER_EXPLORE] = TRUE;
299 viewer->oktypes[VIEWER_LOOKAT] = TRUE;
300 viewer->oktypes[VIEWER_SPHERICAL] = TRUE;
301 viewer->oktypes[VIEWER_TURNTABLE] = TRUE;
302 viewer->oktypes[VIEWER_DIST] = TRUE;
303 viewer->oktypes[VIEWER_PAN] = TRUE;
304 viewer->oktypes[VIEWER_ZOOM] = TRUE;
305 if (i==0) fwl_set_viewer_type0(viewer, VIEWER_WALK); /* just choose one */
306 }
307 }
308 viewer->headlight = node->headlight;
309 /* tell the menu buttons of the state of this headlight */
310 //setMenuButton_headlight(node->headlight);
311
312 /* transition effects */
313 viewer->transitionTime = node->transitionTime;
314 /* bounds checking */
315 if (viewer->transitionTime < 0.0) viewer->transitionTime = 0.0;
316
317 viewer->transitionType = VIEWER_TRANSITION_LINEAR; /* assume LINEAR */
318 if (node->transitionType.n > 0) {
319 if (strcmp("LINEAR", node->transitionType.p[0]->strptr) == 0) viewer->transitionType = VIEWER_TRANSITION_LINEAR;
320 else if (strcmp("TELEPORT", node->transitionType.p[0]->strptr) == 0) viewer->transitionType = VIEWER_TRANSITION_TELEPORT;
321 else if (strcmp("ANIMATE", node->transitionType.p[0]->strptr) == 0) viewer->transitionType = VIEWER_TRANSITION_ANIMATE;
322 else {
323 ConsoleMessage ("Unknown NavigationInfo transitionType :%s:",node->transitionType.p[0]->strptr);
324 }
325 }
326
327}
328
329
330int layerFromBindable(struct X3D_Node *node){
331 int layerId = 0;
332 switch(node->_nodeType){
333 case NODE_Viewpoint:
334 layerId = X3D_VIEWPOINT(node)->_layerId; break;
335 case NODE_OrthoViewpoint:
336 layerId = X3D_ORTHOVIEWPOINT(node)->_layerId; break;
337 case NODE_GeoViewpoint:
338 layerId = X3D_GEOVIEWPOINT(node)->_layerId; break;
339 case NODE_Background:
340 layerId = X3D_BACKGROUND(node)->_layerId; break;
341 case NODE_TextureBackground:
342 layerId = X3D_TEXTUREBACKGROUND(node)->_layerId; break;
343 case NODE_Fog:
344 layerId = X3D_FOG(node)->_layerId; break;
345 case NODE_NavigationInfo:
346 layerId = X3D_NAVIGATIONINFO(node)->_layerId; break;
347 default:
348 layerId = 0; break;
349 }
350 return layerId;
351}
352static int reachable_new_way = 0;
353int is_reachable_new_way() {
354 return reachable_new_way;
355}
356/* send a set_bind event from an event to this Bindable node */
357void send_bind_to(struct X3D_Node *node, int value) {
358 int layerId;
359 ttglobal tg = gglobal();
360 //printf ("\n%lf: send_bind_to, nodetype %s node %p value %d\n",TickTime(),stringNodeType(node->_nodeType),node,value);
361
362 layerId = layerFromBindable(node);
363 switch (node->_nodeType) {
364 case NODE_Background: {
365 struct X3D_Background *bg = (struct X3D_Background *) node;
366 bg->set_bind = value;
367 bind_node (node, getBindableStacksByLayer(tg,bg->_layerId)->background); //tg->Bindable.background_stack
368 break;
369 }
370
371 case NODE_TextureBackground: {
372 struct X3D_TextureBackground *tbg = (struct X3D_TextureBackground *) node;
373 tbg->set_bind = value;
374 bind_node (node, getBindableStacksByLayer(tg,tbg->_layerId)->background);
375 break;
376 }
377
378 case NODE_OrthoViewpoint: {
379 struct X3D_OrthoViewpoint *ovp = (struct X3D_OrthoViewpoint *) node;
380 ovp->set_bind = value;
381 //ovp->set_bind = ovp->_reachablethispass ? value : 0;
382 setMenuStatusVP (ovp->description->strptr);
383 bind_node (node, getBindableStacksByLayer(tg,ovp->_layerId)->viewpoint);
384 if (value == 1) { //ovp->set_bind > 0) {
385 bind_OrthoViewpoint(ovp);
386 }
387 break;
388 }
389
390 case NODE_Viewpoint: {
391 struct X3D_Viewpoint* vp = (struct X3D_Viewpoint*)node;
392 vp->set_bind = value;
393 setMenuStatusVP (vp->description->strptr);
394 bind_node(node, getBindableStacksByLayer(tg, vp->_layerId)->viewpoint);
395 if (value == 1) {
396 bind_Viewpoint(vp);
397 }
398 break;
399 }
400
401 case NODE_GeoViewpoint: {
402 struct X3D_GeoViewpoint* gvp = (struct X3D_GeoViewpoint*)node;
403 gvp->set_bind = value;
404 setMenuStatusVP(gvp->description->strptr);
405 bind_node(node, getBindableStacksByLayer(tg, gvp->_layerId)->viewpoint);
406 if (value == 1) {
407 bind_GeoViewpoint(gvp);
408 }
409 break;
410 }
411
412
413 case NODE_Fog: {
414 struct X3D_Fog *fg = (struct X3D_Fog *) node;
415 fg->set_bind = value;
416 bind_node (node, getBindableStacksByLayer(tg,fg->_layerId)->fog);
417 if(value==1){
418 bind_Fog(fg);
419 }
420 break;
421 }
422
423 case NODE_NavigationInfo: {
424 struct X3D_NavigationInfo *nv = (struct X3D_NavigationInfo *) node;
425 nv->set_bind = value;
426 bind_node (node, getBindableStacksByLayer(tg,nv->_layerId)->navigation);
427 if (value==1) set_naviinfo(nv);
428 break;
429 }
430
431 default:
432 ConsoleMessage("send_bind_to, cant send a set_bind to %s %p!!\n",stringNodeType(node->_nodeType),node);
433 }
434}
435
436
437
438
439/* Do binding for node and stack - works for all bindable nodes */
440
441/* return the setBind offset of this node */
442static size_t setBindofst(void *node) {
443 struct X3D_Background *tn;
444 tn = (struct X3D_Background *) node;
445 switch (tn->_nodeType) {
446 case NODE_Background: return offsetof(struct X3D_Background, set_bind);
447 case NODE_TextureBackground: return offsetof(struct X3D_TextureBackground, set_bind);
448 case NODE_Viewpoint: return offsetof(struct X3D_Viewpoint, set_bind);
449 case NODE_OrthoViewpoint: return offsetof(struct X3D_OrthoViewpoint, set_bind);
450 case NODE_GeoViewpoint: return offsetof(struct X3D_GeoViewpoint, set_bind);
451 case NODE_Fog: return offsetof(struct X3D_Fog, set_bind);
452 case NODE_NavigationInfo: return offsetof(struct X3D_NavigationInfo, set_bind);
453 default: {printf ("setBindoffst - huh? node type %d\n",tn->_nodeType); }
454 }
455 return 0;
456}
457
458/* return the isBound offset of this node */
459static size_t bindTimeoffst (struct X3D_Node *node) {
460 X3D_NODE_CHECK(node);
461
462 switch (node->_nodeType) {
463 case NODE_Background: return offsetof(struct X3D_Background, bindTime);
464 case NODE_TextureBackground: return offsetof(struct X3D_TextureBackground, bindTime);
465 case NODE_Viewpoint: return offsetof(struct X3D_Viewpoint, bindTime);
466 case NODE_OrthoViewpoint: return offsetof(struct X3D_OrthoViewpoint, bindTime);
467 case NODE_GeoViewpoint: return offsetof(struct X3D_GeoViewpoint, bindTime);
468 case NODE_Fog: return offsetof(struct X3D_Fog, bindTime);
469 case NODE_NavigationInfo: return offsetof(struct X3D_NavigationInfo, bindTime);
470 default: {printf ("bindTimeoffst - huh? node type %s\n",stringNodeType(node->_nodeType)); }
471 }
472 return 0;
473}
474
475/* return the isBound offset of this node */
476static size_t isboundofst(void *node) {
477 struct X3D_Background *tn;
478
479 /* initialization */
480 tn = (struct X3D_Background *) node;
481
482 X3D_NODE_CHECK(node);
483
484 switch (tn->_nodeType) {
485 case NODE_Background: return offsetof(struct X3D_Background, isBound);
486 case NODE_TextureBackground: return offsetof(struct X3D_TextureBackground, isBound);
487 case NODE_Viewpoint: return offsetof(struct X3D_Viewpoint, isBound);
488 case NODE_OrthoViewpoint: return offsetof(struct X3D_OrthoViewpoint, isBound);
489 case NODE_GeoViewpoint: return offsetof(struct X3D_GeoViewpoint, isBound);
490 case NODE_Fog: return offsetof(struct X3D_Fog, isBound);
491 case NODE_NavigationInfo: return offsetof(struct X3D_NavigationInfo, isBound);
492 default: {printf ("isBoundoffst - huh? node type %s\n",stringNodeType(tn->_nodeType)); }
493 }
494 return 0;
495}
496int removeNodeFromVector(int iaction, struct Vector *v, struct X3D_Node *node);
497void bind_node (struct X3D_Node *node, struct Vector *thisStack) {
498 int *isBoundPtr;
499 int *setBindPtr;
500 size_t offst;
501
502 isBoundPtr = offsetPointer_deref(int*, node, isboundofst(node));
503 setBindPtr = offsetPointer_deref(int*, node, setBindofst(node));
504
505 #ifdef BINDVERBOSE
506 printf ("bind_node, node %p (%s), set_bind %d isBound %d\n",node,stringNodeType(node->_nodeType),*setBindPtr,*isBoundPtr);
507 #endif
508
509 /* is this guy already bound? */
510 if (*isBoundPtr && (*setBindPtr != 0) ){
511 #ifdef BINDVERBOSE
512 printf("%p already bound\n",node);
513 #endif
514 *setBindPtr = 100;
515 return; /* It has to be at the top of the stack so return */
516 }
517
518
519 /* we either have a setBind of 1, which is a push, or 0, which
520 is a pop. the value of 100 (arbitrary) indicates that this
521 is not a new push or pop */
522
523 /* is this a push? */
524 if (*setBindPtr == 1) {
525 /* PUSH THIS TO THE TOP OF THE STACK */
526
527 /* isBound mimics setBind */
528 *isBoundPtr = 1;
529
530 /* unset the set_bind flag - setBind can be 0 or 1; lets make it garbage */
531 *setBindPtr = 100;
532
533 MARK_EVENT (node, (unsigned int) isboundofst(node));
534
535 /* set up the "bindTime" field */
536 offst = bindTimeoffst(node);
537 if (offst != 0) {
538 double *dp;
539 dp = offsetPointer_deref(double*, node, offst);
540 *dp = TickTime();
541 MARK_EVENT (node, offst);
542 }
543
544 /* unbind the one below, unless it is same node */
545 if (vectorSize(thisStack)>0) {
546 struct X3D_Node* oldTOS;
547
548 oldTOS = vector_back(struct X3D_Node *,thisStack);
549 /* printf ("already have a node here...have to unbind it %p %p\n",node,oldTOS); */
550
551 if (oldTOS == node) return; /* do not unbind */
552 isBoundPtr = offsetPointer_deref(int*, oldTOS, isboundofst(oldTOS));
553 setBindPtr = offsetPointer_deref(int*, oldTOS, setBindofst(oldTOS));
554 *isBoundPtr = 0;
555 *setBindPtr = 100;
556 MARK_EVENT (oldTOS, (unsigned int) isboundofst(oldTOS));
557 }
558
559 /* push it now */
560 vector_pushBack(struct X3D_Node*,thisStack,node);
561
562
563 } else if (*setBindPtr == 0) {
564 /* POP FROM TOP OF STACK - if we ARE the top of stack */
565 /* isBound mimics setBind */
566 *isBoundPtr = 0;
567
568 /* unset the set_bind flag - setBind can be 0 or 1; lets make it garbage */
569 *setBindPtr = 100;
570
571 MARK_EVENT (node, (unsigned int) isboundofst(node));
572
573 /* are we top of stack? */
574 if (vectorSize(thisStack)>0) {
575 struct X3D_Node* oldTOS;
576
577 oldTOS = vector_back(struct X3D_Node *,thisStack);
578 /* printf ("already have a node here...have to unbind it %p %p\n",node,oldTOS); */
579
580 if (oldTOS != node) {
581 if(!removeNodeFromVector(0, thisStack, node)){
582 if (node->_nodeType == NODE_Viewpoint){
583 if(0){
584 //bad scene design etiquette, but no harm done
585 printf ("can not pop from stack, not top (%p != %p)\n",node,oldTOS);
586 printf ("%p Viewpoint, description :%s:\n",node,X3D_VIEWPOINT(node)->description->strptr);
587 printf ("%p Viewpoint, description :%s:\n",oldTOS,X3D_VIEWPOINT(oldTOS)->description->strptr);
588 printf ("oldTOS, isBound %d, setBindPtr %d\n",*(offsetPointer_deref(int*, oldTOS, isboundofst(oldTOS))),
589 *(offsetPointer_deref(int*, oldTOS, setBindofst(oldTOS))));
590 printf("and not found in stack\n");
591 }
592 }
593 }
594 return;
595 } else {
596 /* we are top of stack... */
597 /* get myself off of the stack */
598 vector_popBack(struct X3D_Node *,thisStack);
599 removeNodeFromVector(0, thisStack, node); //sometimes there are duplicates further down the stack. for unloading inlines, we need to get rid of all occurrances
600 if (vectorSize(thisStack)>0) {
601 /* get the older one back */
602 oldTOS = vector_back(struct X3D_Node *,thisStack);
603
604 /* set it to be bound */
605 isBoundPtr = offsetPointer_deref(int*, oldTOS, isboundofst(oldTOS));
606 setBindPtr = offsetPointer_deref(int*, oldTOS, setBindofst(oldTOS));
607 *isBoundPtr = 1;
608 *setBindPtr = 100;
609 MARK_EVENT (oldTOS, (unsigned int) isboundofst(oldTOS));
610 }
611 }
612 } else {
613 /* printf ("stack is zero size, can not pop off\n"); */
614 }
615
616
617 } else {
618 printf ("setBindPtr %d\n",*setBindPtr);
619 }
620#undef BINDVERBOSE
621}
622
623//fog: see also notes in Component_EnvironEffects.c
624void bind_Fog(struct X3D_Fog *node){
625 //new Aug 2016, goal GLES2 compatible (no builtin opengl fog)
626 //nothing to do in here - we'll check the binding stack for fog before rendering
627 //ttglobal tg = gglobal();
628
629 /* check the set_bind eventin to see if it is TRUE or FALSE */
630 //if (node->set_bind < 100) {
631 // bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->fog);
632
633 /* if we do not have any more nodes on top of stack, disable fog */
634 //if(vectorSize(getActiveBindableStacks(tg)->fog) <= 0)
635 // we'll check before general scengraph rendering glDisable(GL_FOG);
636 //}
637 //glEnable(GL_FOG);
638
639 //if(!node->isBound) return;
640 //if(node->isBound)
641 // printf("bound global fog\n");
642}
643
644void render_Fog_OLD (struct X3D_Fog *node) {
645 #ifndef GL_ES_VERSION_2_0 // this should be handled in material shader
646 GLDOUBLE mod[16];
647 GLDOUBLE proj[16];
648 GLDOUBLE x,y,z;
649 GLDOUBLE x1,y1,z1;
650 GLDOUBLE sx, sy, sz;
651 GLfloat fog_colour [4];
652 char *fogptr;
653 int foglen;
654 GLDOUBLE unit[16] = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1};
655 ttglobal tg = gglobal();
656
657 UNUSED(foglen); //mitigate compiler warnings - should eventually use this variable though!
658
659 /* printf ("render_Fog, node %d isBound %d color %f %f %f set_bind %d\n",
660 node, node->isBound, node->color.c[0],node->color.c[1],node->color.c[2],node->set_bind); */
661
662 /* check the set_bind eventin to see if it is TRUE or FALSE */
663 if (node->set_bind < 100) {
664
665 bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->fog);
666
667 /* if we do not have any more nodes on top of stack, disable fog */
668 glDisable(GL_FOG);
669 }
670
671 if(!node->isBound) return;
672 if (node->visibilityRange <= 0.00001) return;
673
674 fog_colour[0] = node->color.c[0];
675 fog_colour[1] = node->color.c[1];
676 fog_colour[2] = node->color.c[2];
677 fog_colour[3] = (float) 1.0;
678
679 fogptr = node->fogType->strptr;
680 foglen = node->fogType->len;
681 FW_GL_PUSH_MATRIX();
682 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, mod);
683 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
684 /* Get origin */
685 FW_GLU_UNPROJECT(0.0f,0.0f,0.0f,mod,proj,viewport,&x,&y,&z);
686 FW_GL_TRANSLATE_D(x,y,z);
687
688 FW_GLU_UNPROJECT(0.0f,0.0f,0.0f,mod,unit,viewport,&x,&y,&z);
689 /* Get scale */
690 FW_GLU_PROJECT(x+1,y,z,mod,unit,viewport,&x1,&y1,&z1);
691 sx = 1/sqrt( x1*x1 + y1*y1 + z1*z1*4 );
692 FW_GLU_PROJECT(x,y+1,z,mod,unit,viewport,&x1,&y1,&z1);
693 sy = 1/sqrt( x1*x1 + y1*y1 + z1*z1*4 );
694 FW_GLU_PROJECT(x,y,z+1,mod,unit,viewport,&x1,&y1,&z1);
695 sz = 1/sqrt( x1*x1 + y1*y1 + z1*z1*4 );
696 /* Undo the translation and scale effects */
697 FW_GL_SCALE_D(sx,sy,sz);
698
699
700 /* now do the foggy stuff */
701 FW_GL_FOGFV(GL_FOG_COLOR,fog_colour);
702
703 /* make the fog look like the examples in the VRML Source Book */
704 if (strcmp("LINEAR",fogptr)) {
705 /* Exponential */
706 FW_GL_FOGF(GL_FOG_DENSITY, (float) (4.0)/ (node->visibilityRange));
707 FW_GL_FOGF(GL_FOG_END, (float) (node->visibilityRange));
708 FW_GL_FOGI(GL_FOG_MODE, GL_EXP);
709 } else {
710 /* Linear */
711 FW_GL_FOGF(GL_FOG_START, (float) 1.0);
712 FW_GL_FOGF(GL_FOG_END, (float) (node->visibilityRange));
713 FW_GL_FOGI(GL_FOG_MODE, GL_LINEAR);
714 }
715 glEnable(GL_FOG);
716
717 FW_GL_POP_MATRIX();
718 #endif /* GL_ES_VERSION_2_0 this should be handled in material shader */
719}
720
721
722/******************************************************************************
723 *
724 * Background, TextureBackground stuff
725 *
726 ******************************************************************************/
727
728/* save a Background vertex into the __points and __colours arrays */
729static void saveBGVert (float *colptr, float *pt,
730 int *vertexno, float *col, double dist,
731 double x, double y, double z) {
732 /* save the colour */
733 memcpy (&colptr[*vertexno*3], col, sizeof(float)*3);
734
735 /* and, save the vertex info */
736 pt[*vertexno*3+0] = (float)(x*dist);
737 pt[*vertexno*3+1] = (float)(y*dist);
738 pt[*vertexno*3+2] = (float)(z*dist);
739
740 (*vertexno)++;
741}
742
743/* the background centre follows our position, so, move it! */
744static void moveBackgroundCentre () {
745 GLDOUBLE mod[16];
746 GLDOUBLE proj[16];
747 GLDOUBLE unit[16] = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1};
748 GLDOUBLE x,y,z;
749 GLDOUBLE x1,y1,z1;
750 GLDOUBLE sx, sy, sz;
751 ttglobal tg = gglobal();
752
753 FW_GL_PUSH_MATRIX();
754 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, mod);
755 if(0){
756 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
757 /* Get origin */
758 FW_GLU_UNPROJECT(0.0f,0.0f,0.0f,mod,proj,viewport,&x,&y,&z);
759 FW_GL_TRANSLATE_D(x,y,z);
760
761 if(0){
762 if(0) LIGHTING_OFF
763
764 FW_GLU_UNPROJECT(0.0f,0.0f,0.0f,mod,unit,viewport,&x,&y,&z);
765 /* Get scale */
766 FW_GLU_PROJECT(x+1,y,z,mod,unit,viewport,&x1,&y1,&z1);
767 sx = 1/sqrt( x1*x1 + y1*y1 + z1*z1*4 );
768 FW_GLU_PROJECT(x,y+1,z,mod,unit,viewport,&x1,&y1,&z1);
769 sy = 1/sqrt( x1*x1 + y1*y1 + z1*z1*4 );
770 FW_GLU_PROJECT(x,y,z+1,mod,unit,viewport,&x1,&y1,&z1);
771 sz = 1/sqrt( x1*x1 + y1*y1 + z1*z1*4 );
772
773 /* Undo the translation and scale effects */
774 FW_GL_SCALE_D(sx,sy,sz);
775 //printf("moveBackground old T %f %f %f old S %f %f %f\n",x,y,z,sx,sy,sz);
776 }
777 }
778 if(1){
779 //feature-AFFINE_GLU_UNPROJECT
780 //translation, scale same as glu_unproject (no 4*z needed for this way)
781 double modi[16];
782 struct point_XYZ p, q;
783 p.x = p.y = p.z = 0.0;
784 matinverseAFFINE(modi,mod);
785 transform(&p,&p,modi);
786 FW_GL_TRANSLATE_D(p.x,p.y,p.z);
787 //printf("moveBackground new T %f %f %f \n",p.x,p.y,p.z);
788 //LIGHTING_OFF
789 if(1){ //jan 2018
790 /* Get scale */
791 q = p;
792 q.x += 1.0;
793 transform(&q,&q,mod);
794 sx = 1.0/sqrt( q.x*q.x + q.y*q.y + q.z*q.z );
795 q = p;
796 q.y += 1.0;
797 transform(&q,&q,mod);
798 sy = 1.0/sqrt( q.x*q.x + q.y*q.y + q.z*q.z );
799 q = p;
800 q.z += 1.0;
801 transform(&q,&q,mod);
802 sz = 1.0/sqrt( q.x*q.x + q.y*q.y + q.z*q.z );
803 }
804 /* Undo the translation and scale effects */
805 // dug9 jan 2018: if(0)
806 FW_GL_SCALE_D(sx,sy,sz);
807 //printf("moveBackground new T %f %f %f new S %f %f %f\n",x,y,z,sx,sy,sz);
808 //printf("\n");
809 }
810}
811
812static void recalculateBackgroundVectors_old(struct X3D_Background *node) {
813 struct SFColor *c1,*c2;
814 int hdiv; /* number of horizontal strips allowed */
815 int h,v;
816 double va1, va2, ha1, ha2; /* JS - vert and horiz angles */
817 int estq;
818 int actq;
819
820 /* filled in if this is a TextureBackground node */
821 struct X3D_TextureBackground *tbnode;
822
823 /* generic structures between nodes used for taking individual pointers from node defns */
824 struct SFColor *skyCol; int skyColCt;
825 struct SFColor *gndCol; int gndColCt;
826 float *skyAng; int skyAngCt;
827 float *gndAng; int gndAngCt;
828 float *newPoints; float *newColors;
829 double outsideRadius, insideRadius;
830
831 /* initialization */
832 tbnode = NULL;
833 hdiv = 20;
834
835 /* We draw spheres, one for the sky, one for the ground - outsideRadius and insideRadius */
836 //outsideRadius = DEFAULT_FARPLANE* 0.750;
837 //insideRadius = DEFAULT_FARPLANE * 0.50;
838
839 /* lets try these values - we will scale when we draw this */
840 outsideRadius = 1.001;// 1.0;
841 insideRadius = 1.0005; // 0.5;
842
843 /* handle Background and TextureBackgrounds here */
844 if (node->_nodeType == NODE_Background) {
845 skyCol = node->skyColor.p;
846 gndCol = node ->groundColor.p;
847 skyColCt = node->skyColor.n;
848 gndColCt = node->groundColor.n;
849 skyAng = node->skyAngle.p;
850 gndAng = node ->groundAngle.p;
851 skyAngCt = node->skyAngle.n;
852 gndAngCt = node->groundAngle.n;
853 } else {
854 tbnode = (struct X3D_TextureBackground *) node;
855 skyCol = tbnode->skyColor.p;
856 gndCol = tbnode ->groundColor.p;
857 skyColCt = tbnode->skyColor.n;
858 gndColCt = tbnode->groundColor.n;
859 skyAng = tbnode->skyAngle.p;
860 gndAng = tbnode ->groundAngle.p;
861 skyAngCt = tbnode->skyAngle.n;
862 gndAngCt = tbnode->groundAngle.n;
863 }
864
865 /* do we have NO background triangles? (ie, maybe all textures??) */
866 if ((skyColCt == 0) && (gndColCt == 0)) {
867 if (node->_nodeType == NODE_Background) {
868 MARK_NODE_COMPILED
869 /* do we have an old background to destroy? */
870 FREE_IF_NZ (node->__points.p);
871 FREE_IF_NZ (node->__colours.p);
872 node->__quadcount = 0;
873 } else {
874 tbnode->_ichange = tbnode->_change; /* mimic MARK_NODE_COMPILED */
875
876 /* do we have an old background to destroy? */
877 FREE_IF_NZ (tbnode->__points.p);
878 FREE_IF_NZ (tbnode->__colours.p);
879 tbnode->__quadcount = 0;
880 }
881 return;
882 }
883
884
885 /* calculate how many quads are required */
886 estq=0; actq=0;
887 if(skyColCt == 1) {
888 estq += 40;
889 } else {
890 estq += (skyColCt-1) * 20 + 20;
891 /* attempt to find exact estimate, fails if no skyAngle, so
892 simply changed above line to add 20 automatically.
893 if ((skyColCt >2) &&
894 (skyAngCt > skyColCt-2)) {
895 if (skyAng[skyColCt-2] < (PI-0.01))
896 estq += 20;
897 }
898 */
899 }
900
901 if(gndColCt == 1) estq += 40;
902 else if (gndColCt>0) estq += (gndColCt-1) * 20;
903
904 /* now, MALLOC space for new arrays - 3 points per vertex, 6 per quad. */
905 newPoints = MALLOC (GLfloat *, sizeof (GLfloat) * estq * 3 * 6);
906 newColors = MALLOC (GLfloat *, sizeof (GLfloat) * estq * 3 * 6);
907
908 if(skyColCt == 1) {
909 c1 = &skyCol[0];
910 va1 = 0;
911 va2 = PI/2;
912
913 for(v=0; v < 2; v++) {
914 for(h=0; h<hdiv; h++) {
915 ha1 = h * PI*2 / hdiv;
916 ha2 = (h+1) * PI*2 / hdiv;
917 /* 0 */ saveBGVert (newColors, newPoints, &actq,&c1->c[0],outsideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2)*sin(ha1));
918 /* 1 */ saveBGVert (newColors, newPoints, &actq,&c1->c[0],outsideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2)*sin(ha2));
919 /* 2 */ saveBGVert (newColors, newPoints, &actq,&c1->c[0],outsideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1)*sin(ha2));
920 /* 0 */ saveBGVert (newColors, newPoints, &actq,&c1->c[0],outsideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2)*sin(ha1));
921 /* 2 */ saveBGVert (newColors, newPoints, &actq,&c1->c[0],outsideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1)*sin(ha2));
922 /* 3 */ saveBGVert (newColors, newPoints, &actq,&c1->c[0],outsideRadius, sin(va1)*cos(ha1), cos(va1), sin(va1) * sin(ha1));
923 }
924 va1 = va2;
925 va2 = PI;
926 }
927 } else {
928 va1 = 0;
929 /* this gets around a compiler warning - we really DO want last values of this from following
930 for loop */
931 c1 = &skyCol[0];
932 if (skyAngCt>0) {
933 va2= skyAng[0];
934 } else {
935 va2 = PI/2;
936 }
937 c2=c1;
938
939
940 for(v=0; v<(skyColCt-1); v++) {
941 c1 = &skyCol[v];
942 c2 = &skyCol[v+1];
943 if (skyAngCt>0) { va2 = skyAng[v];}
944 else { va2 = PI/2; }
945
946 for(h=0; h<hdiv; h++) {
947 ha1 = h * PI*2 / hdiv;
948 ha2 = (h+1) * PI*2 / hdiv;
949 /* 0 */ saveBGVert(newColors,newPoints, &actq,&c2->c[0],outsideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2) * sin(ha1));
950 /* 1 */ saveBGVert(newColors,newPoints, &actq,&c2->c[0],outsideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2) * sin(ha2));
951 /* 2 */ saveBGVert(newColors,newPoints, &actq,&c1->c[0],outsideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1) * sin(ha2));
952 /* 0 */ saveBGVert(newColors,newPoints, &actq,&c2->c[0],outsideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2) * sin(ha1));
953 /* 2 */ saveBGVert(newColors,newPoints, &actq,&c1->c[0],outsideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1) * sin(ha2));
954 /* 3 */ saveBGVert(newColors,newPoints, &actq,&c1->c[0],outsideRadius, sin(va1) * cos(ha1), cos(va1), sin(va1) * sin(ha1));
955 }
956 va1 = va2;
957 }
958
959 /* now, the spec states: "If the last skyAngle is less than pi, then the
960 colour band between the last skyAngle and the nadir is clamped to the last skyColor." */
961 if (va2 < (PI-0.01)) {
962 for(h=0; h<hdiv; h++) {
963 ha1 = h * PI*2 / hdiv;
964 ha2 = (h+1) * PI*2 / hdiv;
965 /* 0 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],outsideRadius, sin(PI) * cos(ha1), cos(PI), sin(PI) * sin(ha1));
966 /* 1 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],outsideRadius, sin(PI) * cos(ha2), cos(PI), sin(PI) * sin(ha2));
967 /* 2 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],outsideRadius, sin(va2) * cos(ha2), cos(va2), sin(va2) * sin(ha2));
968 /* 0 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],outsideRadius, sin(PI) * cos(ha1), cos(PI), sin(PI) * sin(ha1));
969 /* 2 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],outsideRadius, sin(va2) * cos(ha2), cos(va2), sin(va2) * sin(ha2));
970 /* 3 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],outsideRadius, sin(va2) * cos(ha1), cos(va2), sin(va2) * sin(ha1));
971 }
972 }
973 }
974
975 /* Do the ground, if there is anything to do. */
976
977 if (gndColCt>0) {
978 if(gndColCt == 1) {
979 c1 = &gndCol[0];
980 for(h=0; h<hdiv; h++) {
981 ha1 = h * PI*2 / hdiv;
982 ha2 = (h+1) * PI*2 / hdiv;
983
984 /* 0 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(PI) * cos(ha1), cos(PI), sin(PI) * sin(ha1));
985 /* 1 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(PI) * cos(ha2), cos(PI), sin(PI) * sin(ha2));
986 /* 2 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(PI/2) * cos(ha2), cos(PI/2), sin(PI/2) * sin(ha2));
987 /* 0 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(PI) * cos(ha1), cos(PI), sin(PI) * sin(ha1));
988 /* 2 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(PI/2) * cos(ha2), cos(PI/2), sin(PI/2) * sin(ha2));
989 /* 3 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(PI/2) * cos(ha1), cos(PI/2), sin(PI/2) * sin(ha1));
990 }
991 } else {
992 va1 = PI;
993 for(v=0; v<gndColCt-1; v++) {
994 c1 = &gndCol[v];
995 c2 = &gndCol[v+1];
996 if (v>=gndAngCt) va2 = PI; /* bounds check */
997 else va2 = PI - gndAng[v];
998
999 for(h=0; h<hdiv; h++) {
1000 ha1 = h * PI*2 / hdiv;
1001 ha2 = (h+1) * PI*2 / hdiv;
1002
1003 /* 0 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(va1)*cos(ha1), cos(va1), sin(va1)*sin(ha1));
1004 /* 1 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1)*sin(ha2));
1005 /* 2 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],insideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2)*sin(ha2));
1006 /* 0 */ saveBGVert(newColors,newPoints,&actq,&c1->c[0],insideRadius, sin(va1)*cos(ha1), cos(va1), sin(va1)*sin(ha1));
1007 /* 2 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],insideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2)*sin(ha2));
1008 /* 3 */ saveBGVert(newColors,newPoints,&actq,&c2->c[0],insideRadius, sin(va2) * cos(ha1), cos(va2), sin(va2)*sin(ha1));
1009 }
1010 va1 = va2;
1011 }
1012 }
1013 }
1014
1015 /* We have guessed at the quad count; lets make sure
1016 * we record what we have. */
1017 if (actq > (estq*6)) {
1018 printf ("Background quadcount error, %d > %d\n",
1019 actq,estq);
1020 actq = 0;
1021 }
1022
1023 /* save changes */
1024 /* if we are doing shaders, we write the vertex and color info to a VBO, else we keep pointers in the node */
1025 if (node->_nodeType == NODE_Background) {
1026
1027 MARK_NODE_COMPILED
1028
1029 /* do we have an old background to destroy? */
1030 FREE_IF_NZ (node->__points.p);
1031 FREE_IF_NZ (node->__colours.p);
1032 node->__quadcount = actq;
1033 } else {
1034 tbnode->_ichange = tbnode->_change; /* mimic MARK_NODE_COMPILED */
1035 /* do we have an old background to destroy? */
1036 FREE_IF_NZ (tbnode->__points.p);
1037 FREE_IF_NZ (tbnode->__colours.p);
1038 tbnode->__quadcount = actq;
1039
1040 }
1041
1042
1043 {
1044 struct MyVertex *combinedBuffer = MALLOC(struct MyVertex *, sizeof (struct MyVertex) * actq * 2);
1045 int i;
1046 float *npp = newPoints;
1047 float *ncp = newColors;
1048
1049
1050 if (node->_nodeType == NODE_Background) {
1051 if (node->__VBO == 0) glGenBuffers(1,(unsigned int*) &node->__VBO);
1052 } else {
1053 if (tbnode->__VBO == 0) glGenBuffers(1,(unsigned int*) &tbnode->__VBO);
1054 }
1055
1056 /* stream both the vertex and colours together (could have done this above, but
1057 maybe can redo this if we go 100% material shaders */
1058
1059 /* NOTE - we use SFColorRGBA - and set the Alpha to 1 so that we can use the
1060 shader with other nodes with Color fields */
1061
1062 for (i=0; i<actq; i++) {
1063 combinedBuffer[i].vert.c[0] = *npp; npp++;
1064 combinedBuffer[i].vert.c[1] = *npp; npp++;
1065 combinedBuffer[i].vert.c[2] = *npp; npp++;
1066 combinedBuffer[i].col.c[0] = *ncp; ncp++;
1067 combinedBuffer[i].col.c[1] = *ncp; ncp++;
1068 combinedBuffer[i].col.c[2] = *ncp; ncp++;
1069 combinedBuffer[i].col.c[3] = 1.0f;
1070 }
1071 FREE_IF_NZ(newPoints);
1072 FREE_IF_NZ(newColors);
1073
1074 /* send this data along ... */
1075 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,node->__VBO);
1076 glBufferData(GL_ARRAY_BUFFER, sizeof (struct MyVertex)*actq, combinedBuffer, GL_STATIC_DRAW);
1077
1078 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,0);
1079
1080 /* and, we can free it */
1081 FREE_IF_NZ(combinedBuffer);
1082 //node->__combined = X3D_NODE(combinedBuffer);
1083 }
1084}
1085static void recalculateBackgroundVectors(struct X3D_Background *node) {
1086 float *c1,*c2;
1087 int hdiv, vdiv; /* number of horizontal strips allowed */
1088 int h,v;
1089 double va1, va2, ha1, ha2; /* JS - vert and horiz angles */
1090 int estq;
1091 int actq;
1092 struct Multi_Float *skyangle, *groundangle;
1093 struct Multi_Color *skycolor, *groundcolor, *colours;
1094 struct Multi_Vec3f *points;
1095 int *quadcount;
1096
1097 /* filled in if this is a TextureBackground node */
1098 struct X3D_TextureBackground *tbnode;
1099
1100 // generic structures between nodes used for taking individual pointers from node defns
1101 struct SFColor *skyCol; int skyColCt;
1102 struct SFColor *gndCol; int gndColCt;
1103 float *skyAng; int skyAngCt;
1104 float *gndAng; int gndAngCt;
1105 float *newPoints; float *newColors;
1106 double outsideRadius, insideRadius;
1107
1108 /* initialization */
1109 tbnode = NULL;
1110 hdiv = 20;
1111 vdiv = 20;
1112
1113 // We draw spheres, one for the sky, one for the ground - outsideRadius and insideRadius
1114 //outsideRadius = DEFAULT_FARPLANE* 0.750;
1115 //insideRadius = DEFAULT_FARPLANE * 0.50;
1116
1117 /* lets try these values - we will scale when we draw this */
1118 outsideRadius = 1.001;// 1.0;
1119 insideRadius = 1.0005; // 0.5;
1120
1121 // handle Background and TextureBackgrounds here
1122 if (node->_nodeType == NODE_Background) {
1123 skycolor = &node->skyColor;
1124 skyangle = &node->skyAngle;
1125 groundcolor = &node->groundColor;
1126 groundangle = &node->groundAngle;
1127 colours = &node->__colours;
1128 points = &node->__points;
1129 quadcount = &node->__quadcount;
1130 } else {
1131 tbnode = (struct X3D_TextureBackground *) node;
1132 skycolor = &tbnode->skyColor;
1133 skyangle = &tbnode->skyAngle;
1134 groundcolor = &tbnode->groundColor;
1135 groundangle = &tbnode->groundAngle;
1136 colours = (struct Multi_Color*)&tbnode->__colours;
1137 points = &tbnode->__points;
1138 quadcount = &tbnode->__quadcount;
1139 }
1140
1141 // do we have NO background triangles? (ie, maybe all textures??)
1142 if ((skycolor->n == 0) && (groundcolor->n == 0)) {
1143 FREE_IF_NZ (points->p);
1144 FREE_IF_NZ (colours->p);
1145 *quadcount = 0;
1146 if (node->_nodeType == NODE_Background) {
1147 MARK_NODE_COMPILED
1148 } else {
1149 tbnode->_ichange = tbnode->_change; /* mimic MARK_NODE_COMPILED */
1150 }
1151 return;
1152 }
1153
1154 if(skycolor->n && skycolor->n != skyangle->n +1){
1155 ConsoleMessage("warning Background: skyColor.n %d should have one more entry than skyAngle.n %d\n",skycolor->n,skyangle->n);
1156 }
1157 if(groundcolor->n && groundcolor->n != groundangle->n +1){
1158 ConsoleMessage("warning Background: groundColor.n %d should have one more entry than groundAngle.n %d\n",groundcolor->n,groundangle->n);
1159 }
1160
1161
1162 // https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/enveffects.html#Backgrounds
1163 // we stick to this pretty close, except:
1164 //- one groundColor is a special case meaning nadir to horizone single color (vs specs: discard/no mention special case)
1165
1166 // calculate how many quads are required
1167 estq=0;actq=0;
1168 int s_vdiv = max(skyangle->n,2);
1169 if(skyangle->n > 0){
1170 if(skyangle->p[skyangle->n-1]< 1.57) s_vdiv += 1; //M_PI/2.0
1171 if(skyangle->p[skyangle->n-1]< M_PI) s_vdiv += 1;
1172 }
1173 int g_vdiv = groundangle->n > 0 ? groundangle->n : 0;
1174 g_vdiv = groundcolor->n == 1 ? 1 : g_vdiv; //exception to web3d rules
1175 vdiv = s_vdiv + g_vdiv;
1176 estq = hdiv * vdiv; // both sky and ground share one (point,color) array
1177
1178 // now, MALLOC space for new arrays - 3 points per vertex, 6 per quad.
1179 newPoints = MALLOC (GLfloat *, sizeof (GLfloat) * estq * 3 * 6);
1180 newColors = MALLOC (GLfloat *, sizeof (GLfloat) * estq * 3 * 6);
1181
1182 float *g_angle = MALLOC (float *, sizeof (float) * (g_vdiv+1));
1183 float *s_angle = MALLOC (float *, sizeof (float) * (s_vdiv+1));
1184 struct SFColor * g_color = MALLOC(struct SFColor*,sizeof(struct SFColor)*(g_vdiv+1) );
1185 struct SFColor * s_color = MALLOC(struct SFColor*,sizeof(struct SFColor)*(s_vdiv+1) );
1186
1187 g_angle[0] = 0.0f;
1188 if(g_vdiv)
1189 for(int i=0;i<g_vdiv+1;i++){
1190 if(i==0) g_angle[i] = 0.0f;
1191 else {
1192 if(groundcolor->n == 1) g_angle[i] = M_PI/2.0f;
1193 else g_angle[i] = min(groundangle->p[i-1],M_PI/2.0f);
1194 }
1195 if(groundcolor->n==1) veccopy3f(g_color[i].c,groundcolor->p[0].c);
1196 else veccopy3f(g_color[i].c,groundcolor->p[i].c);
1197 //printf("g_angle[%d] %f g_color %f %f %f\n",i, g_angle[i], g_color[i].c[0], g_color[i].c[1], g_color[i].c[2]);
1198 }
1199 s_angle[0] = 0.0f;
1200 float lastcolor[3];
1201 veccopy3f(lastcolor,skycolor->p[skycolor->n-1].c);
1202 for(int i=0;i<s_vdiv+1;i++){
1203 if(i==0) s_angle[i] = 0.0f;
1204 else if(i-1<skyangle->n)
1205 s_angle[i] = skyangle->p[i-1];
1206 else if(i==s_vdiv) s_angle[i] = M_PI;
1207 else s_angle[i] = M_PI/2.0;
1208 veccopy3f(s_color[i].c,lastcolor);
1209 if(i < skycolor->n ){
1210 veccopy3f(s_color[i].c,skycolor->p[i].c);
1211 }
1212 //printf("s_angle[%d] %f s_color %f %f %f\n",i,s_angle[i], s_color[i].c[0], s_color[i].c[1], s_color[i].c[2]);
1213
1214 }
1215
1216 //sky
1217 int count = 0;
1218 for(int i=0; i < s_vdiv; i++) {
1219 va1 = s_angle[i];
1220 va2 = s_angle[i+1];
1221 c1 = s_color[i].c;
1222 c2 = s_color[i+1].c;
1223
1224 for(h=0; h<hdiv; h++) {
1225 ha1 = h * PI*2 / hdiv;
1226 ha2 = (h+1) * PI*2 / hdiv;
1227 saveBGVert(newColors,newPoints, &actq,c2,outsideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2) * sin(ha1)); //0
1228 saveBGVert(newColors,newPoints, &actq,c2,outsideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2) * sin(ha2)); //1
1229 saveBGVert(newColors,newPoints, &actq,c1,outsideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1) * sin(ha2)); //2
1230 saveBGVert(newColors,newPoints, &actq,c2,outsideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2) * sin(ha1)); //0
1231 saveBGVert(newColors,newPoints, &actq,c1,outsideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1) * sin(ha2)); //2
1232 saveBGVert(newColors,newPoints, &actq,c1,outsideRadius, sin(va1)*cos(ha1), cos(va1), sin(va1) * sin(ha1)); //3
1233 count += 6;
1234 }
1235 }
1236 //printf("skycount %d hdiv %d vdiv %d\n",count,hdiv,s_vdiv);
1237 //ground
1238 count = 0;
1239 for(int i=0; i<g_vdiv; i++) {
1240 va1 = M_PI - g_angle[i];
1241 va2 = M_PI - g_angle[i+1];
1242 c1 = g_color[i].c;
1243 c2 = g_color[i+1].c;
1244 for(h=0; h<hdiv; h++) {
1245 ha1 = h * PI*2 / hdiv;
1246 ha2 = (h+1) * PI*2 / hdiv;
1247
1248 saveBGVert(newColors,newPoints,&actq,c1,insideRadius, sin(va1)*cos(ha1), cos(va1), sin(va1)*sin(ha1)); //0
1249 saveBGVert(newColors,newPoints,&actq,c1,insideRadius, sin(va1)*cos(ha2), cos(va1), sin(va1)*sin(ha2)); //1
1250 saveBGVert(newColors,newPoints,&actq,c2,insideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2)*sin(ha2)); //2
1251 saveBGVert(newColors,newPoints,&actq,c1,insideRadius, sin(va1)*cos(ha1), cos(va1), sin(va1)*sin(ha1)); //0
1252 saveBGVert(newColors,newPoints,&actq,c2,insideRadius, sin(va2)*cos(ha2), cos(va2), sin(va2)*sin(ha2)); //2
1253 saveBGVert(newColors,newPoints,&actq,c2,insideRadius, sin(va2)*cos(ha1), cos(va2), sin(va2)*sin(ha1)); //3
1254 count +=6;
1255 }
1256 }
1257 //printf("groundcount %d hdiv %d vdiv %d\n",count,hdiv,g_vdiv);
1258
1259 /* We have guessed at the quad count; lets make sure
1260 * we record what we have. */
1261 if (actq > (estq*6)) {
1262 printf ("Background quadcount error, %d > %d\n",
1263 actq,estq);
1264 actq = 0;
1265 }
1266
1267 /* save changes */
1268 /* if we are doing shaders, we write the vertex and color info to a VBO, else we keep pointers in the node */
1269 if (node->_nodeType == NODE_Background) {
1270
1271 MARK_NODE_COMPILED
1272
1273 /* do we have an old background to destroy? */
1274 FREE_IF_NZ (node->__points.p);
1275 FREE_IF_NZ (node->__colours.p);
1276 node->__quadcount = actq;
1277 } else {
1278 tbnode->_ichange = tbnode->_change; /* mimic MARK_NODE_COMPILED */
1279 /* do we have an old background to destroy? */
1280 FREE_IF_NZ (tbnode->__points.p);
1281 FREE_IF_NZ (tbnode->__colours.p);
1282 tbnode->__quadcount = actq;
1283
1284 }
1285
1286
1287 {
1288 struct MyVertex *combinedBuffer = MALLOC(struct MyVertex *, sizeof (struct MyVertex) * actq * 2);
1289 int i;
1290 float *npp = newPoints;
1291 float *ncp = newColors;
1292
1293
1294 if (node->_nodeType == NODE_Background) {
1295 if (node->__VBO == 0) glGenBuffers(1,(unsigned int*) &node->__VBO);
1296 } else {
1297 if (tbnode->__VBO == 0) glGenBuffers(1,(unsigned int*) &tbnode->__VBO);
1298 }
1299
1300 /* stream both the vertex and colours together (could have done this above, but
1301 maybe can redo this if we go 100% material shaders */
1302
1303 /* NOTE - we use SFColorRGBA - and set the Alpha to 1 so that we can use the
1304 shader with other nodes with Color fields */
1305
1306 for (i=0; i<actq; i++) {
1307 combinedBuffer[i].vert.c[0] = *npp; npp++;
1308 combinedBuffer[i].vert.c[1] = *npp; npp++;
1309 combinedBuffer[i].vert.c[2] = *npp; npp++;
1310 combinedBuffer[i].col.c[0] = *ncp; ncp++;
1311 combinedBuffer[i].col.c[1] = *ncp; ncp++;
1312 combinedBuffer[i].col.c[2] = *ncp; ncp++;
1313 combinedBuffer[i].col.c[3] = 1.0f;
1314 }
1315 FREE_IF_NZ(newPoints);
1316 FREE_IF_NZ(newColors);
1317
1318 /* send this data along ... */
1319 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,node->__VBO);
1320 glBufferData(GL_ARRAY_BUFFER, sizeof (struct MyVertex)*actq, combinedBuffer, GL_STATIC_DRAW);
1321
1322 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,0);
1323
1324 /* and, we can free it */
1325 FREE_IF_NZ(combinedBuffer);
1326 //node->__combined = X3D_NODE(combinedBuffer);
1327 }
1328}
1329static void recalculateTextureBackgroundVectors(struct X3D_TextureBackground* node) {
1330 float* c1, * c2;
1331 int hdiv, vdiv; /* number of horizontal strips allowed */
1332 int h, v;
1333 double va1, va2, ha1, ha2; /* JS - vert and horiz angles */
1334 int estq;
1335 int actq;
1336 struct Multi_Float* skyangle, * groundangle;
1337 struct Multi_Color* skycolor, * groundcolor, * colours;
1338 struct Multi_Vec3f* points;
1339 int* quadcount;
1340
1341 /* filled in if this is a TextureBackground node */
1342
1343 // generic structures between nodes used for taking individual pointers from node defns
1344 struct SFColor* skyCol; int skyColCt;
1345 struct SFColor* gndCol; int gndColCt;
1346 float* skyAng; int skyAngCt;
1347 float* gndAng; int gndAngCt;
1348 float* newPoints; float* newColors;
1349 double outsideRadius, insideRadius;
1350
1351 /* initialization */
1352 hdiv = 20;
1353 vdiv = 20;
1354
1355 // We draw spheres, one for the sky, one for the ground - outsideRadius and insideRadius
1356 //outsideRadius = DEFAULT_FARPLANE* 0.750;
1357 //insideRadius = DEFAULT_FARPLANE * 0.50;
1358
1359 /* lets try these values - we will scale when we draw this */
1360 outsideRadius = 1.001;// 1.0;
1361 insideRadius = 1.0005; // 0.5;
1362
1363 // handle Background and TextureBackgrounds here
1364
1365 skycolor = &node->skyColor;
1366 skyangle = &node->skyAngle;
1367 groundcolor = &node->groundColor;
1368 groundangle = &node->groundAngle;
1369 colours = (struct Multi_Color*)&node->__colours;
1370 points = &node->__points;
1371 quadcount = &node->__quadcount;
1372
1373
1374 // do we have NO background triangles? (ie, maybe all textures??)
1375 if ((skycolor->n == 0) && (groundcolor->n == 0)) {
1376 FREE_IF_NZ(points->p);
1377 FREE_IF_NZ(colours->p);
1378 *quadcount = 0;
1379 MARK_NODE_COMPILED
1380 return;
1381 }
1382
1383 if (skycolor->n && skycolor->n != skyangle->n + 1) {
1384 ConsoleMessage("warning TextureBackground: skyColor.n %d should have one more entry than skyAngle.n %d\n", skycolor->n, skyangle->n);
1385 }
1386 if (groundcolor->n && groundcolor->n != groundangle->n + 1) {
1387 ConsoleMessage("warning TextureBackground: groundColor.n %d should have one more entry than groundAngle.n %d\n", groundcolor->n, groundangle->n);
1388 }
1389
1390
1391 // https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/enveffects.html#Backgrounds
1392 // we stick to this pretty close, except:
1393 //- one groundColor is a special case meaning nadir to horizone single color (vs specs: discard/no mention special case)
1394
1395 // calculate how many quads are required
1396 estq = 0; actq = 0;
1397 int s_vdiv = max(skyangle->n, 2);
1398 if (skyangle->n > 0) {
1399 if (skyangle->p[skyangle->n - 1] < 1.57) s_vdiv += 1; //M_PI/2.0
1400 if (skyangle->p[skyangle->n - 1] < M_PI) s_vdiv += 1;
1401 }
1402 int g_vdiv = groundangle->n > 0 ? groundangle->n : 0;
1403 g_vdiv = groundcolor->n == 1 ? 1 : g_vdiv; //exception to web3d rules
1404 vdiv = s_vdiv + g_vdiv;
1405 estq = hdiv * vdiv; // both sky and ground share one (point,color) array
1406
1407 // now, MALLOC space for new arrays - 3 points per vertex, 6 per quad.
1408 newPoints = MALLOC(GLfloat*, sizeof(GLfloat) * estq * 3 * 6);
1409 newColors = MALLOC(GLfloat*, sizeof(GLfloat) * estq * 3 * 6);
1410
1411 float* g_angle = MALLOC(float*, sizeof(float) * (g_vdiv + 1));
1412 float* s_angle = MALLOC(float*, sizeof(float) * (s_vdiv + 1));
1413 struct SFColor* g_color = MALLOC(struct SFColor*, sizeof(struct SFColor) * (g_vdiv + 1));
1414 struct SFColor* s_color = MALLOC(struct SFColor*, sizeof(struct SFColor) * (s_vdiv + 1));
1415
1416 g_angle[0] = 0.0f;
1417 if (g_vdiv)
1418 for (int i = 0; i < g_vdiv + 1; i++) {
1419 if (i == 0) g_angle[i] = 0.0f;
1420 else {
1421 if (groundcolor->n == 1) g_angle[i] = M_PI / 2.0f;
1422 else g_angle[i] = min(groundangle->p[i - 1], M_PI / 2.0f);
1423 }
1424 if (groundcolor->n == 1) veccopy3f(g_color[i].c, groundcolor->p[0].c);
1425 else veccopy3f(g_color[i].c, groundcolor->p[i].c);
1426 //printf("g_angle[%d] %f g_color %f %f %f\n",i, g_angle[i], g_color[i].c[0], g_color[i].c[1], g_color[i].c[2]);
1427 }
1428 s_angle[0] = 0.0f;
1429 float lastcolor[3];
1430 veccopy3f(lastcolor, skycolor->p[skycolor->n - 1].c);
1431 for (int i = 0; i < s_vdiv + 1; i++) {
1432 if (i == 0) s_angle[i] = 0.0f;
1433 else if (i - 1 < skyangle->n)
1434 s_angle[i] = skyangle->p[i - 1];
1435 else if (i == s_vdiv) s_angle[i] = M_PI;
1436 else s_angle[i] = M_PI / 2.0;
1437 veccopy3f(s_color[i].c, lastcolor);
1438 if (i < skycolor->n) {
1439 veccopy3f(s_color[i].c, skycolor->p[i].c);
1440 }
1441 //printf("s_angle[%d] %f s_color %f %f %f\n",i,s_angle[i], s_color[i].c[0], s_color[i].c[1], s_color[i].c[2]);
1442
1443 }
1444
1445 //sky
1446 int count = 0;
1447 for (int i = 0; i < s_vdiv; i++) {
1448 va1 = s_angle[i];
1449 va2 = s_angle[i + 1];
1450 c1 = s_color[i].c;
1451 c2 = s_color[i + 1].c;
1452
1453 for (h = 0; h < hdiv; h++) {
1454 ha1 = h * PI * 2 / hdiv;
1455 ha2 = (h + 1) * PI * 2 / hdiv;
1456 saveBGVert(newColors, newPoints, &actq, c2, outsideRadius, sin(va2) * cos(ha1), cos(va2), sin(va2) * sin(ha1)); //0
1457 saveBGVert(newColors, newPoints, &actq, c2, outsideRadius, sin(va2) * cos(ha2), cos(va2), sin(va2) * sin(ha2)); //1
1458 saveBGVert(newColors, newPoints, &actq, c1, outsideRadius, sin(va1) * cos(ha2), cos(va1), sin(va1) * sin(ha2)); //2
1459 saveBGVert(newColors, newPoints, &actq, c2, outsideRadius, sin(va2) * cos(ha1), cos(va2), sin(va2) * sin(ha1)); //0
1460 saveBGVert(newColors, newPoints, &actq, c1, outsideRadius, sin(va1) * cos(ha2), cos(va1), sin(va1) * sin(ha2)); //2
1461 saveBGVert(newColors, newPoints, &actq, c1, outsideRadius, sin(va1) * cos(ha1), cos(va1), sin(va1) * sin(ha1)); //3
1462 count += 6;
1463 }
1464 }
1465 //printf("skycount %d hdiv %d vdiv %d\n",count,hdiv,s_vdiv);
1466 //ground
1467 count = 0;
1468 for (int i = 0; i < g_vdiv; i++) {
1469 va1 = M_PI - g_angle[i];
1470 va2 = M_PI - g_angle[i + 1];
1471 c1 = g_color[i].c;
1472 c2 = g_color[i + 1].c;
1473 for (h = 0; h < hdiv; h++) {
1474 ha1 = h * PI * 2 / hdiv;
1475 ha2 = (h + 1) * PI * 2 / hdiv;
1476
1477 saveBGVert(newColors, newPoints, &actq, c1, insideRadius, sin(va1) * cos(ha1), cos(va1), sin(va1) * sin(ha1)); //0
1478 saveBGVert(newColors, newPoints, &actq, c1, insideRadius, sin(va1) * cos(ha2), cos(va1), sin(va1) * sin(ha2)); //1
1479 saveBGVert(newColors, newPoints, &actq, c2, insideRadius, sin(va2) * cos(ha2), cos(va2), sin(va2) * sin(ha2)); //2
1480 saveBGVert(newColors, newPoints, &actq, c1, insideRadius, sin(va1) * cos(ha1), cos(va1), sin(va1) * sin(ha1)); //0
1481 saveBGVert(newColors, newPoints, &actq, c2, insideRadius, sin(va2) * cos(ha2), cos(va2), sin(va2) * sin(ha2)); //2
1482 saveBGVert(newColors, newPoints, &actq, c2, insideRadius, sin(va2) * cos(ha1), cos(va2), sin(va2) * sin(ha1)); //3
1483 count += 6;
1484 }
1485 }
1486 //printf("groundcount %d hdiv %d vdiv %d\n",count,hdiv,g_vdiv);
1487
1488 /* We have guessed at the quad count; lets make sure
1489 * we record what we have. */
1490 if (actq > (estq * 6)) {
1491 printf("Background quadcount error, %d > %d\n",
1492 actq, estq);
1493 actq = 0;
1494 }
1495
1496 /* save changes */
1497 /* if we are doing shaders, we write the vertex and color info to a VBO, else we keep pointers in the node */
1498 MARK_NODE_COMPILED
1499 /* do we have an old background to destroy? */
1500 FREE_IF_NZ(node->__points.p);
1501 FREE_IF_NZ(node->__colours.p);
1502 node->__quadcount = actq;
1503
1504
1505
1506
1507 {
1508 struct MyVertex* combinedBuffer = MALLOC(struct MyVertex*, sizeof(struct MyVertex) * actq * 2);
1509 int i;
1510 float* npp = newPoints;
1511 float* ncp = newColors;
1512
1513
1514 if (node->__VBO == 0) glGenBuffers(1, (unsigned int*)&node->__VBO);
1515
1516 /* stream both the vertex and colours together (could have done this above, but
1517 maybe can redo this if we go 100% material shaders */
1518
1519 /* NOTE - we use SFColorRGBA - and set the Alpha to 1 so that we can use the
1520 shader with other nodes with Color fields */
1521
1522 for (i = 0; i < actq; i++) {
1523 combinedBuffer[i].vert.c[0] = *npp; npp++;
1524 combinedBuffer[i].vert.c[1] = *npp; npp++;
1525 combinedBuffer[i].vert.c[2] = *npp; npp++;
1526 combinedBuffer[i].col.c[0] = *ncp; ncp++;
1527 combinedBuffer[i].col.c[1] = *ncp; ncp++;
1528 combinedBuffer[i].col.c[2] = *ncp; ncp++;
1529 combinedBuffer[i].col.c[3] = 1.0f;
1530 }
1531 FREE_IF_NZ(newPoints);
1532 FREE_IF_NZ(newColors);
1533
1534 /* send this data along ... */
1535 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, node->__VBO);
1536 glBufferData(GL_ARRAY_BUFFER, sizeof(struct MyVertex) * actq, combinedBuffer, GL_STATIC_DRAW);
1537
1538 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
1539
1540 /* and, we can free it */
1541 FREE_IF_NZ(combinedBuffer);
1542 //node->__combined = X3D_NODE(combinedBuffer);
1543 }
1544}
1545void reallyDraw();
1546void render_Background(struct X3D_Background *node){
1547 if (renderstate()->render_blend) return;
1548 if(!node->isBound) return;
1549 {
1550 //we need the model matrix - between root node and background - to capture any scene authored background tilts
1551 double viewi[16], mat[16], bmat[16];
1552 bindablestack *bstack;
1553 ttglobal tg = gglobal();
1554
1555 bstack = getActiveBindableStacks(tg);
1556 matinverseAFFINE(viewi,bstack->viewmatrix);
1557 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX,mat);
1558 //matmultiplyAFFINE(bstack->backgroundmatrix,viewi,mat);
1559 //matmultiplyAFFINE(bstack->backgroundmatrix,mat,viewi);
1560 matmultiplyAFFINE(bmat, mat, viewi);
1561 matrixAFFINE2RotationMatrix(bstack->backgroundmatrix, bmat);
1562 }
1563
1564}
1565void render_TextureBackground(struct X3D_TextureBackground *node){
1566 if (renderstate()->render_blend) return;
1567 if(!node->isBound) return;
1568 {
1569 //we need the model matrix - between root node and background - to capture any scene authored background tilts
1570 double viewi[16], mat[16], bmat[16];
1571 bindablestack *bstack;
1572 ttglobal tg = gglobal();
1573
1574 bstack = getActiveBindableStacks(tg);
1575 matinverseAFFINE(viewi,bstack->viewmatrix);
1576 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX,mat);
1577 //matmultiplyAFFINE(bstack->backgroundmatrix,viewi,mat);
1578 //matmultiplyAFFINE(bstack->backgroundmatrix,mat,viewi);
1579 matmultiplyAFFINE(bmat, mat, viewi);
1580 matrixAFFINE2RotationMatrix(bstack->backgroundmatrix, bmat);
1581 }
1582}
1583void render_Background_OLD (struct X3D_Background *node) {
1584 ttglobal tg = gglobal();
1585
1586 X3D_Viewer *viewer = Viewer();
1587 /* if we are rendering blended nodes, don't bother with this one */
1588 if (renderstate()->render_blend) return;
1589
1590 /* printf ("RBG, num %d node %d ib %d sb %d gepvp\n",node->__BGNumber, node,node->isBound,node->set_bind); */
1591 /* check the set_bind eventin to see if it is TRUE or FALSE */
1592 if (node->set_bind < 100) {
1593 bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->background);
1594 }
1595
1596 /* don't even bother going further if this node is not bound on the top */
1597 if(!node->isBound) return;
1598
1599 if (vectorSize(getActiveBindableStacks(tg)->fog) >0) glDisable(GL_FOG);
1600
1601 /* Cannot start_list() because of moving center, so we do our own list later */
1602 moveBackgroundCentre();
1603
1604 if (NODE_NEEDS_COMPILING) {
1605 recalculateBackgroundVectors(node);
1606 }
1607
1608 /* we have a sphere (maybe one and a half, as the sky and ground are different) so scale it up so that
1609 all geometry fits within the spheres
1610 dug9 Sept 2014: background could in theory be a tiny box or sphere that wraps around the avatar, if
1611 you can draw it first on each frame _and_ turn off 'depth' when you draw it.
1612 dug9 Jan 2018: turned off scaling of background geom, and toggled depth test)
1613 - due to problems with float coordinate rounding when doing a geoSpatial scene
1614 - (with GC geocentric) coords at rootnode when using geoViewpoint
1615 - still problem with geo-horizon leveling of background (for near-ground)
1616 */
1617 //if(0) FW_GL_SCALE_D (viewer->backgroundPlane, viewer->backgroundPlane, viewer->backgroundPlane);
1618 glDisable(GL_DEPTH_TEST);
1619 enableGlobalShader(getMyShader(COLOUR_MATERIAL_SHADER));
1620 initialize_front_and_back_material_params();
1621 LIGHTING_OFF
1622
1623 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1624 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, node->__VBO);
1625 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
1626 FW_GL_VERTEX_POINTER(3, GL_FLOAT, (GLsizei) sizeof(struct MyVertex), (GLfloat *)BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
1627 FW_GL_COLOR_POINTER(4, GL_FLOAT, (GLsizei) sizeof(struct MyVertex), (GLfloat *)BUFFER_OFFSET(sizeof(struct SFVec3f))); //The starting point of Colours, 12 bytes away
1628
1629 if(setupShaderB()){
1630 sendArraysToGPU (GL_TRIANGLES, 0, node->__quadcount);
1631 reallyDraw();
1632 }
1633 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
1634 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1635 finishedWithGlobalShader();
1636
1637 /* now, for the textures, if they exist */
1638 if (((node->backUrl).n>0) ||
1639 ((node->frontUrl).n>0) ||
1640 ((node->leftUrl).n>0) ||
1641 ((node->rightUrl).n>0) ||
1642 ((node->topUrl).n>0) ||
1643 ((node->bottomUrl).n>0)) {
1644
1645 glEnable(GL_TEXTURE_2D);
1646
1647 FW_GL_VERTEX_POINTER (3,GL_FLOAT,0,BackgroundVert);
1648 FW_GL_NORMAL_POINTER (GL_FLOAT,0,Backnorms);
1649 FW_GL_TEXCOORD_POINTER (2,GL_FLOAT,0,boxtex,0);
1650
1651 enableGlobalShader(getMyShader(ONE_TEX_APPEARANCE_SHADER));
1652 initialize_front_and_back_material_params();
1653
1654 loadBackgroundTextures(node);
1655
1656 finishedWithGlobalShader();
1657 }
1658 glEnable(GL_DEPTH_TEST);
1659
1660 FW_GL_POP_MATRIX();
1661
1662 /* is fog enabled? if so, disable it right now */
1663 if (vectorSize(getActiveBindableStacks(tg)->fog) >0) glEnable(GL_FOG);
1664}
1665//void prep_Background (struct X3D_Background *node) {
1666// ttglobal tg = gglobal();
1667//
1668// /* if we are rendering blended nodes, don't bother with this one */
1669// if (!renderstate()->render_background) return;
1670//
1671// /* printf ("RBG, num %d node %d ib %d sb %d gepvp\n",node->__BGNumber, node,node->isBound,node->set_bind); */
1672// /* check the set_bind eventin to see if it is TRUE or FALSE */
1673// if (node->set_bind < 100) {
1674// bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->background);
1675// }
1676//}
1677void fw_gluPerspective_2(GLDOUBLE xcenter, GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar);
1678void fw_depth_slice_push(double nearplane, double farplane){
1679 //lets say you have a big scene -maybe a planet and a few moons to scale,
1680 //and avatar on the surface of a moon, planting a flag and looking up at the main planet
1681 //And lets say your 24bit depth buffer seems a bit strained.
1682 //one idea is to iterate from far to near, over depth slices.
1683 //start with the farthest slices, slices can 'touch' but not overlap
1684 //then you could have your usual .1 to 21000 for human-size things close by,
1685 // and 21000 to infinity for distant mountains, planets etc.
1686 // and backgrounds could be rendered in .1 to 10 range
1687 // - enough to cover sphere radius 1 or box size 2 -
1688 // - with depth testing off, before anything else
1689 // haven't tried it in render() but I think you would do this:
1690 // render_background
1691 // for(i=0;i<dept_slices;i++){
1692 // fw_depth_slice_push(nearp[i],farp[i]);
1693 // glClear(GL_DEPTH)
1694 // render_hier() - theres a few of these
1695 // fw_depth_slice_pop();
1696 // }
1697 // would that work?
1698 double save_nearPlane, save_farPlane;
1699 X3D_Viewer *viewer = Viewer();
1700
1701 FW_GL_MATRIX_MODE(GL_PROJECTION);
1702 FW_GL_PUSH_MATRIX();
1703
1704 save_nearPlane = viewer->nearPlane;
1705 save_farPlane = viewer->farPlane;
1706 viewer->nearPlane = nearplane;
1707 viewer->farPlane = farplane;
1708 setup_projection(); //will put back in modelview mode
1709 viewer->nearPlane = save_nearPlane;
1710 viewer->farPlane = save_farPlane;
1711}
1712void fw_depth_slice_pop(){
1713 FW_GL_MATRIX_MODE(GL_PROJECTION);
1714 FW_GL_POP_MATRIX();
1715 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1716}
1717
1718void render_prepped_Background(struct X3D_Background *node){
1719 double bgscale;
1720 int didPerspective;
1721 ttglobal tg = gglobal();
1722 X3D_Viewer *viewer = Viewer();
1723
1724 if (vectorSize(getActiveBindableStacks(tg)->fog) >0) glDisable(GL_FOG);
1725
1726 /* Cannot start_list() because of moving center, so we do our own list later */
1727
1728 if(0){
1729 //this ignors tilts and yaws (but with respect to what? bound viewpoint?)
1730 moveBackgroundCentre();
1731 }else if(1){
1732 //March 2018 - this re-allows scene-file authored tilts to the background like other browsers
1733 // <Transform> <Background> </Transform> - tilts captured in render_Background
1734 // which we broke a few months ago
1735 double pp[3], mvmat[16], mvinv[16];
1736 bindablestack *bstack;
1737 ttglobal tg = gglobal();
1738 bstack = getActiveBindableStacks(tg);
1739 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1740 FW_GL_PUSH_MATRIX();
1741 FW_GL_TRANSFORM_D(bstack->backgroundmatrix); //see (new) render_Background
1742 //we now need to cancel/undo the translation part
1743 // by moving the background back to where the vp is at 0,0,0
1744 // see also:
1745 // double * matrixAFFINE2RotationMatrix(double* rotmat, double *fullmat);
1746 // which I made from this code, but didn't have time to try here.
1747 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, mvmat);
1748 matinverseAFFINE(mvinv,mvmat);
1749 vecsetd(pp,0.0,0.0,0.0);
1750 transformAFFINEd(pp,pp,mvinv);
1751 FW_GL_TRANSLATE_D(pp[0],pp[1],pp[2]);
1752 if(1){
1753 //cancel/undo scale part, so that our background mesh stays at radius 1.0
1754 double sx,sy,sz, q[3],p[3],d[3];
1755 /* Get scale */
1756 vecsetd(p,0.0,0.0,0.0);
1757 transformAFFINEd(p,p,mvmat);
1758 vecsetd(q,1.0,0.0,0.0);
1759 transformAFFINEd(q,q,mvmat);
1760 sx = 1.0/veclengthd(vecdifd(d,q,p));
1761 vecsetd(q,0.0,1.0,0.0);
1762 transformAFFINEd(q,q,mvmat);
1763 sy = 1.0/veclengthd(vecdifd(d,q,p));
1764 vecsetd(q,0.0,0.0,1.0);
1765 transformAFFINEd(q,q,mvmat);
1766 sz = 1.0/veclengthd(vecdifd(d,q,p));
1767 /* Undo the scale effects */
1768 FW_GL_SCALE_D(sx,sy,sz);
1769 }
1770 }else if(0){
1771 //instead of transforming back to viewpoint, can we just replace transform top-of-stack with identity?
1772 //benefit: good for diagnosing background problems: near/far plane vs offset
1773 //problem: then the horizon (or orientation with texture background)- doesn't change with a tilt (or yaw)
1774 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1775 FW_GL_PUSH_MATRIX();
1776 FW_GL_LOAD_IDENTITY();
1777 if(1){
1778 //this adds vertical tilt but not horizontal yaw
1779 double matA2BVVA[16],matBVVA2A[16];
1780 avatar2BoundViewpointVerticalAvatar(matA2BVVA,matBVVA2A);
1781 fw_glSetDoublev(GL_MODELVIEW_MATRIX,matBVVA2A);
1782 }
1783 }
1784
1785 if (NODE_NEEDS_COMPILING) {
1786 recalculateBackgroundVectors(node);
1787 }
1788
1789 /* we have a sphere (maybe one and a half, as the sky and ground are different) so scale it up so that
1790 all geometry fits within the spheres
1791 dug9 Sept 2014: background could in theory be a tiny box or sphere that wraps around the avatar, if
1792 you can draw it first on each frame _and_ turn off 'depth' when you draw it.
1793 dug9 Jan 2018: turned off scaling of background geom, and toggled depth test)
1794 - due to problems with float coordinate rounding when doing a geoSpatial scene
1795 - (with GC geocentric) coords at rootnode when using geoViewpoint
1796 - still problem with geo-horizon leveling of background (for near-ground)
1797 */
1798 didPerspective = FALSE;
1799
1800 if(1){
1801 //we need to scale because somewhere else we set up a perspective transformation that
1802 //may have a big number for a nearPlane (ie with geo scenes stretching depth range)
1803 //and the perspective transforms our z's into gl's 0 to 1 range for depth
1804 //if(1) FW_GL_SCALE_D (viewer->backgroundPlane, viewer->backgroundPlane, viewer->backgroundPlane);
1805 bgscale = 1.0;
1806 //if( viewer->nearPlane >= bgscale*.5)
1807 bgscale = viewer->nearPlane + (viewer->farPlane - viewer->nearPlane)*.3;
1808 //printf("near %lf far %lf bgscale %lf\n",viewer->nearPlane,viewer->farPlane,bgscale);
1809 FW_GL_SCALE_D (bgscale, bgscale, bgscale);
1810 }else{
1811 //alternately we can replace the perspective transform, or scale the depth range
1812 GLclampd znear, zfar;
1813 fw_depth_slice_push(.1,100); //SEEMS TO WORK remember to pop
1814 didPerspective = TRUE;
1815 }
1816 glDisable(GL_DEPTH_TEST);
1817 glDepthMask(GL_FALSE);
1818 initialize_front_and_back_material_params();
1819 enableGlobalShader(getMyShader(COLOUR_MATERIAL_SHADER));
1820 LIGHTING_OFF
1821
1822 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1823 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, node->__VBO);
1824 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
1825 FW_GL_VERTEX_POINTER(3, GL_FLOAT, (GLsizei) sizeof(struct MyVertex), (GLfloat *)BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
1826 FW_GL_COLOR_POINTER(4, GL_FLOAT, (GLsizei) sizeof(struct MyVertex), (GLfloat *)BUFFER_OFFSET(sizeof(struct SFVec3f))); //The starting point of Colours, 12 bytes away
1827 clear_textureUnit_used(); //appearance.texture material.textureXXX, PTMs.texture all need TEXTURE0+ XXX, where xxx starts from 0
1828 clear_material_samplers(); //PTM and material.textureXXX share frag shader sampler2D textureUnit[16] array
1829 clear_materialparameters_per_draw_counts(); //especially diffuse texture counts which both appearance and material share
1830
1831 if(setupShaderB()){
1832 sendArraysToGPU (GL_TRIANGLES, 0, node->__quadcount);
1833 reallyDraw();
1834 }
1835 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
1836 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1837 finishedWithGlobalShader();
1838
1839 /* now, for the textures, if they exist */
1840 if (((node->backUrl).n>0) ||
1841 ((node->frontUrl).n>0) ||
1842 ((node->leftUrl).n>0) ||
1843 ((node->rightUrl).n>0) ||
1844 ((node->topUrl).n>0) ||
1845 ((node->bottomUrl).n>0)) {
1846 glEnable(GL_TEXTURE_2D);
1847
1848 FW_GL_VERTEX_POINTER (3,GL_FLOAT,0,BackgroundVert);
1849 FW_GL_NORMAL_POINTER (GL_FLOAT,0,Backnorms);
1850 FW_GL_TEXCOORD_POINTER (2,GL_FLOAT,0,boxtex,0);
1851
1852 enableGlobalShader(getMyShader(ONE_TEX_APPEARANCE_SHADER));
1853
1854
1855 loadBackgroundTextures(node);
1856 finishedWithGlobalShader();
1857 }
1858 glDepthMask(GL_TRUE);
1859 glEnable(GL_DEPTH_TEST);
1860 if(didPerspective){
1861 if(1) {
1862 FW_GL_MATRIX_MODE(GL_PROJECTION);
1863 FW_GL_POP_MATRIX();
1864 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1865 }
1866 else
1867 fw_depth_slice_pop();
1868 }
1869
1870 FW_GL_POP_MATRIX();
1871
1872 /* is fog enabled? if so, disable it right now */
1873 if (vectorSize(getActiveBindableStacks(tg)->fog) >0) glEnable(GL_FOG);
1874}
1875
1876
1877void render_TextureBackground_OLD (struct X3D_TextureBackground *node) {
1878 ttglobal tg = gglobal();
1879
1880 X3D_Viewer *viewer = Viewer();
1881 /* if we are rendering blended nodes, don't bother with this one */
1882 if (renderstate()->render_blend) return;
1883
1884
1885 /* printf ("RTBG, node %d ib %d sb %d gepvp\n",node,node->isBound,node->set_bind); */
1886 /* check the set_bind eventin to see if it is TRUE or FALSE */
1887 if (node->set_bind < 100) {
1888 bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->background);
1889 }
1890
1891 /* don't even bother going further if this node is not bound on the top */
1892 if(!node->isBound) return;
1893
1894 /* is fog enabled? if so, disable it right now */
1895 if (vectorSize(getActiveBindableStacks(tg)->fog) >0) glDisable(GL_FOG);
1896
1897 /* Cannot start_list() because of moving center, so we do our own list later */
1898 moveBackgroundCentre();
1899
1900 if NODE_NEEDS_COMPILING
1901 /* recalculateBackgroundVectors will determine exact node type */
1902 recalculateBackgroundVectors((struct X3D_Background *)node);
1903
1904 /* we have a sphere (maybe one and a half, as the sky and ground are different) so scale it up so that
1905 all geometry fits within the spheres */
1906 //FW_GL_SCALE_D (viewer->backgroundPlane, viewer->backgroundPlane, viewer->backgroundPlane);
1907 glDisable(GL_DEPTH_TEST);
1908
1909 enableGlobalShader(getMyShader(COLOUR_MATERIAL_SHADER));
1910
1911 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, node->__VBO);
1912 //FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1913
1914 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
1915 FW_GL_VERTEX_POINTER(3, GL_FLOAT, sizeof(struct MyVertex), (GLfloat *)BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
1916 FW_GL_COLOR_POINTER(4, GL_FLOAT, sizeof(struct MyVertex), (GLfloat *)BUFFER_OFFSET(sizeof(struct SFVec3f))); //The starting point of Colours, 12 bytes away
1917
1918 sendArraysToGPU (GL_TRIANGLES, 0, node->__quadcount);
1919 reallyDraw();
1920 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
1921 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
1922 finishedWithGlobalShader();
1923
1924 /* now, for the textures, if they exist */
1925 if ((node->backTexture !=0) ||
1926 (node->frontTexture !=0) ||
1927 (node->leftTexture !=0) ||
1928 (node->rightTexture !=0) ||
1929 (node->topTexture !=0) ||
1930 (node->bottomTexture !=0)) {
1931
1932
1933 enableGlobalShader(getMyShader(ONE_TEX_APPEARANCE_SHADER));
1934
1935
1936
1937 loadTextureBackgroundTextures(node);
1938
1939 finishedWithGlobalShader();
1940
1941 }
1942 glEnable(GL_DEPTH_TEST);
1943
1944 /* pushes are done in moveBackgroundCentre */
1945 FW_GL_POP_MATRIX();
1946
1947 if (vectorSize(getActiveBindableStacks(tg)->fog) >0) glEnable (GL_FOG);
1948}
1949
1950//void prep_TextureBackground (struct X3D_TextureBackground *node) {
1951// ttglobal tg = gglobal();
1952//
1953// X3D_Viewer *viewer = Viewer();
1954// /* if we are rendering blended nodes, don't bother with this one */
1955// if (renderstate()->render_blend) return;
1956//
1957//
1958// /* printf ("RTBG, node %d ib %d sb %d gepvp\n",node,node->isBound,node->set_bind); */
1959// /* check the set_bind eventin to see if it is TRUE or FALSE */
1960// if (node->set_bind < 100) {
1961// bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->background);
1962// }
1963//}
1964void render_prepped_TextureBackground(struct X3D_TextureBackground *node) {
1965 double bgscale;
1966 int didPerspective;
1967 ttglobal tg = gglobal();
1968 X3D_Viewer* viewer = Viewer();
1969
1970 if (vectorSize(getActiveBindableStacks(tg)->fog) > 0) glDisable(GL_FOG);
1971
1972 /* Cannot start_list() because of moving center, so we do our own list later */
1973
1974 if (0) {
1975 //this ignors tilts and yaws (but with respect to what? bound viewpoint?)
1976 moveBackgroundCentre();
1977 }
1978 else if (1) {
1979 //March 2018 - this re-allows scene-file authored tilts to the background like other browsers
1980 // <Transform> <Background> </Transform> - tilts captured in render_Background
1981 // which we broke a few months ago
1982 double pp[3], mvmat[16], mvinv[16];
1983 bindablestack* bstack;
1984 ttglobal tg = gglobal();
1985 bstack = getActiveBindableStacks(tg);
1986 FW_GL_MATRIX_MODE(GL_MODELVIEW);
1987 FW_GL_PUSH_MATRIX();
1988 FW_GL_TRANSFORM_D(bstack->backgroundmatrix); //see (new) render_Background
1989 //we now need to cancel/undo the translation part
1990 // by moving the background back to where the vp is at 0,0,0
1991 // see also:
1992 // double * matrixAFFINE2RotationMatrix(double* rotmat, double *fullmat);
1993 // which I made from this code, but didn't have time to try here.
1994 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, mvmat);
1995 matinverseAFFINE(mvinv, mvmat);
1996 vecsetd(pp, 0.0, 0.0, 0.0);
1997 transformAFFINEd(pp, pp, mvinv);
1998 FW_GL_TRANSLATE_D(pp[0], pp[1], pp[2]);
1999 if (1) {
2000 //cancel/undo scale part, so that our background mesh stays at radius 1.0
2001 double sx, sy, sz, q[3], p[3], d[3];
2002 /* Get scale */
2003 vecsetd(p, 0.0, 0.0, 0.0);
2004 transformAFFINEd(p, p, mvmat);
2005 vecsetd(q, 1.0, 0.0, 0.0);
2006 transformAFFINEd(q, q, mvmat);
2007 sx = 1.0 / veclengthd(vecdifd(d, q, p));
2008 vecsetd(q, 0.0, 1.0, 0.0);
2009 transformAFFINEd(q, q, mvmat);
2010 sy = 1.0 / veclengthd(vecdifd(d, q, p));
2011 vecsetd(q, 0.0, 0.0, 1.0);
2012 transformAFFINEd(q, q, mvmat);
2013 sz = 1.0 / veclengthd(vecdifd(d, q, p));
2014 /* Undo the scale effects */
2015 FW_GL_SCALE_D(sx, sy, sz);
2016 }
2017 }
2018 else if (0) {
2019 //instead of transforming back to viewpoint, can we just replace transform top-of-stack with identity?
2020 //benefit: good for diagnosing background problems: near/far plane vs offset
2021 //problem: then the horizon (or orientation with texture background)- doesn't change with a tilt (or yaw)
2022 FW_GL_MATRIX_MODE(GL_MODELVIEW);
2023 FW_GL_PUSH_MATRIX();
2024 FW_GL_LOAD_IDENTITY();
2025 if (1) {
2026 //this adds vertical tilt but not horizontal yaw
2027 double matA2BVVA[16], matBVVA2A[16];
2028 avatar2BoundViewpointVerticalAvatar(matA2BVVA, matBVVA2A);
2029 fw_glSetDoublev(GL_MODELVIEW_MATRIX, matBVVA2A);
2030 }
2031 }
2032
2033 if (NODE_NEEDS_COMPILING) {
2034 recalculateTextureBackgroundVectors(node);
2035 }
2036
2037 /* we have a sphere (maybe one and a half, as the sky and ground are different) so scale it up so that
2038 all geometry fits within the spheres
2039 dug9 Sept 2014: background could in theory be a tiny box or sphere that wraps around the avatar, if
2040 you can draw it first on each frame _and_ turn off 'depth' when you draw it.
2041 dug9 Jan 2018: turned off scaling of background geom, and toggled depth test)
2042 - due to problems with float coordinate rounding when doing a geoSpatial scene
2043 - (with GC geocentric) coords at rootnode when using geoViewpoint
2044 - still problem with geo-horizon leveling of background (for near-ground)
2045 */
2046 didPerspective = FALSE;
2047
2048 if (1) {
2049 //we need to scale because somewhere else we set up a perspective transformation that
2050 //may have a big number for a nearPlane (ie with geo scenes stretching depth range)
2051 //and the perspective transforms our z's into gl's 0 to 1 range for depth
2052 //if(1) FW_GL_SCALE_D (viewer->backgroundPlane, viewer->backgroundPlane, viewer->backgroundPlane);
2053 bgscale = 1.0;
2054 //if( viewer->nearPlane >= bgscale*.5)
2055 bgscale = viewer->nearPlane + (viewer->farPlane - viewer->nearPlane) * .3;
2056 //printf("near %lf far %lf bgscale %lf\n",viewer->nearPlane,viewer->farPlane,bgscale);
2057 FW_GL_SCALE_D(bgscale, bgscale, bgscale);
2058 }
2059 else {
2060 //alternately we can replace the perspective transform, or scale the depth range
2061 GLclampd znear, zfar;
2062 fw_depth_slice_push(.1, 100); //SEEMS TO WORK remember to pop
2063 didPerspective = TRUE;
2064 }
2065 glDisable(GL_DEPTH_TEST);
2066 glDepthMask(GL_FALSE);
2067 enableGlobalShader(getMyShader(COLOUR_MATERIAL_SHADER));
2068
2069 LIGHTING_OFF
2070
2071 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
2072 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, node->__VBO);
2073#define BUFFER_OFFSET(i) ((char *)NULL + (i))
2074 FW_GL_VERTEX_POINTER(3, GL_FLOAT, (GLsizei)sizeof(struct MyVertex), (GLfloat*)BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
2075 FW_GL_COLOR_POINTER(4, GL_FLOAT, (GLsizei)sizeof(struct MyVertex), (GLfloat*)BUFFER_OFFSET(sizeof(struct SFVec3f))); //The starting point of Colours, 12 bytes away
2076
2077
2078 if (setupShaderB()) {
2079 sendArraysToGPU(GL_TRIANGLES, 0, node->__quadcount);
2080 reallyDraw();
2081 }
2082 FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
2083 FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
2084 finishedWithGlobalShader();
2085
2086 /* now, for the textures, if they exist */
2087 /* now, for the textures, if they exist */
2088 if ((node->backTexture != 0) ||
2089 (node->frontTexture != 0) ||
2090 (node->leftTexture != 0) ||
2091 (node->rightTexture != 0) ||
2092 (node->topTexture != 0) ||
2093 (node->bottomTexture != 0)) {
2094
2095 glEnable(GL_TEXTURE_2D);
2096
2097 FW_GL_VERTEX_POINTER (3,GL_FLOAT,0,BackgroundVert);
2098 FW_GL_NORMAL_POINTER (GL_FLOAT,0,Backnorms);
2099 FW_GL_TEXCOORD_POINTER (2,GL_FLOAT,0,boxtex,0);
2100
2101 enableGlobalShader(getMyShader(ONE_TEX_APPEARANCE_SHADER));
2102
2103 loadTextureBackgroundTextures(node);
2104
2105 finishedWithGlobalShader();
2106
2107 }
2108 glDepthMask(GL_TRUE);
2109 glEnable(GL_DEPTH_TEST);
2110 if (didPerspective) {
2111 if (1) {
2112 FW_GL_MATRIX_MODE(GL_PROJECTION);
2113 FW_GL_POP_MATRIX();
2114 FW_GL_MATRIX_MODE(GL_MODELVIEW);
2115 }
2116 else
2117 fw_depth_slice_pop();
2118 }
2119
2120 FW_GL_POP_MATRIX();
2121
2122 /* is fog enabled? if so, disable it right now */
2123 if (vectorSize(getActiveBindableStacks(tg)->fog) > 0) glEnable(GL_FOG);
2124}
2125
2126void render_bound_background(){
2127 //Jan 2018 changed to render bound Background first, before other nodes,
2128 // - so can turn off gl depth and don't need to scale it up - can be unit sphere, unit cube
2129
2130 ttglobal tg = gglobal();
2131 if (vectorSize(getActiveBindableStacks(tg)->background) >0){
2132 struct X3D_Node * node = vector_back(struct X3D_Node *,getActiveBindableStacks(tg)->background);
2133 switch(node->_nodeType){
2134 case NODE_Background:
2135 render_prepped_Background((struct X3D_Background*)node);
2136 break;
2137 case NODE_TextureBackground:
2138 render_prepped_TextureBackground((struct X3D_TextureBackground*)node);
2139 break;
2140 default: break;
2141 }
2142 }
2143}