FreeWRL / FreeX3D 4.3.0
Component_Rendering.c
1/*
2
3
4X3D Rendering Component
5
6*/
7
8
9/****************************************************************************
10 This file is part of the FreeWRL/FreeX3D Distribution.
11
12 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13
14 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15 it under the terms of the GNU Lesser Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26****************************************************************************/
27
28
29
30#include <config.h>
31#include <system.h>
32#include <display.h>
33#include <internal.h>
34
35#include <libFreeWRL.h>
36
37#include "../vrml_parser/Structs.h"
38#include "../main/headers.h"
39#include "../opengl/Frustum.h"
40#include "../opengl/Material.h"
41#include "../opengl/OpenGL_Utils.h"
42#include "Component_Shape.h"
43#include "../scenegraph/RenderFuncs.h"
44#include "../scenegraph/Polyrep.h"
45
46#define FW_MAXCLIPPLANES 4
47
48typedef struct pComponent_Rendering{
49
50 Stack *clipplane_stack;
51 float clipplanes[4*FW_MAXCLIPPLANES];
52}* ppComponent_Rendering;
53void *Component_Rendering_constructor(){
54 void *v = MALLOCV(sizeof(struct pComponent_Rendering));
55 memset(v,0,sizeof(struct pComponent_Rendering));
56 return v;
57}
58void Component_Rendering_init(struct tComponent_Rendering *t){
59 //public
60
61 //private
62 t->prv = Component_Rendering_constructor();
63 {
64 ppComponent_Rendering p = (ppComponent_Rendering)t->prv;
65 p->clipplane_stack = newStack(usehit);
66 }
67}
68void Component_Rendering_clear(struct tComponent_Rendering *t){
69 ppComponent_Rendering p = (ppComponent_Rendering)t->prv;
70 deleteVector(struct X3D_Node*,p->clipplane_stack);
71}
72
73
74
75/* find a bounding box that fits the coord structure. save it in the common-node area for extents.*/
76void findExtentInCoord0 (struct X3D_Node *node, int count, float* coord, int dimensions) {
77 int i;
78
79 INITIALIZE_EXTENT
80
81 if (!coord || count < 1 || dimensions < 1) return;
82 //assume dimensions > dimension are zero ie for 2D assume 3rd dimension is extent 0,0
83 if (dimensions < 3)
84 node->EXTENT_MAX_Z = node->EXTENT_MIN_Z = 0.0f;
85 if (dimensions < 2)
86 node->EXTENT_MAX_Y = node->EXTENT_MIN_Y = 0.0f;
87 for (i=0; i<count; i++) {
88 float* point = &coord[i * dimensions];
89 if (point[0] > node->EXTENT_MAX_X) node->EXTENT_MAX_X = point[0];
90 if (point[0] < node->EXTENT_MIN_X) node->EXTENT_MIN_X = point[0];
91 if (dimensions > 1) {
92 if (point[1] > node->EXTENT_MAX_Y) node->EXTENT_MAX_Y = point[1];
93 if (point[1] < node->EXTENT_MIN_Y) node->EXTENT_MIN_Y = point[1];
94 if (dimensions > 2) {
95 if (point[2] > node->EXTENT_MAX_Z) node->EXTENT_MAX_Z = point[2];
96 if (point[2] < node->EXTENT_MIN_Z) node->EXTENT_MIN_Z = point[2];
97 }
98 }
99 }
100 /* printf ("extents %f %f, %f %f, %f %f\n",node->EXTENT_MIN_X, node->EXTENT_MAX_X,
101 node->EXTENT_MIN_Y, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z, node->EXTENT_MAX_Z); */
102}
103void findExtentInCoord(struct X3D_Node* node, int count, struct SFVec3f* coord) {
104 findExtentInCoord0(node, count, (float*)coord, 3);
105}
106void render_IndexedTriangleFanSet (struct X3D_IndexedTriangleFanSet *node) {
107 //COMPILE_POLY_IF_REQUIRED(node->coord, node->fogCoord, node->color, node->normal, node->texCoord)
108 if (!compile_poly_if_required(node, node->coord, node->fogCoord, node->color, node->normal, node->texCoord))return;
109 CULL_FACE(node->solid)
110 render_polyrep(node);
111}
112
113void render_IndexedTriangleSet (struct X3D_IndexedTriangleSet *node) {
114 //COMPILE_POLY_IF_REQUIRED(node->coord, node->fogCoord, node->color, node->normal, node->texCoord)
115 if (!compile_poly_if_required(node, node->coord, node->fogCoord, node->color, node->normal, node->texCoord))return;
116 CULL_FACE(node->solid)
117 render_polyrep(node);
118
119}
120
121void render_IndexedTriangleStripSet (struct X3D_IndexedTriangleStripSet *node) {
122 //COMPILE_POLY_IF_REQUIRED( node->coord, node->fogCoord, node->color, node->normal, NULL)
123 if (!compile_poly_if_required(node, node->coord, node->fogCoord, node->color, node->normal, NULL))return;
124 CULL_FACE(node->solid)
125 render_polyrep(node);
126}
127
128void render_TriangleFanSet (struct X3D_TriangleFanSet *node) {
129 //COMPILE_POLY_IF_REQUIRED (node->coord, node->fogCoord, node->color, node->normal, node->texCoord)
130 if (!compile_poly_if_required(node, node->coord, node->fogCoord, node->color, node->normal, node->texCoord)) return;
131 CULL_FACE(node->solid)
132 render_polyrep(node);
133}
134
135void render_TriangleStripSet (struct X3D_TriangleStripSet *node) {
136 //COMPILE_POLY_IF_REQUIRED(node->coord, node->fogCoord, node->color, node->normal, node->texCoord)
137 if (!compile_poly_if_required(node, node->coord, node->fogCoord, node->color, node->normal, node->texCoord))return;
138 CULL_FACE(node->solid)
139 render_polyrep(node);
140}
141
142void render_TriangleSet (struct X3D_TriangleSet *node) {
143 //COMPILE_POLY_IF_REQUIRED(node->coord, node->fogCoord, node->color, node->normal, node->texCoord)
144 if (!compile_poly_if_required(node, node->coord, node->fogCoord, node->color, node->normal, node->texCoord))return;
145 CULL_FACE(node->solid)
146 render_polyrep(node);
147}
148
149
150
151void* set_LineRep(void *_linerep, struct SFVec3f *points, struct SFVec2f *points2D,
152 struct SFColorRGBA *colorRgba, struct SFColor *color, float *fog,
153 int nsegments, int *counts, int *starts, int *skindex)
154 {
155 //to be called from compile_Polyline2D, _Arc2D, _ArcClose2D, _Circle2D, _LineSet, _IndexedLineSet
156 if(!_linerep){
157 _linerep = MALLOC(struct X3D_LineRep*,sizeof(struct X3D_LineRep));
158 memset(_linerep,0,sizeof(struct X3D_LineRep));
159 }
160 struct X3D_LineRep *linerep = (struct X3D_LineRep *)_linerep;
161 linerep->itype = 1; //0 points 1 lines 2 mesh
162 linerep->mode = 1; //1 LINES 2 LINE_LOOP 3 LINE_STRIP
163 linerep->point = points;
164 linerep->point2D = points2D;
165 linerep->colorRgba = colorRgba;
166 linerep->color = color;
167 linerep->fogcoord = fog;
168 linerep->skindex = skindex;
169 linerep->count = counts;
170 linerep->start = starts;
171 linerep->nsegments = nsegments;
172 linerep->npoint = 0;
173 for(int i=0;i<nsegments;i++){
174 linerep->npoint += counts[i];
175 }
176 //printf("nseg %d",nsegments);
177 //for(int i=0;i<nsegments;i++){
178 // printf("[%d] count %d start %d\n",i,linerep->count[i],linerep->start[i]);
179 //}
180 return linerep;
181}
182void clear_LineRep(void *_linerep){
183 if(_linerep){
184 struct X3D_LineRep *linerep = (struct X3D_LineRep *)_linerep;
185 //doesnt own these, caller does
186 //FREE_IF_NZ(linerep->point);
187 //FREE_IF_NZ(linerep->point2D);
188 //FREE_IF_NZ(linerep->colorRgba);
189 //FREE_IF_NZ(linerep->color);
190 //FREE_IF_NZ(linerep->start);
191 //owns this
192 FREE_IF_NZ(linerep->prev);
193 FREE_IF_NZ(linerep->next);
194 memset(_linerep,0,sizeof(struct X3D_LineRep));
195 }
196}
197#define DESIRE(whichOne,zzz) ((whichOne & zzz)==zzz)
198void render_LineRep(struct X3D_LineRep *linerep){
199 //to be called from render_Polyline2D, _Arc2D, _ArcClose2D, _Circle2D, _LineSet, _IndexedLineSet
200 if (linerep && linerep->nsegments > 0) {
201 if (linerep->color) {
202 FW_GL_COLOR_POINTER (3,GL_FLOAT,0,(float *)linerep->color);
203 } else if(linerep->colorRgba) {
204 FW_GL_COLOR_POINTER (4,GL_FLOAT,0,(float *)linerep->colorRgba);
205 }
206 if (linerep->fogcoord) {
207 FW_GL_FOG_POINTER (GL_FLOAT,0,(float*)linerep->fogcoord);
208 }
209 if(linerep->point){
210 FW_GL_VERTEX_POINTER (3,GL_FLOAT,0,(float *)linerep->point);
211 }else if(linerep->point2D){
212 FW_GL_VERTEX_POINTER (2,GL_FLOAT,0,(float *)linerep->point2D);
213 }
214 if (linerep->skindex) {
215 FW_GL_CINDEX_POINTER(GL_INT, 0, (unsigned int*)linerep->skindex);
216 }
217 if(getAppearanceProperties()->linetype > 1){
218 //uh-oh - glLineStipple broken and someone wants a dashed line. We'll make our own
219 //all the home-made dashed line algos send previous and next point as attribute arrays to vertex shader
220 if(!linerep->prev){
221 linerep->prev = MALLOC(struct SFVec3f*,linerep->npoint*3*sizeof(float));
222 for(int i=1;i<linerep->npoint;i++){
223 if(linerep->point2D){
224 veccopy2f(linerep->prev[i].c,linerep->point2D[i-1].c);
225 }else if(linerep->point){
226 veccopy3f(linerep->prev[i].c,linerep->point[i-1].c);
227 }
228 }
229 if(linerep->point2D){
230 veccopy2f(linerep->prev[0].c,linerep->point2D[0].c);
231 }else if(linerep->point){
232 veccopy3f(linerep->prev[0].c,linerep->point[0].c);
233 }
234 }
235 //for GL_LINE_STRIP we don't need the nexts in the shader
236 if(1) if(!linerep->next){
237 linerep->next = MALLOC(struct SFVec3f*,linerep->npoint*3*sizeof(float));
238 if(0){
239 //conventinoal next point like prev
240 for(int i=0;i<linerep->npoint-1;i++){
241 if(linerep->point2D){
242 veccopy2f(linerep->next[i].c,linerep->point2D[i+1].c);
243 }else if(linerep->point){
244 veccopy3f(linerep->next[i].c,linerep->point[i+1].c);
245 }
246 }
247 if(linerep->point2D){
248 veccopy2f(linerep->next[linerep->npoint-1].c,linerep->point2D[linerep->npoint-1].c);
249 }else if(linerep->point){
250 veccopy3f(linerep->next[linerep->npoint-1].c,linerep->point[linerep->npoint-1].c);
251 }
252 }else if(1){
253 //float (index,segmentcount) aka findex method for vertex shader to determine
254 // if its on a starting or ending line of a polyline
255 // assumes vertexes are packed in order of segments. good luck
256 int knext = 0;
257 for (int i=0; i<linerep->nsegments; i++) {
258 for(int j=0;j<linerep->count[i];j++) {
259 linerep->next[knext].c[0] = (float)j;
260 linerep->next[knext].c[1] = (float)linerep->count[i];
261 knext++;
262 }
263 }
264 if(knext != linerep->npoint) printf("ouch in render_LineRep findexes %d points %d\n",knext,linerep->npoint);
265 }
266 }
267
268 s_shader_capabilities_t *me = getAppearanceProperties()->currentShaderProperties;
269 if (me->prevVertex != -1) {
270 glEnableVertexAttribArray(me->prevVertex);
271 glVertexAttribPointer(me->prevVertex, 3, GL_FLOAT, FALSE, 0, linerep->prev);
272 }
273 if (me->nextVertex != -1 && linerep->next) {
274 glEnableVertexAttribArray(me->nextVertex);
275 glVertexAttribPointer(me->nextVertex, 3, GL_FLOAT, FALSE, 0, linerep->next);
276 }
277
278 }
279
280 for (int i=0; i<linerep->nsegments; i++) {
281 //https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glDrawArrays.xhtml
282 if (0) {
283 printf("%d %d %d\n", i, linerep->start[i], linerep->count[i]);
284 for (int j = linerep->start[i]; j < (linerep->start[i] + linerep->count[i]); j++) {
285 struct SFVec3f pp = linerep->point[j];
286 int skindex = linerep->skindex[j];
287 printf("[% d(% f % f % f) % d]\n", j, pp.c[0], pp.c[1], pp.c[2], skindex);
288 }
289 }
290 sendArraysToGPU (GL_LINE_STRIP, linerep->start[i], linerep->count[i]);
291
292 }
293 }
294}
295
296
297void compile_IndexedLineSet (struct X3D_IndexedLineSet *node) {
298 int i, ivertex; /* temporary */
299 struct SFVec3f *points;
300 struct SFVec3f *newpoints;
301 struct SFVec3f *oldpoint;
302 struct SFColorRGBA *newcolors;
303 struct SFColorRGBA *oldcolor;
304 int* skindex;
305
306 int npoints;
307 int maxCoordFound; /* for bounds checking */
308 struct X3D_Color *cc;
309 int nSegments; /* how many individual lines in this shape */
310 int ipoly; /* for colours, !cpv, this is the color index */
311 int nVertices; /* how many vertices in the streamed set */
312 int segLength; /* temporary */
313 int *vertCountPtr; /* temporary, for vertexCount filling */
314 int **indxStartPtr; /* temporary, for creating pointer to index arr */
315 //int *vertCountPtr; /* temporary, for vertexCount filling */
316 //int **indxStartPtr; /* temporary, for creating pointer to index arr */
317 float *fog, *newfog;
318 int nfog;
319
320 int * pt;
321 //int * pt;
322 int vtc; /* temp counter - "vertex count" */
323 int curcolor; /* temp for colorIndexing. */
324 int * colorIndInt; /* used for streaming colors */
325 int * colorIndShort; /* used for streaming colors */
326 //int * colorIndShort; /* used for streaming colors */
327 int * starts; //array of starting indexes integers, used for glDrawArrays method (vs glDrawElements that takes array of index pointers)
328 int * counts; //array of point counts per segment
329
330 /* believe it or not - material emissiveColor can affect us... */
331 GLfloat defcolorRGBA[] = {1.0f, 1.0f, 1.0f,1.0f};
332
333 /* we either use the (sizeof (int)) indices passed in from user, or calculated int one */
334 colorIndInt = NULL;
335 colorIndShort = NULL;
336
337 MARK_NODE_COMPILED
338 nSegments = 0;
339 node->__segCount = 0;
340 clear_LineRep(node->_intern);
341
342 /* ok, what we do is this. Although this is Indexed, colours and vertices can have
343 different indexes; so we make them all the same. To do this, we create another
344 index (really simple one - element x contains x...) that we send to the OpenGL
345 calls.
346
347 So first, we find out the maximum coordinate requested in the IndexedLineSet,
348 AND, we find out how many line segments there are.
349 */
350
351 if (node->coord) {
352 struct Multi_Vec3f *dtmp;
353 dtmp = getCoordinate (node->coord, "IndexedLineSet");
354 npoints = dtmp->n;
355 points = dtmp->p;
356
357 /* find the extents */
358 findExtentInCoord(X3D_NODE(node), npoints, points);
359 } else {
360 return; /* no coordinates - nothing to do */
361 }
362
363 if (node->coordIndex.n == 0) return; /* no coord indexes - nothing to do */
364
365 /* sanity check that we have enough coordinates */
366 maxCoordFound = -1000;
367 nSegments = 1;
368 nVertices = 0;
369 for (i=0; i<node->coordIndex.n; i++) {
370 /* make sure that the coordIndex is greater than -1 */
371 if (node->coordIndex.p[i] < -1) {
372 ConsoleMessage ("IndexedLineSet - coordIndex less than 0 at %d\n",i);
373 return;
374 }
375
376 /* count segments; dont bother if the very last number is -1 */
377 if (node->coordIndex.p[i] == -1) {
378 if (i!=((node->coordIndex.n)-1)) nSegments++;
379 } else nVertices++;
380
381 /* try to find the highest coordinate index for bounds checking */
382 if (node->coordIndex.p[i] > maxCoordFound) maxCoordFound = node->coordIndex.p[i];
383 }
384 if (maxCoordFound > npoints) {
385 //JAS - cheat - remove the BoundingBox for root node by simply making the coordinate element count 0,
386 //JAS - but if we do that, we get this console message.
387 //JAS ConsoleMessage ("IndexedLineSet - not enough coordinates - coordindex contains higher index\n");
388 return;
389 }
390
391 /* so, at this step, we know how many line segments "nSegments" we require (starting at 0)
392 and, what the maximum coordinate is. So, lets create the new index...
393 create the index for the arrays. Really simple... Used to index
394 into the coords, so, eg, __vertArr is [0,1,2], which means use
395 coordinates 0, 1, and 2
396
397 https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/rendering.html#IndexedLineSet
398 11.4.5 has a 2D table for when
399
400 1) color field not NULL
401 CPV=true CPV=false
402 colorIndex A colorIndex per vertex C colorIndex[ipoly] per polyline
403 NULL B coordIndex per vertex D Color[ipoly] per polyline
404
405 can be passed to opengl as:
406 A. GL_LINE_STRIP vertex 1:1 color
407 B. GL_LINE_STRIP vertex 1:1 color
408 C. GL_LINE_STRIP vertex m:1 constant color for polyline
409 D. GL_LINE_STRIP vertex m:1 constant color for polyline
410 and tell the vetex shader to look in attribute fw_Color for a color
411 - and do that in compile_shape > whichShapeColorShader = getShapeColourShader(node) and shape node->_shaderflags_base |= whichShapeColorShader
412
413 2) color field NULL
414 - if Material > material.emissive
415 -- else (1,1,1)
416
417 */
418 FREE_IF_NZ (node->__vertArr);
419 node->__vertArr = MALLOC (int *, sizeof(int)*(nVertices+1));
420
421 pt = (int *)node->__vertArr;
422 //node->__vertArr = MALLOC (int *, sizeof(int)*(nVertices+1));
423 //pt = (int *)node->__vertArr;
424
425 for (vtc = 0; vtc < nVertices; vtc++) {
426 *pt=vtc; pt++; /* ie, index n contains the number n */
427 }
428
429
430 /* now, lets go through and; 1) copy old vertices into new vertex array; and
431 2) create an array of indexes into "__vertArr" for sending to the GL call */
432
433
434 FREE_IF_NZ (node->__vertIndx);
435 FREE_IF_NZ (node->__starts);
436 node->__vertIndx = MALLOC (int **,sizeof(int*)*(nSegments+2));
437 node->__starts = MALLOC (int *, sizeof(int)*(nSegments+2));
438 //node->__vertIndx = MALLOC (int **,sizeof(int*)*(nSegments+2));
439 //printf("mallocing %d segnments at address %u\n",nSegments+2,node->__vertIndx);
440 FREE_IF_NZ (node->__vertices);
441 node->__vertices = MALLOC (struct SFVec3f *, sizeof(struct SFVec3f)*(nVertices+1));
442 FREE_IF_NZ(node->__skindex);
443 node->__skindex = MALLOC(unsigned int *, sizeof(unsigned int) * (nVertices + 1));
444
445 FREE_IF_NZ (node->__vertexCount);
446 FREE_IF_NZ (node->__counts);
447 node->__vertexCount = MALLOC (int *,sizeof(int)*(nSegments+2));
448 node->__counts = MALLOC (int *, sizeof(int)*(nSegments+2));
449 //node->__vertexCount = MALLOC (int *,sizeof(int)*(nSegments+2));
450
451 int *colorIndInt2 = NULL;
452
453 /* do we have to worry about colours? */
454 /* sanity check the colors, if they exist */
455 if (node->color) {
456 /* we resort the color nodes so that we have an RGBA color node per vertex */
457 FREE_IF_NZ (node->__xcolours);
458 node->__xcolours = MALLOC (struct SFColorRGBA *, sizeof(struct SFColorRGBA)*(nVertices+1));
459 newcolors = (struct SFColorRGBA *) node->__xcolours;
460 POSSIBLE_PROTO_EXPANSION(struct X3D_Color *, node->color,cc)
461 /* cc = (struct X3D_Color *) node->color; */
462 if(cc)
463 if ((cc->_nodeType != NODE_Color) && (cc->_nodeType != NODE_ColorRGBA)) {
464 ConsoleMessage ("make_IndexedLineSet, color node, expected %d got %d\n", NODE_Color, cc->_nodeType);
465 return;
466 }
467
468 /* 4 choices here - we have colorPerVertex, and, possibly, a ColorIndex */
469
470 if (node->colorPerVertex) {
471 /* assume for now that we are using the coordIndex for colour selection */
472 colorIndInt = node->coordIndex.p;
473 /* so, we have a color per line segment. Lets check this stuff... */
474 if ((node->colorIndex.n)>0) {
475 if ((node->colorIndex.n) < (node->coordIndex.n)) {
476 ConsoleMessage ("IndexedLineSet - expect more colorIndexes to match coords\n");
477 return;
478 }
479 //cae A use colorIndex[ivertex] to get a color per vertex
480 colorIndInt = node->colorIndex.p; /* use ColorIndex */
481 } else {
482 //cae B use coordIndex[ivertex] to get a color per vertex
483 //colorIndShort = node->__vertArr;
484 colorIndInt2 = node->coordIndex.p;
485 }
486 } else {
487
488 /* so, we have a color per polyline. Lets check this stuff... */
489 if ((node->colorIndex.n)>0) {
490 if ((node->colorIndex.n) < (nSegments)) {
491 ConsoleMessage ("IndexedLineSet - expect more colorIndexes to match coords\n");
492 return;
493 }
494 // case C. use colorIndex[ipolyline] to get a color per polyline
495 colorIndInt = node->colorIndex.p; /* use ColorIndex */
496 } else {
497 /* we are using the simple index for colour selection */
498 // case D: use [jpolyline] to get color per polyline
499 colorIndShort = node->__vertArr;
500 //colorIndInt2 = node->coordIndex.p;
501 }
502 }
503
504 }
505 fog = newfog = NULL;
506 nfog = 0;
507 if(node->fogCoord){
508 struct X3D_FogCoordinate *fc;
509 FREE_IF_NZ (node->__xfog);
510 node->__xfog = MALLOC (float *, sizeof(float)*(nVertices+1));
511 newfog = node->__xfog;
512 POSSIBLE_PROTO_EXPANSION(struct X3D_FogCoordinate *, node->fogCoord,fc)
513 /* cc = (struct X3D_Color *) node->color; */
514 if(fc) {
515 if (fc->_nodeType != NODE_FogCoordinate) {
516 ConsoleMessage ("make_IndexedLineSet, fog node, expected %d got %d\n", NODE_FogCoordinate, fc->_nodeType);
517 return;
518 }
519 fog = fc->depth.p;
520 nfog = fc->depth.n;
521 }
522 //use node->coordindex.p to get a fog
523 }
524
525
526 indxStartPtr = (int **)node->__vertIndx;
527 starts = (int *)node->__starts;
528 //indxStartPtr = (int **)node->__vertIndx;
529 //printf("0 address %u\n",indxStartPtr);
530 newpoints = node->__vertices;
531 skindex = node->__skindex;
532 vertCountPtr = (int *) node->__vertexCount;
533 //vertCountPtr = (int *) node->__vertexCount;
534 counts = (int *)node->__counts;
535 pt = (int *)node->__vertArr;
536 //pt = (int *)node->__vertArr;
537
538 vtc=0;
539 segLength=0;
540 *indxStartPtr = pt; /* first segment starts off at index zero */
541 int istart = 0, ip = 0;
542 indxStartPtr++;
543 //printf("1 address %u\n",indxStartPtr);
544
545 ipoly = 0;
546 ivertex = 0;
547 starts[istart] = ip;
548
549 for (i=0; i<node->coordIndex.n+1; i++) {
550 /* count segments; dont bother if the very last number is -1 */
551 //because we may or may not have a -1 at the end of coordIndex - no requirement
552 if (node->coordIndex.p[i] == -1 || i == (node->coordIndex.n)) {
553 /* record the old segment length */
554 *vertCountPtr = segLength;
555 *indxStartPtr = pt;
556 counts[istart] = segLength;
557 istart++;
558 starts[istart] = ip;
559 ipoly++;
560 if(i < (node->coordIndex.n)){
561 /* new segment */
562 indxStartPtr++;
563 //printf("2 address %u\n",indxStartPtr);
564 segLength=0;
565 vertCountPtr ++;
566 if(colorIndInt2)
567 ivertex++;
568 }
569 } else {
570 /* new vertex */
571 oldpoint = &points[node->coordIndex.p[i]];
572 memcpy (newpoints, oldpoint,sizeof(struct SFColor));
573 *skindex = node->coordIndex.p[i];
574 if(fog){
575 int index = node->coordIndex.p[i];
576 if(index < nfog)
577 newfog[ip] = fog[index];
578 else
579 newfog[ip] = fog[nfog-1];
580 }
581 if(node->color){
582 /* have a vertex, match colour */
583 do {
584 if (node->colorPerVertex) {
585 if (colorIndInt != NULL)
586 curcolor = colorIndInt[ivertex];
587 else
588 curcolor = colorIndInt2[ivertex];
589 //curcolor = colorIndShort[ivertex];
590 } else {
591 if (colorIndInt != NULL)
592 curcolor = colorIndInt[ipoly];
593 else
594 //curcolor = colorIndInt2[ipoly];
595 curcolor = ipoly;//colorIndShort[ipoly];
596 }
597 ivertex++;
598 }while(curcolor == -1 && curcolor < cc->color.n);
599 if ((curcolor < 0) || (curcolor >= cc->color.n)) {
600 ConsoleMessage ("IndexedLineSet, colorIndex %d (for vertex %d or segment %d) out of range (0..%d)\n",
601 curcolor, i, ipoly, cc->color.n);
602 return;
603 }
604
605
606 /* copy the correct color over for this vertex */
607 if (cc->_nodeType == NODE_Color) {
608 struct SFColor* oldcolor = (struct SFColor *) cc->color.p;
609 memcpy (newcolors, defcolorRGBA, sizeof (defcolorRGBA));
610 memcpy (newcolors, &oldcolor[curcolor],sizeof(struct SFColor));
611 } else {
612 struct SFColorRGBA *oldcolor = (struct SFColorRGBA *)cc->color.p;
613 memcpy (newcolors, &oldcolor[curcolor],sizeof(struct SFColorRGBA));
614 }
615 //printf ("ipoly %d ci %d colour selected %f %f %f %f\n",ipoly, curcolor, newcolors->c[0],newcolors->c[1],newcolors->c[2],newcolors->c[3]);
616
617 newcolors ++;
618
619 }
620 newpoints ++;
621 skindex++;
622 segLength ++;
623 pt ++;
624 ip++;
625 }
626 }
627 /*
628 if(0){
629 int k=0;
630 vertCountPtr = (int *) node->__vertexCount;
631 //vertCountPtr = (int *) node->__vertexCount;
632 newcolors = (struct SFColorRGBA *) node->__xcolours;
633 float * vert = node->__vertices;
634 printf("ipoly=%d \n",ipoly);
635 for(int j=0;j<ipoly;j++){
636 printf("poly %d verts %d\n",j,(int)vertCountPtr[j]);
637 for(int i=0;i<vertCountPtr[j];i++){
638
639 struct SFColorRGBA *rgba = &newcolors[k];
640 //printf ("ipoly %d ci %d colour selected %f %f %f %f\n",j, i, rgba->c[0],rgba->c[1],rgba->c[2],rgba->c[3]);
641 printf(" ipoly %d ci %d coord %3.1f %3.1f %3.1f\n",j,i,vert[3*k],vert[3*k+1],vert[3*k+2]);
642 k++;
643 }
644 }
645 }
646 */
647 /* finish this for loop off... */
648 node->__segCount = nSegments; /* we passed, so we can render */
649 //for(int i=0;i<nSegments;i++){
650 // printf("starts[%d] = %d counts %d\n",i,starts[i],counts[i]);
651 //}
652 node->_intern = set_LineRep(node->_intern,node->__vertices,NULL,node->__xcolours,NULL,node->__xfog,node->__segCount, (int *)node->__counts,(int*)node->__starts,node->__skindex);
653 struct X3D_LineRep* lr = (struct X3D_LineRep*)node->_intern;
654 lr->coordinate_node = node->coord;
655
656}
657
658void render_IndexedLineSet (struct X3D_IndexedLineSet *node) {
659 int **indxStartPtr;
660 int *count;
661 int i;
662 ttglobal tg = gglobal();
663
664 LIGHTING_OFF
665 DISABLE_CULL_FACE
666
667 COMPILE_IF_REQUIRED
668
669 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X, node->EXTENT_MAX_Y,
670 node->EXTENT_MIN_Y, node->EXTENT_MAX_Z, node->EXTENT_MIN_Z,
671 X3D_NODE(node));
672
673 render_LineRep((struct X3D_LineRep*)node->_intern);
674}
675static struct dataType_byteSize {
676 int dataType;
677 int byteSize;
678} dataTypeSize_lookup[] = {
679 {GL_BYTE, 1},
680 {GL_SHORT, 2},
681 {GL_UNSIGNED_SHORT,2},
682 {GL_INT,4},
683 {GL_UNSIGNED_INT,4},
684 {GL_FLOAT, 4},
685 {GL_DOUBLE,8},
686 {-1,0},
687};
688
689int lookup_dataType_size(int dataType) {
690 struct dataType_byteSize* typeSize;
691 int byteSize = 0;
692 int index = -1;
693 typeSize = NULL;
694 for(index = 0;; index++) {
695 if (dataTypeSize_lookup[index].dataType < 0) break;
696 if (dataType == dataTypeSize_lookup[index].dataType) {
697 byteSize = dataTypeSize_lookup[index].byteSize;
698 break;
699 }
700 }
701
702 return byteSize;
703}
704void add_buffer_to_broto_context0(void *ectx, void* buffer) {
705 struct X3D_Proto* context = X3D_PROTO(ectx);
706 //printf("add_buffer_to_broto_context context = %p\n", context);
707 if (context) {
708 Stack* __GC;
709 if (!context->__GC)
710 context->__GC = newVector(struct X3D_Node*, 4);
711 __GC = context->__GC;
712 stack_push(void*, __GC, buffer);
713 }
714}
715void add_buffer_to_broto_context(void *buffer) {
716 struct X3D_Proto* context = X3D_PROTO(get_executionContext());
717 add_buffer_to_broto_context0(context, buffer);
718}
719void remove_buffer_from_broto_context(void * buffer) {
720 struct X3D_Proto* context = X3D_PROTO(get_executionContext());
721 if (context) {
722 if (context->__GC) {
723 int i;
724 for (i = 0; i < vectorSize(context->__GC); i++) {
725 void* ns = vector_get(void *, context->__GC, i);
726 if (ns == buffer) {
727 vector_remove_elem(void *, context->__GC, i);
728 break; //assumes its not added twice or more.
729 }
730 }
731 }
732 }
733}
734struct geomBuffer * find_buffer_in_broto_context_from_cgltf_buffer(void *ectx, void* cgltf_buffer) {
735 struct geomBuffer* found = NULL;
736 struct X3D_Proto* context = X3D_PROTO(ectx);
737 //printf("find_buffer_in_broto_context_from_cgltf_buffer context = %p\n", context);
738
739 if (context) {
740 if (context->__GC) {
741 int i;
742 for (i = 0; i < vectorSize(context->__GC); i++) {
743 void* ns = vector_get(void*, context->__GC, i);
744 if (ns) {
745 struct geomBuffer* gb = (struct geomBuffer*)ns;
746 if (gb->cgltf_buffer == cgltf_buffer) {
747 found = gb;
748 break;
749 }
750 }
751 }
752 }
753 }
754 return found;
755}
756
757struct geomBuffer* add_geomBuffer0(void *ectx, int buffersize, int users) {
758 struct geomBuffer* gb = MALLOC(struct geomBuffer*, sizeof(struct geomBuffer));
759 memset(gb, 0, sizeof(struct geomBuffer));
760 gb->address = malloc(buffersize);
761 memset(gb->address, 0, buffersize);
762 gb->byteSize = buffersize;
763 gb->users = users;
764 add_buffer_to_broto_context0(ectx,gb); //do we need to track buffers allocated? If so, adding to broto context might help
765 return gb;
766}
767struct geomBuffer* add_geomBuffer(int buffersize, int users) {
768 struct X3D_Proto* context = X3D_PROTO(get_executionContext());
769 return add_geomBuffer0(context, buffersize, users);
770}
771void set_geomBuffer(struct geomBuffer* gb) {
772 if (gb->VBO < 1) {
773 glGenBuffers(1, (GLuint*)&gb->VBO);
774 }
775 glBindBuffer(GL_ARRAY_BUFFER, (GLuint)gb->VBO);
776 glBufferData(GL_ARRAY_BUFFER, gb->byteSize, gb->address, GL_STATIC_DRAW);
777 glBindBuffer(GL_ARRAY_BUFFER, 0);
778 gb->loaded = 2;
779}
780void update_geomBufferSize(struct geomBuffer* gb, int buffersize) {
781 gb->address = realloc(gb->address,buffersize);
782 memset(gb->address, 0, buffersize);
783 gb->byteSize = buffersize;
784 set_geomBuffer(gb);
785}
786void remove_geomBuffer(struct geomBuffer *gb) {
787 glDeleteBuffers(1, &gb->VBO);
788 remove_buffer_from_broto_context(gb); //do we need to track?
789 FREE_IF_NZ(gb->address);
790 FREE_IF_NZ(gb);
791}
792void subtract_geomBufferUser(struct geomBuffer* gb) {
793 gb->users--;
794 if (gb->users < 1) remove_geomBuffer(gb);
795}
796void add_geomBufferUser(struct geomBuffer* gb) {
797 gb->users++;
798}
799int set_Attrib(struct bufAccess* ba, int dataSize, int dataType, int byteOffset) {
800 int byteSize;
801 ba->dataSize = dataSize;
802 ba->in_use = 1;
803 ba->dataType = dataType;
804 ba->byteOffset = byteOffset;
805 byteSize = ba->byteSize = ba->dataSize * lookup_dataType_size(ba->dataType);
806 return byteSize;
807}
808char* get_Attribi(struct bufAccess* ba, struct geomBuffer *gb, int index) {
809 return &gb->address[ba->byteOffset + index * ba->byteStride];
810}
811
812void* set_PointRep(void* _pointrep, float* points, int pointSize, int npoint,
813 float* color, int colorSize, int ncolor, float* fog, int nfog)
814{
815 struct X3D_PointRep* pointrep = NULL;
816 //to be called from compile_PolyPoint2D, compile_PointSet
817 //deep copies points, colors, fog. X3D_PointRep owns the copies
818 if (!points || npoint == 0) return NULL;
819
820 if (!_pointrep) {
821 _pointrep = MALLOC(struct X3D_PointRep*, sizeof(struct X3D_PointRep));
822 memset(_pointrep, 0, sizeof(struct X3D_PointRep));
823 }
824 pointrep = (struct X3D_PointRep*)_pointrep;
825 pointrep->itype = 0; //0 pointrep 1 linerep 2 polyrep
826 pointrep->mode = 0; //0 points
827
828 //experiment to see if we can do it all with sharable buffer, like glTF
829 int nbyte_per_point = set_Attrib(&pointrep->attrib[0], pointSize, GL_FLOAT, 0);
830 if (color) {
831 nbyte_per_point += set_Attrib(&pointrep->attrib[1], colorSize, GL_FLOAT, nbyte_per_point);
832 }
833 if (fog) {
834 nbyte_per_point += set_Attrib(&pointrep->attrib[2], 1, GL_FLOAT, nbyte_per_point);
835 }
836 //we have a certain way of packing attributes here,
837 // but gltf can have them packed separately with separate strides
838 for (int i = 0; i < 3; i++) pointrep->attrib[i].byteStride = nbyte_per_point;
839 //pointrep->attribByteStride = nbyte_per_point;
840 pointrep->ncoord = npoint;
841 int buffersize = nbyte_per_point * pointrep->ncoord;
842 if (!pointrep->buffer)
843 pointrep->buffer = add_geomBuffer(buffersize,1);
844 else
845 update_geomBufferSize(pointrep->buffer, buffersize);
846 struct geomBuffer* gb = pointrep->buffer;
847 struct bufAccess* ba = &pointrep->attrib[0];
848 for (int i = 0; i < pointrep->ncoord; i++) {
849 char* target = get_Attribi(ba, gb, i);
850 memcpy(target, &points[i * pointSize], pointSize * sizeof(float));
851 }
852
853 if (color) {
854 ba = &pointrep->attrib[1];
855 for (int i = 0; i < pointrep->ncoord; i++) {
856 char* target = get_Attribi(ba, gb, i);
857 int j = min(i, ncolor - 1);
858 //rgba[3] = 1.0; //default opacity, don't need if respect dataSize
859 memcpy(target, &color[j * colorSize], colorSize * sizeof(float));
860 }
861 }
862
863 if (fog) {
864 ba = &pointrep->attrib[2];
865 for (int i = 0; i < pointrep->ncoord; i++) {
866 char* target = get_Attribi(ba, gb, i);
867 int j = min(i, nfog - 1);
868 memcpy(target, &fog[j], sizeof(float));
869 }
870 }
871 set_geomBuffer(pointrep->buffer);
872 return pointrep;
873}
874
875void compile_PointSet (struct X3D_PointSet *node) {
876 int ncolor = 0, nfog = 0, npoint = 0, colorSize = 3;
877 struct X3D_Color *cc;
878 float* fog = NULL;
879 float* points = NULL;
880 float* colors = NULL; // , * colorRGBA = NULL;
881
882 /* do nothing, except get the extents here */
883 MARK_NODE_COMPILED
884
885 if (node->coord) {
886 struct Multi_Vec3f *dtmp;
887 dtmp = getCoordinate (node->coord, "PointSet");
888 if (dtmp) {
889 points = (float*)dtmp->p;
890 /* find the extents */
891 findExtentInCoord(X3D_NODE(node), dtmp->n, dtmp->p);
892
893 if (dtmp->n == 0) return;
894 npoint = dtmp->n;
895 }
896 }
897
898 if (node->color) {
899 POSSIBLE_PROTO_EXPANSION(struct X3D_Color *, node->color,cc)
900 if(cc){
901 ncolor = cc->color.n;
902 colors = (float*)cc->color.p;
903 if (cc->_nodeType == NODE_Color) {
904 colorSize = 3;
905 }
906 else if (cc->_nodeType == NODE_ColorRGBA) {
907 colorSize = 4;
908 }
909 else {
910 ConsoleMessage("make_PointSet, expected %d got %d\n", NODE_Color, cc->_nodeType);
911 ncolor = 0;
912 }
913 }
914 }
915 if (node->fogCoord) {
916 struct X3D_FogCoordinate *fc = NULL;
917 POSSIBLE_PROTO_EXPANSION(struct X3D_FogCoordinate *, node->fogCoord,fc)
918 if(fc){
919 if (fc->_nodeType != NODE_FogCoordinate) {
920 ConsoleMessage ("make_PointSet fogCoord, expected %d got %d\n", NODE_FogCoordinate, fc->_nodeType);
921 } else {
922 nfog = fc->depth.n;
923 fog = fc->depth.p;
924 }
925 }
926 }
927 node->_intern = set_PointRep(node->_intern, points, 3, npoint, colors, colorSize, ncolor, fog, nfog);
928}
929
930//same as Particle system quads
931static GLfloat quadtris [18] = {-.5f,-.5f,0.0f, .5f,-.5f,0.0f, .5f,.5f,0.0f, .5f,.5f,0.0f, -.5f,.5f,0.0f, -.5f,-.5f,0.0f,};
932static GLfloat twotrisnorms [18] = {0.f,0.f,1.f, 0.f,0.f,1.f, 0.f,0.f,1.f, 0.f,0.f,1.f, 0.f,0.f,1.f, 0.f,0.f,1.f,};
933static GLfloat twotristex [12] = {0.f,0.f, 1.f,0.f, 1.f,1.f, 1.f,1.f, 0.f,1.f, 0.f,0.f};
934
935void clearDraw();
936void reallyDrawOnce();
937
938void render_PointRep(void* _pointrep) {
939 struct X3D_PointRep* pointrep = (struct X3D_PointRep*)_pointrep;
940 if (getAppearanceProperties()->pointMethod == PM_NONE) {
941 //old style simple only, see render_PointSet for fancy.
942 struct geomBuffer *gb = pointrep->buffer;
943 if (!gb || gb->VBO < 1) return;
944 //old-stile GL_POINTS rendering - opengl generates point triangles in geometry shader automatically
945
946 glBindBuffer(GL_ARRAY_BUFFER, gb->VBO);
947 struct bufAccess* ba = &pointrep->attrib[0];
948 FW_GL_VERTEX_POINTER(ba->dataSize, ba->dataType, ba->byteStride, (GLfloat*)BUFFER_OFFSET(ba->byteOffset)); //dataSize, dataType, stride, pointer
949 //sendAttribToGPU(FW_VERTEX_POINTER_TYPE, dataSize, dataType, GL_FALSE, stride, pointer, 0, __FILE__, __LINE__);
950
951 // do we have colours?
952 ba = &pointrep->attrib[1];
953 if (ba->in_use) {
954 FW_GL_COLOR_POINTER(ba->dataSize, ba->dataType, ba->byteStride, (GLfloat*)BUFFER_OFFSET(ba->byteOffset)); //dataSize, dataType, stride, pointer
955 }
956 // do we have fogcoord?
957 ba = &pointrep->attrib[2];
958 if (ba->in_use) {
959 FW_GL_FOG_POINTER(ba->dataType, ba->byteStride, (GLfloat*)BUFFER_OFFSET(ba->byteOffset)); //dataType, stride, pointer
960 }
961 sendArraysToGPU(GL_POINTS, 0, pointrep->ncoord);
962 //printf for debugging accessors.
963 if (0) {
964 char* paddress;
965 for (int i = 0; i < pointrep->ncoord; i++) {
966 printf("%d [", i);
967 ba = &pointrep->attrib[0]; //point
968 paddress = get_Attribi(ba, gb, i);;
969 float* ai = (float*)paddress;
970 for (int j = 0; j < ba->dataSize; j++) {
971 printf("%f ", ai[j]);
972 }
973 printf("]");
974 ba = &pointrep->attrib[1]; //color
975 if (ba->in_use) {
976 paddress = get_Attribi(ba, gb, i);;
977 float* ai = (float*)paddress;
978 printf(" [");
979 for (int j = 0; j < ba->dataSize; j++)
980 printf("%f ", ai[j]);
981 printf("]");
982 }
983 ba = &pointrep->attrib[2]; //fog
984 if (ba->in_use) {
985 paddress = get_Attribi(ba, gb, i);;
986 float* ai = (float*)paddress;
987 printf(" [");
988 for (int j = 0; j < ba->dataSize; j++)
989 printf("%f ", ai[j]);
990 printf("]");
991 }
992
993 printf("\n");
994 }
995 printf("");
996 }
997 } else {
998 //PointProperties needs fancy scaling or sprite texturing
999 // we send a ParticleSystem-like quad
1000 // and send the vertex (and fogCoord, CPV) as a uniform, in a loop over the vertices.
1001 // - see also render_Polypoint2D which uses a simpler version of below
1002 s_shader_capabilities_t* mysp = getAppearanceProperties()->currentShaderProperties;
1003
1004 FW_GL_VERTEX_POINTER(3, GL_FLOAT, 0, (GLfloat*)quadtris); //node->_tris); //quadtris);
1005 FW_GL_NORMAL_POINTER(GL_FLOAT, 0, twotrisnorms);
1006 FW_GL_TEXCOORD_POINTER(2, GL_FLOAT, 0, twotristex, 0);
1007 glUniform1i(mysp->nTexCoordChannels, 1);
1008 glUniform1i(mysp->flipuv, 0);
1009 sendArraysToGPU(GL_TRIANGLES, 0, 6);
1010 GLint ppos = mysp->pointPosition; //GET_UNIFORM(mysp->myShaderProgram,"u_pointPosition");
1011 GLint pcpv = mysp->pointCPV;
1012 GLint pfog = mysp->pointFogCoord;
1013 int markertype = getAppearanceProperties()->markerType;
1014 markertype = markertype > 1 && markertype < 27 ? markertype : 0;
1015 if (markertype) {
1016 //push built-in marker texture
1017 printf("push marker texture/");
1018 }
1019
1020 for (int i = 0; i < pointrep->ncoord; i++) {
1021 //send uniform
1022 float point[3];
1023 memset(point, 0, 3 * sizeof(float));
1024 struct bufAccess* ba;
1025 char *paddress;
1026 struct geomBuffer* gb = pointrep->buffer;
1027 ba = &pointrep->attrib[0];
1028 paddress = get_Attribi(ba, gb, i);;
1029 memcpy(point, paddress, ba->byteSize);
1030 glUniform3fv(ppos, 1, point);
1031 ba = &pointrep->attrib[1];
1032 if (pcpv > -1 && ba->in_use) {
1033 float rgba[4];
1034 rgba[3] = 1.0;
1035 paddress = get_Attribi(ba, gb, i);;
1036 memcpy(rgba, paddress, ba->byteSize);
1037 glUniform4fv(pcpv, 1, rgba);
1038 }
1039 ba = &pointrep->attrib[2];
1040 if (pfog > -1 && ba->in_use) {
1041 float fog;
1042 paddress = get_Attribi(ba, gb, i);;
1043 memcpy(&fog, paddress, ba->byteSize);
1044 glUniform1f(pfog, fog );
1045 }
1046
1047 //draw
1048 reallyDrawOnce();
1049 }
1050 if (markertype) {
1051 //pop built-in marker texture
1052 printf("pop marker texture/");
1053 }
1054 clearDraw(); //child_shape also does this, redundant>
1055 }
1056}
1057
1058void delete_PointRep(void* _pointrep) {
1059 struct X3D_PointRep* pr;
1060 pr = (struct X3D_PointRep*)_pointrep;
1061 subtract_geomBufferUser(pr->buffer);
1062 FREE_IF_NZ(pr);
1063}
1064void render_PointSet (struct X3D_PointSet *node) {
1065 struct X3D_PointRep* pointrep;
1066 ttglobal tg = gglobal();
1067 if(node->coord && node->coord->_ichange != node->coord->_change)
1068 node->_ichange++;
1069 if (node->color && node->color->_ichange != node->color->_change)
1070 node->_ichange++;
1071 COMPILE_IF_REQUIRED
1072
1073 pointrep = (struct X3D_PointRep*)node->_intern;
1074 if (!pointrep)return;
1075
1076 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X, node->EXTENT_MAX_Y,
1077 node->EXTENT_MIN_Y, node->EXTENT_MAX_Z, node->EXTENT_MIN_Z,
1078 X3D_NODE(node));
1079
1080 LIGHTING_OFF
1081 DISABLE_CULL_FACE
1082
1083 render_PointRep(pointrep);
1084}
1085
1086void render_LineSet (struct X3D_LineSet *node) {
1087
1088 struct X3D_Color *cc;
1089 GLint **indices;
1090 GLsizei *count;
1091 int i;
1092 struct Multi_Vec3f* points;
1093 ttglobal tg = gglobal();
1094
1095 LIGHTING_OFF
1096 DISABLE_CULL_FACE
1097
1098 COMPILE_IF_REQUIRED
1099
1100 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X, node->EXTENT_MAX_Y,
1101 node->EXTENT_MIN_Y, node->EXTENT_MAX_Z, node->EXTENT_MIN_Z,
1102 X3D_NODE(node));
1103
1104 render_LineRep((struct X3D_LineRep*)node->_intern);
1105}
1106
1107
1108void compile_LineSet (struct X3D_LineSet *node) {
1109 int vtc; /* which vertexCount[] we should be using for this line segment */
1110 int c; /* temp variable */
1111 struct SFVec3f *coord=0; int ncoord;
1112 //struct SFColor *color=0;
1113 int ncolor=0;
1114 int *vertexC; int nvertexc;
1115 int totVertexRequired;
1116
1117 struct X3D_Color *cc;
1118 GLint *pt;
1119 int **vpt;
1120 int *starts;
1121 //int *pt;
1122 //int **vpt;
1123
1124 MARK_NODE_COMPILED
1125 node->__segCount = 0; /* assume this for now */
1126 clear_LineRep(node->_intern);
1127
1128
1129 nvertexc = (node->vertexCount).n; vertexC = (node->vertexCount).p;
1130 if (nvertexc==0) return;
1131 totVertexRequired = 0;
1132
1133 //printf ("compile_LineSet, nvertexc %d\n",nvertexc);
1134
1135
1136 /* sanity check vertex counts */
1137 for (c=0; c<nvertexc; c++) {
1138 totVertexRequired += vertexC[c];
1139 if (vertexC[c]<2) {
1140 ConsoleMessage ("make_LineSet, we have a vertexCount of %d, must be >=2,\n",vertexC[c]);
1141 return;
1142 }
1143 }
1144
1145 if (node->coord) {
1146 struct Multi_Vec3f *dtmp;
1147 dtmp = getCoordinate (node->coord, "IndexedLineSet");
1148 ncoord = dtmp->n;
1149 coord = dtmp->p;
1150
1151 /* find the extents */
1152 findExtentInCoord(X3D_NODE(node), ncoord, coord);
1153 } else {
1154 return; /* no coordinates - nothing to do */
1155 }
1156
1157 /* check that we have enough vertexes */
1158 if (totVertexRequired > ncoord) {
1159 ConsoleMessage ("make_LineSet, not enough points for vertexCount (vertices:%d points:%d)\n",
1160 totVertexRequired, ncoord);
1161 return;
1162 }
1163
1164 if (node->color) {
1165 /* cc = (struct X3D_Color *) node->color; */
1166 POSSIBLE_PROTO_EXPANSION(struct X3D_Color *, node->color,cc)
1167 if(cc){
1168 if ((cc->_nodeType != NODE_Color) && (cc->_nodeType != NODE_ColorRGBA)) {
1169 ConsoleMessage ("make_LineSet, expected %d got %d\n", NODE_Color, cc->_nodeType);
1170 } else {
1171 ncolor = cc->color.n;
1172 //color = cc->color.p;
1173 }
1174 }
1175 /* check that we have enough verticies for the Colors */
1176 if (totVertexRequired > ncolor) {
1177 ConsoleMessage ("make_LineSet, not enough colors for vertexCount (vertices:%d colors:%d)\n",
1178 totVertexRequired, ncolor);
1179 return;
1180 }
1181 }
1182
1183 /* create the index for the arrays. Really simple... Used to index
1184 into the coords, so, eg, __vertArr is [0,1,2], which means use
1185 coordinates 0, 1, and 2 */
1186 FREE_IF_NZ (node->__vertArr);
1187 node->__vertArr = MALLOC (GLuint *, sizeof(GLuint)*(ncoord));
1188 pt = (GLint *)node->__vertArr;
1189 //pt = (int *)node->__vertArr;
1190 for (vtc = 0; vtc < ncoord; vtc++) {
1191 *pt=vtc; pt++; /* ie, index n contains the number n */
1192 }
1193
1194 /* create the index for each line segment. What happens here is
1195 that we create an array of pointers; each pointer points into
1196 the __vertArr array - this gives a starting index for each line
1197 segment The LENGTH of each segment (good question) comes from the
1198 vertexCount parameter of the LineSet node */
1199 FREE_IF_NZ (node->__vertIndx);
1200 node->__vertIndx = MALLOC (int **, sizeof(int*)*(nvertexc));
1201 FREE_IF_NZ (node->__starts);
1202 node->__starts = MALLOC (int *,sizeof(int)*(nvertexc));
1203 //node->__vertIndx = MALLOC (int **, sizeof(int*)*(nvertexc));
1204 c = 0;
1205 pt = (GLint *)node->__vertArr;
1206 vpt = (int**) node->__vertIndx;
1207 starts = (int*) node->__starts;
1208 //pt = (int *)node->__vertArr;
1209 //vpt = (int**) node->__vertIndx;
1210
1211 for (vtc=0; vtc<nvertexc; vtc++) {
1212 //printf ("in position %d of __vertIndx, we have put pointer to %u\n",vtc,*pt);
1213 vpt[vtc] = (int*) pt;
1214 //vpt[vtc] = (int*) pt;
1215 pt += vertexC[vtc];
1216 if(vtc == 0)
1217 starts[vtc] = 0;
1218 else
1219 starts[vtc] = starts[vtc-1] + vertexC[vtc];
1220 }
1221
1222 /* if we made it this far, we are ok tell the rendering engine that we are ok */
1223 node->__segCount = nvertexc;
1224 //for(int i=0;i<node->__segCount;i++){
1225 // printf("[%d] start %d count %d\n",i,((int*)node->__starts)[i],vertexC[i]);
1226 //}
1227 float *fog = NULL;
1228 if(node->fogCoord){
1229 struct X3D_FogCoordinate *fogcoord = (struct X3D_FogCoordinate*)node->fogCoord;
1230 fog = fogcoord->depth.p;
1231 }
1232 node->_intern = set_LineRep(node->_intern,coord,NULL,NULL,NULL,fog,nvertexc,vertexC,(int*)node->__starts,node->__vertArr);
1233 struct X3D_LineRep* lr = (struct X3D_LineRep*)node->_intern;
1234 lr->coordinate_node = node->coord;
1235}
1236
1237/* ClipPlane
1238 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/rendering.html#ClipPlanes
1239 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/rendering.html#ClipPlane
1240 GLES2 supports only frustum clipplane. For user clipplanes:
1241 https://www.khronos.org/registry/gles/specs/2.0/es_cm_spec_2.0.25.pdf
1242 "Userclipping planes can be emulated by dot product clipping plane and vertex, and threshold result in shader"
1243 http://mrkaktus.org/opengl-clip-planes-explained/
1244 - shows different gl versions and different support technique / mechanism, desktop different than ES2 different than ES3
1245 A few links here to clipping in shader es 2:
1246 http://stackoverflow.com/questions/7408855/clipping-planes-in-opengl-es-2-0
1247 https://www.opengl.org/discussion_boards/showthread.php/171914-How-to-activate-clip-planes-via-shader
1248
1249 Implementation Suggestions:
1250 A. render_hier plubming
1251 11.2.4.4 > scoping of clipplanes >
1252 - their transform siblings are affected and children below
1253 - (dug9: maybe it could/should have been a grouping node, with its own children, like collision?)
1254 - to implement, you would use a stack, and push going down, pop coming back
1255 - need to flag parent like other sibling-affectors - see OpenGL_UTils.c VF_Sensitive
1256 - in render_node(node) on render_geom pass (doesn't make sense on any other pass?)
1257 -on prep-side of children, test for VF_ClipPlane on parent, go through children to find ClipPlane, push clipplane
1258 if node & VF_ClipPlane
1259 ifound = push_child_clipplane(node);
1260 if( ifound) pushed_clipplane = TRUE;
1261 -on fin side of children, if pushed_clipplane pop_child_clipplane
1262 B. shader plumbing
1263 https://www.opengl.org/discussion_boards/showthread.php/171914-How-to-activate-clip-planes-via-shader
1264 in shader:
1265 uniform vec4 ClipPlane[MaxClipPlanes];
1266 ...
1267 for ( int i=0; i<MaxClipPlanes; i++ )
1268 {
1269 gl_ClipDistance[i] = dot( ClipPlane[i], vec4(MCvertex,1.0));
1270 }
1271*/
1272float *getTransformedClipPlanes(){
1273 #define tactic_one_shot 1
1274 #define tactic_point_plus_normal 2
1275 int i,nsend, tactic;
1276 double modelviewmatrix[16], meinv[16], u2me[16], me2u[16], me2ut[16], u2met[16], *M, *MIT;
1277 ppComponent_Rendering p = (ppComponent_Rendering)gglobal()->Component_Rendering.prv;
1278
1279 nsend = min(FW_MAXCLIPPLANES,vectorSize(p->clipplane_stack));
1280 //Q. how transform a plane by a matrix?
1281 //option 1: 4x4 * 4x1
1282 //https://www.opengl.org/discussion_boards/showthread.php/159564-Clever-way-to-transform-plane-by-matrix
1283 //tactic = tactic_one_shot; //works
1284 //option 2: convert abcd plane into normal + 3d point, transform point and normal, then convert back to abcd
1285 //http://stackoverflow.com/questions/7685495/transforming-a-3d-plane-by-4x4-matrix
1286 tactic = tactic_point_plus_normal; //works
1287 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewmatrix);
1288 matinverseAFFINE(meinv,modelviewmatrix);
1289
1290 for(i=0;i<nsend;i++){
1291 //we take from the top-most end of the stack, in case more than MAX, using vectorget
1292 int j;
1293 struct X3D_ClipPlane *cplane;
1294 double dplane[4],dplane2[4];
1295 usehit uhit;
1296 uhit = vector_get(usehit,p->clipplane_stack,i);
1297 cplane = (struct X3D_ClipPlane *)uhit.node;
1298 matmultiplyAFFINE(u2me,uhit.mvm,meinv);
1299 mattranspose(u2met,u2me);
1300 matinverseAFFINE(me2u,u2me);
1301 mattranspose(me2ut,me2u);
1302 M = u2me; //matrix, for transforming point
1303 MIT = me2ut; //matrix inverse transpose, for transforming normal
1304
1305 for(j=0;j<4;j++) dplane[j] = cplane->plane.c[j]; //float to double
1306 if(tactic == tactic_one_shot){
1307 //works
1308 transformFULL4d(dplane2,dplane,MIT);
1309 }
1310 else
1311 {
1312 //tactic_point_plus_normal - works
1313 //vector4 O = (xyz * d, 1)
1314 double O4[4], N4[4], d;
1315 vecscaled(O4,dplane,-dplane[3]);
1316 O4[3] = 1.0;
1317 //vector4 N = (xyz, 0)
1318 veccopyd(N4,dplane);
1319 N4[3] = 0.0;
1320 //O = M * O
1321 transformAFFINEd(O4,O4,M);
1322 //N = transpose(invert(M)) * N
1323 transformAFFINEd(N4,N4,MIT);
1324 //xyz = N.xyz
1325 veccopyd(dplane2,N4);
1326 //d = dot(O.xyz, N.xyz)
1327 d = vecdotd(O4,N4);
1328 dplane2[3] = -d;
1329 }
1330 for(j=0;j<4;j++) p->clipplanes[i*4 + j] = (float) dplane2[j]; //double to float
1331 }
1332 return p->clipplanes;
1333}
1334int getClipPlaneCount(){
1335 int nsend;
1336 ppComponent_Rendering p = (ppComponent_Rendering)gglobal()->Component_Rendering.prv;
1337 nsend = min(FW_MAXCLIPPLANES,vectorSize(p->clipplane_stack));
1338 return nsend;
1339}
1340void pushShaderFlags(shaderflagsstruct flags);
1341void popShaderFlags();
1342
1343void sib_prep_ClipPlane(struct X3D_Node *parent, struct X3D_Node *sibAffector){
1344 //search for child clipplane
1345 //if found and enabled
1346 if(sibAffector && sibAffector->_nodeType == NODE_ClipPlane){
1347 // push on stack like push_sensor()
1348 struct X3D_ClipPlane * cplane = (struct X3D_ClipPlane*)sibAffector;
1349 if(cplane->enabled == TRUE){
1350 //unsigned int shaderflags;
1351 shaderflagsstruct shaderflags;
1352 double modelviewmatrix[16];
1353 usehit uhit;
1354 ppComponent_Rendering p = (ppComponent_Rendering)gglobal()->Component_Rendering.prv;
1355
1356 shaderflags = getShaderFlags();
1357 shaderflags.base |= CLIPPLANE_SHADER;
1358 pushShaderFlags(shaderflags);
1359
1360 //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/rendering.html#ClipPlanes
1361 //we'll snapshot the modelview matrix and push with clipplane node onto stack,
1362 //for use when applying in leaf shape node
1363 uhit.node = X3D_NODE(cplane); //x3dnode clipplane
1364 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewmatrix);
1365 memcpy(uhit.mvm,modelviewmatrix,16*sizeof(double)); //deep copy
1366 stack_push(usehit,p->clipplane_stack,uhit); //fat elements do another deep copy
1367
1368 //jplane = vectorSize(p->clipplane_stack) -1;
1369 //if(jplane < FW_MAXCLIPPLANES){
1370 // memcpy(&p->clipplanes[jplane*4],cplane->plane.c,4*sizeof(float));
1371 //}
1372
1373 // somehow add to end of list of clipplanes available to shader (but how precisely?)
1374 // https://www.opengl.org/discussion_boards/showthread.php/171914-How-to-activate-clip-planes-via-shader
1375 // m_pProgram->SetUniform("ClipPlane[0]", vect, 4, 1);
1376 // //except construct the name string: k = clipplanestac.n-1; "ClipPlane[%1d]",k
1377 // glEnable(GL_CLIP_DISTANCE0); //except DISTANCEk ?
1378 // might need: to set a flag indicating which shader to use?
1379
1380 }
1381 }
1382}
1383void sib_fin_ClipPlane(struct X3D_Node *parent, struct X3D_Node *sibAffector){
1384 //pop clipplane
1385 if(sibAffector && sibAffector->_nodeType == NODE_ClipPlane){
1386 struct X3D_ClipPlane * cplane = (struct X3D_ClipPlane*)sibAffector;
1387 if(cplane->enabled == TRUE){
1388 ppComponent_Rendering p = (ppComponent_Rendering)gglobal()->Component_Rendering.prv;
1389 stack_pop(usehit,p->clipplane_stack);
1390 popShaderFlags();
1391 }
1392 }
1393}