FS2_Open
Open source remastering of the Freespace 2 engine
fvi.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 #include "math/floating.h"
12 #include "math/fvi.h"
13 #include "math/vecmat.h"
14 
15 
16 #define SMALL_NUM 1E-6
17 
18 #define UNINITIALIZED_VALUE -1234567.8f
19 #define WARN_DIST 1.0
20 
21 static void accurate_square_root( float A, float B, float C, float discriminant, float *root1, float *root2 ) __UNUSED;
22 
23 static float matrix_determinant_from_vectors(const vec3d *v1, const vec3d *v2, const vec3d *v3)
24 {
25  float ans;
26  ans = v1->xyz.x * v2->xyz.y * v3->xyz.z;
27  ans += v2->xyz.x * v3->xyz.y * v1->xyz.z;
28  ans += v3->xyz.x * v1->xyz.y * v2->xyz.z;
29  ans -= v1->xyz.z * v2->xyz.y * v3->xyz.x;
30  ans -= v2->xyz.z * v3->xyz.y * v1->xyz.x;
31  ans -= v3->xyz.z * v1->xyz.y * v2->xyz.x;
32 
33  return ans;
34 }
35 
42 void fvi_two_lines_in_3space(const vec3d *p1, const vec3d *v1, const vec3d *p2, const vec3d *v2, float *s, float *t)
43 {
44  vec3d cross,delta;
45  vm_vec_cross(&cross, v1, v2);
46  vm_vec_sub(&delta, p2, p1);
47 
48  float denominator = vm_vec_mag_squared(&cross);
49  float num_t, num_s;
50 
51  if (denominator > 1e-10) {
52  num_s = matrix_determinant_from_vectors(&delta, v2, &cross);
53  *s = num_s / denominator;
54 
55  num_t = matrix_determinant_from_vectors(&delta, v1, &cross);
56  *t = num_t / denominator;
57  } else {
58  // two lines are parallel
59  *s = FLT_MAX;
60  *t = FLT_MAX;
61  }
62 }
63 
71 float fvi_point_dist_plane(const vec3d *plane_pnt,const vec3d *plane_norm,
72  const vec3d *point
73  )
74 {
75  float dist,D;
76 
77  D = -vm_vec_dot(plane_norm,plane_pnt);
78 
79  dist = vm_vec_dot(plane_norm, point) + D;
80  return dist;
81 }
82 
118 float fvi_ray_plane(vec3d *new_pnt,
119  const vec3d *plane_pnt, const vec3d *plane_norm,
120  const vec3d *ray_origin, const vec3d *ray_direction,
121  float rad)
122 {
123  vec3d w;
124  float num,den,t;
125 
126  vm_vec_sub(&w,ray_origin,plane_pnt);
127 
128  den = -vm_vec_dot(plane_norm,ray_direction);
129  if ( den == 0.0f ) { // Ray & plane are parallel, so there is no intersection
130  if ( new_pnt ) {
131  new_pnt->xyz.x = -FLT_MAX;
132  new_pnt->xyz.y = -FLT_MAX;
133  new_pnt->xyz.z = -FLT_MAX;
134  }
135  return -FLT_MAX;
136  }
137 
138  num = vm_vec_dot(plane_norm,&w);
139  num -= rad; //move point out by rad
140 
141  t = num / den;
142 
143  if ( new_pnt )
144  vm_vec_scale_add(new_pnt,ray_origin,ray_direction,t);
145 
146  return t;
147 }
148 
163  const vec3d *plane_pnt, const vec3d *plane_norm,
164  const vec3d *p0, const vec3d *p1,float rad)
165 {
166  float t;
167  vec3d d;
168 
169  vm_vec_sub( &d, p1, p0 );
170 
171  t = fvi_ray_plane(new_pnt,
172  plane_pnt,plane_norm, // Plane description, a point and a normal
173  p0,&d, // Ray description, a point and a direction
174  rad);
175 
176  if ( t < 0.0f ) return 0; // intersection lies behind p0
177  if ( t > 1.0f ) return 0; // intersection lies past p1
178 
179  return 1; // They intersect!
180 }
181 
188 int fvi_segment_sphere(vec3d *intp, const vec3d *p0, const vec3d *p1, const vec3d *sphere_pos, float sphere_rad)
189 {
190  vec3d d,dn,w,closest_point;
191  float mag_d,dist,w_dist,int_dist;
192 
193  //this routine could be optimized if it's taking too much time!
194 
195  vm_vec_sub(&d,p1,p0);
196  vm_vec_sub(&w,sphere_pos,p0);
197 
198  mag_d = vm_vec_mag(&d);
199 
200  if (mag_d <= 0.0f) {
201  int_dist = vm_vec_mag(&w);
202  *intp = *p0;
203  return (int_dist<sphere_rad)?1:0;
204  }
205 
206  // normalize dn
207  dn.xyz.x = d.xyz.x / mag_d;
208  dn.xyz.y = d.xyz.y / mag_d;
209  dn.xyz.z = d.xyz.z / mag_d;
210 
211  w_dist = vm_vec_dot(&dn,&w);
212 
213  if (w_dist < -sphere_rad) //moving away from object
214  return 0;
215 
216  if (w_dist > mag_d+sphere_rad)
217  return 0; //cannot hit
218 
219  vm_vec_scale_add(&closest_point,p0,&dn,w_dist);
220 
221  dist = vm_vec_dist(&closest_point,sphere_pos);
222 
223  if (dist < sphere_rad) {
224  float dist2,rad2,shorten;
225 
226  dist2 = dist*dist;
227  rad2 = sphere_rad*sphere_rad;
228 
229  shorten = fl_sqrt(rad2 - dist2);
230 
231  int_dist = w_dist-shorten;
232 
233  if (int_dist > mag_d || int_dist < 0.0f) {
234  //past one or the other end of vector, which means we're inside
235 
236  *intp = *p0; //don't move at all
237  return 1;
238  }
239 
240  vm_vec_scale_add(intp,p0,&dn,int_dist); //calc intersection point
241 
242  return 1;
243  }
244  else
245  return 0;
246 }
247 
248 
255 int fvi_ray_sphere(vec3d *intp, const vec3d *p0, const vec3d *p1, const vec3d *sphere_pos,float sphere_rad)
256 {
257  vec3d d,dn,w,closest_point;
258  float mag_d,dist,w_dist,int_dist;
259 
260  //this routine could be optimized if it's taking too much time!
261 
262  vm_vec_sub(&d,p1,p0);
263  vm_vec_sub(&w,sphere_pos,p0);
264 
265  mag_d = vm_vec_mag(&d);
266 
267  if (mag_d <= 0.0f) {
268  int_dist = vm_vec_mag(&w);
269  *intp = *p0;
270  return (int_dist<sphere_rad)?1:0;
271  }
272 
273  // normalize dn
274  dn.xyz.x = d.xyz.x / mag_d;
275  dn.xyz.y = d.xyz.y / mag_d;
276  dn.xyz.z = d.xyz.z / mag_d;
277 
278  w_dist = vm_vec_dot(&dn,&w);
279 
280  if (w_dist < -sphere_rad) //moving away from object
281  return 0;
282 
283  vm_vec_scale_add(&closest_point,p0,&dn,w_dist);
284 
285  dist = vm_vec_dist(&closest_point,sphere_pos);
286 
287  if (dist < sphere_rad) {
288  float dist2,rad2,shorten;
289 
290  dist2 = dist*dist;
291  rad2 = sphere_rad*sphere_rad;
292 
293  shorten = fl_sqrt(rad2 - dist2);
294 
295  int_dist = w_dist-shorten;
296 
297  if (int_dist < 0.0f) {
298  //past one or the begining of vector, which means we're inside
299 
300  *intp = *p0; //don't move at all
301  return 1;
302  }
303 
304  vm_vec_scale_add(intp,p0,&dn,int_dist); //calc intersection point
305 
306  return 1;
307  }
308  else
309  return 0;
310 }
311 
321 int fvi_ray_boundingbox(const vec3d *min, const vec3d *max, const vec3d * p0, const vec3d *pdir, vec3d *hitpt )
322 {
323  int middle = ((1<<0) | (1<<1) | (1<<2));
324  int i;
325  int which_plane;
326  float maxt[3];
327  float candidate_plane[3];
328 
329  for (i = 0; i < 3; i++) {
330  if (p0->a1d[i] < min->a1d[i]) {
331  candidate_plane[i] = min->a1d[i];
332  middle &= ~(1<<i);
333  } else if (p0->a1d[i] > max->a1d[i]) {
334  candidate_plane[i] = max->a1d[i];
335  middle &= ~(1<<i);
336  }
337  }
338 
339  // ray origin inside bounding box?
340  // (are all three bits still set?)
341  if (middle == ((1<<0) | (1<<1) | (1<<2))) {
342  *hitpt = *p0;
343  return 1;
344  }
345 
346  // calculate T distances to candidate plane
347  for (i = 0; i < 3; i++) {
348  if ( (middle & (1<<i)) || (pdir->a1d[i] == 0.0f) ) {
349  maxt[i] = -1.0f;
350  } else {
351  maxt[i] = (candidate_plane[i] - p0->a1d[i]) / pdir->a1d[i];
352  }
353  }
354 
355  // Get largest of the maxt's for final choice of intersection
356  which_plane = 0;
357  for (i = 1; i < 3; i++) {
358  if (maxt[which_plane] < maxt[i]) {
359  which_plane = i;
360  }
361  }
362 
363  // check final candidate actually inside box
364  if (maxt[which_plane] < 0.0f) {
365  return 0;
366  }
367 
368  for (i = 0; i < 3; i++) {
369  if (which_plane == i) {
370  hitpt->a1d[i] = candidate_plane[i];
371  } else {
372  hitpt->a1d[i] = (maxt[which_plane] * pdir->a1d[i]) + p0->a1d[i];
373 
374  if ( (hitpt->a1d[i] < min->a1d[i]) || (hitpt->a1d[i] > max->a1d[i]) ) {
375  return 0;
376  }
377  }
378  }
379 
380  return 1;
381 }
382 
387 static int ij_table[3][2] = {
388  {2,1}, //pos x biggest
389  {0,2}, //pos y biggest
390  {1,0}, //pos z biggest
391  };
392 
418 #define delta 0.0001f
419 int fvi_point_face(const vec3d *checkp, int nv, vec3d const *const *verts, const vec3d * norm1, float *u_out,float *v_out, const uv_pair * uvls )
420 {
421  const float *norm;
422  const float *P;
423  vec3d t;
424  int i0, i1,i2;
425 
426  norm = (float *)norm1;
427 
428  //project polygon onto plane by finding largest component of normal
429  t.xyz.x = fl_abs(norm[0]);
430  t.xyz.y = fl_abs(norm[1]);
431  t.xyz.z = fl_abs(norm[2]);
432 
433  if (t.xyz.x > t.xyz.y) if (t.xyz.x > t.xyz.z) i0=0; else i0=2;
434  else if (t.xyz.y > t.xyz.z) i0=1; else i0=2;
435 
436  if (norm[i0] > 0.0f) {
437  i1 = ij_table[i0][0];
438  i2 = ij_table[i0][1];
439  }
440  else {
441  i1 = ij_table[i0][1];
442  i2 = ij_table[i0][0];
443  }
444 
445  // Have i0, i1, i2
446  P = (float *)checkp;
447 
448  float u0, u1, u2, v0, v1, v2, alpha = UNINITIALIZED_VALUE, gamma;
449  float beta;
450 
451  int inter=0, i = 2;
452 
453  u0 = P[i1] - verts[0]->a1d[i1];
454  v0 = P[i2] - verts[0]->a1d[i2];
455 
456  do {
457 
458  u1 = verts[i-1]->a1d[i1] - verts[0]->a1d[i1];
459  u2 = verts[i ]->a1d[i1] - verts[0]->a1d[i1];
460 
461  v1 = verts[i-1]->a1d[i2] - verts[0]->a1d[i2];
462  v2 = verts[i ]->a1d[i2] - verts[0]->a1d[i2];
463 
464 
465  if ( (u1 >-delta) && (u1<delta) ) {
466  beta = u0 / u2;
467  if ((beta >=0.0f) && (beta<=1.0f)) {
468  alpha = (v0 - beta*v2)/v1;
469  inter = ((alpha>=0.0f)&&(alpha+beta<=1.0f));
470  }
471  } else {
472 
473  beta = (v0*u1 - u0*v1) / (v2*u1 - u2*v1);
474  if ((beta >=0.0f) && (beta<=1.0f)) {
475  Assert(beta != UNINITIALIZED_VALUE);
476  alpha = (u0 - beta*u2)/u1;
477  inter = ((alpha>=0.0f)&&(alpha+beta<=1.0f));
478  }
479  }
480 
481  } while ((!inter) && (++i < nv) );
482 
483  if ( inter && uvls && u_out && v_out ) {
484  gamma = 1.0f - (alpha+beta);
485  *u_out = gamma * uvls[0].u + alpha*uvls[i-1].u + beta*uvls[i].u;
486  *v_out = gamma * uvls[0].v + alpha*uvls[i-1].v + beta*uvls[i].v;
487  }
488 
489  return inter;
490 }
491 
492 // ****************************************************************************
493 //
494 // SPHERE FACE INTERSECTION CODE
495 //
496 // ****************************************************************************
497 
498 static int check_sphere_point(const vec3d *point, const vec3d *sphere_start, const vec3d *sphere_vel, float radius, float *collide_time );
499 
516 int fvi_sphere_plane(vec3d *intersect_point, const vec3d *sphere_center_start, const vec3d *sphere_velocity, float sphere_radius,
517  const vec3d *plane_normal, const vec3d *plane_point, float *hit_time, float *crossing_time)
518 {
519  float D, xs0_dot_norm, vs_dot_norm;
520  float t1, t2;
521 
522  // find the time and position of the ray-plane intersection
523  D = -vm_vec_dot( plane_normal, plane_point );
524  xs0_dot_norm = vm_vec_dot( plane_normal, sphere_center_start );
525  vs_dot_norm = vm_vec_dot( plane_normal, sphere_velocity);
526 
527  // protect against divide by zero
528  if (fl_abs(vs_dot_norm) > 1e-30) {
529  t1 = (-D - xs0_dot_norm + sphere_radius) / vs_dot_norm;
530  t2 = (-D - xs0_dot_norm - sphere_radius) / vs_dot_norm;
531  } else {
532  return 0;
533  }
534 
535  // sort t1 < t2
536  if (t2 < t1) {
537  float temp = t1;
538  t1 = t2;
539  t2 = temp;
540  }
541 
542  *hit_time = t1;
543 
544  // find hit pos if t1 in range 0-1
545  if (t1 > 0 && t1 < 1) {
546  vec3d v_temp;
547  vm_vec_scale_add( &v_temp, sphere_center_start, sphere_velocity, t1 );
548  vm_project_point_onto_plane( intersect_point, &v_temp, plane_normal, plane_point );
549  }
550 
551  // get time to cross
552  *crossing_time = t2 - t1;
553 
554  return ( (t1 < 1) && (t2 > 0) );
555 }
556 
570 int fvi_sphere_perp_edge(vec3d *intersect_point, const vec3d *sphere_center_start, const vec3d *sphere_velocity,
571  float sphere_radius, vec3d *edge_point1, vec3d *edge_point2, float *collide_time)
572 {
573  // find the intersection in the plane normal to sphere velocity and edge velocity
574  // choose a plane point V0 (first vertex of the edge)
575  // project vectors and points into the plane
576  // find the projection of the intersection and see if it lies on the edge
577 
578  vec3d edge_velocity;
579  vec3d V0, V1;
580  vec3d Xe_proj, Xs_proj;
581 
582  V0 = *edge_point1;
583  V1 = *edge_point2;
584  vm_vec_sub(&edge_velocity, &V1, &V0);
585 
586  // define a set of local unit vectors
587  vec3d x_hat, y_hat, z_hat;
588  float max_edge_parameter;
589 
590  vm_vec_copy_normalize( &x_hat, &edge_velocity );
591  vm_vec_copy_normalize( &y_hat, sphere_velocity );
592  vm_vec_cross( &z_hat, &x_hat, &y_hat );
593  max_edge_parameter = vm_vec_mag( &edge_velocity );
594 
595  vec3d temp;
596  // next two temp should be same as starting velocities
597  vm_vec_projection_onto_plane(&temp, sphere_velocity, &z_hat);
598  Assert ( !vm_vec_cmp(&temp, sphere_velocity) );
599  vm_vec_projection_onto_plane(&temp, &edge_velocity, &z_hat);
600  Assert ( !vm_vec_cmp(&temp, &edge_velocity) );
601 
602  // should return V0
603  vm_project_point_onto_plane(&Xe_proj, &V0, &z_hat, &V0);
604  Assert ( !vm_vec_cmp(&Xe_proj, &V0) );
605 
606  vm_project_point_onto_plane(&Xs_proj, sphere_center_start, &z_hat, &V0);
607 
608  vec3d plane_coord;
609  plane_coord.xyz.x = vm_vec_dot(&Xs_proj, &x_hat);
610  plane_coord.xyz.y = vm_vec_dot(&Xe_proj, &y_hat);
611  plane_coord.xyz.z = vm_vec_dot(&Xe_proj, &z_hat);
612 
613  // determime the position on the edge line
614  vm_vec_copy_scale( intersect_point, &x_hat, plane_coord.xyz.x );
615  vm_vec_scale_add2( intersect_point, &y_hat, plane_coord.xyz.y );
616  vm_vec_scale_add2( intersect_point, &z_hat, plane_coord.xyz.z );
617 
618  // check if point is actually on edge
619  float edge_parameter;
620  vec3d temp_vec;
621 
622  vm_vec_sub( &temp_vec, intersect_point, &V0 );
623  edge_parameter = vm_vec_dot( &temp_vec, &x_hat );
624 
625  if ( edge_parameter < 0 || edge_parameter > max_edge_parameter ) {
626  return 0;
627  }
628 
629  return ( check_sphere_point(intersect_point, sphere_center_start, sphere_velocity, sphere_radius, collide_time) );
630 }
631 
632 
642 static int check_sphere_point(const vec3d *point, const vec3d *sphere_start, const vec3d *sphere_vel, float radius, float *collide_time )
643 {
644  vec3d delta_x;
645  float delta_x_sqr, vs_sqr, delta_x_dot_vs;
646 
647  vm_vec_sub( &delta_x, sphere_start, point );
648  delta_x_sqr = vm_vec_mag_squared( &delta_x );
649  vs_sqr = vm_vec_mag_squared( sphere_vel );
650  delta_x_dot_vs = vm_vec_dot( &delta_x, sphere_vel );
651 
652  float discriminant = delta_x_dot_vs*delta_x_dot_vs - vs_sqr*(delta_x_sqr - radius*radius);
653  if (discriminant < 0) {
654  return 0;
655  }
656 
657  float radical, time1, time2;
658  radical = fl_sqrt(discriminant);
659  time1 = (-delta_x_dot_vs + radical) / vs_sqr;
660  time2 = (-delta_x_dot_vs - radical) / vs_sqr;
661 
662  if (time1 > time2) {
663  float temp = time1;
664  time1 = time2;
665  time2 = temp;
666  }
667 
668  if (time1 >= 0 && time1 <= 1.0) {
669  *collide_time = time1;
670  return 1;
671  }
672 
673  if (time2 >= 0 && time2 <= 1.0) {
674  *collide_time = time2;
675  return 1;
676  }
677 
678  return 0;
679 }
680 
694 int fvi_polyedge_sphereline(vec3d *hit_point, const vec3d *xs0, const vec3d *vs, float Rs, int nv, vec3d const *const *verts, float *hit_time)
695 {
696  int i;
697  vec3d v0, v1;
698  vec3d ve; // edge velocity
699  float best_sphere_time; // earliest time sphere hits edge
700  vec3d delta_x;
701  float delta_x_dot_ve, delta_x_dot_vs, ve_dot_vs, ve_sqr, vs_sqr, delta_x_sqr;
702  vec3d temp_edge_hit, temp_sphere_hit;
703  float t_sphere_hit = 0.0f;
704  float A, B, C, temp, discriminant, invA;
705  float root, root1, root2;
706  float Rs2 = (Rs * Rs);
707  float Rs_point2 = (0.2f * Rs);
708 
709  best_sphere_time = FLT_MAX;
710 
711  vs_sqr = vm_vec_mag_squared(vs);
712 
713  for (i = 0; i < nv; i++) {
714  // Get vertices of edge to check
715  v0 = *verts[i];
716  if (i+1 != nv) {
717  v1 = *verts[i+1];
718  } else {
719  v1 = *verts[0];
720  }
721 
722  // Calculate edge velocity.
723  // Position along the edge is given by: P_edge = v0 + ve*t, where t is in the range [0,1]
724  vm_vec_sub(&ve, &v1, &v0);
725 
726  // First find the closest intersection between the edge_line and the sphere_line.
727  vm_vec_sub(&delta_x, xs0, &v0);
728 
729  delta_x_dot_ve = vm_vec_dot(&delta_x, &ve);
730  delta_x_dot_vs = vm_vec_dot(&delta_x, vs);
731  delta_x_sqr = vm_vec_mag_squared(&delta_x);
732  ve_dot_vs = vm_vec_dot(&ve, vs);
733  ve_sqr = vm_vec_mag_squared(&ve);
734 
735  /*
736  * Solve for sphere time
737  *
738  * This code uses the following variation of the quadratic equation:
739  * A*x*x + 2*B*x + C = 0
740  *
741  * Solving for x yields ...
742  *
743  * -B +- sqrt(B*B - A*C)
744  * x = ---------------------
745  * A
746  */
747 
748  A = ve_dot_vs*ve_dot_vs - ve_sqr*vs_sqr;
749  B = delta_x_dot_ve*ve_dot_vs - delta_x_dot_vs*ve_sqr;
750  C = delta_x_dot_ve*delta_x_dot_ve + Rs2*ve_sqr - delta_x_sqr*ve_sqr;
751 
752  discriminant = B*B - A*C;
753  if (discriminant > 0.0f) {
754  invA = 1.0f / A;
755  root = sqrt(discriminant);
756  root1 = (-B + root) * invA;
757  root2 = (-B - root) * invA;
758 
759  // sort root1 and root2
760  if (root2 < root1) {
761  temp = root1;
762  root1 = root2;
763  root2 = temp;
764  }
765 
766  if ( (root1 < 0.0f) && (root1 >= -0.05f) )
767  root1 = 0.000001f;
768 
769  // look only at first hit
770  if ( (root1 <= 1.0f) && (root1 >= 0.0f) ) {
771  t_sphere_hit = root1;
772  } else {
773  goto TryVertex;
774  }
775  } else {
776  // discriminant negative, so no hit possible
777  continue;
778  }
779 
780  // check if best time with this edge is less than best so far
781  if (t_sphere_hit >= best_sphere_time)
782  continue;
783 
784  vm_vec_scale_add( &temp_sphere_hit, xs0, vs, t_sphere_hit );
785 
786  // solve for edge time
787  A *= ve_sqr;
788  B = ve_sqr * (delta_x_dot_ve*vs_sqr - delta_x_dot_vs*ve_dot_vs);
789  C = 2.0f*delta_x_dot_ve*delta_x_dot_vs*ve_dot_vs + Rs2*ve_dot_vs*ve_dot_vs
790  - delta_x_sqr*ve_dot_vs*ve_dot_vs - delta_x_dot_ve*delta_x_dot_ve*vs_sqr;
791 
792  discriminant = B*B - A*C;
793  invA = 1.0f / A;
794 
795  // guard against nearly perpendicular sphere edge velocities
796  if (discriminant < 0.0f)
797  root = 0.0f;
798  else
799  root = fl_sqrt(discriminant);
800 
801  root1 = (-B + root) * invA;
802  root2 = (-B - root) * invA;
803 
804  // given sphere position, find which edge time (position) allows a valid solution
805  if ( (root1 <= 1.0f) && (root1 >= 0.0f) ) {
806  // try edge root1
807  vm_vec_scale_add( &temp_edge_hit, &v0, &ve, root1 );
808  float q = vm_vec_dist_squared(&temp_edge_hit, &temp_sphere_hit);
809  if ( fl_abs(q - Rs2) < Rs_point2 ) { // error less than 0.1m absolute (2*delta*Radius)
810  goto Hit;
811  }
812  }
813 
814  if ( (root2 <= 1.0f) && (root2 >= 0.0f) ) {
815  // try edge root2
816  vm_vec_scale_add( &temp_edge_hit, &v0, &ve, root2 );
817  float q = vm_vec_dist_squared(&temp_edge_hit, &temp_sphere_hit);
818  if ( fl_abs(q - Rs2) < Rs_point2 ) { // error less than 0.1m absolute
819  goto Hit;
820  }
821  } else {
822  // both root1 and root2 out of range so we have to check vertices
823  goto TryVertex;
824  }
825 
826 TryVertex:
827  // try V0
828  A = vs_sqr;
829  B = delta_x_dot_vs;
830  C = delta_x_sqr - Rs2;
831  int v0_hit;
832  float sphere_v0, sphere_v1;
833 
834  v0_hit = 0;
835  sphere_v0 = UNINITIALIZED_VALUE;
836  sphere_v1 = UNINITIALIZED_VALUE;
837 
838  invA = 1.0f / A;
839  discriminant = B*B - A*C;
840  if (discriminant > 0.0f) {
841  root = fl_sqrt(discriminant);
842  root1 = (-B + root) * invA;
843  root2 = (-B - root) * invA;
844 
845  if (root1 > root2) {
846  temp = root1;
847  root1 = root2;
848  root2 = temp;
849  }
850 
851  // look only at the first hit (ignore negative first hit)
852  if ( (root1 < 1.0f) && (root1 > 0.0f) ) {
853  v0_hit = 1;
854  sphere_v0 = root1;
855  }
856  }
857 
858  // try V1
859  vm_vec_sub( &delta_x, xs0, &v1 );
860  delta_x_sqr = vm_vec_mag_squared( &delta_x );
861  delta_x_dot_vs = vm_vec_dot( &delta_x, vs );
862  int v1_hit;
863 
864  B = delta_x_dot_vs;
865  C = delta_x_sqr - Rs2;
866 
867  v1_hit = 0;
868  discriminant = B*B - A*C;
869  if (discriminant > 0.0f) {
870  root = fl_sqrt(discriminant);
871  root1 = (-B + root) * invA;
872  root2 = (-B - root) * invA;
873 
874  if (root1 > root2) {
875  temp = root1;
876  root1 = root2;
877  root2 = temp;
878  }
879 
880  // look only at the first hit (ignore negative first hit)
881  if ( (root1 < 1.0f) && (root1 > 0.0f) ) {
882  v1_hit = 1;
883  sphere_v1 = root1;
884  }
885  }
886 
887  // set hitpoint to closest vetex hit, if any
888  if ( v0_hit ) {
889  Assert(sphere_v0 != UNINITIALIZED_VALUE);
890  t_sphere_hit = sphere_v0;
891  temp_edge_hit = v0;
892 
893  if (v1_hit) {
894  Assert( sphere_v1 != UNINITIALIZED_VALUE );
895  if (sphere_v1 < sphere_v0) {
896  t_sphere_hit = sphere_v1;
897  temp_edge_hit = v1;
898  }
899  }
900  } else if ( v1_hit ) {
901  Assert(sphere_v1 != UNINITIALIZED_VALUE);
902  t_sphere_hit = sphere_v1;
903  temp_edge_hit = v1;
904  } else {
905  continue;
906  }
907 
908  //vm_vec_scale_add( &temp_sphere_hit, xs0, vs, t_sphere_hit );
909  //q = vm_vec_dist_squared(&temp_edge_hit, &temp_sphere_hit);
910 
911 
912 Hit:
913  if (t_sphere_hit < best_sphere_time) {
914  best_sphere_time = t_sphere_hit;
915  *hit_point = temp_edge_hit;
916  }
917  } // end edge loop
918 
919  if (best_sphere_time <= 1.0f) {
920  *hit_time = best_sphere_time;
921  return 1;
922  } else {
923  return 0;
924  }
925 }
926 
935 void fvi_closest_point_on_line_segment(vec3d *closest_point, const vec3d *fixed_point, const vec3d *line_point1, const vec3d *line_point2)
936 {
937  vec3d delta_x, line_velocity;
938  float t;
939 
940  vm_vec_sub(&line_velocity, line_point2, line_point1);
941  vm_vec_sub(&delta_x, line_point1, fixed_point);
942  t = -vm_vec_dot(&delta_x, &line_velocity) / vm_vec_mag_squared(&line_velocity);
943 
944  // Constrain t to be in range [0,1]
945  if (t < 0) {
946  t = 0.0f;
947  } else if (t > 1) {
948  t = 1.0f;
949  }
950 
951  vm_vec_scale_add(closest_point, line_point1, &line_velocity, t);
952 }
953 
969 int fvi_check_sphere_sphere(const vec3d *x_p0, const vec3d *x_p1, const vec3d *x_s0, const vec3d *x_s1, float radius_p, float radius_s, float *t1, float *t2)
970 {
971  vec3d delta_x, delta_v;
972  float discriminant, separation, delta_x_dot_delta_v, delta_v_sqr, delta_x_sqr;
973  float time1, time2;
974 
975  // Check that there are either 0 or 2 pointers to time
976  Assert( (!(t1) && !(t2)) || (t1 && t2) );
977 
978  vm_vec_sub(&delta_x, x_s0, x_p0);
979  delta_x_sqr = vm_vec_mag_squared(&delta_x);
980  separation = radius_p + radius_s;
981 
982  // Check if already touching
983  if (delta_x_sqr < separation*separation) {
984  if ( !t1 ) {
985  return 1;
986  }
987  }
988 
989  // Find delta_v (in polymodel sphere frame of ref)
990  // Note: x_p0 and x_p1 will be same for fixed polymodel
991  vm_vec_sub(&delta_v, x_s1, x_s0);
992  vm_vec_add2(&delta_v, x_p0);
993  vm_vec_sub2(&delta_v, x_p1);
994 
995  delta_x_dot_delta_v = vm_vec_dot(&delta_x, &delta_v);
996  delta_v_sqr = vm_vec_mag_squared(&delta_v);
997 
998  discriminant = delta_x_dot_delta_v*delta_x_dot_delta_v - delta_v_sqr*(delta_x_sqr - separation*separation);
999 
1000  if (discriminant < 0) {
1001  return 0;
1002  }
1003 
1004  float radical = fl_sqrt(discriminant);
1005 
1006  time1 = (-delta_x_dot_delta_v + radical) / delta_v_sqr;
1007  time2 = (-delta_x_dot_delta_v - radical) / delta_v_sqr;
1008 
1009  // sort t1 < t2
1010  float temp;
1011  if (time1 > time2) {
1012  temp = time1;
1013  time1 = time2;
1014  time2 = temp;
1015  }
1016 
1017  if ( t1 ) {
1018  *t1 = time1;
1019  *t2 = time2;
1020  }
1021 
1022  // check whether the range from t1 to t2 intersects [0,1]
1023  if (time1 > 1 || time2 < 0) {
1024  return 0;
1025  } else {
1026  return 1;
1027  }
1028 }
1029 
1044 int fvi_cull_polyface_sphere(const vec3d *poly_center, float poly_r, const vec3d *sphere_start, const vec3d *sphere_end, float sphere_r)
1045 {
1046  vec3d closest_point, closest_separation;
1047  float max_sep;
1048 
1049  fvi_closest_point_on_line_segment(&closest_point, poly_center, sphere_start, sphere_end);
1050  vm_vec_sub(&closest_separation, &closest_point, poly_center);
1051 
1052  max_sep = vm_vec_mag(&closest_separation) + poly_r;
1053 
1054  if ( max_sep > sphere_r ) {
1055  return 0;
1056  } else {
1057  return 1;
1058  }
1059 }
1060 
1064 void fvi_closest_line_line(const vec3d *x0, const vec3d *vx, const vec3d *y0, const vec3d *vy, float *x_time, float *y_time )
1065 {
1066  vec3d vx_cross_vy, delta_l, delta_l_cross_vx, delta_l_cross_vy;
1067  float denominator;
1068 
1069  vm_vec_sub(&delta_l, y0, x0);
1070 
1071  vm_vec_cross(&vx_cross_vy, vx, vy);
1072  vm_vec_cross(&delta_l_cross_vx, &delta_l, vx);
1073  vm_vec_cross(&delta_l_cross_vy, &delta_l, vy);
1074 
1075  denominator = vm_vec_mag_squared(&vx_cross_vy);
1076 
1077  *x_time = vm_vec_dot(&delta_l_cross_vy, &vx_cross_vy) / denominator;
1078  *y_time = vm_vec_dot(&delta_l_cross_vx, &vx_cross_vy) / denominator;
1079 }
1080 
1081 // --------------------------------------------------------------------------------------------------------------------
1082 static void accurate_square_root( float A, float B, float C, float discriminant, float *root1, float *root2 )
1083 {
1084  float root = fl_sqrt(discriminant);
1085 
1086  if (B > 0) {
1087  *root1 = 2.0f*C / (-B - root);
1088  *root2 = (-B - root) / (2.0f*A);
1089  } else { // B < 0
1090  *root1 = (-B + root) / (2.0f*A);
1091  *root2 = 2.0f*C / (-B + root);
1092  }
1093 }
1094 
1107 int project_point_onto_bbox(const vec3d *mins, const vec3d *maxs, const vec3d *start, vec3d *box_pt)
1108 {
1109  int inside = TRUE;
1110 
1111  if (start->xyz.x > maxs->xyz.x) {
1112  box_pt->xyz.x = maxs->xyz.x;
1113  inside = FALSE;
1114  } else if (start->xyz.x < mins->xyz.x) {
1115  box_pt->xyz.x = mins->xyz.x;
1116  inside = FALSE;
1117  } else {
1118  box_pt->xyz.x = start->xyz.x;
1119  }
1120 
1121  if (start->xyz.y > maxs->xyz.y) {
1122  box_pt->xyz.y = maxs->xyz.y;
1123  inside = FALSE;
1124  } else if (start->xyz.y < mins->xyz.y) {
1125  box_pt->xyz.y = mins->xyz.y;
1126  inside = FALSE;
1127  } else {
1128  box_pt->xyz.y = start->xyz.y;
1129  }
1130 
1131  if (start->xyz.z > maxs->xyz.z) {
1132  box_pt->xyz.z = maxs->xyz.z;
1133  inside = FALSE;
1134  } else if (start->xyz.z < mins->xyz.z) {
1135  box_pt->xyz.z = mins->xyz.z;
1136  inside = FALSE;
1137  } else {
1138  box_pt->xyz.z = start->xyz.z;
1139  }
1140 
1141  return inside;
1142 }
#define __UNUSED
Definition: clang.h:23
void vm_vec_projection_onto_plane(vec3d *projection, const vec3d *src, const vec3d *unit_normal)
Definition: vecmat.cpp:112
int i
Definition: multi_pxo.cpp:466
int fvi_polyedge_sphereline(vec3d *hit_point, const vec3d *xs0, const vec3d *vs, float Rs, int nv, vec3d const *const *verts, float *hit_time)
Definition: fvi.cpp:694
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
float v
Definition: pstypes.h:135
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
Assert(pm!=NULL)
Definition: pstypes.h:88
hull_check p0
Definition: lua.cpp:5051
struct vec3d::@225::@227 xyz
GLclampf f
Definition: Glext.h:7097
#define TRUE
Definition: pstypes.h:399
void fvi_closest_point_on_line_segment(vec3d *closest_point, const vec3d *fixed_point, const vec3d *line_point1, const vec3d *line_point2)
Definition: fvi.cpp:935
fix t2
Definition: animplay.cpp:37
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
matrix * B
Definition: lua.cpp:445
GLfloat GLfloat GLfloat v2
Definition: Glext.h:5640
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
float fvi_point_dist_plane(const vec3d *plane_pnt, const vec3d *plane_norm, const vec3d *point)
Definition: fvi.cpp:71
GLdouble u1
Definition: Glext.h:7779
int fvi_sphere_plane(vec3d *intersect_point, const vec3d *sphere_center_start, const vec3d *sphere_velocity, float sphere_radius, const vec3d *plane_normal, const vec3d *plane_point, float *hit_time, float *crossing_time)
Definition: fvi.cpp:516
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
float a1d[3]
Definition: pstypes.h:93
int fvi_point_face(const vec3d *checkp, int nv, vec3d const *const *verts, const vec3d *norm1, float *u_out, float *v_out, const uv_pair *uvls)
Definition: fvi.cpp:419
int fvi_sphere_perp_edge(vec3d *intersect_point, const vec3d *sphere_center_start, const vec3d *sphere_velocity, float sphere_radius, vec3d *edge_point1, vec3d *edge_point2, float *collide_time)
Definition: fvi.cpp:570
GLfloat v0
Definition: Glext.h:5638
void vm_vec_sub2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:187
#define w(p)
Definition: modelsinc.h:68
hull_check p1
Definition: lua.cpp:5052
#define fl_abs(fl)
Definition: floating.h:31
GLdouble s
Definition: Glext.h:5321
float u
Definition: pstypes.h:135
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
#define delta
Definition: fvi.cpp:418
GLdouble GLdouble t
Definition: Glext.h:5329
float vm_vec_dist_squared(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:344
int fvi_ray_sphere(vec3d *intp, const vec3d *p0, const vec3d *p1, const vec3d *sphere_pos, float sphere_rad)
Definition: fvi.cpp:255
GLuint start
Definition: Gl.h:1502
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
GLfloat GLfloat v1
Definition: Glext.h:5639
int fvi_cull_polyface_sphere(const vec3d *poly_center, float poly_r, const vec3d *sphere_start, const vec3d *sphere_end, float sphere_r)
Definition: fvi.cpp:1044
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
#define UNINITIALIZED_VALUE
Definition: fvi.cpp:18
fix t1
Definition: animplay.cpp:37
INT32 INT32 * denominator
Definition: wglext.h:659
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
GLdouble GLdouble GLdouble GLdouble q
Definition: Glext.h:5345
GLuint GLuint num
Definition: Glext.h:9089
void fvi_closest_line_line(const vec3d *x0, const vec3d *vx, const vec3d *y0, const vec3d *vy, float *x_time, float *y_time)
Definition: fvi.cpp:1064
void fvi_two_lines_in_3space(const vec3d *p1, const vec3d *v1, const vec3d *p2, const vec3d *v2, float *s, float *t)
Definition: fvi.cpp:42
int fvi_check_sphere_sphere(const vec3d *x_p0, const vec3d *x_p1, const vec3d *x_s0, const vec3d *x_s1, float radius_p, float radius_s, float *t1, float *t2)
Definition: fvi.cpp:969
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
#define fl_sqrt(fl)
Definition: floating.h:29
int fvi_segment_sphere(vec3d *intp, const vec3d *p0, const vec3d *p1, const vec3d *sphere_pos, float sphere_rad)
Definition: fvi.cpp:188
void vm_project_point_onto_plane(vec3d *new_point, const vec3d *point, const vec3d *plane_normal, const vec3d *plane_point)
Definition: vecmat.cpp:128
int vm_vec_cmp(const vec3d *a, const vec3d *b)
Definition: vecmat.cpp:1415
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
matrix * A
Definition: lua.cpp:444
int temp
Definition: lua.cpp:4996
float fvi_ray_plane(vec3d *new_pnt, const vec3d *plane_pnt, const vec3d *plane_norm, const vec3d *ray_origin, const vec3d *ray_direction, float rad)
Definition: fvi.cpp:118
vec3d * vm_vec_cross(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:645
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
int fvi_segment_plane(vec3d *new_pnt, const vec3d *plane_pnt, const vec3d *plane_norm, const vec3d *p0, const vec3d *p1, float rad)
Definition: fvi.cpp:162
#define FALSE
Definition: pstypes.h:400
GLdouble GLdouble u2
Definition: Glext.h:7779
int fvi_ray_boundingbox(const vec3d *min, const vec3d *max, const vec3d *p0, const vec3d *pdir, vec3d *hitpt)
Definition: fvi.cpp:321
int project_point_onto_bbox(const vec3d *mins, const vec3d *maxs, const vec3d *start, vec3d *box_pt)
Definition: fvi.cpp:1107
GLfloat GLfloat GLfloat GLfloat v3
Definition: Glext.h:5641