FreeWRL/FreeX3D  3.0.0
Component_Layout.c
1 /*
2 
3 
4 X3D Layout 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 
41 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/layout.html
42 /* oct 2015 not sure what I need here
43 a few easy ones:
44 ScreenFontStyle is the same as FontStyle except with pixelSize instead of size
45 - I suspect implementation code would be primarily in Component_Text.c L.1326
46 - size (FontStyle) and pointSize (ScreenFontStyle) are both float, so no diff in struct, just NODE_Type
47 ScreenGroup is like Group or perhaps Transform, except it may need to alter the transform stack
48  with x,y scales so as to treat children's coords as being in screen pixels.
49 Layout - (just info node used in other nodes)
50 LayoutGroup - (like Group, sets viewport, layout) prep, fin, ChildC [compileC]
51 LayoutLayer - always called from layerset: render, rendray
52 ScreenFontStyle - (same as FontStyle node - just info node for Text)
53 ScreenGroup - (like Group except modifies scale) prep, fin, ChildC [compileC]
54 (note regular Group is funny: it sorts children by depth often, for transparency blending purposes
55  - but I assume we won't do any sorting by depth from our group-like nodes, therefore we don't need Compile)
56 */
57 enum {
58  LAYOUT_LEFT,
59  LAYOUT_CENTER,
60  LAYOUT_RIGHT,
61  LAYOUT_BOTTOM,
62  LAYOUT_TOP,
63  LAYOUT_NONE,
64  LAYOUT_WORLD,
65  LAYOUT_FRACTION,
66  LAYOUT_PIXEL,
67  LAYOUT_STRETCH,
68 };
69 
70 typedef struct layout_scale_item {
71  float scale[2];
72  int scalemode[2];
74 static layout_scale_item default_layout_scale_item = {{1.0f,1.0f},{LAYOUT_FRACTION,LAYOUT_FRACTION}};
75 
76 typedef struct pComponent_Layout{
77  Stack *layout_scale_stack;
79 void *Component_Layout_constructor(){
80  void *v = MALLOCV(sizeof(struct pComponent_Layout));
81  memset(v,0,sizeof(struct pComponent_Layout));
82  return v;
83 }
84 void Component_Layout_init(struct tComponent_Layout *t){
85  //public
86  //private
87  t->prv = Component_Layout_constructor();
88  {
90  p->layout_scale_stack = newVector(layout_scale_item, 2);
91  stack_push(layout_scale_item,p->layout_scale_stack,default_layout_scale_item);
92  }
93 }
94 void Component_Layout_clear(struct tComponent_Text *t){
95  //public
96  //private
97  {
99  //FREE_IF_NZ(p->xxx);
100  deleteStack(layout_scale_item,p->layout_scale_stack);
101  }
102 }
103 
104 
105 
106 #ifdef _MSC_VER
107 #define strcasecmp _stricmp
108 #endif
109 struct layoutmode {
110  char *key;
111  int type;
112 } layoutmodes [] = {
113  {"LEFT",LAYOUT_LEFT},
114  {"CENTER",LAYOUT_CENTER},
115  {"RIGHT",LAYOUT_RIGHT},
116  {"BOTTOM",LAYOUT_BOTTOM},
117  {"TOP",LAYOUT_TOP},
118  {"NONE",LAYOUT_NONE},
119  {"WORLD",LAYOUT_WORLD},
120  {"FRACTION",LAYOUT_FRACTION},
121  {"PIXEL",LAYOUT_PIXEL},
122  {"STRETCH",LAYOUT_STRETCH},
123  {NULL,0},
124 };
125 int lookup_layoutmode(char *cmode){
126  int i;
127  int retval;
128  struct layoutmode *lm;
129  i = 0;
130  retval = 0;
131  do{
132  lm = &layoutmodes[i];
133  if(!strcasecmp(lm->key,cmode)){
134  retval = lm->type;
135  break;
136  }
137  i++;
138  }while(layoutmodes[i].key);
139  return retval;
140 }
141 void prep_Layout(struct X3D_Node *_node);
142 void fin_Layout(struct X3D_Node *_node);
143 void getPickrayXY(int *x, int *y);
144 void prep_Viewport(struct X3D_Node * node);
145 void fin_Viewport(struct X3D_Node * node);
146 int pointinsideviewport(ivec4 vp, ivec2 pt);
147 void upd_ray();
148 
149 void prep_LayoutGroup(struct X3D_Node *_node){
150  if(_node->_nodeType == NODE_LayoutGroup){
151  ttglobal tg;
153  layout_scale_item lsi;
154 
155  struct X3D_LayoutGroup *node = (struct X3D_LayoutGroup*)_node;
156  tg = gglobal();
157  p = (ppComponent_Layout)tg->Component_Layout.prv;
158 
159  //my understanding of layoutgroup: its a child of a) LayoutLayer or b) (another) LayoutGroup
160  //except not a normal child, by my interpretation, it has its own layout scales
161  //so it needs to undo any scales applied by its parent LayoutLayer/LayoutGroup and
162  //do its own. That could be implemented different ways, I chose
163  //a scale stack just for LayoutGroup
164  lsi = stack_top(layout_scale_item,p->layout_scale_stack);
165  FW_GL_PUSH_MATRIX();
166  FW_GL_SCALE_F(1.0f/lsi.scale[0],1.0f/lsi.scale[1],1.0f);
167 
168  if(node->viewport) prep_Viewport(node->viewport);
169 
170  //now it does its own scales
171  if(node->layout) prep_Layout(node->layout);
172  }
173 }
174 void child_LayoutGroup(struct X3D_Node *_node){
175  if(_node->_nodeType == NODE_LayoutGroup){
176  int ivpvis;
177  Stack *vportstack;
178  ttglobal tg;
179  ttrenderstate rs;
180  struct X3D_LayoutGroup *node = (struct X3D_LayoutGroup*)_node;
181 
182  // compiler warning mitigation
183  UNUSED(rs);
184 
185  rs = renderstate();
186  ivpvis = TRUE;
187  if(!rs->render_vp && !rs->render_collision){
188 
189  tg = gglobal();
190  vportstack = (Stack *)tg->Mainloop._vportstack;
191  ivpvis = currentviewportvisible(vportstack);
192  if(ivpvis)
193  setcurrentviewport(vportstack);
194  }
195  if(ivpvis){
196 
197  //see prep_transform for equivalent
198  // UNUSED struct X3D_Layout *layout = NULL;
199  // UNUSED if(node->layout && node->layout->_nodeType == NODE_Layout)
200  // UNUSED layout = (struct X3D_Layout*) node->layout;
201  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
202  normalChildren(node->children);
203  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
204  }
205  }
206 }
207 void fin_LayoutGroup(struct X3D_Node *_node){
208  if(_node->_nodeType == NODE_LayoutGroup){
209  ttrenderstate rs;
210  struct X3D_LayoutGroup *node = (struct X3D_LayoutGroup*)_node;
211 
212  // compiler warning mitigation
213  UNUSED(rs);
214 
215 
216  if(node->layout) fin_Layout(node->layout);
217  if(node->viewport) fin_Viewport(node->viewport);
218  rs = renderstate();
219 
220  FW_GL_POP_MATRIX();
221 
222  }
223 }
224 
225 void compile_Layout(struct X3D_Node *_node){
226  int k;
227  struct X3D_Layout *node = (struct X3D_Layout*)_node;
228 
229  //convert string constants to integer constants,
230  // if only one string value, then it applies to both dimensions
231  node->_align.p[0] = lookup_layoutmode(node->align.p[0]->strptr);
232  k = node->align.n -1;
233  node->_align.p[1] = lookup_layoutmode(node->align.p[k]->strptr);
234  node->_offsetUnits.p[0] = lookup_layoutmode(node->offsetUnits.p[0]->strptr);
235  k = node->offsetUnits.n -1;
236  node->_offsetUnits.p[1] = lookup_layoutmode(node->offsetUnits.p[k]->strptr);
237  node->_scaleMode.p[0] = lookup_layoutmode(node->scaleMode.p[0]->strptr);
238  k = node->scaleMode.n -1;
239  node->_scaleMode.p[1] = lookup_layoutmode(node->scaleMode.p[k]->strptr);
240  node->_sizeUnits.p[0] = lookup_layoutmode(node->sizeUnits.p[0]->strptr);
241  k = node->sizeUnits.n -1;
242  node->_sizeUnits.p[1] = lookup_layoutmode(node->sizeUnits.p[k]->strptr);
243 
244 }
245 void check_compile_layout_required(struct X3D_Node *node){
246  //macro has a return; statement in it
247  COMPILE_IF_REQUIRED
248 }
249 
250 void prep_Layout(struct X3D_Node *_node){
251  //push Layout transform (backward if VF_Viewpoint pass, like Transform prep)
252  //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/layout.html#Layout
253  if(_node) {
254  float offsetpx[2], differential_scale;
255  double scale[2];
256  Stack *vportstack;
257  ivec4 pvport,vport;
258  layout_scale_item lsi;
259  struct X3D_Layout *node;
260  ttrenderstate rs;
261  ttglobal tg;
263  tg = gglobal();
264  p = (ppComponent_Layout)tg->Component_Layout.prv;
265  rs = renderstate();
266 
267  node = (struct X3D_Layout*)_node;
268  vportstack = (Stack *)tg->Mainloop._vportstack;
269  pvport = stack_top(ivec4,vportstack); //parent context viewport
270 
271  // we can/should convert string fields to int flags in a compile_layout
272  check_compile_layout_required(_node);
273 
274  //size
275  if(node->_sizeUnits.p[0] == LAYOUT_PIXEL)
276  vport.W =(int)node->size.p[0]; //pixel
277  else
278  vport.W = (int)(pvport.W * node->size.p[0]); //fraction
279  if(node->_sizeUnits.p[1] == LAYOUT_PIXEL)
280  vport.H = (int)(node->size.p[1]); //pixel
281  else
282  vport.H = (int)(pvport.H * node->size.p[1]); //fraction
283 
284  //align
285  if(node->_align.p[0] == LAYOUT_LEFT)
286  vport.X = pvport.X;
287  else if(node->_align.p[0] == LAYOUT_RIGHT)
288  vport.X = (pvport.X + pvport.W) - vport.W;
289  else //CENTER
290  vport.X = (pvport.X + pvport.W/2) - vport.W/2;
291 
292  if(node->_align.p[1] == LAYOUT_BOTTOM)
293  vport.Y = pvport.Y;
294  else if(node->_align.p[1] == LAYOUT_TOP)
295  vport.Y = (pvport.Y + pvport.H) - vport.H;
296  else //CENTER
297  vport.Y = (pvport.Y + pvport.H/2) - vport.H/2;
298 
299  //offset
300  if(node->_offsetUnits.p[0] == LAYOUT_PIXEL)
301  offsetpx[0] = node->offset.p[0]; //pixel
302  else
303  offsetpx[0] = pvport.W * node->offset.p[0]; //fraction
304  if(node->_offsetUnits.p[1] == LAYOUT_PIXEL)
305  offsetpx[1] = node->offset.p[1]; //pixel
306  else
307  offsetpx[1] = pvport.H * node->offset.p[1]; //fraction
308 
309 
310  vport.X += (int)offsetpx[0];
311  vport.Y += (int)offsetpx[1];
312 
313 
314  if(!rs->render_vp && !rs->render_collision){
315  if(rs->render_sensitive){
316  int mouseX, mouseY, inside;
317  ivec2 pt;
318  getPickrayXY(&mouseX, &mouseY);
319  pt.X = mouseX;
320  pt.Y = mouseY;
321  inside = pointinsideviewport(vport,pt);
322  if(!inside){
323  vport.W = 0;
324  vport.H = 0;
325  }
326  }
327 
328  pushviewport(vportstack, vport);
329  setcurrentviewport(vportstack);
330  upd_ray();
331  //for testing to see the rectangle
332  if(0){
333  glEnable(GL_SCISSOR_TEST);
334  glScissor(vport.X,vport.Y,vport.W,vport.H);
335  glClearColor(1.0f,1.0f,0.0f,.2f); //yellow
336  glClear(GL_COLOR_BUFFER_BIT);
337  glDisable(GL_SCISSOR_TEST);
338  }
339  }
340 
341 
342  //scale
343  differential_scale = ((float)vport.H/(float)pvport.H)/((float)vport.W/(float)pvport.W);
344  scale[0] = scale[1] = 1.0;
345  if(node->_scaleMode.p[0] == LAYOUT_PIXEL)
346  scale[0] = 2.0/(double)(vport.W); //pixel
347  if(node->_scaleMode.p[0] == LAYOUT_WORLD)
348  scale[0] = 2.0; //world same as fraction
349  else if(node->_scaleMode.p[0] == LAYOUT_FRACTION)
350  scale[0] = 2.0; //fraction
351 
352  if(node->_scaleMode.p[1] == LAYOUT_PIXEL)
353  scale[1] = 2.0/(double)(vport.H); //pixel
354  if(node->_scaleMode.p[1] == LAYOUT_WORLD)
355  scale[1] = 2.0; //world same as fraction
356  else if(node->_scaleMode.p[1] == LAYOUT_FRACTION)
357  scale[1] = 2.0; //fraction
358 
359 
360  //strech post-processing of scale
361  if(node->_scaleMode.p[0] == LAYOUT_STRETCH)
362  scale[0] = scale[1] * differential_scale;
363  if(node->_scaleMode.p[1] == LAYOUT_STRETCH)
364  scale[1] = scale[0] * 1.0f/differential_scale;
365  node->_scale.p[0] = (float) scale[0];
366  node->_scale.p[1] = (float) scale[1];
367 
368  //see prep_transform for equivalent
369  if(!rs->render_vp ) {
370  FW_GL_PUSH_MATRIX();
371  FW_GL_SCALE_F(node->_scale.p[0],node->_scale.p[1],1.0f);
372  lsi.scale[0] = (float)scale[0];
373  lsi.scale[1] = (float)scale[1];
374  lsi.scalemode[0] = node->_scaleMode.p[0];
375  lsi.scalemode[1] = node->_scaleMode.p[1];
376  stack_push(layout_scale_item,p->layout_scale_stack,lsi);
377  }else{
378  lsi.scale[0] = 1.0f;
379  lsi.scale[1] = 1.0f;
380  lsi.scalemode[0] = LAYOUT_FRACTION;
381  lsi.scalemode[1] = LAYOUT_FRACTION;
382  stack_push(layout_scale_item,p->layout_scale_stack,lsi);
383  }
384  }
385 }
386 void fin_Layout(struct X3D_Node *_node){
387  //similar to fin_Transform except the transform is reverse of prep_Layout
388  if(_node){
389  Stack *vportstack;
390  struct X3D_Layout *node;
391  ttrenderstate rs;
392  ttglobal tg;
394  tg = gglobal();
395  p = (ppComponent_Layout)tg->Component_Layout.prv;
396  rs = renderstate();
397 
398  node = (struct X3D_Layout*)_node;
399 
400 
401 
402  if(!rs->render_vp && !rs->render_collision){
403  vportstack = (Stack *)tg->Mainloop._vportstack;
404  popviewport(vportstack);
405  setcurrentviewport(vportstack);
406  upd_ray();
407  }
408 
409  stack_pop(layout_scale_item,p->layout_scale_stack);
410  if(rs->render_vp) {
411  if((node->_renderFlags & VF_Viewpoint) == VF_Viewpoint) {
412  FW_GL_SCALE_F(1.0f/node->_scale.p[0],1.0f/node->_scale.p[1],1.0f);
413  }
414  }else{
415  FW_GL_POP_MATRIX();
416  }
417  }
418 }
419 void prep_Layer(struct X3D_Node * _node);
420 void child_Layer(struct X3D_Node * _node);
421 void fin_Layer(struct X3D_Node * _node);
422 //layoutLayer functions are called only by Layerset, not via virtual functions in render_hier()
423 // - except for fun/testing they can be put in root scene to see what happens
424 void prep_LayoutLayer(struct X3D_Node *_node){
425  struct X3D_LayoutLayer *layoutlayer = (struct X3D_LayoutLayer*)_node;
426  prep_Layer(_node); //does the viewport part
427  if(layoutlayer->layout)
428  prep_Layout(layoutlayer->layout);
429 
430 }
431 void child_LayoutLayer(struct X3D_Node *_node){
432  child_Layer(_node);
433 }
434 void fin_LayoutLayer(struct X3D_Node *_node){
435  struct X3D_LayoutLayer *layoutlayer = (struct X3D_LayoutLayer*)_node;
436  //pop Layout transform (backward if VF_Viewpoint pass, like Transform fin)
437  if(layoutlayer->layout)
438  fin_Layout(layoutlayer->layout);
439  fin_Layer(_node); //pops the viewport part
440 }
441 
442 void prep_ScreenGroup(struct X3D_Node *node){
443  if(node && node->_nodeType == NODE_ScreenGroup){
444  ttglobal tg;
445  Stack *vportstack;
446  ivec4 pvport;
447  float sx,sy;
448  tg = gglobal();
449  vportstack = (Stack *)tg->Mainloop._vportstack;
450  pvport = stack_top(ivec4,vportstack); //parent context viewport
451 
452  sx = 1.0f/(float)(pvport.W);
453  sy = 1.0f/(float)(pvport.H);
454  FW_GL_PUSH_MATRIX();
455 
456  /* SCALE */
457  FW_GL_SCALE_F(sx,sy,sx);
458  //FW_GL_SCALE_F(.01f,.01f,.01f);
459  }
460 
461 }
462 void child_ScreenGroup(struct X3D_Node *_node){
463  struct X3D_ScreenGroup *node = (struct X3D_ScreenGroup*)_node;
464  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
465  normalChildren(node->children);
466  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
467 }
468 void fin_ScreenGroup(struct X3D_Node *node){
469  if(node && node->_nodeType == NODE_ScreenGroup){
470  FW_GL_POP_MATRIX();
471  }
472 }
Definition: Vector.h:36
Definition: display.c:66
Definition: display.c:65
Definition: Viewer.h:174