FreeWRL / FreeX3D 4.3.0
Component_Layout.c
1/*
2
3
4X3D 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
43a few easy ones:
44ScreenFontStyle 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
47ScreenGroup 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.
49Layout - (just info node used in other nodes)
50LayoutGroup - (like Group, sets viewport, layout) prep, fin, ChildC [compileC]
51LayoutLayer - always called from layerset: render, rendray
52ScreenFontStyle - (same as FontStyle node - just info node for Text)
53ScreenGroup - (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*/
57enum {
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
70typedef struct layout_scale_item {
71 float scale[2];
72 int scalemode[2];
74static layout_scale_item default_layout_scale_item = {{1.0f,1.0f},{LAYOUT_FRACTION,LAYOUT_FRACTION}};
75
76typedef struct pComponent_Layout{
77 Stack *layout_scale_stack;
79void *Component_Layout_constructor(){
80 void *v = MALLOCV(sizeof(struct pComponent_Layout));
81 memset(v,0,sizeof(struct pComponent_Layout));
82 return v;
83}
84void 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}
94void 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
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};
125int 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}
141void prep_Layout(struct X3D_Node *_node);
142void fin_Layout(struct X3D_Node *_node);
143void getPickrayXY(int *x, int *y);
144void prep_Viewport(struct X3D_Node * node);
145void fin_Viewport(struct X3D_Node * node);
146int pointinsideviewport(ivec4 vp, ivec2 pt);
147void upd_ray();
148
149void prep_LayoutGroup(struct X3D_Node *_node){
150 if(_node->_nodeType == NODE_LayoutGroup){
151 ttglobal tg;
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}
174void 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}
207void 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
225void 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}
245void check_compile_layout_required(struct X3D_Node *node){
246 //macro has a return; statement in it
247 COMPILE_IF_REQUIRED
248}
249
250void 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;
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}
386void 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}
419void prep_Layer(struct X3D_Node * _node);
420void child_Layer(struct X3D_Node * _node);
421void 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
424void 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}
431void child_LayoutLayer(struct X3D_Node *_node){
432 child_Layer(_node);
433}
434void 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
442void 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}
462void 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}
468void fin_ScreenGroup(struct X3D_Node *node){
469 if(node && node->_nodeType == NODE_ScreenGroup){
470 FW_GL_POP_MATRIX();
471 }
472}
Definition Viewer.h:139