FreeWRL/FreeX3D  3.0.0
Collision.c
1 /*
2 
3 
4 Render the children of nodes.
5 
6 */
7 
8 /****************************************************************************
9  This file is part of the FreeWRL/FreeX3D Distribution.
10 
11  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12 
13  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14  it under the terms of the GNU Lesser Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25 ****************************************************************************/
26 
27 
28 #include <config.h>
29 #include <system.h>
30 #include <display.h>
31 #include <internal.h>
32 
33 #include <libFreeWRL.h>
34 
35 #include "Viewer.h"
36 #include "RenderFuncs.h"
37 
38 #include "../vrml_parser/Structs.h"
39 #include "../main/headers.h"
40 
41 #include "LinearAlgebra.h"
42 #ifdef HAVE_OPENCL
43 #include "../opencl/OpenCL_Utils.h"
44 #endif //HAVE_OPENCL
45 #include "Collision.h"
46 #include "../internal.h"
47 static struct point_XYZ get_poly_min_disp_with_sphere(double r, struct point_XYZ* p, int num, struct point_XYZ n);
48 
49 static struct point_XYZ weighted_sum(struct point_XYZ p1, struct point_XYZ p2, double k);
50 static struct point_XYZ get_point_disp(double y1, double y2, double ystep, double r, struct point_XYZ p1, struct point_XYZ n);
51 static void accumulateFallingClimbing(double y1, double y2, double ystep, struct point_XYZ *p, int num, struct point_XYZ nused, double *tmin, double *tmax);
52 
53 
54 
55 
56 #define DJ_KEEP_COMPILER_WARNING 0
57 
58 //static int dug9debug = 0;
59 //int setdug9debug()
60 //{ dug9debug = 1; return 0;}
61 //int cleardug9debug()
62 //{ dug9debug = 0; return 0;}
63 
64 #define swap(x,y) {double k = x; x = y; y = k; }
65 #define FLOAT_TOLERANCE 0.00000001
66 #if DJ_KEEP_COMPILER_WARNING
67 #define MAX_POLYREP_DISP_RECURSION_COUNT 10
68 #endif
69 #define STEPUP_MAXINCLINE 0.9
70 
71 #ifdef DEBUGPTS
72 #define DEBUGPTSPRINT(x,y,z) printf(x,y,z)
73 #else
74 #define DEBUGPTSPRINT(x,y,z) {}
75 #endif
76 
77 static const struct point_XYZ zero = {0,0,0};
78 
79 typedef struct pcollision{
80  float* prd_newc_floats;// = NULL;
81  unsigned int prd_newc_floats_size;// = 0;
82  struct point_XYZ* prd_normals;// = NULL;
83  int prd_normals_size;// = 0;
84  struct point_XYZ* clippedPoly1;// = NULL;
85  int clippedPoly1Size;// = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
86  struct point_XYZ* clippedPoly2;// = NULL;
87  int clippedPoly2Size;// = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
88  struct point_XYZ* clippedPoly3;// = NULL;
89  int clippedPoly3Size;// = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
90  struct point_XYZ* clippedPoly4;// = NULL;
91  int clippedPoly4Size;// = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
92  struct point_XYZ* clippedPoly5;// = NULL;
93  int clippedPoly5Size;// = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
94 
95 
96  /* JAS - make return val global, not local for polyrep-disp */
97  #ifdef HAVE_OPENCL
98  struct sCollisionGPU CollisionGPU;
99  #endif
100 
101 
102  /* Collision detection results */
103  struct point_XYZ res;
104  double get_poly_mindisp;
105  struct sCollisionInfo CollisionInfo;// = { {0,0,0} , 0, 0. };
106  struct sFallInfo FallInfo; /* = {100.0,1.0,0.0,0.0, 0,1,0,0}; ... too many to initialize here */
107 
108  /* did the OpenCL GPU Collision compile ok? */
109  bool OpenCL_Collision_Program_initialized;
110 
111 }* ppcollision;
112 void *collision_constructor(){
113  void *v = MALLOCV(sizeof(struct pcollision));
114  memset(v,0,sizeof(struct pcollision));
115  return v;
116 }
117 void collision_init(struct tcollision *t){
118  //public
119  //private
120 
121  t->prv = collision_constructor();
122  {
123  ppcollision p = (ppcollision)t->prv;
124  p->prd_newc_floats = NULL;
125  p->prd_newc_floats_size = 0;
126  p->prd_normals = NULL;
127  p->prd_normals_size = 0;
128  p->clippedPoly1 = NULL;
129  p->clippedPoly1Size = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
130  p->clippedPoly2 = NULL;
131  p->clippedPoly2Size = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
132  p->clippedPoly3 = NULL;
133  p->clippedPoly3Size = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
134  p->clippedPoly4 = NULL;
135  p->clippedPoly4Size = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
136  p->clippedPoly5 = NULL;
137  p->clippedPoly5Size = 0; /* number of struct point_XYZ* 's in the clippedPoly data area */
138 
139 
140  /* Collision detection results */
141  p->CollisionInfo.Count = 0;
142  p->CollisionInfo.Maximum2 = 0.0;
143  p->CollisionInfo.Offset.x = 0.0;
144  p->CollisionInfo.Offset.y = 0.0;
145  p->CollisionInfo.Offset.z = 0.0;
146  //p->FallInfo; /* = {100.0,1.0,0.0,0.0, 0,1,0,0}; ... too many to initialize here */
147 
148  #ifdef HAVE_OPENCL
149  p->CollisionGPU.CollideGPU_program = NULL;
150  p->CollisionGPU.CollideGPU_kernel = NULL;
151  p->CollisionGPU.CollideGPU_output_buffer = NULL;
152  p->CollisionGPU.CollideGPU_matrix_buffer = NULL;
153  p->CollisionGPU.CollideGPU_vertex_buffer = NULL;
154  p->CollisionGPU.CollideGPU_index_buffer = NULL;
155  p->CollisionGPU.CollideGPU_returnValues.n = 0;
156  p->CollisionGPU.CollideGPU_returnValues.p = NULL;
157 
158  p->OpenCL_Collision_Program_initialized = FALSE;
159 
160  #endif
161  }
162 }
163 void collision_clear(struct tcollision *t){
164  //public
165  //private
166  {
167  ppcollision p = (ppcollision)t->prv;
168  FREE_IF_NZ(p->prd_newc_floats);
169  FREE_IF_NZ(p->prd_normals);
170  }
171 }
172 
173 // ppcollision p = (ppcollision)gglobal()->collision.prv;
174 struct sCollisionInfo* CollisionInfo()
175 {
176  ppcollision p = (ppcollision)gglobal()->collision.prv;
177  return &p->CollisionInfo;
178 }
179 struct sFallInfo* FallInfo()
180 {
181  ppcollision p = (ppcollision)gglobal()->collision.prv;
182  return &p->FallInfo;
183 }
184 
185 
186 
187 #ifdef HAVE_OPENCL
188 // compile the collision gpu program here, with the local structures.
189 void createGPUCollisionProgram () {
190 
191  ppcollision p = (ppcollision)gglobal()->collision.prv;
192  p->OpenCL_Collision_Program_initialized = collision_initGPUCollide(&p->CollisionGPU);
193 }
194 
195 struct sCollisionGPU* GPUCollisionInfo()
196 {
197  ppcollision p = (ppcollision)gglobal()->collision.prv;
198  return &p->CollisionGPU;
199 }
200 #endif // HAVE_OPENCL
201 
202 /*a constructor */
203 #define make_pt(p,xc,yc,zc) { p.x = (xc); p.y = (yc); p.z = (zc); }
204 
205 int overlapMBBs(GLDOUBLE *MBBmin1, GLDOUBLE *MBBmax1, GLDOUBLE *MBBmin2, GLDOUBLE* MBBmax2)
206 {
207  /* test for overlap between two axes aligned minimum bounding boxes MBBs in same space.
208  returns true if they overlap
209  rule: must overlap in all 3 dimensions in order to intersect
210  dimension your MBB: double MBBmin[3], MBBmax[3];
211  */
212 
213  int i, overlap;
214  overlap = TRUE;
215  for(i=0;i<3;i++)
216  {
217  overlap = overlap && !(MBBmin1[i] > MBBmax2[i] || MBBmax1[i] < MBBmin2[i]);
218  }
219  return overlap;
220 }
221 
222 
223 
224 /*accumulator function, for displacements. */
225 void accumulate_disp(struct sCollisionInfo* ci, struct point_XYZ add) {
226  double len2 = vecdot(&add,&add);
227  ci->Count++;
228  VECADD(ci->Offset,add);
229  if(len2 > ci->Maximum2)
230  ci->Maximum2 = len2;
231 }
232 
233 static double closest_point_of_segment_to_origin(struct point_XYZ p1, struct point_XYZ p2) {
234  /*the equation (guessed from above)*/
235  double x12 = (p1.x - p2.x);
236  double y12 = (p1.y - p2.y);
237  double z12 = (p1.z - p2.z);
238  double q = ( x12*x12 + y12*y12 + z12*z12 );
239 
240  /* double i = ((q == 0.) ? 0.5 : (p1.x * x12 + p1.y * y12 + p1.z * z12) / q); */
241  double i = ((APPROX(q, 0)) ? 0.5 : (p1.x * x12 + p1.y * y12 + p1.z * z12) / q);
242 
243  /* struct point_XYZ result; */
244 
245  /*clamp result to constraints */
246  if(i < 0) i = 0.;
247  if(i > 1) i = 1.;
248 
249  return i;
250 
251 }
252 
253 /*n must be normal */
254 static struct point_XYZ closest_point_of_plane_to_origin(struct point_XYZ b, struct point_XYZ n) {
255  /*the equation*/
256  double k = b.x*n.x + b.y*n.y + b.z*n.z;
257  vecscale(&n,&n,k);
258  return n;
259 }
260 
261 
262 /* [p1,p2[ is segment, q1,q2 defines line */
263 /* ignores y coord. eg intersection is done on projection of segment and line on the y plane */
264 /* nowtice point p2 is NOT included, (for simplification elsewhere) */
265 
266 static int intersect_segment_with_line_on_yplane(struct point_XYZ* pk, struct point_XYZ p1, struct point_XYZ p2, struct point_XYZ q1, struct point_XYZ q2) {
267  double k,quotient;
268  //double l;
269 
270  /* p2 becomes offset */
271  VECDIFF(p2,p1,p2);
272  /* q2 becomes offset */
273  VECDIFF(q2,q1,q2);
274 
275  /* if(q2.x == 0 && q2.z == 0.) */
276  if(APPROX(q2.x, 0) && APPROX(q2.z, 0)) {
277  /* degenerate case.
278  it fits our objective to simply specify a random line. */
279  q2.x = 1;
280  q2.y = 0;
281  q2.z = 0;
282  }
283 
284  quotient = ((-p2.z)*q2.x + p2.x*q2.z);
285  /* if(quotient == 0.) return 0; */
286  if(APPROX(quotient, 0)) return 0;
287 
288  k = (p1.z*q2.x - q1.z*q2.x - p1.x*q2.z + q1.x*q2.z)/quotient;
289  //l = (p1.z*p2.x - p1.x*p2.z + p2.z*q1.x - p2.x*q1.z)/quotient;
290 
291  if((k >= 0.) && (k < 1.)) {
292  vecscale(pk,&p2,k);
293  VECADD(*pk,p1);
294  return 1;
295  } else
296  return 0;
297 
298 }
299 
300 /*finds the intersection of the line pp1 + k n with a cylinder on the y axis.
301  returns the 0,1 or 2 values.
302  */
303 static int getk_intersect_line_with_ycylinder(double* k1, double* k2, double r, struct point_XYZ pp1, struct point_XYZ n) {
304  double b,a,sqrdelta,delta;
305  /* int res = 0; */
306 
307  /*solves (pp1+ k n) . (pp1 + k n) = r^2 , ignoring y values.*/
308  a = 2*(n.x*n.x + n.z*n.z);
309  b = -2*(pp1.x*n.x + pp1.z*n.z);
310  delta = (4*((pp1.x*n.x + pp1.z*n.z)*(pp1.x*n.x + pp1.z*n.z)) -
311  4*((n.x*n.x + n.z*n.z))*((pp1.x*pp1.x + pp1.z*pp1.z - r*r)));
312  if(delta < 0.) return 0;
313  sqrdelta = sqrt(delta);
314 
315  *k1 = (b+sqrdelta)/a;
316  /* if(sqrdelta == 0.) return 1; */
317  if(APPROX(sqrdelta, 0)) return 1;
318 
319  *k2 = (b-sqrdelta)/a;
320  return 2;
321 }
322 
323 
324 /*projects a point on the y="y" plane, in the direction of n. *
325  n probably needs to be normal. */
326 static struct point_XYZ project_on_yplane(struct point_XYZ p1, struct point_XYZ n,double y) {
327  struct point_XYZ ret;
328  make_pt(ret,p1.x - (n.x*(p1.y-y))/n.y,y,(p1.z - (n.z*(p1.y-y))/n.y));
329  return ret;
330 }
331 
332 /*projects a point on the plane tangent to the surface of the cylinder at point -kn (the prolonged normal)
333  , in the inverse direction of n.
334  n probably needs to be normal. */
335 static struct point_XYZ project_on_cylindersurface_plane(struct point_XYZ p, struct point_XYZ n,double r) {
336  struct point_XYZ pp;
337  struct point_XYZ ret;
338  vecscale(&n,&n,-1.0);
339  pp = n;
340  pp.y = 0;
341  vecnormal(&pp,&pp);
342  vecscale(&pp,&pp,r);
343 
344  ret.x = p.x + (n.x*((n.x*((pp.x - p.x)) + n.z*((pp.z - p.z)))))/(n.x*n.x + n.z*n.z);
345  ret.y = p.y + (n.y*((n.x*((pp.x - p.x)) + n.z*((pp.z - p.z)))))/(n.x*n.x + n.z*n.z);
346  ret.z = p.z + (n.z*((n.x*((pp.x - p.x)) + n.z*((pp.z - p.z)))))/(n.x*n.x + n.z*n.z);
347 
348  return ret;
349 }
350 
351 /*makes half-plane starting at point, perpendicular to plane (eg: passing through origin)
352  if this plane cuts through polygon edges an odd number of time, we are inside polygon*/
353 /* works for line passing through origin, polygon plane must not pass through origin. */
354 static int perpendicular_line_passing_inside_poly(struct point_XYZ a,struct point_XYZ* p, int num) {
355  struct point_XYZ n; /*half-plane will be defined as: */
356  struct point_XYZ i; /* p(x,y) = xn + yi, with i >= 0 */
357  struct point_XYZ j; /* j is half-plane normal */
358  int f,sectcount = 0;
359  struct point_XYZ epsilon; /* computationnal trick to handle points directly on plane. displace them. */
360 
361 //printf ("\t\t\tperpendicular_line_passing_inside_poly, num %d\n",num);
362 
363  /* if(vecnormal(&n,&a) == 0) */
364  if(APPROX(vecnormal(&n,&a), 0)) {
365  /* happens when polygon plane passes through origin */
366  return 0;
367  }
368  make_orthogonal_vector_space(&i,&j,n);
369 
370  vecscale(&epsilon,&j,FLOAT_TOLERANCE); /*make our epsilon*/
371 
372  for(f = 0; f < num; f++) {
373  /*segment points relative to point a */
374  struct point_XYZ p1,p2;
375  double p1j,p2j;
376  VECDIFF(p[f],a,p1);
377  VECDIFF(p[(f+1)%num],a,p2);
378  /* while((p1j = vecdot(&p1,&j)) == 0.) VECADD(p1,epsilon); */
379  while(APPROX((p1j = vecdot(&p1,&j)), 0)) VECADD(p1,epsilon);
380 
381  /* while((p2j = vecdot(&p2,&j)) == 0.) VECADD(p2,epsilon); */
382  while(APPROX((p2j = vecdot(&p2,&j)), 0)) VECADD(p2,epsilon);
383 
384  /*see if segment crosses plane*/
385  if(p1j * p2j <= 0 /*if signs differ*/) {
386  double k;
387  struct point_XYZ p0;
388  /* solves (k p1 + (1 - k)p2).j = 0 */
389  /* k = (p1j-p2j != 0) ? (p1j/ (p1j - p2j)) : 0.; */
390  k = (! APPROX(p1j-p2j, 0)) ? (p1j/ (p1j - p2j)) : 0.;
391 
392  /*see if point on segment that is on the plane (p0), is also on the half-plane */
393  p0 = weighted_sum(p1, p2, k);
394  if(vecdot(&p0,&i) >= 0)
395  sectcount++;
396  }
397  }
398 
399 //printf ("\t\t\tend perpendicular_line_passing_inside_poly, ret %d\n",sectcount % 2);
400  return sectcount % 2;
401 
402 }
403 
404 
405 /*finds the intersection of the segment(pp1,pp2) with a cylinder on the y axis.
406  returns the 0,1 or 2 values in the range [0..1]
407  */
408 static int getk_intersect_segment_with_ycylinder(double* k1, double* k2, double r, struct point_XYZ pp1, struct point_XYZ pp2) {
409  double b,a,sqrdelta,delta;
410  int res = 0;
411 
412  /* pp2 becomes offset */
413  VECDIFF(pp2,pp1,pp2);
414 
415  /*solves (pp1+ k pp2) . (pp1 + k pp2) = r^2 */
416  a = 2*(pp2.x*pp2.x + pp2.z*pp2.z);
417  b = -2*(pp1.x*pp2.x + pp1.z*pp2.z);
418  delta = (4*((pp1.x*pp2.x + pp1.z*pp2.z)*(pp1.x*pp2.x + pp1.z*pp2.z)) -
419  4*((pp2.x*pp2.x + pp2.z*pp2.z))*((pp1.x*pp1.x + pp1.z*pp1.z - r*r)));
420  if(delta < 0.) return 0;
421  sqrdelta = sqrt(delta);
422  /* keep the ks that are in the segment */
423  *k1 = (b+sqrdelta)/a;
424  *k2 = (b-sqrdelta)/a;
425 
426  if(*k1 >= 0. && *k1 <= 1.) res++;
427  if(*k2 >= 0. && *k2 <= 1.) res++;
428  if(res == 1 && (*k1 < 0. || *k1 > 1.)) swap(*k1,*k2);
429 /* if(res == 2 && sqrdelta == 0.) res = 1; */
430 
431  return res;
432 }
433 
434 /*returns (1-k)p1 + k p2 */
435 static struct point_XYZ weighted_sum(struct point_XYZ p1, struct point_XYZ p2, double k) {
436  struct point_XYZ ret;
437  make_pt(ret,
438  p1.x*(1-k)+p2.x*k,
439  p1.y*(1-k)+p2.y*k,
440  p1.z*(1-k)+p2.z*k);
441 
442  /* printf ("weighted sum, from %lf %lf %lf, %lf %lf %lf, return %lf %lf %lf\n",
443  p1.x,p1.y,p1.z,p2.x,p2.y,p2.z,ret.x,ret.y,ret.z); */
444  return ret;
445 }
446 
447 
448 static int pointOnPlaneInsidePoly(struct point_XYZ D,struct point_XYZ *p, int num, struct point_XYZ* n )
449 {
450  int i,j,inside;
451 
452  struct point_XYZ a, b,c,last; //,d,e;
453 
454  inside = 1;
455  for(i=0;i<num;i++)
456  {
457  j = (i+1)%num; //i==(num-1)? 0 : i + 1;
458  vecdiff(&a,&D,&p[i]);
459  vecdiff(&b,&p[j],&p[i]);
460  veccross(&c,a,b);
461  if( i > 0 )
462  inside = inside && vecdot(&last,&c) >= 0.0;
463  last = c;
464  }
465  return inside;
466 }
467 
468 static int intersectLineSegmentWithPoly(struct point_XYZ s0,struct point_XYZ s1,double r, struct point_XYZ *p,int num,struct point_XYZ n,double *dr)
469 {
470  /* returns 1 if a line segment intersects a convex planar polygon, else 0
471  if 1, returns dr the fraction of D=(s1-s0) where the intersection point is
472  so to get the intersection point from dr, go (s1-s0)*dr + s0 in your calling code
473  tested use: send in s1 normalized (length 1), s0=0,0,0 and r the length you want the segment
474  see p.391 of Graphics Gems I (a book)
475  line segment:
476  s0 - starting point of ray
477  s1 - direction vector of ray unit length
478  r - scalar length of ray
479  polygon:
480  p[num] - points
481  n - normal (precomputed)
482  return:
483  0 - no intersection
484  1 - intersection within poly and within line segment
485  dr - intersection point expressed as fraction of (s1-s0) in range 0 to r
486  */
487 
488  int hit = 0;
489  double d,t, ndotD;
490  struct point_XYZ D;
491  /* step1 intersect infinite line with infinite plane */
492  d = -vecdot(&n,&p[0]); /* compute plane constant */
493  VECDIFF(s1,s0,D); /* compute ray direction vector from line segment start and end points */
494  /* vecnormal(&D,&D); D should already be normalized - just sin & cos values */
495  ndotD = vecdot(&n,&D);
496  *dr = 0.0; /* displacement inward from r */
497  if(APPROX(ndotD,0.0) )
498  {
499  /* infinite plane and infinite line are parallel - no intersection */
500  *dr = 0.0;
501  return hit;
502  }
503  t = - ( (d + vecdot(&n,&s0)) / ndotD ); /*magic plane-line intersection equation - t is parametric value of intersection point on line */
504  /* step2 test intersection in line segment */
505  if( t < 0.0 || t > r )
506  {
507  /* intersection is outside of line segment */
508  return hit;
509  }
510 
511  /* step3 test intersection in poly */
512  vecscale(&D,&D,t);
513  VECADD(D,s0);
514  hit = pointOnPlaneInsidePoly(D,p,num,&n);
515  if( hit ) *dr = t;
516  return hit;
517 }
518 
519 /*feed a poly, and stats of a cylinder, it returns the displacement in the radial direction of the
520  avatar that is needed for them not to intersect any more */
521 static struct point_XYZ get_poly_radialSample_disp(double y1, double y2, double ystep, double r,struct point_XYZ* p, int num, struct point_XYZ n, double *tmin, double *tmax)
522 {
523  /* uses a statistical sampler method - 8 radial rays at the ystep, avatar origin Y=0, and y2, levels, each ray segment r long
524  It's a sampler because it will miss small things. But it is supposed to catch major things like walls.
525  */
526  int i,j,hit;
527  double level[3],dr,dmax,eighth,theta, avmin[3], avmax[3];
528  struct point_XYZ s0,s1,result = zero;
529  level[0] = ystep;
530  level[1] = 0.0;
531  level[2] = y2;
532  s0.x = s0.y = s0.z = 0.0; /*avatar axis*/
533  dmax = 0.0;
534  eighth = M_PI * 2.0 / 8.0;
535 
536  for(i=0;i<3;i++)
537  {
538  avmin[i] = -r;
539  avmax[i] = r;
540  }
541  avmin[1] = ystep; avmax[1] = y2;
542  if(!overlapMBBs(avmin,avmax,tmin,tmax)) return result;
543 
544 
545  for(i=0;i<3;i++)
546  {
547  s0.y = level[i];
548  s1.y = level[i];
549  theta = 0.0;
550  for(j=0;j<8;j++)
551  {
552  theta += eighth;
553  s1.x = cos(theta);
554  s1.z = sin(theta);
555  /* quick check of overlap */
556  avmin[0] = DOUBLE_MIN(s0.x,s1.x);
557  avmin[1] = DOUBLE_MIN(s0.y,s1.y);
558  avmin[2] = DOUBLE_MIN(s0.z,s1.z);
559  avmax[0] = DOUBLE_MAX(s0.x,s1.x);
560  avmax[1] = DOUBLE_MAX(s0.y,s1.y);
561  avmax[2] = DOUBLE_MAX(s0.z,s1.z);
562  if( overlapMBBs(avmin,avmax,tmin,tmax) )
563  {
564  hit = intersectLineSegmentWithPoly(s0,s1,r,p,num,n,&dr);
565  if(hit)
566  {
567  if( (dr > FLOAT_TOLERANCE) && (dr > dmax) )
568  {
569  dmax = r-dr;
570  vecscale(&result,&s1,r-dr);
571  result.y = 0.0;
572  //printf(">");
573  }
574  }
575  }
576  }
577  }
578  /* process hits to find optimal direction and magnitude */
579  return result;
580 }
581 
582 static int get_poly_penetration_disp( double r,struct point_XYZ* p, int num, struct point_XYZ n, double *tmin, double *tmax, struct point_XYZ *result, double *rmax)
583 {
584  /* checks for wall penetration and computes a correction
585  checks between the convex poly you pass in,
586  and LastPos-Pos vector saved in FallInfo struct in render_collision()
587  r - avatar radius - will be added onto a penetration correction so avatar is repositioned off the wall
588  p[num] - convex planar poly to test
589  n - poly normal precomputed
590  tmin[3],tmax[3] - poly MBB precomputed
591  returns:
592  zero (0,0,0) if no intersection else
593  result - the displacement vector needed to move the avatar back
594  all coordinates in collision space
595  */
596  int hit = 0;
597  double dr;
598  struct sFallInfo *fi;
599  struct point_XYZ s0=zero;
600  *result = zero;
601  *rmax = 0.0;
602  fi = FallInfo();
603 
604  /* from FallInfo struct:
605  penvec - unit vector in direction from avatar (0,0,0) toward the last avatar position on the last loop (or more precisely, last time checked)
606  penRadius - distance between avatar(0,0,0) and last avatar position 0+ - infinity
607  penMin[3],penMax[3] - pre-computed MBB of penvec
608  all coordinates in collision space
609  */
610  if( overlapMBBs(fi->penMin,fi->penMax,tmin,tmax) )
611  {
612  /* penvec length 1.0 normalized. penRadius can be 0 to 1000+ - how far did you travel/navigate on one loop */
613  hit = intersectLineSegmentWithPoly(s0,fi->penvec,fi->penRadius,p,num,n,&dr);
614  if(hit)
615  {
616  vecscale(result,&fi->penvec,(dr + r));
617  *rmax = dr;
618  }
619  }
620  return hit;
621 }
622 
623 struct point_XYZ get_poly_disp_2(struct point_XYZ* p, int num, struct point_XYZ n) {
624 
625  /*
626  generalized logic for all planar facet geometry and avatar collision volumes
627  If you can break your geometry into planar facets, then call this for each facet.
628  We will know what to do here based on global structs.
629 
630  The avatar collision volume -
631  A.for flying/examining:
632  1. sphere.
633 
634  B.For walking:
635  1. cylinder (body) from (-Height + stepSize) to (+avatarWidth)
636  2. line - climb/fall (legs,feet) from (-FallInfo.FallHeight to 0)
637  3. ray to last avatar position for wall penetration
638  Order of tests (so can exit early to save unnecessary computations):
639  a) ray b) cylinder c) line
640  If you have a wall penetration ray hit, you don't need to check for cylinder collision.
641  If you have a cylinder hit, you don't need to test climb/fall.
642  if you have a climb, you can skip the fall.
643  otherwise test for fall.
644 
645  fast tests using MBB in the caller elliminate some volumes by setting check variables to true if MBB overlap
646  checkPenetration - ray for wall penetration should be tested
647  checkCylinder - sphere or cyclinder should be tested
648  checkFall - climb and fall should be tested
649  */
650 
651  struct point_XYZ result;
652  int hit,i;
653  double tmin[3],tmax[3]; /* MBB for facet */
654  struct sFallInfo *fi;
655  struct sNaviInfo *naviinfo;
656  GLDOUBLE awidth, atop, abottom, astep;
657  ppcollision pp;
658  ttglobal tg = gglobal();
659  naviinfo = (struct sNaviInfo *)tg->Bindable.naviinfo;
660  awidth = naviinfo->width; /*avatar width*/
661  atop = naviinfo->width; /*top of avatar (relative to eyepoint)*/
662  abottom = -naviinfo->height; /*bottom of avatar (relative to eyepoint)*/
663  astep = -naviinfo->height+naviinfo->step;
664  pp = (ppcollision)tg->collision.prv;
665 
666  result = zero;
667  pp->get_poly_mindisp = 0.0;
668  fi = FallInfo();
669 
670  if(fi->walking)
671  {
672  tmin[0] = tmax[0] = p[0].x;
673  tmin[1] = tmax[1] = p[0].y;
674  tmin[2] = tmax[2] = p[0].z;
675  for(i=1;i<num;i++)
676  {
677  tmin[0] = DOUBLE_MIN(tmin[0],p[i].x);
678  tmin[1] = DOUBLE_MIN(tmin[1],p[i].y);
679  tmin[2] = DOUBLE_MIN(tmin[2],p[i].z);
680  tmax[0] = DOUBLE_MAX(tmax[0],p[i].x);
681  tmax[1] = DOUBLE_MAX(tmax[1],p[i].y);
682  tmax[2] = DOUBLE_MAX(tmax[2],p[i].z);
683  }
684 
685 // printf ("get_poly_disp_2, checkPenetration %d checkCylinder %d checkFall %d true %d\n",fi->checkPenetration, fi->checkCylinder, fi->checkFall, TRUE);
686 
687  /* walking */
688  hit = 0;
689  if(fi->checkPenetration)
690  {
691  double rmax;
692  struct point_XYZ presult;
693  hit = get_poly_penetration_disp(awidth,p,num,n,tmin,tmax,&presult,&rmax);
694  if(hit)
695  {
696  fi->isPenetrate = 1;
697  if(rmax > fi->pendisp)
698  {
699  fi->pencorrection = presult;
700  fi->pendisp = rmax;
701  }
702  }
703  }
704  if(fi->checkCylinder && !hit)
705  {
706  result = get_poly_radialSample_disp(abottom,atop,astep,awidth,p,num,n,tmin,tmax); //statistical method
707 
708  hit = !(APPROX(result.x, 0) && APPROX(result.y, 0) && APPROX(result.z, 0));
709  if(hit)
710  fi->canFall = 0; /* rule: don't fall or climb if we are colliding */
711  }
712  if(fi->checkFall && !hit)
713  {
714  accumulateFallingClimbing(abottom,atop,astep,p,num,n,tmin,tmax); //y1, y2, p, num, n);
715 
716  }
717  }
718  else
719  {
720  /* fly, examine */
721  // printf ("calling get_poly_min_disp_with_sphere at %s:%d\n",__FILE__,__LINE__);
722  result = get_poly_min_disp_with_sphere(awidth, p, num, n);
723  }
724  pp->get_poly_mindisp = vecdot(&result,&result);
725  // printf ("\tend get_poly_disp_2, result %lf %lf %lf\n",result.x,result.y,result.z);
726  return result;
727 }
728 
729 
730 /*feed a poly, and radius of a sphere, it returns the minimum displacement and
731  the direction that is needed for them not to intersect any more.
732 */
733 static struct point_XYZ get_poly_min_disp_with_sphere(double r, struct point_XYZ* p, int num, struct point_XYZ n) {
734  int i,j;
735  /* double polydisp; */
736  struct point_XYZ result;
737  double tmin[3],tmax[3],rmin[3],rmax[3],q[3];
738  double get_poly_mindisp;
739  int clippedPoly4num = 0;
740  ppcollision pp = (ppcollision)gglobal()->collision.prv;
741  get_poly_mindisp = 1E90;
742 
743  /* printf ("\nstart of get_poly_min_disp_with_sphere\n"); */
744 
745  /* cheap MBB test */
746  //double tmin[3],tmax[3],rmin[3],rmax[3],q[3];
747 
748  /* initialize the point array to something... */
749  memcpy(tmin,&p[0],3*sizeof(double));
750  memcpy(tmax,&p[num-1],3*sizeof(double));
751 
752  for(i=0;i<num;i++)
753  {
754  memcpy(q,&p[i],3*sizeof(double));
755  for(j=0;j<3;j++)
756  {
757  tmin[j] = DOUBLE_MIN(tmin[j],q[j]);
758  tmax[j] = DOUBLE_MAX(tmax[j],q[j]);
759  }
760  }
761  for(i=0;i<3;i++)
762  {
763  rmin[i] = -r;
764  rmax[i] = r;
765  }
766 
767  if( !overlapMBBs(rmin,rmax,tmin,tmax) )
768  {
769  return zero;
770  }
771  /* end cheap MBB test */
772 
773 #ifdef DEBUGFACEMASK
774  if(facemask != debugsurface++)
775  return zero;
776 #endif
777  /*allocate data */
778  if ((num+1)> pp->clippedPoly4Size) {
779  pp->clippedPoly4 = (struct point_XYZ*) REALLOC(pp->clippedPoly4,sizeof(struct point_XYZ) * (num + 1));
780  pp->clippedPoly4Size = num+1;
781  }
782 
783  /*if normal not specified, calculate it */
784  /* if(n.x == 0 && n.y == 0 && n.z == 0) */
785  if(APPROX(n.x, 0) && APPROX(n.y, 0) && APPROX(n.z, 0)) {
786  polynormal(&n,&p[0],&p[1],&p[2]);
787  }
788 
789 
790  for(i = 0; i < num; i++) {
791  DEBUGPTSPRINT("intersect_closestpolypoints_on_surface[%d]= %d\n",i,clippedPoly4num);
792  pp->clippedPoly4[clippedPoly4num++] = weighted_sum(p[i],p[(i+1)%num],closest_point_of_segment_to_origin(p[i],p[(i+1)%num]));
793  }
794 
795  /*find closest point of polygon plane*/
796  pp->clippedPoly4[clippedPoly4num] = closest_point_of_plane_to_origin(p[0],n);
797 
798 
799 /* {
800 int m;
801 printf ("\t\tget_poly_min_disp_with_sphere, clippedPoly4 array\n");
802 for (m=0; m<=clippedPoly4num; m++)
803 printf ("\t\t\tclippedPoly4 %d is %f %f %f\n",m,pp->clippedPoly4[m].x, pp->clippedPoly4[m].y, pp->clippedPoly4[m].z);
804 } */
805 
806 
807 
808 
809  /*keep if inside*/
810  if(perpendicular_line_passing_inside_poly(pp->clippedPoly4[clippedPoly4num],p, num)) {
811  DEBUGPTSPRINT("perpendicular_line_passing_inside_poly[%d]= %d\n",0,clippedPoly4num);
812  clippedPoly4num++;
813  }
814 
815 #ifdef DEBUGPTS
816  for(i=0; i < clippedPoly4num; i++) {
817  debugpts.push_back(clippedPoly4[i]);
818  }
819 #endif
820 
821  /*here we find mimimum displacement possible */
822 
823  /*calculate the closest point to origin */
824 //printf ("\t\tget_poly_min_disp_with_sphere, clippedPoly4num %d\n",clippedPoly4num);
825  for(i = 0; i < clippedPoly4num; i++)
826  {
827  /* printf ("\t\tget_poly_min_disp_with_sphere, checking against %d %f %f %f",i,pp->clippedPoly4[i].x,
828  pp->clippedPoly4[i].y,pp->clippedPoly4[i].z); */
829 
830  double disp = vecdot(&pp->clippedPoly4[i],&pp->clippedPoly4[i]);
831 
832  /* printf (" disp %lf, get_poly_mindisp %lf\n",disp,get_poly_mindisp); */
833 
834  if(disp < get_poly_mindisp)
835  {
836  get_poly_mindisp = disp;
837  result = pp->clippedPoly4[i];
838  }
839  }
840  /* printf ("SW, get_poly_min_disp_with_sphere way, get_poly_mindisp %f\n",get_poly_mindisp); */
841 
842  if(get_poly_mindisp <= r*r)
843  {
844  double rl;
845 
846  /* printf ("\t\tWOW!!! WOW!!! get_poly_min_disp_with_sphere, less than r*r\n");
847  printf ("have to move, have poly_mindisp %f, r*r %f, point %f %f %f\n",get_poly_mindisp, r*r, result.x,result.y,result.z);
848  */
849 
850 
851  /* scale result to length of missing distance. */
852  rl = veclength(result);
853  /* printf ("get_poly_min_disp_with_sphere, comparing %f and %f veclen %lf result %f %f %f\n",get_poly_mindisp, r*r, rl, result.x,result.y,result.z); */
854  /* if(rl != 0.) */
855  if(! APPROX(rl, 0))
856  {
857  /* printf ("approx rl, 0... scaling by %lf, %lf - %lf / %lf\n",(r-sqrt(get_poly_mindisp)) / rl,
858  r, sqrt(get_poly_mindisp), rl); */
859  vecscale(&result,&result,(r-sqrt(get_poly_mindisp)) / rl);
860 
861  /* printf ("by the non-OpenCL software way, result %f %f %f\n",result.x, result.y, result.z); */
862  }
863  else
864  {
865  result = zero;
866  }
867  }
868  else
869  {
870  result = zero;
871  }
872  // printf ("\t\tend get_poly_min_disp_with_sphere result %lf %lf %lf\n",result.x, result.y, result.z);
873  return result;
874 }
875 
876 
877 /*used by get_line_normal_disp to clip the polygon on the cylinder caps, called twice*/
878 static int helper_line_clip_cap(struct point_XYZ* clippedpoly, int clippedpolynum, struct point_XYZ p1, struct point_XYZ p2, double r, struct point_XYZ n, double y, int stepping)
879 {
880  struct point_XYZ ppoly[2];
881  int allin = 1;
882  int i;
883 
884  if(!stepping) {
885  /*sqush poly on cylinder cap plane.*/
886  ppoly[0] = project_on_yplane(p1,n,y);
887  ppoly[1] = project_on_yplane(p2,n,y);
888  } else {
889  ppoly[0] = p1;
890  ppoly[1] = p2;
891  }
892 
893  /*find points of poly hitting cylinder cap*/
894  for(i= 0; i < 2; i++) {
895  if(ppoly[i].x*ppoly[i].x + ppoly[i].z*ppoly[i].z > r*r) {
896  allin = 0;
897  } else {
898  clippedpoly[clippedpolynum++] = ppoly[i];
899  }
900  }
901 
902  if(!allin) {
903  /* int numdessect = 0; */
904  struct point_XYZ dessect;
905  double k1,k2;
906  int nsect;
907 
908 
909  /*find intersections of line with cylinder cap edge*/
910  nsect = getk_intersect_segment_with_ycylinder(&k1,&k2,r,ppoly[0],ppoly[1]);
911  switch(nsect) {
912  case 2:
913  if(fabs(k1-k2) < FLOAT_TOLERANCE) /* segment touches edge of circle. we want to ignore this. */
914  break;
915  clippedpoly[clippedpolynum++] = weighted_sum(ppoly[0],ppoly[1],k2);
916  case 1:
917  clippedpoly[clippedpolynum++] = weighted_sum(ppoly[0],ppoly[1],k1);
918  case 0: break;
919  }
920  /*find intersections of descending segment too.
921  these will point out maximum and minimum in cylinder cap edge that is inside triangle */
922  if(intersect_segment_with_line_on_yplane(&dessect,ppoly[0],ppoly[1],n,zero)) {
923  if(dessect.x*dessect.x + dessect.z*dessect.z < r*r) {
924 
925  clippedpoly[clippedpolynum++] = dessect;
926  }
927  }
928  }
929 
930  return clippedpolynum;
931 }
932 
933 /*feed a line and a normal, and stats of a cylinder, it returns the displacement in the direction of the
934  normal that is needed for them not to intersect any more.*/
935 static struct point_XYZ get_line_normal_disp(double y1, double y2, double r, struct point_XYZ p1, struct point_XYZ p2, struct point_XYZ n) {
936  int i;
937  double mindisp = 0;
938  double polydisp;
939  struct point_XYZ p[2];
940  int num = 2;
941  struct point_XYZ result;
942 
943  struct point_XYZ clippedpoly[14];
944  int clippedpolynum = 0;
945 
946  p[0] = p1;
947  p[1] = p2;
948 
949  /* clip line on top and bottom cap */
950  /* if(n.y!= 0.) */
951  if(! APPROX(n.y, 0)) {
952  clippedpolynum = helper_line_clip_cap(clippedpoly, clippedpolynum, p1, p2, r, n, y1, 0);
953  clippedpolynum = helper_line_clip_cap(clippedpoly, clippedpolynum, p1, p2, r, n, y2, 0);
954  }
955 
956  /*find intersections of line with cylinder side*/
957  /* if(n.y != 1. && n.y != -1.) */ /*n.y == +/-1 makes n.x == n.z == 0, wich does div's by 0, besides making no sense at all. */
958  if(! APPROX(n.y, 1) && ! APPROX(n.y, -1)) { /*n.y == +/-1 makes n.x == n.z == 0, wich does div's by 0, besides making no sense at all. */
959 
960  struct point_XYZ dessect3d;
961  double k1,k2;
962  int nsect;
963 
964 
965  /*find points of poly intersecting descending line on poly, (non-projected)*/
966  if(intersect_segment_with_line_on_yplane(&dessect3d,p[0],p[1],n,zero)) {
967  dessect3d = project_on_cylindersurface_plane(dessect3d,n,r);
968 
969  if(dessect3d.y < y2 &&
970  dessect3d.y > y1)
971  clippedpoly[clippedpolynum++] = dessect3d;
972 
973  }
974  { /*find intersections on cylinder of polygon points projected on surface */
975  struct point_XYZ sect[2];
976  for(i = 0; i < num; i++) {
977  nsect = getk_intersect_line_with_ycylinder(&k1, &k2, r, p[i], n);
978  if(nsect == 0) continue;
979 
980  /*sect = p[i] + k2 n*/
981  vecscale(&sect[i],&n,k2);
982  VECADD(sect[i],p[i]);
983 
984  if(sect[i].y > y1 && sect[i].y < y2) {
985  clippedpoly[clippedpolynum++] = sect[i];
986  }
987  }
988  /*case where vertical line passes through cylinder, but no edges are inside */
989  /* if( (n.y == 0.) && ( */
990  if( (APPROX(n.y, 0)) && (
991  (sect[0].y <= y1 && sect[1].y >= y2) ||
992  (sect[1].y <= y1 && sect[0].y >= y2) )) {
993  sect[0].y = (y1+y2)/2;
994  clippedpoly[clippedpolynum++] = sect[0];
995  }
996  }
997 
998  }
999 
1000 #ifdef DEBUGPTS
1001  for(i=0; i < clippedpolynum; i++) {
1002  debugpts.push_back(clippedpoly[i]);
1003  }
1004 #endif
1005 
1006  /*here we find mimimum displacement possible */
1007  polydisp = vecdot(&p[0],&n);
1008 
1009  /*calculate farthest point from the "n" plane passing through the origin */
1010  for(i = 0; i < clippedpolynum; i++) {
1011  double disp = vecdot(&clippedpoly[i],&n) - polydisp;
1012  if(disp < mindisp) mindisp = disp;
1013  }
1014  vecscale(&result,&n,mindisp);
1015 
1016  return result;
1017 }
1018 
1019 /*feed a line and a normal, and stats of a cylinder, it returns the vertical displacement
1020  that is needed for them not to intersect any more.*/
1021 static struct point_XYZ get_line_step_disp(double y1, double y2, double r, struct point_XYZ p1, struct point_XYZ p2, struct point_XYZ n) {
1022  int i;
1023  /* int allin = 1; */
1024  double dmax = -1E99;
1025  struct point_XYZ result;
1026 
1027  int clippedPoly5num = 0;
1028  ppcollision pp = (ppcollision)gglobal()->collision.prv;
1029 
1030  pp->get_poly_mindisp = 1E90;
1031 
1032 #ifdef DEBUGFACEMASK
1033  printf("facemask = %d, debugsurface = %d\n",facemask,debugsurface);
1034  if((facemask & (1 <<debugsurface++)) ) return zero;
1035 #endif
1036 
1037  if((p1.y > y2 || p2.y > y2 || n.y < 0) && n.y < STEPUP_MAXINCLINE) /*to high to step on and to steep to step on or facing downwards*/
1038  return zero;
1039 
1040  /*allocate data */
1041  if ((10)> pp->clippedPoly5Size) {
1042  pp->clippedPoly5 = (struct point_XYZ*) REALLOC(pp->clippedPoly5,sizeof(struct point_XYZ) * (10));
1043  pp->clippedPoly5Size = 10;
1044  }
1045 
1046 
1047  clippedPoly5num = helper_line_clip_cap(pp->clippedPoly5, clippedPoly5num, p1, p2, r, n, y1,1 );
1048 
1049 #ifdef DEBUGPTS
1050  for(i=0; i < clippedPoly5num; i++) {
1051  debugpts.push_back(clippedPoly5[i]);
1052  }
1053 #endif
1054 
1055  /*get maximum*/
1056  for(i = 0; i < clippedPoly5num; i++) {
1057  if(pp->clippedPoly5[i].y > dmax)
1058  dmax = pp->clippedPoly5[i].y;
1059  }
1060 
1061  /*diplace only if displacement completely clears line*/
1062  if(dmax > y2)
1063  return zero;
1064 
1065  pp->get_poly_mindisp = y1-dmax;
1066 
1067  if(dmax > y1) {
1068  result.x = 0;
1069  result.y = pp->get_poly_mindisp;
1070  result.z = 0;
1071  return result;
1072  } else
1073  return zero;
1074 }
1075 
1076 /* JASJASJAS */
1077 
1078 
1079 
1080 /*feed a line and a normal, and stats of a cylinder, it returns the displacement in the direction of the
1081  normal, or the vertical displacement(in case of stepping) that is needed for them not to intersect any more.*/
1082 static struct point_XYZ get_line_disp(double y1, double y2, double ystep, double r, struct point_XYZ p1, struct point_XYZ p2, struct point_XYZ n) {
1083  struct point_XYZ result;
1084  result = get_line_step_disp(y1,ystep,r,p1,p2,n);
1085  /* if(result.y != 0.) */
1086  if (! APPROX(result.y, 0)) {
1087  return result;
1088  } else {
1089  return get_line_normal_disp(y1,y2,r,p1,p2,n);
1090  }
1091 }
1092 
1093 
1094 /*feed a point and a normal, and stats of a cylinder, it returns the displacement in the direction of the
1095  normal, or the vertical displacement(in case of stepping) that is needed for them not to intersect any more.*/
1096 static struct point_XYZ get_point_disp(double y1, double y2, double ystep, double r, struct point_XYZ p1, struct point_XYZ n) {
1097  double y;
1098  struct point_XYZ result = {0,0,0};
1099  struct point_XYZ cp;
1100 
1101  /*check if stepup.*/
1102  if((p1.y <= ystep && p1.y > y1 && p1.x*p1.x + p1.z*p1.z < r*r) && (n.y > STEPUP_MAXINCLINE) /*to steep to step on*/) {
1103  result.y = y1-p1.y;
1104  return result;
1105  }
1106 
1107  /*select relevant cap*/
1108  y = (n.y < 0.) ? y2 : y1;
1109 
1110  /*check if intersect cap*/
1111  /* if(n.y != 0) */
1112  if (! APPROX(n.y, 0)) {
1113  cp = project_on_yplane(p1,n,y);
1114  if(cp.x*cp.x + cp.z*cp.z < r*r) {
1115  VECDIFF(cp,p1,result);
1116  return result;
1117  }
1118  }
1119 
1120  /*find intersections of point with cylinder side*/
1121  /* if(n.y != 1. && n.y != -1.) */ /*n.y == +/-1 makes n.x == n.z == 0, wich does div's by 0, besides making no sense at all. */
1122  if (! APPROX(n.y, 1) && ! APPROX(n.y, -1)) { /*n.y == +/-1 makes n.x == n.z == 0, wich does div's by 0, besides making no sense at all. */
1123  int nsect;
1124  double k1,k2;
1125  /*find pos of the point projected on surface of cylinder*/
1126  nsect = getk_intersect_line_with_ycylinder(&k1, &k2, r, p1, n);
1127  if(nsect != 0) {
1128  /*sect = p1 + k2 n*/
1129  if(k2 >= 0) return zero; /* wrong direction. we are out. */
1130  vecscale(&result,&n,k2);
1131  cp = result;
1132  VECADD(cp,p1);
1133 
1134  if(cp.y > y1 && cp.y < y2) {
1135  return result;
1136  }
1137  }
1138 
1139  }
1140 
1141  return zero;
1142 }
1143 
1144 
1145 /*feed a box (a corner, and the three vertice sides) and the stats of a cylinder, it returns the
1146  displacement of the box that is needed for them not to intersect any more, with optionnal stepping displacement */
1147 struct point_XYZ box_disp(double y1, double y2, double ystep, double r,struct point_XYZ p0, struct point_XYZ i, struct point_XYZ j, struct point_XYZ k) {
1148  struct point_XYZ p[8];
1149  struct point_XYZ n[6];
1150  struct point_XYZ maxdispv = {0,0,0};
1151  double maxdisp = 0;
1152  //struct point_XYZ middle;
1153  /*draw this up, you will understand: */
1154  static const int faces[6][4] = {
1155  {1,7,2,0},
1156  {2,6,3,0},
1157  {3,5,1,0},
1158  {5,3,6,4},
1159  {7,1,5,4},
1160  {6,2,7,4}
1161  };
1162  int ci;
1163 
1164  for(ci = 0; ci < 8; ci++) p[ci] = p0;
1165 
1166  /*compute points of box*/
1167  VECADD(p[1],i);
1168  VECADD(p[2],j);
1169  VECADD(p[3],k);
1170  VECADD(p[4],i); VECADD(p[4],j); VECADD(p[4],k); /*p[4]= i+j+k */
1171  VECADD(p[5],k); VECADD(p[5],i); /*p[6]= k+i */
1172  VECADD(p[6],j); VECADD(p[6],k); /*p[5]= j+k */
1173  VECADD(p[7],i); VECADD(p[7],j); /*p[7]= i+j */
1174 
1175  /*compute normals, in case of perfectly orthogonal box, a shortcut exists*/
1176  veccross(&n[0],j,i);
1177  veccross(&n[1],k,j);
1178  veccross(&n[2],i,k);
1179  vecnormal(&n[0],&n[0]);
1180  vecnormal(&n[1],&n[1]);
1181  vecnormal(&n[2],&n[2]);
1182  vecscale(&n[3],&n[0],-1.);
1183  vecscale(&n[4],&n[1],-1.);
1184  vecscale(&n[5],&n[2],-1.);
1185 
1186  /*what it says : middle of box */
1187  //middle = weighted_sum(p[0],p[4],.5);
1188 
1189  for(ci = 0; ci < 6; ci++) {
1190  /*only clip faces "facing" origin */
1191  //if(vecdot(&n[ci],&middle) < 0.) {
1192  {
1193  struct point_XYZ pts[5];
1194  struct point_XYZ dispv;
1195  double disp;
1196  pts[0] = p[faces[ci][0]];
1197  pts[1] = p[faces[ci][1]];
1198  pts[2] = p[faces[ci][2]];
1199  pts[3] = p[faces[ci][3]];
1200  pts[4] = p[faces[ci][0]]; /* dug9 - for test split into 2 triangles for sphere test - no help with sphere*/
1201  //dispv = get_poly_disp(y1,y2,ystep,r,pts,4,n[ci]);
1202  dispv = get_poly_disp_2(pts,4,n[ci]);
1203  disp = vecdot(&dispv,&dispv);
1204 
1205  /*keep result only if:
1206  displacement is positive
1207  displacement is smaller than minimum displacement up to date
1208  */
1209  if( (disp > FLOAT_TOLERANCE) && (disp > maxdisp) ){
1210  maxdisp = disp;
1211  maxdispv = dispv;
1212  }
1213  }
1214  }
1215  return maxdispv;
1216 }
1217 
1218 /*
1219  * fast test to see if a box intersects a y-cylinder,
1220  * gives false positives.
1221  */
1222 int fast_ycylinder_box_intersect(double y1, double y2, double r,struct point_XYZ pcenter, double xs, double ys, double zs) {
1223  double y = pcenter.y < 0 ? y1 : y2;
1224 
1225  double lefteq = sqrt(y*y + r*r) + sqrt(xs*xs + ys*ys + zs*zs);
1226  return lefteq*lefteq > vecdot(&pcenter,&pcenter);
1227 }
1228 
1229 
1230 double *transformFULL4d(double *r4, double *a4, double *mat);
1231 void __gluMultMatrixVecd(const GLDOUBLE matrix[16], const GLDOUBLE in[4], GLDOUBLE out[4]);
1232 
1233 int transformMBB4d(GLDOUBLE *rMBBmin, GLDOUBLE *rMBBmax, GLDOUBLE *matTransform, GLDOUBLE* inMBBmin, GLDOUBLE* inMBBmax, int isAffine)
1234 {
1235  /* transform axes aligned minimum bounding box MBB via octo box / cuboid - will expand as necessary to cover original volume
1236  return value:
1237  1 - success
1238  0 - divide by 0, usually with projecting a point that's at 90 degrees to camera axis ie to the right, left, up, doown
1239  */
1240  struct point_XYZ abox[8];
1241  int i,j,k,m, iret;
1242  GLDOUBLE p[3],rx,ry,rz;
1243  iret = 1;
1244  /* generate an 8 corner box in shape space to represent the shape collision volume */
1245  m = 0;
1246  for(i=0;i<2;i++)
1247  {
1248  rx = i==0? inMBBmin[0] : inMBBmax[0];
1249  for(j=0;j<2;j++)
1250  {
1251  ry = j==0? inMBBmin[1] : inMBBmax[1];
1252  for(k=0;k<2;k++)
1253  {
1254  rz = k==0? inMBBmin[2] : inMBBmax[2];
1255  abox[m].x = rx;
1256  abox[m].y = ry;
1257  abox[m].z = rz;
1258  m++;
1259  }
1260  }
1261  }
1262 
1263  /* transform the corners of the octo box */
1264  if(isAffine) {
1265  for(m=0;m<8;m++)
1266  transform(&abox[m],&abox[m],matTransform);
1267  }else{
1268  GLDOUBLE in[4];
1269  GLDOUBLE out[4];
1270  for(m=0;m<8;m++){
1271  pointxyz2double(in,&abox[m]);
1272  in[3]=1.0;
1273  __gluMultMatrixVecd(matTransform, in, out);
1274  //transformFULL4d(out,in, matTransform);
1275  if(0) if (fabs(out[3]) < .0001) {
1276  iret = 0;
1277  return iret;
1278  }
1279  vecscaled(out,out,1.0/out[3]);
1280  double2pointxyz(&abox[m],out);
1281  }
1282  }
1283  if(iret){
1284  /*find the MBB of the transformed octo box */
1285  //memcpy(rMBBmin,&abox[0],3*sizeof(GLDOUBLE)); //sizeof(struct point_XYZ));
1286  //memcpy(rMBBmax,&abox[0],3*sizeof(GLDOUBLE));
1287  pointxyz2double(rMBBmin,&abox[0]); //something to initialize them
1288  pointxyz2double(rMBBmax,&abox[0]);
1289  for(m=1;m<8;m++)
1290  {
1291  //memcpy(p,&abox[m],3*sizeof(GLDOUBLE));
1292  pointxyz2double(p,&abox[m]);
1293  for(i=0;i<3;i++)
1294  {
1295  rMBBmin[i] = DOUBLE_MIN(rMBBmin[i],p[i]);
1296  rMBBmax[i] = DOUBLE_MAX(rMBBmax[i],p[i]);
1297  }
1298  }
1299  }
1300  return iret;
1301 }
1302 void transformMBB(GLDOUBLE *rMBBmin, GLDOUBLE *rMBBmax, GLDOUBLE *matTransform, GLDOUBLE* inMBBmin, GLDOUBLE* inMBBmax){
1303  //AFFINE version, assumes matTransform is not projection / has no projection matrix
1304  int isAffine = 1, iret;
1305 
1306  UNUSED(iret);
1307 
1308  iret = transformMBB4d(rMBBmin, rMBBmax, matTransform, inMBBmin, inMBBmax,isAffine);
1309 }
1310 
1311 
1312 
1313 
1314 int fast_ycylinder_MBB_intersect_collisionSpace(double y1, double y2, double r, GLDOUBLE *shape2collision, GLDOUBLE *shapeMBBmin, GLDOUBLE *shapeMBBmax )
1315 {
1316  /* goal: transform shape MBB to avatar/collision space, get its MBB there, and return 1 if the shape MBB intersects
1317  the avatar cylinderical collision volume MBB
1318  Issue: you'll likely have more false positives with the avatar-space MBB intersection test (versus shape-space)
1319  shapes in shape space are statistically more often cuboid and axes-aligned - think of wall-like objects.
1320  As a result a MBB in shape space is relatively smaller than the MBB recomputed after transforming to
1321  avatar space. (Same could be said in theory for the avatar cylinder going the other way, but when I think of wall
1322  objects I'd rather be doing it in shape space.
1323  */
1324  int i;
1325  GLDOUBLE smin[3], smax[3], avmin[3], avmax[3];
1326 
1327  /* generate mins and maxes for avatar cylinder in avatar space to represent the avatar collision volume */
1328  for(i=0;i<3;i++)
1329  {
1330  avmin[i] = -r;
1331  avmax[i] = r;
1332  }
1333  avmin[1] = y1; avmax[1] = y2;
1334 
1335  transformMBB(smin,smax,shape2collision,shapeMBBmin,shapeMBBmax);
1336  return overlapMBBs(avmin,avmax,smin,smax);
1337 }
1338 
1339 
1340 int fast_sphere_MBB_intersect_collisionSpace(double r, GLDOUBLE *shape2collision, GLDOUBLE *shapeMBBmin, GLDOUBLE *shapeMBBmax )
1341 {
1342  /* goal: transform shape MBB to avatar/collision space, get its MBB there, and return 1 if the shape MBB intersects
1343  the avatar spherical collision volume MBB
1344  */
1345  int i;
1346  GLDOUBLE smin[3], smax[3], avmin[3], avmax[3];
1347 
1348  /* generate mins and maxes for avatar cylinder in avatar space to represent the avatar collision volume */
1349  for(i=0;i<3;i++)
1350  {
1351  avmin[i] = -r;
1352  avmax[i] = r;
1353  }
1354  transformMBB(smin,smax,shape2collision,shapeMBBmin,shapeMBBmax);
1355  return overlapMBBs(avmin,avmax,smin,smax);
1356 }
1357 
1358 
1359 /*fast test to see if a cone intersects a y-cylinder. */
1360 /*gives false positives. */
1361 int fast_ycylinder_cone_intersect(double y1, double y2, double r,struct point_XYZ pcenter, double halfheight, double baseradius) {
1362  double y = pcenter.y < 0 ? y1 : y2;
1363 
1364  double lefteq = sqrt(y*y + r*r) + sqrt(halfheight*halfheight + baseradius*baseradius);
1365  return lefteq*lefteq > vecdot(&pcenter,&pcenter);
1366 }
1367 
1368 
1369 
1370 /*algorithm is approximative */
1371 /*basically, it does collision with a triangle on a plane that passes through the origin.*/
1372 struct point_XYZ cone_disp(double y1, double y2, double ystep, double r, struct point_XYZ base, struct point_XYZ top, double baseradius) {
1373 
1374  struct point_XYZ i; /* cone axis vector*/
1375  double h; /* height of cone*/
1376  struct point_XYZ tmp;
1377  struct point_XYZ bn; /* direction from cone to cylinder*/
1378  struct point_XYZ side; /* side of base in direction of origin*/
1379  struct point_XYZ normalbase; /* collision normal of base (points downwards)*/
1380  struct point_XYZ normalside; /* collision normal of side (points outside)*/
1381  struct point_XYZ normaltop; /* collision normal of top (points up)*/
1382  //struct point_XYZ bn_normal; /* bn, normalized;*/
1383  struct point_XYZ mindispv= {0,0,0};
1384  double mindisp = 1E99;
1385 
1386  /*find closest point of cone base to origin. */
1387 
1388  vecscale(&bn,&base,-1.0);
1389 
1390  VECDIFF(top,base,i);
1391  vecscale(&tmp,&i,- vecdot(&i,&bn)/vecdot(&i,&i));
1392  VECADD(bn,tmp);
1393  /* if(vecnormal(&bn,&bn) == 0.) */
1394  if (APPROX(vecnormal(&bn,&bn), 0)) {
1395  /* origin is aligned with cone axis */
1396  /* must use different algorithm to find side */
1397  struct point_XYZ tmpn = i;
1398  struct point_XYZ tmpj;
1399  vecnormal(&tmpn,&tmpn);
1400  make_orthogonal_vector_space(&bn,&tmpj,tmpn);
1401  //bn_normal = bn;
1402  }
1403  vecscale(&side,&bn,baseradius);
1404  VECADD(side,base);
1405 
1406  /* find normals ;*/
1407  h = vecnormal(&i,&i);
1408  normaltop = i;
1409  vecscale(&normalbase,&normaltop,-1.0);
1410  vecscale(&i,&i,-baseradius);
1411  vecscale(&normalside,&bn,-h);
1412  VECADD(normalside,i);
1413  vecnormal(&normalside,&normalside);
1414  vecscale(&normalside,&normalside,-1.0);
1415 
1416  {
1417  /*get minimal displacement*/
1418  struct point_XYZ dispv;
1419  double disp;
1420 
1421  if( vecdot(&normalside,&top) < 0. ) {
1422  dispv = get_line_disp(y1,y2,ystep,r,top,side,normalside);
1423  disp = vecdot(&dispv,&dispv);
1424  if(disp < mindisp)
1425  mindispv = dispv, mindisp = disp;
1426  }
1427 
1428  if( vecdot(&normalbase,&base) < 0. ) {
1429  dispv = get_line_disp(y1,y2,ystep,r,base,side,normalbase);
1430  disp = vecdot(&dispv,&dispv);
1431  if(disp < mindisp)
1432  mindispv = dispv, mindisp = disp;
1433  }
1434 
1435  if( vecdot(&normaltop,&top) < 0. ) {
1436  dispv = get_point_disp(y1,y2,ystep,r,top,normaltop);
1437  disp = vecdot(&dispv,&dispv);
1438  /*i don't like "disp !=0." there should be a different condition for
1439  * non applicability.*/
1440  /* if(disp != 0. && disp < mindisp) */
1441  if(! APPROX(disp, 0) && disp < mindisp)
1442  mindispv = dispv, mindisp = disp;
1443  }
1444  }
1445 
1446  return mindispv;
1447 }
1448 
1449 
1450 /*algorithm is approximative */
1451 /*basically, it does collision with a rectangle on a plane that passes through the origin.*/
1452 struct point_XYZ cylinder_disp(double y1, double y2, double ystep, double r, struct point_XYZ base, struct point_XYZ top, double baseradius) {
1453 
1454  struct point_XYZ i; /* cone axis vector*/
1455  //double h; /* height of cone*/
1456  struct point_XYZ tmp;
1457  struct point_XYZ bn; /* direction from cone to cylinder*/
1458  struct point_XYZ sidetop; /* side of top in direction of origin*/
1459  struct point_XYZ sidebase; /* side of base in direction of origin*/
1460  struct point_XYZ normalbase; /* collision normal of base (points downwards)*/
1461  struct point_XYZ normalside; /* collision normal of side (points outside)*/
1462  struct point_XYZ normaltop; /* collision normal of top (points upwards)*/
1463  struct point_XYZ mindispv= {0,0,0};
1464  double mindisp = 1E99;
1465 
1466  /*find closest point of cone base to origin. */
1467 
1468  vecscale(&bn,&base,-1.0);
1469 
1470  VECDIFF(top,base,i);
1471  vecscale(&tmp,&i,- vecdot(&i,&bn)/vecdot(&i,&i));
1472  VECADD(bn,tmp);
1473  /* if(vecnormal(&bn,&bn) == 0.) */
1474  if (APPROX(vecnormal(&bn,&bn), 0)) {
1475  /* origin is aligned with cone axis */
1476  /* must use different algorithm to find side */
1477  struct point_XYZ tmpn = i;
1478  struct point_XYZ tmpj;
1479  vecnormal(&tmpn,&tmpn);
1480  make_orthogonal_vector_space(&bn,&tmpj,tmpn);
1481  }
1482  vecscale(&sidebase,&bn,baseradius);
1483  sidetop = top;
1484  VECADD(sidetop,sidebase);
1485  VECADD(sidebase,base);
1486 
1487  /* find normals ;*/
1488  //h = vecnormal(&i,&i);
1489  normaltop = i;
1490  vecscale(&normalbase,&normaltop,-1.0);
1491  normalside = bn;
1492 
1493  {
1494  /*get minimal displacement*/
1495  struct point_XYZ dispv;
1496  double disp;
1497 
1498  if( vecdot(&normalside,&sidetop) < 0. ) {
1499  dispv = get_line_disp(y1,y2,ystep,r,sidetop,sidebase,normalside);
1500  disp = vecdot(&dispv,&dispv);
1501  if(disp < mindisp)
1502  mindispv = dispv, mindisp = disp;
1503  }
1504 
1505  if( vecdot(&normalbase,&base) < 0. ) {
1506  dispv = get_line_disp(y1,y2,ystep,r,base,sidebase,normalbase);
1507  disp = vecdot(&dispv,&dispv);
1508  if(disp < mindisp)
1509  mindispv = dispv, mindisp = disp;
1510  }
1511 
1512  if( vecdot(&normaltop,&top) < 0. ) {
1513  dispv = get_line_disp(y1,y2,ystep,r,top,sidetop,normaltop);
1514  disp = vecdot(&dispv,&dispv);
1515  if( disp < mindisp)
1516  mindispv = dispv, mindisp = disp;
1517  }
1518  }
1519 
1520  return mindispv;
1521 }
1522 
1523 
1524 
1525 static int intersectionHeightOfVerticalLineWithSurfaceElement(double* height, struct point_XYZ* p, int num, struct point_XYZ* n, double *tmin, double *tmax )
1526 {
1527 
1528  /* Intersects a Y vertical infinite line passing through origin with a convex polygon
1529  convex polygon - like a triangle or quad or pentagon. Not like a star or general polygon like font glyph outline
1530  etc which could be concave like a U
1531  Input:
1532  p[num] - polygon vertices
1533  n - polygon normal
1534  returns:
1535  0 if intersection fails due to either vertical polygon face or intesection point outside polygon
1536  height - if inside, this will be the Y height relative to the origin of the intersection point
1537  */
1538  /* step 1 compute the infinite plane through the points p. Use the normal N passed in. */
1539  int overlap;
1540  struct point_XYZ D;
1541  double dd, ndotD;
1542  overlap = tmax[0] >= 0.0 && tmin[0] <= 0.0 && tmax[2] >= 0.0 && tmin[2] <= 0.0;
1543  if(!overlap) return 0;
1544  /* end cheap MBR test */
1545  dd = -vecdot(&p[0],n);
1546  /* the Origin is 0,0,0 and N*O is 0 */
1547  /* D is the ray direction - our zenith vector */
1548  D.x = 0.0;
1549  D.y = 1.0;
1550  D.z = 0.0;
1551  ndotD = vecdot(n,&D);
1552  /* slope check - if near vertical should we skip it?. */
1553  if( fabs(ndotD) < .1 )
1554  {
1555  return 0; /* vertical wall */
1556  }
1557  *height = - dd/ndotD;
1558  /* step 2 determine if inside the triangle */
1559  /* in theory if the cross products (D*height - p[i]) x (p[i+1] - p[i])
1560  point in the same general direction, it's inside (if one alternates, its outside)*/
1561  D.y = *height;
1562  return pointOnPlaneInsidePoly(D,p,num,n);
1563 }
1564 
1565 static void accumulateFallingClimbing(double y1, double y2, double ystep, struct point_XYZ *p, int num, struct point_XYZ nused, double *tmin, double *tmax)
1566 {
1567  struct sFallInfo *fi = FallInfo();
1568 
1569  if(fi->walking)
1570  {
1571  /* Goal: Falling - if we're floating above the terrain we'll have no regular collision
1572  so we need special test to see if we should fall. If climbing we nullify any fall.
1573  */
1574  double hh;
1575  if( intersectionHeightOfVerticalLineWithSurfaceElement(&hh,&p[0],num,&nused, tmin, tmax))
1576  {
1577  /* terrain below avatar at 0,0,0? */
1578  double hhbelowy1 = hh - y1;
1579  if( hh < 0.0 )
1580  {
1581  /* falling */
1582  if( hh < y1 && hh > -fi->fallHeight)
1583  {
1584  /* FALLING */
1585  if(fi->hits ==0)
1586  fi->hfall = hhbelowy1; //hh - y1;
1587  else
1588  if(hhbelowy1 > fi->hfall) fi->hfall = hhbelowy1; //hh - y1;
1589  fi->hits++;
1590  fi->isFall = 1;
1591  }else
1592  /* regular below / nadir collision - below avatar center but above avatar's feet which are at 0.0 - avatar.height*/
1593  if( hh >= y1 ) /* && hh <= (y1-ystep) ) //no step height implementation */
1594  {
1595  /* CLIMBING. handled elsewhere for displacements, except annihilates any fall*/
1596  fi->canFall = 0;
1597 
1598  if( fi->isClimb == 0 )
1599  fi->hclimb = hhbelowy1; //hh - y1;
1600  else
1601  fi->hclimb = DOUBLE_MAX(fi->hclimb,hhbelowy1);
1602  fi->isClimb = 1;
1603  }
1604  /* no stepheight implementation here
1605  else
1606  if(hh > (y1-ystep) && hh < 0.0 )
1607  {
1608  // blocked by a high step, no climb
1609  printf("S");
1610  }
1611  */
1612 
1613 
1614  }else{
1615  /* regular above / zenith collision */
1616  if( hh > 0.0 && hh < y2 )
1617  {
1618  /* HEAD-BUMP handled elsewhere */
1619  if(0) printf("c");
1620  }
1621  else
1622  if(0) printf("B"); /* head is CLEAR of ceiling point */
1623  }
1624  }
1625  }
1626 }
1627 
1628 /*used by polyrep_disp
1629  - coming in - all coords are already transformed into collision space
1630  - sets up avatar collision volume: a cyclinder for walking/stepping, a sphere for fly/examine
1631  - tests triangle by triangle for a collision
1632  - accumulates displacements from collisions
1633 y1,y2,ystep,r (usually abottom,atop,astep,width from naviinfo height,step,width for the avatar) are in global scale coordinates
1634  pr.actualCoord[pr->ntri]
1635  n[pr->ntri] - one normal for each triangle
1636 dispsum.xyz - output - sum of collision displacement vectors - a mean will be computed by caller
1637 flags - doublesided, front/back facing hints, no-stepping (?)
1638 */
1639 //struct point_XYZ polyrep_disp_rec(double y1, double y2, double ystep, double r, struct X3D_PolyRep* pr, struct point_XYZ* n, struct point_XYZ dispsum, prflags flags) {
1640 static struct point_XYZ polyrep_disp_rec2(struct X3D_PolyRep* pr, struct point_XYZ* n, struct point_XYZ dispsum, prflags flags) {
1641  struct point_XYZ p[3];
1642  double maxdisp = 0;
1643  struct point_XYZ maxdispv = {0,0,0};
1644  double disp;
1645  struct point_XYZ dispv;
1646  int i;
1647  int frontfacing;
1648  int ccw;
1649 
1650  ccw = pr->ccw;
1651 
1652 //printf ("start polyrep_disp_rec2\n");
1653 
1654  for(i = 0; i < pr->ntri; i++)
1655  {
1656  p[0].x = pr->actualCoord[pr->cindex[i*3]*3] +dispsum.x;
1657  p[0].y = pr->actualCoord[pr->cindex[i*3]*3+1] +dispsum.y;
1658  p[0].z = pr->actualCoord[pr->cindex[i*3]*3+2] +dispsum.z;
1659 
1660  if (ccw) frontfacing = (vecdot(&n[i],&p[0]) < 0); /*if normal facing avatar. avatar is at 0,0,0. If vector P going opposite direction to N, P*N will be negative */
1661  else frontfacing = (vecdot(&n[i],&p[0]) >= 0); /*if ccw facing avatar */
1662 
1663  /* printf ("polyrep_disp_rec, frontfacing %d BACKFACING %d FRONTFACING %d DOUBLESIDED %d\n",
1664  frontfacing, flags & PR_BACKFACING, flags & PR_FRONTFACING, flags & PR_DOUBLESIDED); */
1665  /* use if either:
1666  -frontfacing and not in doubleside mode;
1667  -if in doubleside mode:
1668  use if either:
1669  -PR_FRONTFACING or PR_BACKFACING not yet specified
1670  -fontfacing and PR_FRONTFACING specified
1671  -not frontfacing and PR_BACKFACING specified
1672  */
1673  if( (frontfacing && !(flags & PR_DOUBLESIDED) )
1674  || ( (flags & PR_DOUBLESIDED) && !(flags & (PR_FRONTFACING | PR_BACKFACING) ) )
1675  || (frontfacing && (flags & PR_FRONTFACING))
1676  || (!frontfacing && (flags & PR_BACKFACING)) )
1677  {
1678 
1679  struct point_XYZ nused;
1680  p[1].x = pr->actualCoord[pr->cindex[i*3+1]*3] +dispsum.x;
1681  p[1].y = pr->actualCoord[pr->cindex[i*3+1]*3+1] +dispsum.y;
1682  p[1].z = pr->actualCoord[pr->cindex[i*3+1]*3+2] +dispsum.z;
1683  p[2].x = pr->actualCoord[pr->cindex[i*3+2]*3] +dispsum.x;
1684  p[2].y = pr->actualCoord[pr->cindex[i*3+2]*3+1] +dispsum.y;
1685  p[2].z = pr->actualCoord[pr->cindex[i*3+2]*3+2] +dispsum.z;
1686 
1687  if(frontfacing)
1688  {
1689  nused = n[i];
1690  } else { /*can only be here in DoubleSided mode*/
1691  /*reverse polygon orientation, and do calculations*/
1692  vecscale(&nused,&n[i],-1.0);
1693  }
1694  /* ready to start testing the triangle against our collision volume (sphere/cylinder/line) tests.
1695  The avatar collision volume -
1696  A.for flying/examining:
1697  1. sphere.
1698 
1699  B.For walking:
1700  1. sphere (head) <<<<< problem I do not like this displacement logic when walking
1701  because you'll end up floating over something that's just below avatar 0,0,0
1702  which for walking is wrong - you should collide with the cylinder going from top to bottom.
1703  Recommendation: either always do both sphere and cylinder or
1704  just do #2 cylinder abottom to atop for head and body.
1705  2. cylinder (body)
1706  3. line - climb/fall (legs,feet)
1707  Order of tests (so can exit early to save unnecessary computations):
1708  sphere > cylinder > climb > fall
1709  if you have a sphere hit you don't need to test the rest.
1710  If you have a cylinder hit, you don't need to test climb/fall.
1711  if you have a climb, you can skip the fall.
1712  otherwise test for fall.
1713 
1714  fast tests using MBB in the caller elliminate some volumes
1715  docollision - sphere and cyclinder should be tested
1716  dofall - climb and fall should be tested
1717 
1718  Total logic for walking:
1719  collision = docollision
1720  if(docollision)
1721  do sphere
1722  if not sphere
1723  do cylinder
1724  if not cylinder
1725  collision = 0
1726  if( dofall && !collision )
1727  do line
1728  if not climb
1729  do fall
1730  */
1731  // printf ("calling get_poly_disp_2 at %s:%d\n",__FILE__,__LINE__);
1732 
1733  dispv = get_poly_disp_2(p, 3, nused); //get_poly_disp_2(y1,y2,ystep,r, p, 3, nused);
1734  disp = vecdot(&dispv,&dispv);
1735 
1736 
1737  #ifdef DEBUGPTS
1738  if(dispv.x != 0 || dispv.y != 0 || dispv.z != 0)
1739  printf("polyd: (%f,%f,%f) |%f|\n",dispv.x,dispv.y,dispv.z,disp);
1740  #endif
1741 
1742 
1743  /*keep result only if:
1744  displacement is positive
1745  displacement is smaller than minimum displacement up to date
1746  */
1747  if( (disp > FLOAT_TOLERANCE) && (disp > maxdisp) )
1748  {
1749  maxdisp = disp;
1750  maxdispv = dispv;
1751  }
1752  }
1753  }
1754 
1755  VECADD(dispsum,maxdispv);
1756  //printf ("end polyrep_disp_rec2, dispsum %lf %lf %lf at end\n",dispsum.x,dispsum.y,dispsum.z);
1757  return dispsum;
1758 }
1759 
1760 #undef POLYREP_DISP2_PERFORMANCE
1761 #ifdef POLYREP_DISP2_PERFORMANCE
1762 
1763 static bool timing = FALSE;
1764 static double startTime = 0.0;
1765 static double stopTime = 0.0;
1766 static double accumTime = 0.0;
1767 static int counter = 0;
1768 
1769 #endif
1770 
1771 /*uses sphere displacement, and a cylinder for stepping
1772  y1, y2, ystep, r - (usually abottom, atop, astep, awidth) are from naviiinfo avatar height, step, width
1773  pr - will be transformed by mat from raw shape coordinates into collision space:
1774  Fly/Examine: avatar space
1775  Walk: Bound-Viewpoint-Vertical-aligned Avatar-centric BVVA space.
1776  flags -
1777 */
1778 struct point_XYZ polyrep_disp2(struct X3D_PolyRep pr, GLDOUBLE* mat, prflags flags) {
1779  int i;
1780  unsigned int maxc;
1781  ppcollision pp = (ppcollision)gglobal()->collision.prv;
1782 
1783 #ifdef POLYREP_DISP2_PERFORMANCE
1784  if (!timing) {
1785  printf ("start timing polyrep_disp2\n");
1786  timing = TRUE;
1787 
1788  }
1789  startTime = Time1970sec();
1790 #endif
1791 
1792 
1793 #ifdef HAVE_OPENCL
1794 
1795  if ((pr.VBO_buffers[VERTEX_VBO] != 0) && pp->OpenCL_Collision_Program_initialized) {
1796  ttglobal tg = gglobal();
1797  float awidth = (float) tg->Bindable.naviinfo.width; /*avatar width*/
1798 
1799  float mymat[16];
1800  for (i=0; i<16; i++) {
1801  mymat[i] = (float) mat[i];
1802  }
1803 
1804  pp->res = run_non_walk_collide_program(
1805  pr.VBO_buffers[VERTEX_VBO],pr.VBO_buffers[INDEX_VBO],mymat, pr.ntri,
1806  pr.ccw, flags, awidth);
1807 
1808  //printf ("openCL sez: move us %f %f %f\n",pp->res.x,pp->res.y,pp->res.z);
1809 
1810 
1811 #ifdef POLYREP_DISP2_PERFORMANCE
1812  stopTime = Time1970sec();
1813  accumTime += stopTime - startTime;
1814 
1815  if (counter == 25) {
1816  printf ("polyrep_disp2, averaged over 25 runs: %f\n",
1817  accumTime/25.0);
1818  counter = 0;
1819  accumTime = 0.0;
1820  }
1821 
1822  counter ++;
1823 #endif
1824 
1825  return pp->res;
1826  }
1827 
1828  /* if we are here, there was an OpenCL issue and we have to do this by software */
1829 #endif
1830 
1831 
1832  pp->res.x=0.0; pp->res.y=0.0; pp->res.z=0.0;
1833  maxc = 0; /* highest cindex, used to point into prd_newc_floats structure.*/
1834 
1835  for(i = 0; i < pr.ntri*3; i++) {
1836  if (pr.cindex[i] > maxc) {maxc = pr.cindex[i];}
1837  }
1838 
1839  /*transform all points from raw shape to viewer(fly) or BVAAC(walk) space */
1840  if (maxc> pp->prd_newc_floats_size) {
1841  pp->prd_newc_floats = REALLOC(pp->prd_newc_floats,maxc*9*sizeof(float));
1842  pp->prd_newc_floats_size = maxc;
1843  }
1844 
1845 
1846  for(i = 0; i < pr.ntri*3; i++) {
1847  transformf(&pp->prd_newc_floats[pr.cindex[i]*3],&pr.actualCoord[pr.cindex[i]*3],mat);
1848  }
1849 
1850  pr.actualCoord = pp->prd_newc_floats; /*remember, coords are only replaced in our local copy of PolyRep */
1851 
1852 
1853  /*pre-calculate face normals */
1854  if (pr.ntri> pp->prd_normals_size) {
1855  pp->prd_normals = REALLOC(pp->prd_normals,pr.ntri*sizeof(struct point_XYZ));
1856  pp->prd_normals_size = pr.ntri;
1857  }
1858 
1859  for(i = 0; i < pr.ntri; i++) {
1860  polynormalf(&pp->prd_normals[i],&pr.actualCoord[pr.cindex[i*3]*3],
1861  &pr.actualCoord[pr.cindex[i*3+1]*3],&pr.actualCoord[pr.cindex[i*3+2]*3]);
1862  }
1863 
1864  pp->res = polyrep_disp_rec2(&pr,pp->prd_normals,pp->res,flags); //polyrep_disp_rec(y1,y2,ystep,r,&pr,prd_normals,res,flags);
1865 
1866  /* printf ("polyrep_disp_rec2 tells us to move: %f %f %f\n",pp->res.x, pp->res.y, pp->res.z); */
1867 
1868  pr.actualCoord = 0;
1869 
1870 #ifdef POLYREP_DISP2_PERFORMANCE
1871  stopTime = Time1970sec();
1872  accumTime += stopTime - startTime;
1873 
1874  if (counter == 25) {
1875  printf ("polyrep_disp2, averaged over 25 runs: %f\n",
1876  accumTime/25.0);
1877  counter = 0;
1878  accumTime = 0.0;
1879  }
1880 
1881  counter ++;
1882 #endif
1883 
1884  return pp->res;
1885 }
1886 
1887 
1888 
1889 
1890 /*Optimized polyrep_disp for planar polyreps.
1891  Used for text.
1892  planar_polyrep_disp computes the normal using the first polygon, if no normal is specified (if it is zero).
1893  JAS - Normal is always specified now. (see VRMLRend.pm for invocation)
1894 */
1895 static struct point_XYZ planar_polyrep_disp_rec(double y1, double y2, double ystep, double r, struct X3D_PolyRep* pr, struct point_XYZ n, struct point_XYZ dispsum, prflags flags) {
1896  struct point_XYZ p[3];
1897  double lmaxdisp = 0;
1898  struct point_XYZ maxdispv = {0,0,0};
1899  double disp;
1900  struct point_XYZ dispv;
1901  /* static int recursion_count = 0; */
1902  int i;
1903  int frontfacing;
1904  ppcollision pp = (ppcollision)gglobal()->collision.prv;
1905 
1906  p[0].x = pr->actualCoord[pr->cindex[0]*3] +dispsum.x;
1907  p[0].y = pr->actualCoord[pr->cindex[0]*3+1] +dispsum.y;
1908  p[0].z = pr->actualCoord[pr->cindex[0]*3+2] +dispsum.z;
1909 
1910  frontfacing = (vecdot(&n,&p[0]) < 0); /*if normal facing avatar */
1911 
1912  if(!frontfacing && !(flags & PR_DOUBLESIDED)) return dispsum;
1913 
1914  if(!frontfacing) vecscale(&n,&n,-1.0);
1915 
1916  for(i = 0; i < pr->ntri; i++) {
1917  p[0].x = pr->actualCoord[pr->cindex[i*3]*3] +dispsum.x;
1918  p[0].y = pr->actualCoord[pr->cindex[i*3]*3+1] +dispsum.y;
1919  p[0].z = pr->actualCoord[pr->cindex[i*3]*3+2] +dispsum.z;
1920  p[1].x = pr->actualCoord[pr->cindex[i*3+1]*3] +dispsum.x;
1921  p[1].y = pr->actualCoord[pr->cindex[i*3+1]*3+1] +dispsum.y;
1922  p[1].z = pr->actualCoord[pr->cindex[i*3+1]*3+2] +dispsum.z;
1923  p[2].x = pr->actualCoord[pr->cindex[i*3+2]*3] +dispsum.x;
1924  p[2].y = pr->actualCoord[pr->cindex[i*3+2]*3+1] +dispsum.y;
1925  p[2].z = pr->actualCoord[pr->cindex[i*3+2]*3+2] +dispsum.z;
1926 
1927  //dispv = get_poly_disp(y1,y2,ystep, r, p, 3, n);
1928  dispv = get_poly_disp_2(p, 3, n);
1929  disp = -pp->get_poly_mindisp; /*global variable. was calculated inside poly_normal_disp already. */
1930 
1931 #ifdef DEBUGPTS
1932  printf("polyd: (%f,%f,%f) |%f|\n",dispv.x,dispv.y,dispv.z,disp);
1933 #endif
1934 
1935  /*keep result only if:
1936  displacement is positive
1937  displacement is bigger than maximum displacement up to date
1938  */
1939  if((disp > FLOAT_TOLERANCE) && (disp > lmaxdisp)) {
1940  lmaxdisp = disp;
1941  maxdispv = dispv;
1942  }
1943 
1944  }
1945  VECADD(dispsum,maxdispv);
1946  return dispsum;
1947 
1948 }
1949 
1950 
1951 struct point_XYZ planar_polyrep_disp(double y1, double y2, double ystep, double r, struct X3D_PolyRep pr, GLDOUBLE* mat, prflags flags, struct point_XYZ n) {
1952  int i;
1953  unsigned int maxc;
1954  ppcollision pp = (ppcollision)gglobal()->collision.prv;
1955 
1956 
1957  pp->res.x=0.0; pp->res.y=0.0; pp->res.z=0.0;
1958  maxc = 0; /* highest cindex, used to point into newc structure.*/
1959 
1960  for(i = 0; i < pr.ntri*3; i++) {
1961  if (pr.cindex[i] > maxc) {maxc = pr.cindex[i];}
1962  }
1963 
1964  /*transform all points to viewer space */
1965  if (maxc> pp->prd_newc_floats_size) {
1966  pp->prd_newc_floats = REALLOC(pp->prd_newc_floats,maxc*9*sizeof(float));
1967  pp->prd_newc_floats_size = maxc;
1968  }
1969 
1970  for(i = 0; i < pr.ntri*3; i++) {
1971  transformf(&pp->prd_newc_floats[pr.cindex[i]*3],&pr.actualCoord[pr.cindex[i]*3],mat);
1972  }
1973  pr.actualCoord = pp->prd_newc_floats; /*remember, coords are only replaced in our local copy of PolyRep */
1974 
1975  /*if normal not speced, calculate it */
1976  /* if(n.x == 0 && n.y == 0 && n.z == 0.) */
1977  if(APPROX(n.x, 0) && APPROX(n.y, 0) && APPROX(n.z, 0)) {
1978  polynormalf(&n,&pr.actualCoord[pr.cindex[0]*3],&pr.actualCoord[pr.cindex[1]*3],&pr.actualCoord[pr.cindex[2]*3]);
1979  }
1980 
1981  pp->res = planar_polyrep_disp_rec(y1,y2,ystep,r,&pr,n,pp->res,flags);
1982 
1983  return pp->res;
1984 }
1985 
1986 
1987 
1988 
1989 
1990 
1991 static void get_collisionoffset(double *x, double *y, double *z)
1992 {
1993  struct sCollisionInfo *ci;
1994  struct sFallInfo *fi;
1995  struct sNaviInfo *naviinfo;
1996  struct point_XYZ xyz;
1997  struct point_XYZ res;
1998  ttglobal tg = gglobal();
1999  ci = CollisionInfo();
2000  fi = FallInfo();
2001  naviinfo = (struct sNaviInfo*)tg->Bindable.naviinfo;
2002  res = ci->Offset;
2003  /* collision.offset should be in collision space coordinates: fly/examine: avatar space, walk: BVVA space */
2004  /* uses mean direction, with maximum distance */
2005 
2006  /* xyz is in collision space- fly/examine: avatar space, walk: BVVA space */
2007  xyz.x = xyz.y = xyz.z = 0.0;
2008 
2009  if(ci->Count > 0 && !APPROX(vecnormal(&res, &res),0.0) )
2010  vecscale(&xyz, &res, sqrt(ci->Maximum2));
2011 
2012  /* for WALK + collision */
2013  if(fi->walking)
2014  {
2015  if(fi->canFall && fi->isFall )
2016  {
2017  /* canFall == true if we aren't climbing, isFall == true if there's no climb, and there's geom to fall to */
2018  double floatfactor = .1;
2019  if(fi->allowClimbing) floatfactor = 0.0; /*popcycle method */
2020  if(fi->smoothStep)
2021  xyz.y = DOUBLE_MAX(fi->hfall,-fi->fallStep) + naviinfo->height*floatfactor;
2022  else
2023  xyz.y = fi->hfall + naviinfo->height*floatfactor; //.1;
2024 
2025  }
2026  if(fi->isClimb && fi->allowClimbing)
2027  {
2028  /* stepping up normally handled by cyclindrical collision, but there are settings to use this climb instead */
2029  if(fi->smoothStep)
2030  xyz.y = DOUBLE_MIN(fi->hclimb,fi->fallStep);
2031  else
2032  xyz.y = fi->hclimb;
2033  }
2034  if(fi->isPenetrate)
2035  {
2036  /*over-ride everything else*/
2037  xyz = fi->pencorrection;
2038  }
2039  }
2040  /* now convert collision-space deltas to avatar space via collision2avatar- fly/examine: identity (do nothing), walk:BVVA2A */
2041  transform3x3(&xyz,&xyz,fi->collision2avatar);
2042  /* now xyz is in avatar space, ready to be added to avatar viewer.pos */
2043  *x = xyz.x;
2044  *y = xyz.y;
2045  *z = xyz.z;
2046  /* another transform possible: from avatar space into navigation space. fly/examine: identity walk: A2BVVA*/
2047 }
2048 struct point_XYZ viewer_get_lastP();
2049 void render_collisions(int Viewer_type) {
2050  struct point_XYZ v;
2051  struct sCollisionInfo *ci;
2052  struct sFallInfo *fi;
2053  if(!(Viewer_type == VIEWER_WALK || Viewer_type == VIEWER_FLY)) return; //no collisions
2054  ci = CollisionInfo();
2055  fi = FallInfo();
2056  ci->Offset.x = 0;
2057  ci->Offset.y = 0;
2058  ci->Offset.z = 0;
2059  ci->Count = 0;
2060  ci->Maximum2 = 0.;
2061 
2062  /* popcycle shaped avatar collision volume: ground to stepheight is a ray, stepheight to avatarheight is a cylinder,
2063  and a sphere on top?
2064  -keeps cyclinder from dragging in terrain mesh, easy to harmonize fall and climb math so not fighting (now a ray both ways)
2065  -2 implementations: analytical cyclinder, sampler
2066  The sampler method intersects line segments radiating from the the avatar axis with shape facets - misses small shapes but good
2067  for walls and floors; intersection math is simple: line intersect plane.
2068  */
2069  fi->fallHeight = 100.0; /* when deciding to fall, how far down do you look for a landing surface before giving up and floating */
2070  fi->fallStep = 1.0; /* maximum height to fall on one frame */
2071  fi->walking = Viewer_type == VIEWER_WALK; //viewer_type == VIEWER_WALK;
2072  fi->canFall = fi->walking; /* && COLLISION (but we wouldn't be in here if not). Will be set to 0 if a climb is found. */
2073  fi->hits = 0; /* counter (number of vertical hits) set to zero here once per frame */
2074  fi->isFall = 0; /*initialize here once per frame - flags if there's a fall found */
2075  fi->isClimb = 0; /* initialize here each frame */
2076  fi->smoothStep = 1; /* [1] setting - will only fall by fallstep on a frame rather than the full hfall */
2077  fi->allowClimbing = 1; /* [0] - setting - 0=climbing done by collision with cyclinder 1=signals popcycle avatar collision volume and allows single-footpoint climbing */
2078 
2079  fi->canPenetrate = 1; /* setting - 0= don't check for wall penetration 1= check for wall penetration */
2080  fi->isPenetrate = 0; /* set to zero once per loop and will come back 1 if there was a penetration detected and corrected */
2081 
2082  /* at this point we know the navigation mode and the pose of the avatar, and of the boundviewpoint
2083  so pre-compute some handy matrices for collision calcs - the avatar2collision and back (a tilt matrix for gravity direction)
2084  */
2085  if(fi->walking)
2086  {
2087  /*bound viewpoint vertical aligned gravity as per specs*/
2088  avatar2BoundViewpointVerticalAvatar(fi->avatar2collision, fi->collision2avatar);
2089  }
2090  else
2091  {
2092  /* when flying or examining, no gravity - up is your avatar's up */
2093  loadIdentityMatrix(fi->avatar2collision);
2094  loadIdentityMatrix(fi->collision2avatar);
2095  }
2096 
2097  /* wall penetration detection and correction initialization */
2098  if(fi->walking && fi->canPenetrate)
2099  {
2100  /* set up avatar to last valid avatar position vector in avatar space */
2101  double plen = 0.0;
2102  struct point_XYZ lastpos;
2103  lastpos = viewer_get_lastP(); /* in viewer/avatar space */
2104  transform(&lastpos,&lastpos,fi->avatar2collision); /* convert to collision space */
2105  /* if vector length == 0 can't penetrate - don't bother to check */
2106  plen = sqrt(vecdot(&lastpos,&lastpos));
2107  if(APPROX(plen,0.0))
2108  fi->canPenetrate = 0;
2109  else
2110  {
2111  /* precompute MBB/extent etc in collision space for penetration vector */
2112  struct point_XYZ pos = {0.0,0.0,0.0};
2113  fi->penMin[0] = DOUBLE_MIN(pos.x,lastpos.x);
2114  fi->penMin[1] = DOUBLE_MIN(pos.y,lastpos.y);
2115  fi->penMin[2] = DOUBLE_MIN(pos.z,lastpos.z);
2116  fi->penMax[0] = DOUBLE_MAX(pos.x,lastpos.x);
2117  fi->penMax[1] = DOUBLE_MAX(pos.y,lastpos.y);
2118  fi->penMax[2] = DOUBLE_MAX(pos.z,lastpos.z);
2119  fi->penRadius = plen;
2120  vecnormal(&lastpos,&lastpos);
2121  fi->penvec = lastpos;
2122  fi->pendisp = 0.0; /* used to sort penetration intersections to pick one closest to last valid avatar position */
2123  }
2124  }
2125 
2126  render_hier(rootNode(), VF_Collision);
2127  if(!fi->isPenetrate)
2128  {
2129  /* we don't clear if we just solved a penetration, otherwise we'll get another penetration going back, from the correction.
2130  No pen? Then clear here to start over on the next loop.
2131  */
2132  viewer_lastP_clear();
2133  }
2134  get_collisionoffset(&(v.x), &(v.y), &(v.z));
2135 
2136  /* if (!APPROX(v.x,0.0) || !APPROX(v.y,0.0) || !APPROX(v.z,0.0)) {
2137  printf ("%lf MainLoop, rendercollisions, offset %f %f %f\n",TickTime(),v.x,v.y,v.z);
2138  } */
2139  /* v should be in avatar coordinates*/
2140  increment_pos(&v);
2141 }
2142 
2143 
2144 
2145 #ifdef DEBUG_SCENE_EXPORT
2146 void printpolyrep(struct X3D_PolyRep pr) {
2147  int i;
2148  int npoints = 0;
2149  printf("X3D_PolyRep makepolyrep() {\n");
2150  printf(" int cindext[%d] = {",pr.ntri*3);
2151  for(i=0; i < pr.ntri*3-1; i++) {
2152  printf("%d,",pr.cindex[i]);
2153  if(pr.cindex[i] > npoints)
2154  npoints = pr.cindex[i];
2155  }
2156  printf("%d};\n",pr.cindex[i]);
2157  if(pr.cindex[i] > npoints)
2158  npoints = pr.cindex[i];
2159 
2160  printf(" float coordt[%d] = {",npoints*3);
2161  for(i=0; i < npoints*3-1; i++)
2162  printf("%f,",pr.actualCoord[i]);
2163  printf("%f};\n",pr.actualCoord[i]);
2164 
2165  printf("static int cindex[%d];\nstatic float coord[%d];\n",pr.ntri*3,npoints*3);
2166  printf("X3D_PolyRep pr = {0,%d,cindex,coord,NULL,NULL,NULL,NULL,NULL,NULL};\n",pr.ntri);
2167  printf("memcpy(cindex,cindext,sizeof(cindex));\n");
2168  printf("memcpy(coord,coordt,sizeof(coord));\n");
2169  printf("return pr; }\n");
2170 
2171 };
2172 
2173 void printmatrix(GLDOUBLE* mat) {
2174  int i;
2175  printf("void getmatrix(GLDOUBLE* mat, struct point_XYZ disp) {\n");
2176  for(i = 0; i< 16; i++) {
2177  printf("mat[%d] = %f%s;\n",i,mat[i],i==12 ? " +disp.x" : i==13? " +disp.y" : i==14? " +disp.z" : "");
2178  }
2179  printf("}\n");
2180 
2181 }
2182 #endif
2183