FreeWRL / FreeX3D 4.3.0
Component_Geometry2D.c
1/*
2
3
4X3D Geometry2D 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
40#include "Collision.h"
41#include "LinearAlgebra.h"
42#include "../opengl/Frustum.h"
43#include "../opengl/Material.h"
44#include "Component_Geometry3D.h"
45#include "../opengl/OpenGL_Utils.h"
46#include "../opengl/Textures.h"
47
48#include "Component_Shape.h"
49#include "../scenegraph/RenderFuncs.h"
50#include "../x3d_parser/Bindable.h"
51#include "Polyrep.h"
52
53#include <float.h>
54#if defined(_MSC_VER) && _MSC_VER < 1500
55#define cosf cos
56#define sinf sin
57#endif
58#define SEGMENTS_PER_CIRCLE 36
59#define PIE 10
60#define CHORD 20
61#define NONE 30
62
63static void *createLines (float start, float end, float radius, int closed, int *size,float *_extent);
64
65#define COMPILE_AND_GET_BOUNDS(myType,myField) \
66void compile_##myType (struct X3D_##myType *node){ \
67 float myminx = FLT_MAX; \
68 float mymaxx = -FLT_MAX; \
69 float myminy = FLT_MAX; \
70 float mymaxy = -FLT_MAX; \
71 int count; \
72 \
73 if (node->myField.n<=0) { \
74 node->EXTENT_MIN_X = 0.0f; \
75 node->EXTENT_MAX_X = 0.0f; \
76 node->EXTENT_MIN_Y = 0.0f; \
77 node->EXTENT_MAX_Y = 0.0f; \
78 } else { \
79 for (count = 0; count < node->myField.n; count++) { \
80 if (node->myField.p[count].c[0] > mymaxx) mymaxx = node->myField.p[count].c[0]; \
81 if (node->myField.p[count].c[0] < myminx) myminx = node->myField.p[count].c[0]; \
82 if (node->myField.p[count].c[1] > mymaxy) mymaxy = node->myField.p[count].c[1]; \
83 if (node->myField.p[count].c[1] < myminy) myminy = node->myField.p[count].c[1]; \
84 } \
85 node->EXTENT_MAX_X = mymaxx; \
86 node->EXTENT_MIN_X = myminx; \
87 node->EXTENT_MAX_Y = mymaxy; \
88 node->EXTENT_MIN_Y = myminy; \
89 } \
90 \
91 MARK_NODE_COMPILED \
92}
93/***********************************************************************************/
94void* set_LineRep(void *_linerep, struct SFVec3f *points, struct SFVec2f *points2D,
95 struct SFColorRGBA *colorRgba, struct SFColor *color, float *fog,
96 int nsegments, int *counts, int *starts, int *skindex);
97void clear_LineRep(void *_linerep);
98void render_LineRep(struct X3D_LineRep *linerep);
99
100void compile_Arc2D (struct X3D_Arc2D *node) {
101 /* have to regen the shape*/
102 struct SFVec2f *tmpptr_a, *tmpptr_b;
103 int tmpint;
104 static int start[1];
105
106 MARK_NODE_COMPILED
107
108 tmpint = 0;
109 clear_LineRep(node->_intern);
110 tmpptr_a = createLines (node->startAngle, node->endAngle, node->radius, NONE, &tmpint, node->_extent);
111
112 /* perform the switch - worry about threading here without locking */
113 node->__numPoints = 0; /* tell us that it has zero points */
114 tmpptr_b = node->__points.p; /* old set of points, for freeing later */
115 node->__points.p = tmpptr_a; /* new points */
116 node->__numPoints = tmpint;
117 FREE_IF_NZ (tmpptr_b);
118 /* switch completed */
119 start[0] = 0;
120 node->_intern = set_LineRep(node->_intern,NULL,node->__points.p,NULL,NULL,NULL,1,&node->__numPoints,start, NULL);
121
122}
123
124void render_Arc2D (struct X3D_Arc2D *node) {
125 ttglobal tg = gglobal();
126 COMPILE_IF_REQUIRED
127 if (node->__numPoints>0) {
128 /* for BoundingBox calculations */
129 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
130 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
131
132 LIGHTING_OFF
133 DISABLE_CULL_FACE
134 render_LineRep((struct X3D_LineRep*)node->_intern);
135 tg->Mainloop.trisThisLoop += node->__numPoints;
136 }
137}
138
139/***********************************************************************************/
140void compile_ArcClose2D (struct X3D_ArcClose2D *node){
141 /* have to regen the shape*/
142 char *ct;
143 struct SFVec2f *fp, *tp;
144 //GLfloat *tp;
145 struct SFVec2f *sfp, *stp;
146 //GLfloat *stp;
147 struct SFVec2f *ofp, *otp;
148 //GLfloat *otp;
149 int i,j,k;
150 GLfloat id;
151 GLfloat od;
152 int tmpint;
153 int simpleDisc;
154 int closure;
155 int *lindex;
156 float start, end, radius, angle, angle_increment;
157 int numPoints, arcpoints;
158
159 MARK_NODE_COMPILED
160
161
162 ct = node->closureType->strptr;
163 //xx = node->closureType->len;
164 tmpint = 0;
165
166 if (strcmp(ct,"PIE") == 0) {
167 closure = PIE;
168 } else if (strcmp(ct,"CHORD") == 0) {
169 closure = CHORD;
170 } else {
171 printf ("ArcClose2D, closureType %s invalid\n",node->closureType->strptr);
172 }
173 start = node->startAngle;
174 end = node->endAngle;
175 radius = node->radius;
176 /* is this a circle? */
177 simpleDisc = APPROX(start,end);
178
179 /* bounds check, and sort values */
180 if(end < start)
181 end += 2.0*PI;
182
183 if (radius < 0.0) radius = 1.0f;
184
185 if(0) if (start > end) {
186 float tmp = start;
187 start = end;
188 end = tmp;
189 }
190
191 if (simpleDisc) {
192 numPoints = SEGMENTS_PER_CIRCLE;
193 } else {
194 numPoints = (int) ((float)(SEGMENTS_PER_CIRCLE * (end - start))/(PI*2.0f));
195 numPoints++; //one more point than segments
196 if (numPoints>SEGMENTS_PER_CIRCLE) numPoints=SEGMENTS_PER_CIRCLE;
197 }
198 arcpoints = numPoints;
199 //add one point for pie center or half-chord - we'll fan from this point.
200 numPoints ++;
201
202 tmpint = SEGMENTS_PER_CIRCLE+2;
203 fp = sfp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * (numPoints));
204 tp = stp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * (numPoints));
205 lindex = MALLOC (int *, sizeof(int) * (numPoints*2)*2); //over malloc by a few. should be nsegs * 2 lines/seg * 2 lineEnds/line
206 //if(!node->_gc) node->_gc = newVector(void *,4); H: FreeWRLPTR gets freed, no need for _gc
207 //vector_pushBack(void*,node->_gc,lindex);
208
209 /* initial TriangleFan point */
210 (*fp).c[0] = 0.0f; (*fp).c[1] = 0.0f; fp++;
211 (*tp).c[0] = 0.5f; (*tp).c[1] = 0.5f; tp++;
212
213 angle = start;
214 angle_increment = (end - start)/(float)(arcpoints -1);
215 for (i=0,k=0,j=1;i<arcpoints;i++,k+=4,j++) {
216 float x,y;
217 x = cosf(angle);
218 y = sinf(angle);
219 (*fp).c[0] = node->radius * x;
220 (*fp).c[1] = node->radius * y;
221 fp++;
222
223 lindex[k + 0] = 0;
224 lindex[k + 1] = j;
225 lindex[k + 2] = j;
226 lindex[k + 3] = j+1;
227
228 (*tp).c[0] = 0.5f + x*.5f; //center 0,0 in middle of texture
229 (*tp).c[1] = 0.5f + y*.5f;
230 tp++;
231 angle += angle_increment;
232 angle = max(angle, start);
233 }
234 if(closure == CHORD){
235 sfp[0].c[0] = .5f * (sfp[1].c[0] + sfp[arcpoints].c[0]);
236 sfp[0].c[1] = .5f * (sfp[1].c[1] + sfp[arcpoints].c[1]);
237 stp[0].c[0] = .5f * (stp[1].c[0] + stp[arcpoints].c[0]);
238 stp[0].c[1] = .5f * (stp[1].c[1] + stp[arcpoints].c[1]);
239 }
240 node->__wireindices = lindex;
241
242
243 /* compiling done, set up for rendering. thread safe */
244 node->__numPoints = 0;
245 ofp = node->__points.p;
246 otp = node->__texCoords.p;
247 node->__points.p = sfp;
248 node->__points.n = numPoints;
249 node->__texCoords.p = stp;
250 node->__simpleDisk = simpleDisc;
251 node->__numPoints = numPoints;
252 FREE_IF_NZ (ofp);
253 FREE_IF_NZ (otp);
254
255 /* we can set the extents here... */
256 {
257 float myminx = FLT_MAX;
258 float mymaxx = -FLT_MAX;
259 float myminy = FLT_MAX;
260 float mymaxy = -FLT_MAX;
261 for (i=0; i<numPoints; i++) {
262 /* do X first */
263 if (sfp[i].c[0] > mymaxx) mymaxx = sfp[i].c[0];
264 if (sfp[i].c[0] < myminx) myminx = sfp[i].c[0];
265 fp++;
266 /* do Y second */
267 if (sfp[i].c[1] > mymaxy) mymaxy = sfp[i].c[1];
268 if (sfp[i].c[1] < myminy) myminy = sfp[i].c[1];
269 }
270
271 node->EXTENT_MAX_X = myminx; //node->radius;
272 node->EXTENT_MIN_X = mymaxx; // -node->radius;
273 node->EXTENT_MAX_Y = myminy; //node->radius;
274 node->EXTENT_MIN_Y = mymaxy; //-node->radius;
275 }
276}
277#define DESIRE(whichOne,zzz) ((whichOne & zzz)==zzz)
278void render_ArcClose2D (struct X3D_ArcClose2D *node){
279 COMPILE_IF_REQUIRED
280 if (node->__numPoints>0) {
281 struct textureVertexInfo mtf = {(GLfloat *)node->__texCoords.p,2,GL_FLOAT,0,NULL,NULL};
282 /* for BoundingBox calculations */
283 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
284 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
285
286 CULL_FACE(node->solid)
287
288 textureCoord_send(&mtf);
289 FW_GL_VERTEX_POINTER (2,GL_FLOAT,0,(GLfloat *)node->__points.p);
290
291
292 /* do the array drawing; sides are simple 0-1-2-3, 4-5-6-7, etc quads */
293 if(DESIRE(getShaderFlags().base,SHADINGSTYLE_WIRE)){
294 //wireframe triangles
295 sendElementsToGPU(GL_LINES,((node->__numPoints-1)*4 -1 ),node->__wireindices); //should be segs x 2 lines/seg = (pts-1) x 2 lines / pt
296 }else{
297 sendArraysToGPU (GL_TRIANGLE_FAN, 0, node->__numPoints);
298 }
299
300 gglobal()->Mainloop.trisThisLoop += node->__numPoints;
301 }
302}
303
304void compile_ArcClose2D_LINE (struct X3D_ArcClose2D *node) {
305 //int xx;
306 char *ct;
307 struct SFVec2f *tmpptr_a, *tmpptr_b;
308 int tmpint;
309
310 /* have to regen the shape*/
311 MARK_NODE_COMPILED
312
313 ct = node->closureType->strptr;
314 //xx = node->closureType->len;
315 tmpint = 0;
316 tmpptr_a = NULL;
317
318 if (strcmp(ct,"PIE") == 0) {
319 tmpptr_a = createLines (node->startAngle,
320 node->endAngle, node->radius, PIE, &tmpint,node->_extent);
321 } else if (strcmp(ct,"CHORD") == 0) {
322 tmpptr_a = createLines (node->startAngle,
323 node->endAngle, node->radius, CHORD, &tmpint,node->_extent);
324 } else {
325 printf ("ArcClose2D, closureType %s invalid\n",node->closureType->strptr);
326 }
327
328 /* perform the switch - worry about threading here without locking */
329 node->__numPoints = 0; /* tell us that it has zero points */
330 tmpptr_b = node->__points.p; /* old set of points, for freeing later */
331 node->__points.p = tmpptr_a; /* new points */
332 node->__numPoints = tmpint;
333 FREE_IF_NZ (tmpptr_b);
334 /* switch completed */
335}
336
337
338void render_ArcClose2D_LINE (struct X3D_ArcClose2D *node) {
339 ttglobal tg = gglobal();
340 COMPILE_IF_REQUIRED
341 if (node->__numPoints>0) {
342 /* for BoundingBox calculations */
343 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
344 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
345
346 LIGHTING_OFF
347 DISABLE_CULL_FACE
348
349
350 FW_GL_VERTEX_POINTER (2,GL_FLOAT,0,(GLfloat *)node->__points.p);
351 sendArraysToGPU (GL_LINE_STRIP, 0, node->__numPoints);
352
353 gglobal()->Mainloop.trisThisLoop += node->__numPoints;
354 }
355}
356int isLeftSide2f(float* p1, float* p2, float* px) {
357//https://en.wikipedia.org/wiki/Cross_product
358//vector 1 v1 = b - a
359//vector 2 v2 = c - a
360//sin(angle) = | v2xv1 / (| v1 | *| v2 | ) |
361
362 float v1[3];
363 float v2[3];
364 float v3[3];
365 vecset3f(v1, 0.0f, 0.0f, 0.0f);
366 vecset3f(v2, 0.0f, 0.0f, 0.0f);
367 vecdif2f(v1, p2, p1);
368 vecdif2f(v2, px, p1);
369 veccross3f(v3, v1, v2);
370 vecscale3f(v3, v3, 1.0f / (veclength3f(v1) * veclength3f(v2))); //sine(angle)
371 float sineangle = v3[2];
372 return sineangle < 0 ? -1 : (sineangle > 0 ? 1 : 0); //1 left -1 right 0 on-line
373}
374BOOL angleCounterClockwiseBetween(float a0, float a1, float angle) {
375 // a0 < angle < a1 ? TRUE : FALSE
376 // technique - get them all +ve angles and a1, angle > a0
377 // but I invented this technique in 5 minutes, if not working please fix - dug9
378 float na0, na1, nangle; //normalized angles
379 na0 = atan2(sin(a0), cos(a0)) + 2*PI;
380 na1 = atan2(sin(a1), cos(a1)) + 2*PI;
381 nangle = atan2(sin(angle), cos(angle)) + 2*PI;
382 if (na1 < na0) na1 += 2 * PI;
383 if (nangle < na0) nangle += 2 * PI;
384 if (nangle > na0 && nangle < na1) return TRUE;
385 return FALSE;
386}
387void rendray_ArcClose2D(struct X3D_ArcClose2D* node) {
388 //copy from rendray_Cylinder and hack
389 float r, a0,a1, z;
390 struct point_XYZ t_r1, t_r2;
391 get_current_ray(&t_r1, &t_r2);
392
393 r = node->radius;
394 a0 = node->startAngle;
395 a1 = node->endAngle;
396 z = 0.0f;
397 /* Caps */
398 if (!ZEQ) {
399 float zrat0 = (float)ZRAT(z);
400 if (TRAT(zrat0)) {
401 float cx = (float)MRATX(zrat0);
402 float cy = (float)MRATY(zrat0);
403 float rhit2 = cx * cx + cy * cy;
404 if (r * r > rhit2 ) {
405 //inside circle
406 float angle = atan2(cy, cx);
407 if(angleCounterClockwiseBetween(a0,a1,angle)){
408 //inside pie
409 if(!strcmp(node->closureType->strptr,"PIE"))
410 rayhit(zrat0, cx, cy, z, 0, 0, 1, -1, -1, "arcclose2dpie");
411 else {
412 //closuretype chord
413 //hypothesis if hitpoint is to the right of clockwise chord [start - end], then its inside
414 float p1[2], p2[2], px[2];
415 p1[0] = r * cos(a0);
416 p1[1] = r * sin(a0);
417 p2[0] = r * cos(a1);
418 p2[1] = r * sin(a1);
419 px[0] = cx;
420 px[1] = cy;
421 if (isLeftSide2f(p1, p2, px) < 0) {
422 rayhit(zrat0, cx, cy, z, 0, 0, 1, -1, -1, "arcclose2dchord");
423 }
424 }
425 }
426 }
427 }
428 }
429}
430
431/***********************************************************************************/
432
433void compile_Circle2D (struct X3D_Circle2D *node) {
434 struct SFVec2f *tmpptr_a, *tmpptr_b;
435 int tmpint;
436 static int start[1];
437 /* have to regen the shape*/
438 MARK_NODE_COMPILED
439
440 clear_LineRep(node->_intern);
441 tmpptr_a = createLines (0.0f, 0.0f, node->radius, NONE, &tmpint,node->_extent);
442
443 /* perform the switch - worry about threading here without locking */
444 node->__numPoints = 0; /* tell us that it has zero points */
445 tmpptr_b = node->__points.p; /* old set of points, for freeing later */
446 node->__points.p = tmpptr_a; /* new points */
447 node->__numPoints = tmpint;
448 FREE_IF_NZ (tmpptr_b);
449 /* switch completed */
450 start[0] = 0;
451 node->_intern = set_LineRep(node->_intern,NULL,node->__points.p,NULL,NULL,NULL,1,&node->__numPoints,start,NULL);
452}
453
454void render_Circle2D (struct X3D_Circle2D *node) {
455 ttglobal tg = gglobal();
456 COMPILE_IF_REQUIRED
457 if (node->__numPoints>0) {
458 /* for BoundingBox calculations */
459 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
460 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
461
462 LIGHTING_OFF
463 DISABLE_CULL_FACE
464 render_LineRep((struct X3D_LineRep*)node->_intern);
465 gglobal()->Mainloop.trisThisLoop += node->__numPoints;
466 }
467}
468
469/***********************************************************************************/
470
471
472//COMPILE_AND_GET_BOUNDS(Polyline2D,lineSegments)
473float * extent6f_from_box2fn(float *extent6,float *p, int n);
474void compile_Polyline2D (struct X3D_Polyline2D *node){
475 static int start[1];
476 extent6f_from_box2fn(node->_extent,(float*)node->lineSegments.p,node->lineSegments.n);
477 MARK_NODE_COMPILED
478 start[0] = 0;
479 node->_intern = set_LineRep(node->_intern,NULL,node->lineSegments.p,NULL,NULL,NULL,1,&node->lineSegments.n,start,NULL);
480}
481
482void render_Polyline2D (struct X3D_Polyline2D *node){
483 ttglobal tg = gglobal();
484
485 COMPILE_IF_REQUIRED
486 if (node->lineSegments.n>0) {
487 /* for BoundingBox calculations */
488 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
489 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
490
491 LIGHTING_OFF
492 DISABLE_CULL_FACE
493
494 render_LineRep((struct X3D_LineRep*)node->_intern);
495 gglobal()->Mainloop.trisThisLoop += node->lineSegments.n;
496 }
497}
498
499/***********************************************************************************/
500
501void compile_Polypoint2D(struct X3D_Polypoint2D* node) {
502 int npoint = 0;
503 float* points = NULL;
504
505 /* do nothing, except get the extents here */
506 MARK_NODE_COMPILED
507 if (node->point.n > 0) {
508 points = (float *)node->point.p;
509 npoint = node->point.n;
510 }
511 findExtentInCoord0(X3D_NODE(node), npoint, points, 2);
512 if(npoint)
513 node->_intern = set_PointRep(node->_intern, points, 2, npoint, NULL, 4,0,NULL,0);
514}
515
516void render_Polypoint2D (struct X3D_Polypoint2D *node){
517 ttglobal tg = gglobal();
518
519 COMPILE_IF_REQUIRED
520
521 LIGHTING_OFF
522 DISABLE_CULL_FACE
523 setExtent(node->EXTENT_MAX_X, node->EXTENT_MIN_X, node->EXTENT_MAX_Y,
524 node->EXTENT_MIN_Y, node->EXTENT_MAX_Z, node->EXTENT_MIN_Z,
525 X3D_NODE(node));
526
527 if (!node->_intern) return;
528 render_PointRep(node->_intern);
529}
530
531/***********************************************************************************/
532
533void compile_Disk2D (struct X3D_Disk2D *node){
534 /* have to regen the shape*/
535 struct SFVec2f *fp, *tp;
536 //GLfloat *tp;
537 struct SFVec2f *sfp, *stp;
538 //GLfloat *stp;
539 struct SFVec2f *ofp, *otp;
540 //GLfloat *otp;
541 int i, j, k, m;
542 GLfloat id;
543 GLfloat od;
544 int tmpint;
545 int simpleDisc;
546 int *lindex;
547
548 MARK_NODE_COMPILED
549
550
551 /* bounds checking */
552 if (node->innerRadius<0) {node->__numPoints = 0; return;}
553 if (node->outerRadius<0) {node->__numPoints = 0; return;}
554
555 /* is this a simple disc ? */
556 if ((APPROX (node->innerRadius, 0.0)) ||
557 (APPROX(node->innerRadius,node->outerRadius))) simpleDisc = TRUE;
558 else simpleDisc = FALSE;
559
560 /* is this a simple disk, or one with an inner circle cut out? */
561 if (simpleDisc) {
562 tmpint = SEGMENTS_PER_CIRCLE+2;
563 fp = sfp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * (tmpint));
564 tp = stp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * (tmpint)); //(GLfloat *, sizeof(GLfloat) * 2 * (tmpint));
565 lindex = MALLOC (int *, sizeof(int) * (tmpint*2)*2); //over malloc by a few. should be nsegs * 2 lines/seg * 2 lineEnds/line
566 //if(!node->_gc) node->_gc = newVector(void *,4); H: FreeWRLPTR gets freed, no need for _gc
567 //vector_pushBack(void*,node->_gc,lindex);
568
569 /* initial TriangleFan point */
570 (*fp).c[0] = 0.0f; (*fp).c[1] = 0.0f; fp++;
571 (*tp).c[0] = 0.5f; (*tp).c[1] = 0.5f; tp++;
572 id = 2.0f;
573
574 for (i=SEGMENTS_PER_CIRCLE,j=1,k=0,m=0; i >= 0; i--,j++,k+=4,m++) {
575 (*fp).c[0] = node->outerRadius * sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
576 (*fp).c[1] = node->outerRadius * cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
577 fp++;
578
579 lindex[k + 0] = 0;
580 lindex[k + 1] = j;
581 lindex[k + 2] = j;
582 lindex[k + 3] = j+1;
583
584 (*tp).c[0] = 0.5f + (sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE))/id);
585 (*tp).c[1] = 0.5f + (cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE))/id);
586 tp++;
587 }
588
589 node->__wireindices = lindex;
590 } else {
591 tmpint = (SEGMENTS_PER_CIRCLE+1) * 2;
592 fp = sfp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * 2 * tmpint);
593 tp = stp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * (tmpint)); //MALLOC (GLfloat *, sizeof(GLfloat) * 2 * tmpint);
594 lindex = MALLOC (int *, sizeof(int) * (tmpint*2) *2); //over malloc by a few, should be (nseg-1)*4 lines/seg * 2 lineEnds per line
595 //if(!node->_gc) node->_gc = newVector(void *,4);
596 //vector_pushBack(void*,node->_gc,lindex);
597
598 /* texture scaling params */
599 od = 2.0f;
600 id = node->outerRadius * 2.0f / node->innerRadius;
601
602 for (i=SEGMENTS_PER_CIRCLE,j=0,k=0,m=0; i >= 0; i--,j+=2,k+=8,m++) {
603 (*fp).c[0] = node->innerRadius * (float) sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
604 (*fp).c[1] = node->innerRadius * (float) cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
605 fp++;
606 (*fp).c[0] = node->outerRadius * (float) sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
607 (*fp).c[1] = node->outerRadius * (float) cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
608 fp++;
609
610 lindex[k + 0] = j;
611 lindex[k + 1] = j+1;
612 lindex[k + 2] = j+1;
613 lindex[k + 3] = j+2;
614 lindex[k + 4] = j+2;
615 lindex[k + 5] = j;
616 lindex[k + 6] = j+1;
617 lindex[k + 7] = j+3;
618
619 (*tp).c[0] = 0.5f + ((float)sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE))/id);
620 (*tp).c[1] = 0.5f + ((float)cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE))/id);
621 tp++;
622 (*tp).c[0] = 0.5f + ((float)sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE))/od);
623 (*tp).c[1] = 0.5f + ((float)cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE))/od);
624 tp++;
625 }
626 node->__wireindices = lindex;
627 }
628
629
630 /* compiling done, set up for rendering. thread safe */
631 node->__numPoints = 0;
632 ofp = node->__points.p;
633 otp = node->__texCoords.p;
634 node->__points.p = sfp;
635 node->__points.n = tmpint;
636 node->__texCoords.p = stp;
637 node->__simpleDisk = simpleDisc;
638 node->__numPoints = tmpint;
639 FREE_IF_NZ (ofp);
640 FREE_IF_NZ (otp);
641
642 /* we can set the extents here... */
643 node->EXTENT_MAX_X = node->outerRadius;
644 node->EXTENT_MIN_X = -node->outerRadius;
645 node->EXTENT_MAX_Y = node->outerRadius;
646 node->EXTENT_MIN_Y = -node->outerRadius;
647}
648
649void render_Disk2D (struct X3D_Disk2D *node){
650 COMPILE_IF_REQUIRED
651 if (node->__numPoints>0) {
652 struct textureVertexInfo mtf = {(GLfloat *)node->__texCoords.p,2,GL_FLOAT,0,NULL,NULL};
653 /* for BoundingBox calculations */
654 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
655 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
656
657 CULL_FACE(node->solid)
658
659 textureCoord_send(&mtf);
660 FW_GL_VERTEX_POINTER (2,GL_FLOAT,0,(GLfloat *)node->__points.p);
661
662
663 /* do the array drawing; sides are simple 0-1-2-3, 4-5-6-7, etc quads */
664 if (node->__simpleDisk) {
665 if(DESIRE(getShaderFlags().base,SHADINGSTYLE_WIRE)){
666 //wireframe triangles
667 sendElementsToGPU(GL_LINES,((node->__numPoints-1)*4 -1 ),node->__wireindices); //should be segs x 2 lines/seg = (pts-1) x 2 lines / pt
668 }else{
669 sendArraysToGPU (GL_TRIANGLE_FAN, 0, node->__numPoints);
670 }
671 }
672 else{
673 if(DESIRE(getShaderFlags().base,SHADINGSTYLE_WIRE)){
674 //wireframe triangles
675 sendElementsToGPU(GL_LINES,(node->__numPoints*4 -4 -1),node->__wireindices); //(nseg -1)*4 = (npts-2)*2 = npts*2 -4
676 }else{
677 sendArraysToGPU (GL_TRIANGLE_STRIP, 0, node->__numPoints);
678 }
679 }
680
681 gglobal()->Mainloop.trisThisLoop += node->__numPoints;
682 }
683}
684void rendray_Disk2D(struct X3D_Disk2D* node) {
685 //copy from rendray_Cylinder and hack
686 float ri,ro, z;
687 struct point_XYZ t_r1, t_r2;
688 get_current_ray(&t_r1, &t_r2);
689
690 ri = node->innerRadius;
691 ro = node->outerRadius;
692 z = 0.0f;
693 /* Caps */
694 if (!ZEQ) {
695 float zrat0 = (float)ZRAT(z);
696 if (TRAT(zrat0)) {
697 float cx = (float)MRATX(zrat0);
698 float cy = (float)MRATY(zrat0);
699 float rhit2 = cx * cx + cy * cy;
700 if (ro * ro > rhit2 && ri * ri < rhit2) {
701 rayhit(zrat0, cx, cy, z, 0, 0, 1, -1, -1, "disk2d");
702 }
703 }
704 }
705}
706
707/***********************************************************************************/
708
709void compile_TriangleSet2D (struct X3D_TriangleSet2D *node){
710 /* have to regen the shape*/
711 GLfloat maxX, minX;
712 GLfloat maxY, minY;
713 GLfloat Ssize, Tsize;
714 int i,j;
715 int *lindex;
716 struct SFVec2f *fp; //GLfloat *fp;
717 int tmpint;
718
719 MARK_NODE_COMPILED
720
721 /* do we have vertex counts in sets of 3? */
722 if ((node->vertices.n %3) != 0) {
723 printf ("TriangleSet2D, have incorrect vertex count, %d\n",node->vertices.n);
724 node->vertices.n -= node->vertices.n % 3;
725 }
726
727 /* save this, and tell renderer that this has 0 vertices (threading stuff) */
728 tmpint = node->vertices.n;
729 node->vertices.n = 0;
730
731 /* ok, now if renderer renders (threading) it'll see zero, so we are safe */
732 FREE_IF_NZ (node->__texCoords.p);
733 node->__texCoords.p = fp = MALLOC (struct SFVec2f *, sizeof(struct SFVec2f) * (tmpint)); //MALLOC (GLfloat *, sizeof (GLfloat) * tmpint * 2);
734 node->__texCoords.n = tmpint;
735 node->__wireindices = lindex = MALLOC (int *, sizeof(int)*(tmpint+1)*2); //over malloc a bit, should be: pts = lines, lines * 2 ends/line
736 /* find min/max values for X and Y axes */
737 minY = minX = FLT_MAX;
738 maxY = maxX = -FLT_MAX;
739 for (i=0; i<tmpint; i++) {
740 if (node->vertices.p[i].c[0] < minX) minX = node->vertices.p[i].c[0];
741 if (node->vertices.p[i].c[1] < minY) minY = node->vertices.p[i].c[1];
742 if (node->vertices.p[i].c[0] > maxX) maxX = node->vertices.p[i].c[0];
743 if (node->vertices.p[i].c[1] > maxY) maxY = node->vertices.p[i].c[1];
744 }
745
746 /* save these numbers for extents */
747 node->EXTENT_MAX_X = maxX;
748 node->EXTENT_MIN_X = minX;
749 node->EXTENT_MAX_Y = maxY;
750 node->EXTENT_MIN_Y = minY;
751
752 /* printf ("minX %f maxX %f minY %f maxY %f\n",minX, maxX, minY, maxY); */
753 Ssize = maxX - minX;
754 Tsize = maxY - minY;
755 /* printf ("ssize %f tsize %f\n",Ssize, Tsize); */
756
757 for (i=0,j=0; i<tmpint/3; i++,j+=6) {
758 //wireframe indices
759 int i3 = i*3;
760 lindex[j + 0] = i3;
761 lindex[j + 1] = i3+1;
762 lindex[j + 2] = i3+1;
763 lindex[j + 3] = i3+2;
764 lindex[j + 4] = i3+2;
765 lindex[j + 5] = i3;
766 }
767
768 for (i=0; i<tmpint; i++) {
769 (*fp).c[0] = (node->vertices.p[i].c[0] - minX) / Ssize;
770 (*fp).c[1] = (node->vertices.p[i].c[1] - minY) / Tsize;
771 fp++;
772 }
773
774 /* restore, so we know how many tris there are */
775 node->vertices.n = tmpint;
776}
777
778void render_TriangleSet2D (struct X3D_TriangleSet2D *node){
779 COMPILE_IF_REQUIRED
780 if (node->vertices.n>0) {
781 struct textureVertexInfo mtf = {(GLfloat *)node->__texCoords.p,2,GL_FLOAT,0,NULL,NULL};
782 /* for BoundingBox calculations */
783 setExtent( node->EXTENT_MAX_X, node->EXTENT_MIN_X,
784 node->EXTENT_MAX_Y, node->EXTENT_MIN_Y, 0.0f,0.0f,X3D_NODE(node));
785
786 CULL_FACE(node->solid)
787
788 textureCoord_send(&mtf);
789 FW_GL_VERTEX_POINTER (2,GL_FLOAT,0,(GLfloat *)node->vertices.p);
790
791
792 if(DESIRE(getShaderFlags().base,SHADINGSTYLE_WIRE)){
793 //wireframe triangles
794 sendElementsToGPU(GL_LINES,(node->vertices.n*2),node->__wireindices); //(nseg -1)*4 = (npts-2)*2 = npts*2 -4
795 }else{
796 sendArraysToGPU (GL_TRIANGLES, 0, node->vertices.n);
797 }
798
799 gglobal()->Mainloop.trisThisLoop += node->vertices.n;
800 }
801}
802//rendray_TriangleSet2D
803void rendray_TriangleSet2D(struct X3D_TriangleSet2D* node) {
804 //copy from rendray_Cylinder and hack
805 float r, a0, a1, z;
806 struct point_XYZ t_r1, t_r2;
807 get_current_ray(&t_r1, &t_r2);
808
809 z = 0.0f;
810 if (!ZEQ) {
811 float zrat0 = (float)ZRAT(z);
812 if (TRAT(zrat0)) {
813 float cx = (float)MRATX(zrat0);
814 float cy = (float)MRATY(zrat0);
815 float px[2];
816 px[0] = cx;
817 px[1] = cy;
818 int iside[3];
819 struct SFVec2f* pp = node->vertices.p;
820 for (int i = 0; i < node->vertices.n; i += 3) {
821 //assuming clockwise vertices around triangle,
822 //if hitpoint is to the right of all 3 triangle sides, its inside
823 iside[0] = isLeftSide2f(pp[i].c, pp[i + 1].c, px);
824 iside[1] = isLeftSide2f(pp[i + 1].c, pp[i + 2].c, px);
825 iside[2] = isLeftSide2f(pp[i + 2].c, pp[i].c, px);
826 //printf("i %d isides %d %d %d\n", i, iside[0], iside[1], iside[2]);
827 if (iside[0] <= 0 && iside[1] <=0 && iside[2] <= 0) {
828 rayhit(zrat0, cx, cy, z, 0, 0, 1, -1, -1, "triangleset2d");
829 break;
830 }
831 //assuming counter-clockwise vertices around triangle,
832 //if hitpoint is to the left of all 3 triangle sides, its inside
833 if (iside[0] >= 0 && iside[1] >= 0 && iside[2] >= 0) {
834 rayhit(zrat0, cx, cy, z, 0, 0, 1, -1, -1, "triangleset2d");
835 break;
836 }
837
838 }
839 }
840 }
841}
842
843
844/***********************************************************************************/
845
846
847/* this code is remarkably like Box, but with a zero z axis. */
848void compile_Rectangle2D (struct X3D_Rectangle2D *node) {
849 float *pt;
850 struct SFVec3f *ptr;
851 float x = ((node->size).c[0])/2;
852 float y = ((node->size).c[1])/2;
853
854 MARK_NODE_COMPILED
855
856 /* MALLOC memory (if possible)*/
857 if (!node->__points.p) ptr = MALLOC (struct SFVec3f *,sizeof(struct SFVec3f)*(6));
858 else ptr = node->__points.p;
859
860 /* now, create points; 6 points per face.*/
861 pt = (float *) ptr;
862 #define PTF0 *pt++ = x; *pt++ = y; *pt++ = 0.0f;
863 #define PTF1 *pt++ = -x; *pt++ = y; *pt++ = 0.0f;
864 #define PTF2 *pt++ = -x; *pt++ = -y; *pt++ = 0.0f;
865 #define PTF3 *pt++ = x; *pt++ = -y; *pt++ = 0.0f;
866
867 PTF0 PTF1 PTF2 PTF0 PTF2 PTF3 /* front */
868 /* finished, and have good data */
869 node->__points.p = (struct SFVec3f*) ptr;
870
871 #undef PTF0
872 #undef PTF1
873 #undef PTF2
874 #undef PTF3
875}
876
877
878void render_Rectangle2D (struct X3D_Rectangle2D *node) {
879 extern GLfloat boxtex[]; /* in CFuncs/statics.c*/
880 extern GLfloat boxnorms[]; /* in CFuncs/statics.c*/
881 struct textureVertexInfo mtf = {boxtex,2,GL_FLOAT,0,NULL,NULL};
882
883 float x = ((node->size).c[0])/2;
884 float y = ((node->size).c[1])/2;
885
886 /* test for <0 of sides */
887 if ((x < 0) || (y < 0)) return;
888
889 COMPILE_IF_REQUIRED
890 if (!node->__points.p) return; /* still compiling */
891
892 /* for BoundingBox calculations */
893 setExtent(x,-x,y,-y,0.0f,0.0f,X3D_NODE(node));
894
895 CULL_FACE(node->solid)
896
897 /* Draw it; assume VERTEX and NORMALS already defined.*/
898 textureCoord_send(&mtf);
899 FW_GL_VERTEX_POINTER (3,GL_FLOAT,0,(GLfloat *)node->__points.p);
900 FW_GL_NORMAL_POINTER (GL_FLOAT,0,boxnorms);
901
902 /* do the array drawing; sides are simple 0-1-2-3, 4-5-6-7, etc quads */
903 if(DESIRE(getShaderFlags().base,SHADINGSTYLE_WIRE)){
904 //wireframe triangles
905 static int wireindices [] = { 0, 1, 1, 2, 2, 0, 3, 4, 4, 5, 5, 3 };
906 sendElementsToGPU(GL_LINES,6*2,wireindices); //(nseg -1)*4 = (npts-2)*2 = npts*2 -4
907 }else{
908 sendArraysToGPU (GL_TRIANGLES, 0, 6);
909 }
910 gglobal()->Mainloop.trisThisLoop += 2;
911}
912
913void rendray_Rectangle2D(struct X3D_Rectangle2D* node) {
914 //copy from rendray_Cylinder and hack
915 float sx,sy, z;
916 struct point_XYZ t_r1, t_r2;
917 get_current_ray(&t_r1, &t_r2);
918
919 sx = node->size.c[0];
920 sy = node->size.c[1];
921 z = 0.0f;
922 if (!ZEQ) {
923 float zrat0 = (float)ZRAT(z);
924 if (TRAT(zrat0)) {
925 float cx = (float)MRATX(zrat0);
926 float cy = (float)MRATY(zrat0);
927 if (fabs(cx) < fabs(sx) && fabs(cy) < fabs(sy)) {
928 rayhit(zrat0, cx, cy, z, 0, 0, 1, -1, -1, "disk2d");
929 }
930 }
931 }
932}
933/***********************************************************************************/
934//http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/geometry2D.html#ArcClose2D
935// "the angle starts at +x and goes toward +y"
936// y^
937// | /
938// | / ) angle
939// |_____> x
940static void *createLines (float start, float end, float radius, int closed, int *size, float *_extent) {
941 int i;
942 int isCircle;
943 int numPoints;
944 GLfloat tmp;
945 GLfloat *points;
946 GLfloat *fp;
947 int arcpoints;
948
949 float myminx = FLT_MAX;
950 float mymaxx = -FLT_MAX;
951 float myminy = FLT_MAX;
952 float mymaxy = -FLT_MAX;
953
954 *size = 0;
955
956 /* is this a circle? */
957 isCircle = APPROX(start,end);
958
959 /* bounds check, and sort values */
960 if ((start < PI*2.0) || (start > PI*2.0)) start = 0.0f;
961 if ((end < PI*2.0) || (end > PI*2.0)) end = (float) (PI/2.0);
962 if (radius<0.0) radius = 1.0f;
963
964 if (end > start) {
965 tmp = start;
966 start = end;
967 end = tmp;
968 }
969
970
971 if (isCircle) {
972 numPoints = SEGMENTS_PER_CIRCLE;
973 closed = NONE; /* this is a circle, CHORD, PIE dont mean anything now */
974 } else {
975 numPoints = (int) ((float)(SEGMENTS_PER_CIRCLE * (start-end))/(PI*2.0f));
976 if (numPoints>SEGMENTS_PER_CIRCLE) numPoints=SEGMENTS_PER_CIRCLE;
977 }
978
979 /* we always have to draw the line - we have a line strip, and we calculate
980 the beginning points; we have also to calculate the ending point. */
981 numPoints++;
982 arcpoints = numPoints;
983
984 /* closure type */
985 if (closed == CHORD) numPoints+=2;
986 if (closed == PIE) numPoints+=2;
987
988 points = MALLOC (float *, sizeof(float)*numPoints*2);
989 fp = points;
990
991 for (i=0; i<arcpoints; i++) {
992 *fp = radius * cosf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
993 fp++;
994 *fp = radius * sinf(((float)PI * 2.0f * (float)i)/((float)SEGMENTS_PER_CIRCLE));
995 fp++;
996 }
997
998 /* do we have to draw any pies, cords, etc, etc? */
999 if (closed == CHORD) {
1000 /* go to mid-chord */
1001 *fp = .5f*(points[0] + points[(arcpoints-1)*2]);
1002 fp++;
1003 *fp = .5f*(points[1] + points[(arcpoints-1)*2 +1]);
1004 fp++;
1005
1006 /* loop back to first point */
1007 *fp = radius * cosf(0.0f/((float)SEGMENTS_PER_CIRCLE));
1008 fp++;
1009 *fp = radius * sinf(0.0f/((float)SEGMENTS_PER_CIRCLE));
1010 fp++;
1011 } else if (closed == PIE) {
1012 /* go to origin */
1013 *fp = 0.0f; fp++; *fp=0.0f; fp++;
1014 /* go back to first point */
1015 *fp = radius * cosf(0.0f/((float)SEGMENTS_PER_CIRCLE));
1016 fp++;
1017 *fp = radius * sinf(0.0f/((float)SEGMENTS_PER_CIRCLE));
1018 fp++;
1019 }
1020
1021
1022 /* find extents */
1023 *size = numPoints;
1024 if (numPoints==0) {
1025 EXTENT_MAX_X = 0.0f;
1026 EXTENT_MIN_X = 0.0f;
1027 EXTENT_MAX_Y = 0.0f;
1028 EXTENT_MIN_Y = 0.0f;
1029 } else {
1030 /* find min/max for setExtent for these points */
1031 fp = points;
1032 for (i=0; i<numPoints; i++) {
1033 /* do X first */
1034 if (*fp > mymaxx) mymaxx = *fp;
1035 if (*fp < myminx) myminx = *fp;
1036 fp++;
1037 /* do Y second */
1038 if (*fp > mymaxy) mymaxy = *fp;
1039 if (*fp < myminy) myminy = *fp;
1040 fp++;
1041 }
1042 EXTENT_MIN_X = myminx;
1043 EXTENT_MAX_X = mymaxx;
1044 EXTENT_MIN_Y = myminy;
1045 EXTENT_MAX_Y = mymaxy;
1046 }
1047
1048 return (void *)points;
1049}
1050
1051struct point_XYZ get_poly_disp_2(struct point_XYZ* p, int num, struct point_XYZ n);
1052#define FLOAT_TOLERANCE 0.00000001
1053void collide_Rectangle2D(struct X3D_Rectangle2D* node) {
1054 GLDOUBLE modelMatrix[16];
1055
1056 ttglobal tg = gglobal();
1057 union upoint_XYZ maxdispv = { .c = {0,0,0} };
1058 double maxdisp = 0.0;
1059
1060 // get the transformed position of the Box, and the scale-corrected radius.
1061 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1062
1063 matmultiplyAFFINE(modelMatrix, modelMatrix, FallInfo()->avatar2collision);
1064 {
1065 // minimum bounding box MBB test in avatar/collision space
1066 float center[3], size[3], bboxmin[3], bboxmax[3];
1067 extent6f2bbox(node->_extent, center, size);
1068 vecdif3f(bboxmin, center, size);
1069 vecadd3f(bboxmax, center, size);
1070 double shapeMBBmin[3], shapeMBBmax[3];
1071 float2double(shapeMBBmin, bboxmin, 3);
1072 float2double(shapeMBBmax, bboxmax, 3);
1073 if (!avatarCollisionVolumeIntersectMBB(modelMatrix, shapeMBBmin, shapeMBBmax))return;
1074 }
1075 struct SFVec2f vertices[4];
1076 vertices[0].c[0] = -node->size.c[0] * .5f;
1077 vertices[0].c[1] = -node->size.c[1] * .5f;
1078 vertices[1].c[0] = -node->size.c[0] * .5f;
1079 vertices[1].c[1] = node->size.c[1] * .5f;
1080 vertices[2].c[0] = node->size.c[0] * .5f;
1081 vertices[2].c[1] = node->size.c[1] * .5f;
1082 vertices[3].c[0] = node->size.c[0] * .5f;
1083 vertices[3].c[1] = -node->size.c[1] * .5f;
1084
1085 union upoint_XYZ pts[4], nn, v1, v2;
1086 double disp;
1087 for (int j = 0; j < 4; j++) {
1088 float2double(pts[j].c, vertices[j].c, 2);
1089 pts[j].p.z = 0.0;
1090 transform(&pts[j].p, &pts[j].p, modelMatrix);
1091 }
1092 vecdifd(v1.c, pts[1].c, pts[0].c);
1093 vecdifd(v2.c, pts[3].c, pts[0].c);
1094 veccrossd(nn.c, v2.c, v1.c);
1095 union upoint_XYZ dispv;
1096 dispv.p = get_poly_disp_2((struct point_XYZ*)pts, 4, nn.p);
1097 disp = vecdot(&dispv.p, &dispv.p);
1098
1099 //keep result only if:
1100 // displacement is positive
1101 // displacement is smaller than minimum displacement up to date
1102 if ((disp > FLOAT_TOLERANCE) && (disp > maxdisp)) {
1103 maxdisp = disp;
1104 maxdispv = dispv;
1105 }
1106 vecscale(&maxdispv.p, &maxdispv.p, -1);
1107
1108 accumulate_disp(CollisionInfo(), maxdispv.p);
1109
1110}
1111
1112void collide_TriangleSet2D(struct X3D_TriangleSet2D* node) {
1113 GLDOUBLE modelMatrix[16];
1114
1115 ttglobal tg = gglobal();
1116 union upoint_XYZ maxdispv = { .c = {0,0,0} };
1117 double maxdisp = 0.0;
1118
1119 // get the transformed position of the Box, and the scale-corrected radius.
1120 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1121
1122 matmultiplyAFFINE(modelMatrix, modelMatrix, FallInfo()->avatar2collision);
1123 {
1124 // minimum bounding box MBB test in avatar/collision space
1125 float center[3], size[3], bboxmin[3], bboxmax[3];
1126 extent6f2bbox(node->_extent, center, size);
1127 vecdif3f(bboxmin, center, size);
1128 vecadd3f(bboxmax, center, size);
1129 double shapeMBBmin[3], shapeMBBmax[3];
1130 float2double(shapeMBBmin, bboxmin, 3);
1131 float2double(shapeMBBmax, bboxmax, 3);
1132 if (!avatarCollisionVolumeIntersectMBB(modelMatrix, shapeMBBmin, shapeMBBmax))return;
1133 }
1134 for(int i=0;i<node->vertices.n;i+=3){
1135 union upoint_XYZ pts[3], nn, v1, v2;
1136 double disp;
1137 for (int j = 0; j < 3; j++) {
1138 float2double(pts[j].c, node->vertices.p[i + j].c, 2);
1139 pts[j].p.z = 0.0;
1140 transform(&pts[j].p, &pts[j].p, modelMatrix);
1141 }
1142 vecdifd(v1.c, pts[1].c, pts[0].c);
1143 vecdifd(v2.c, pts[2].c, pts[0].c);
1144 veccrossd(nn.c, v2.c, v1.c);
1145 union upoint_XYZ dispv;
1146 dispv.p = get_poly_disp_2((struct point_XYZ*)pts, 3, nn.p);
1147 disp = vecdot(&dispv.p, &dispv.p);
1148
1149 //keep result only if:
1150 // displacement is positive
1151 // displacement is smaller than minimum displacement up to date
1152 if ((disp > FLOAT_TOLERANCE) && (disp > maxdisp)) {
1153 maxdisp = disp;
1154 maxdispv = dispv;
1155 }
1156 }
1157 vecscale(&maxdispv.p, &maxdispv.p, -1);
1158
1159 accumulate_disp(CollisionInfo(), maxdispv.p);
1160
1161}
1162
1163void collide_ArcClose2D(struct X3D_ArcClose2D* node) {
1164 GLDOUBLE modelMatrix[16];
1165
1166 ttglobal tg = gglobal();
1167 union upoint_XYZ maxdispv = { .c = {0,0,0} };
1168 double maxdisp = 0.0;
1169
1170 // get the transformed position of the Box, and the scale-corrected radius.
1171 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1172
1173 matmultiplyAFFINE(modelMatrix, modelMatrix, FallInfo()->avatar2collision);
1174 {
1175 // minimum bounding box MBB test in avatar/collision space
1176 float center[3], size[3], bboxmin[3], bboxmax[3];
1177 extent6f2bbox(node->_extent, center, size);
1178 vecdif3f(bboxmin, center, size);
1179 vecadd3f(bboxmax, center, size);
1180 double shapeMBBmin[3], shapeMBBmax[3];
1181 float2double(shapeMBBmin, bboxmin, 3);
1182 float2double(shapeMBBmax, bboxmax, 3);
1183 if (!avatarCollisionVolumeIntersectMBB(modelMatrix, shapeMBBmin, shapeMBBmax))return;
1184 }
1185 union upoint_XYZ pts[3], nn, v1, v2;
1186 double disp;
1187
1188 //triangle fan point:
1189 float2double(pts[0].c, node->__points.p[0].c, 2);
1190 pts[0].p.z = 0.0;
1191 transform(&pts[0].p, &pts[0].p, modelMatrix);
1192 //triangle fan starts at point[1]
1193 for (int i = 1; i < node->__points.n; i++) {
1194 float2double(pts[1].c, node->__points.p[i].c, 2);
1195 pts[1].p.z = 0.0;
1196 transform(&pts[1].p, &pts[1].p, modelMatrix);
1197 float2double(pts[2].c, node->__points.p[2].c, 2);
1198 pts[2].p.z = 0.0;
1199 transform(&pts[2].p, &pts[2].p, modelMatrix);
1200
1201 vecdifd(v1.c, pts[1].c, pts[0].c);
1202 vecdifd(v2.c, pts[2].c, pts[0].c);
1203 veccrossd(nn.c, v2.c, v1.c);
1204 union upoint_XYZ dispv;
1205 dispv.p = get_poly_disp_2((struct point_XYZ*)pts, 3, nn.p);
1206 disp = vecdot(&dispv.p, &dispv.p);
1207
1208 //keep result only if:
1209 // displacement is positive
1210 // displacement is smaller than minimum displacement up to date
1211 if ((disp > FLOAT_TOLERANCE) && (disp > maxdisp)) {
1212 maxdisp = disp;
1213 maxdispv = dispv;
1214 }
1215 }
1216 vecscale(&maxdispv.p, &maxdispv.p, -1);
1217
1218 accumulate_disp(CollisionInfo(), maxdispv.p);
1219
1220}
1221
1222void collide_Disk2D(struct X3D_Disk2D* node) {
1223 GLDOUBLE modelMatrix[16];
1224
1225 ttglobal tg = gglobal();
1226 union upoint_XYZ maxdispv = { .c = {0,0,0} };
1227 double maxdisp = 0.0;
1228
1229 // get the transformed position of the Box, and the scale-corrected radius.
1230 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1231
1232 matmultiplyAFFINE(modelMatrix, modelMatrix, FallInfo()->avatar2collision);
1233 {
1234 // minimum bounding box MBB test in avatar/collision space
1235 float center[3], size[3], bboxmin[3], bboxmax[3];
1236 extent6f2bbox(node->_extent, center, size);
1237 vecdif3f(bboxmin, center, size);
1238 vecadd3f(bboxmax, center, size);
1239 double shapeMBBmin[3], shapeMBBmax[3];
1240 float2double(shapeMBBmin, bboxmin, 3);
1241 float2double(shapeMBBmax, bboxmax, 3);
1242 if (!avatarCollisionVolumeIntersectMBB(modelMatrix, shapeMBBmin, shapeMBBmax))return;
1243 }
1244 union upoint_XYZ pts[3], nn, v1, v2;
1245 double disp;
1246
1247 if (node->__simpleDisk) {
1248 //simple disk with TRIANGLE_FAN
1249 //fan point:
1250 float2double(pts[0].c, node->__points.p[0].c, 2);
1251 pts[0].p.z = 0.0;
1252 transform(&pts[0].p, &pts[0].p, modelMatrix);
1253 //triangle fan starts at point[1]
1254 for (int i = 1; i < node->__points.n; i++) {
1255 float2double(pts[1].c, node->__points.p[i].c, 2);
1256 pts[1].p.z = 0.0;
1257 transform(&pts[1].p, &pts[1].p, modelMatrix);
1258 float2double(pts[2].c, node->__points.p[2].c, 2);
1259 pts[2].p.z = 0.0;
1260 transform(&pts[2].p, &pts[2].p, modelMatrix);
1261
1262 vecdifd(v1.c, pts[1].c, pts[0].c);
1263 vecdifd(v2.c, pts[2].c, pts[0].c);
1264 veccrossd(nn.c, v2.c, v1.c);
1265 union upoint_XYZ dispv;
1266 dispv.p = get_poly_disp_2((struct point_XYZ*)pts, 3, nn.p);
1267 disp = vecdot(&dispv.p, &dispv.p);
1268
1269 //keep result only if:
1270 // displacement is positive
1271 // displacement is smaller than minimum displacement up to date
1272 if ((disp > FLOAT_TOLERANCE) && (disp > maxdisp)) {
1273 maxdisp = disp;
1274 maxdispv = dispv;
1275 }
1276 }
1277 }else{
1278 //donut disk with TRIANGLE_STRIP
1279 for (int i = 0; i < node->__points.n -1; i++) {
1280 for (int j = 0; j < 3; j++) {
1281 float2double(pts[j].c, node->__points.p[i + j].c, 2);
1282 pts[j].p.z = 0.0;
1283 transform(&pts[j].p, &pts[j].p, modelMatrix);
1284 }
1285 vecdifd(v1.c, pts[1].c, pts[0].c);
1286 vecdifd(v2.c, pts[2].c, pts[0].c);
1287 veccrossd(nn.c, v2.c, v1.c);
1288 union upoint_XYZ dispv;
1289 dispv.p = get_poly_disp_2((struct point_XYZ*)pts, 3, nn.p);
1290 disp = vecdot(&dispv.p, &dispv.p);
1291
1292 //keep result only if:
1293 // displacement is positive
1294 // displacement is smaller than minimum displacement up to date
1295 if ((disp > FLOAT_TOLERANCE) && (disp > maxdisp)) {
1296 maxdisp = disp;
1297 maxdispv = dispv;
1298 }
1299 }
1300 }
1301 vecscale(&maxdispv.p, &maxdispv.p, -1);
1302
1303 accumulate_disp(CollisionInfo(), maxdispv.p);
1304
1305}