FreeWRL/FreeX3D  3.0.0
Component_Layering.c
1 /*
2 
3 
4 X3D Layering Component
5 
6 */
7 /****************************************************************************
8  This file is part of the FreeWRL/FreeX3D Distribution.
9 
10  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
11 
12  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
13  it under the terms of the GNU Lesser Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
24 ****************************************************************************/
25 
26 #include <config.h>
27 #include <system.h>
28 #include <display.h>
29 #include <internal.h>
30 
31 #include <libFreeWRL.h>
32 
33 #include "../vrml_parser/Structs.h"
34 #include "../main/headers.h"
35 
36 #include "../x3d_parser/Bindable.h"
37 #include "Children.h"
38 #include "../opengl/OpenGL_Utils.h"
39 #include "../scenegraph/RenderFuncs.h"
40 #include "Viewer.h"
41 
42 
43 /*
44  http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/layering.html
45 layer - called from layerset on its render and rendray
46 layerset -kindof group, but layers not children: render and rendray
47 viewport -usage 1: info node for Layer/LayoutLayer
48  -usage 2: (standalone Group-like) prep (push&set clip), fin(pop), ChildC
49 
50 status:
51 oct 22, 2015: pseudo-code
52 Jan 2016: version 1 attempt, with:
53  - off-spec:
54  - Layer, LayoutLayer DEF namespace/executionContext shared with main scene - no EXPORT semantics (off spec, but handy)
55  - bindables from all layers end up in ProdCon bindables lists,
56  so ViewpointList (for NextViewpoint, PrevViewpoint) will (wrongly) show/allow viewpoints from all Layers
57  (should be just from activeLayer)
58  - have an extra field in all bindables for node->_layerId if that helps
59  - on-spec:
60  - Layer, LayoutLayer pushing and popping its own binding stacks in hyperstack as per specs
61  - navigation, menubar work on activeLayer
62  - per-layer viewer = Viewer()
63  */
64 
65 
66 typedef struct pComponent_Layering{
67  int layerId, saveActive, binding_stack_set;
68  struct X3D_Node *layersetnode;
70 void *Component_Layering_constructor(){
71  void *v = MALLOCV(sizeof(struct pComponent_Layering));
72  memset(v,0,sizeof(struct pComponent_Layering));
73  return v;
74 }
75 void Component_Layering_init(struct tComponent_Layering *t){
76  //public
77  //private
78  t->prv = Component_Layering_constructor();
79  {
81  p->layersetnode = NULL;
82  p->layerId = 0;
83  p->saveActive = 0;
84  p->binding_stack_set = 0;
85  }
86 }
87 void Component_Layering_clear(struct tComponent_Text *t){
88  //public
89  //private
90  {
91  // ppComponent_Layering p = (ppComponent_Layering)t->prv;
92  //FREE_IF_NZ(p->xxx);
93  }
94 }
95 
96 void getPickrayXY(int *x, int *y);
97 int pointinsideviewport(ivec4 vp, ivec2 pt);
98 ivec4 childViewport(ivec4 parentViewport, float *clipBoundary){
99  ivec4 vport;
100  vport.W = (int)((clipBoundary[1] - clipBoundary[0]) *parentViewport.W);
101  vport.X = (int)(parentViewport.X + (clipBoundary[0] * parentViewport.W));
102  vport.H = (int)((clipBoundary[3] - clipBoundary[2]) *parentViewport.H);
103  vport.Y = (int)(parentViewport.Y + (clipBoundary[2] * parentViewport.H));
104  return vport;
105 }
106 void prep_Viewport(struct X3D_Node * node);
107 void fin_Viewport(struct X3D_Node * node);
108 static float defaultClipBoundary [] = {0.0f, 1.0f, 0.0f, 1.0f}; // left/right/bottom/top 0,1,0,1
109 //Layer has 3 virtual functions prep, children, fin
110 //- LayerSet should be the only caller for these 3 normally, according to specs
111 //- if no LayerSet but a Layer then Layer doesn't do any per-layer stacks or viewer
112 void prep_Layer(struct X3D_Node * _node){
113  ttrenderstate rs;
114  struct X3D_Layer *node = (struct X3D_Layer*)_node;
115 
116 
117  rs = renderstate();
118 
119  //There's no concept of window or viewpoint on the
120  // fwl_rendersceneupdatescene(dtime) > render_pre() > render_hier VF_Viewpoint or VF_Collision
121  // pass which is just for updating the world and avatar position within the world
122  if(!rs->render_vp && !rs->render_collision){
123  //push layer.viewport onto viewport stack, setting it as the current window
124  if(node->viewport) prep_Viewport(node->viewport);
125  }
126 
127 }
128 void child_Layer(struct X3D_Node * _node){
129  int ivpvis;
130  Stack *vportstack;
131  ttglobal tg;
132  struct X3D_Layer *node;
133  ttrenderstate rs;
134 
135  rs = renderstate();
136  ivpvis = TRUE;
137  node = (struct X3D_Layer*)_node;
138  if(!rs->render_vp && !rs->render_collision){
139 
140  tg = gglobal();
141  vportstack = (Stack *)tg->Mainloop._vportstack;
142  ivpvis = currentviewportvisible(vportstack);
143  if(ivpvis)
144  setcurrentviewport(vportstack);
145  }
146  if(ivpvis){
147  if (rs->render_geom == VF_Geom)
148  glClear(GL_DEPTH_BUFFER_BIT); //if another layer has already drawn, don't clear it, just its depth fingerprint
149  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
150  normalChildren(node->children);
151  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
152  }
153 }
154 void fin_Layer(struct X3D_Node * _node){
155  ttrenderstate rs;
156  struct X3D_Layer *node = (struct X3D_Layer*)_node;
157 
158  rs = renderstate();
159 
160  if(!rs->render_vp && !rs->render_collision){
161  if(node->viewport) fin_Viewport(node->viewport);
162  }
163 
164 }
165 
166 
167 struct X3D_Node* getRayHit(void);
168 /*
169  How bindables -viewpoint, navigationInfo, background ...- get bound
170  in the correct layer's binding stacks:
171  1) during parsing we figure out their layerId, and assign it to
172  the bindable's new _layerId field
173  2) during set_bind we look at the bindable nodes's _layerId
174  and put it in the binding stacks for that layer
175  How we do #1 figure out layerId during parsing:
176  a) if no layerSet, everything goes into default layerId 0 (main scene layer)
177  b) when we hit a LayerSet during parsing we push_binding_stack_set()
178  with starts a list from 0
179  c) when we hit a Layer / LayoutLayer during parsing, we add it to the pushed list
180  via push_next_layerId_fro_binding_stack_set(), and it sets tg->Bindable.activeLayer
181  d) when we parse a bindable, during creation we set its _layerId = tg->bindable.activeLayer
182 */
183 //static int layerId, saveActive, binding_stack_set;
184 //in theory the 3 parsing temps could be stored in the LayerSet node
185 void push_binding_stack_set(struct X3D_Node* layersetnode){
186  //used during parsing to control layerId for controlling binding stack use
187  ttglobal tg = gglobal();
188  ppComponent_Layering p = (ppComponent_Layering)tg->Component_Layering.prv;
189  p->binding_stack_set++;
190  p->saveActive = tg->Bindable.activeLayer;
191  p->layerId = 0;
192  p->layersetnode = layersetnode; //specs: max one of them per scenefile
193 }
194 void push_next_layerId_from_binding_stack_set(struct X3D_Node *layer){
195  bindablestack* bstack;
196  ttglobal tg = gglobal();
197  ppComponent_Layering p = (ppComponent_Layering)tg->Component_Layering.prv;
198 
199  //only change binding stacks if there was a LayerSet node otherwise accorindg to specs everything is in one binding stack set (default layerId = 0)
200  if(p->binding_stack_set > 0){
201  p->layerId ++;
202  bstack = getBindableStacksByLayer(tg, p->layerId );
203  if(bstack == NULL){
204  bstack = MALLOCV(sizeof(bindablestack));
205  init_bindablestack(bstack, p->layerId, layer->_nodeType);
206  addBindableStack(tg,bstack);
207  }
208  //push_bindingstacks(node);
209  tg->Bindable.activeLayer = p->layerId;
210  }
211 }
212 
213 void pop_binding_stack_set(){
214  ttglobal tg = gglobal();
215  ppComponent_Layering p = (ppComponent_Layering)tg->Component_Layering.prv;
216 
217  p->binding_stack_set--;
218  tg->Bindable.activeLayer = p->saveActive;
219 }
220 void post_parse_set_activeLayer(){
221  ttglobal tg = gglobal();
222  ppComponent_Layering p = (ppComponent_Layering)tg->Component_Layering.prv;
223 
224  if(p->layersetnode && p->layersetnode->_nodeType == NODE_LayerSet){
225  struct X3D_LayerSet *ls = (struct X3D_LayerSet*)p->layersetnode;
226  tg->Bindable.activeLayer = ls->activeLayer;
227  }
228 }
229 
230 
231 
232 void prep_LayoutLayer(struct X3D_Node * _node);
233 void child_LayoutLayer(struct X3D_Node * _node);
234 void fin_LayoutLayer(struct X3D_Node * _node);
235 
236 void setup_viewpoint_part1();
237 void setup_viewpoint_part3();
238 void set_viewmatrix();
239 void setup_projection();
240 void setup_projection_tinkering();
241 void upd_ray();
242 void push_ray();
243 void pop_ray();
244 void setup_pickray0();
245 void child_LayerSet(struct X3D_Node * node){
246  // has similar responsibilities to render_heir except just for Layer, LayoutLayer children
247  // child is the only virtual function for LayerSet
248  // Bindables in Core:
249  // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/core.html#BindableChildrenNodes
250  // "If there is no LayerSet node defined, there shall be only one set of binding stacks"
251  // -that means its up to LayerSet to switch binding stacks, and manage per-layer modelview matrix stack
252  // Picking reverses the order of layers so top layer can 'swallow the mouse'
253 
254  if(node && node->_nodeType == NODE_LayerSet){
255  int ii,i,layerId;
256 
257  // UNUSED OLDCODE activeLayer
258 
259  ttglobal tg;
260  struct X3D_LayerSet * layerset;
261  ttrenderstate rs;
262 
263  rs = renderstate();
264  layerset = (struct X3D_LayerSet *)node;
265  tg = gglobal();
266  // UNUSED OLDCODE activeLayer = layerset->activeLayer;
267 
268  for(i=0;i<layerset->order.n;i++){
269 
270  int i0, saveActive, isActive;
271  struct X3D_Node *rayhit;
272  struct X3D_Layer * layer = NULL;
273  // UNUSED OLDCODE X3D_Viewer *viewer;
274  bindablestack* bstack;
275 
276  ii = i;
277  //if(0) //uncomment to pick in same layer order as render, for diagnostic testing
278  if(rs->render_sensitive == VF_Sensitive){
279  ii = layerset->order.n - ii -1; //reverse order compared to rendering
280  }
281 
282  layerId = layerset->order.p[ii];
283  isActive = layerId == tg->Bindable.activeLayer;
284  i0 = max(0,layerId -1);
285  layer = (struct X3D_Layer*)layerset->layers.p[i0];
286 
287  if(rs->render_sensitive == VF_Sensitive){
288  if(!layer->isPickable) continue; //skip unpickable layers on sensitive pass
289  }
290  if(rs->render_collision == VF_Collision && !isActive)
291  continue; //skip non-navigation layers on collision pass
292 
293 
294  //push/set binding stacks (some of this done in x3d parsing now, so bstack shouldn't be null)
295  bstack = getBindableStacksByLayer(tg, layerId );
296  if(bstack == NULL){
297  bstack = MALLOCV(sizeof(bindablestack));
298  init_bindablestack(bstack, layerId, layer->_nodeType);
299  addBindableStack(tg,bstack);
300  }
301  saveActive = tg->Bindable.activeLayer;
302  // UNUSED OLDCODE viewer = (X3D_Viewer*)bstack->viewer;
303  // UNUSED OLDCODE if(viewer) printf("layerid=%d ortho=%d ofield=%f %f %f %f\n",layerId,viewer->ortho,viewer->orthoField[0],viewer->orthoField[1],viewer->orthoField[2],viewer->orthoField[3]);
304 
305  tg->Bindable.activeLayer = layerId;
306 
307  //per-layer modelview matrix is handled here in LayerSet because according
308  //to the specs if there is no LayerSet, then there's only one
309  //set of binding stacks (one modelview matrix)
310 
311  //push modelview matrix
312  if(!isActive){
313  FW_GL_MATRIX_MODE(GL_PROJECTION);
314  FW_GL_PUSH_MATRIX();
315  FW_GL_MATRIX_MODE(GL_MODELVIEW);
316  FW_GL_PUSH_MATRIX();
317  if(rs->render_vp == VF_Viewpoint){
318  setup_viewpoint_part1();
319  }else{
320  set_viewmatrix();
321  }
322  }
323  if(!rs->render_vp && !rs->render_collision )
324  setup_projection();
325  if(rs->render_sensitive == VF_Sensitive){
326  push_ray();
327  if(!isActive) upd_ray();
328  }
329 
330 
331  //both layer and layoutlayer can be in here
332  if(layer->_nodeType == NODE_Layer){
333  prep_Layer((struct X3D_Node*)layer);
334  child_Layer((struct X3D_Node*)layer);
335  fin_Layer((struct X3D_Node*)layer);
336  }
337  else if(layer->_nodeType == NODE_LayoutLayer){
338  prep_LayoutLayer((struct X3D_Node*)layer);
339  child_LayoutLayer((struct X3D_Node*)layer);
340  fin_LayoutLayer((struct X3D_Node*)layer);
341  }
342  rayhit = NULL;
343  if(rs->render_sensitive == VF_Sensitive){
344  rayhit = getRayHit(); //if there's a clear pick of something on a higher layer, no need to check lower layers
345  pop_ray();
346  }
347 
348 
349  //pop modelview matrix
350  if(!isActive){
351  if(rs->render_vp == VF_Viewpoint){
352  setup_viewpoint_part3();
353  }
354  FW_GL_MATRIX_MODE(GL_PROJECTION);
355  FW_GL_POP_MATRIX();
356  FW_GL_MATRIX_MODE(GL_MODELVIEW);
357  FW_GL_POP_MATRIX();
358  }
359 
360  //pop binding stacks
361  tg->Bindable.activeLayer = saveActive;
362  //setup_projection();
363  if(rayhit) break;
364  }
365  tg->Bindable.activeLayer = layerset->activeLayer;
366  }
367 }
368 
369 //not sure what I need for viewport.
370 //Situation #1 standalone viewport:
371 //Maybe there should be a push and pop from a viewport stack, if rendering its children
372 // ie pre: push vport
373 // render: render children via normalChildren
374 // fin/post: pop vport
375 //Situation #2 viewport in SFNode viewport field of another layer / layout node
376 // the host node would do
377 // pre: push vport
378 // render: render itself
379 // post/fin: pop vport
380 void prep_Viewport(struct X3D_Node * node){
381  if(node && node->_nodeType == NODE_Viewport){
382  Stack *vportstack;
383  ivec4 pvport,vport;
384  float *clipBoundary; // left/right/bottom/top 0,1,0,1
385  ttrenderstate rs;
386  ttglobal tg;
387  struct X3D_Viewport * viewport = (struct X3D_Viewport *)node;
388  tg = gglobal();
389 
390  rs = renderstate();
391  //There's no concept of window or viewpoint on the
392  // fwl_rendersceneupdatescene(dtime) > render_pre() > render_hier VF_Viewpoint or VF_Collision
393  // pass which is just for updating the world and avatar position within the world
394  if(!rs->render_vp && !rs->render_collision){
395 
396  //push viewport onto viewport stack, setting it as the current window
397  vportstack = (Stack *)tg->Mainloop._vportstack;
398  pvport = stack_top(ivec4,vportstack); //parent context viewport
399  clipBoundary = defaultClipBoundary;
400  if(viewport->clipBoundary.p && viewport->clipBoundary.n > 3)
401  clipBoundary = viewport->clipBoundary.p;
402 
403  vport = childViewport(pvport,clipBoundary);
404  if(rs->render_sensitive){
405  int mouseX, mouseY, inside;
406  ivec2 pt;
407  getPickrayXY(&mouseX, &mouseY);
408  pt.X = mouseX;
409  pt.Y = mouseY;
410  inside = pointinsideviewport(vport,pt);
411  if(!inside){
412  vport.W = 0;
413  vport.H = 0;
414  }
415  }
416  pushviewport(vportstack, vport);
417  if(currentviewportvisible(vportstack)){
418  setcurrentviewport(vportstack);
419  upd_ray();
420  }
421  }
422  }
423 
424 }
425 
426 void child_Viewport(struct X3D_Node * node){
427  if(node && node->_nodeType == NODE_Viewport){
428  Stack *vportstack;
429  struct X3D_Viewport * viewport;
430  ttglobal tg;
431  tg = gglobal();
432 
433  viewport = (struct X3D_Viewport *)node;
434  vportstack = (Stack *)tg->Mainloop._vportstack;
435 
436  if(currentviewportvisible(vportstack)){
437  prep_sibAffectors((struct X3D_Node*)node,&viewport->__sibAffectors);
438  normalChildren(viewport->children);
439  fin_sibAffectors((struct X3D_Node*)node,&viewport->__sibAffectors);
440  }
441  }
442 }
443 void fin_Viewport(struct X3D_Node * node){
444  if(node && node->_nodeType == NODE_Viewport){
445  Stack *vportstack;
446  ttrenderstate rs;
447  ttglobal tg;
448  // OLDCODE UNUSED struct X3D_Viewport * viewport = (struct X3D_Viewport *)node;
449 
450  // compiler warning mitigation
451  UNUSED(rs);
452 
453  tg = gglobal();
454 
455  rs = renderstate();
456 
457  if(!rs->render_vp && !rs->render_collision){
458 
459  vportstack = (Stack *)tg->Mainloop._vportstack;
460 
461  //pop viewport
462  popviewport(vportstack);
463  setcurrentviewport(vportstack);
464  upd_ray();
465  }
466  }
467 }
Definition: Vector.h:36
Definition: display.c:66
Definition: display.c:65