]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/mediasource/extra/netradiant-src/libs/mathlib/bbox.c
Include netRadiant source in this GIT
[voretournament/voretournament.git] / misc / mediasource / extra / netradiant-src / libs / mathlib / bbox.c
diff --git a/misc/mediasource/extra/netradiant-src/libs/mathlib/bbox.c b/misc/mediasource/extra/netradiant-src/libs/mathlib/bbox.c
new file mode 100644 (file)
index 0000000..e8dc865
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+Copyright (C) 2001-2006, William Joseph.
+All Rights Reserved.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include <float.h>
+
+#include "mathlib.h"
+
+const aabb_t g_aabb_null = {
+  { 0, 0, 0, },
+  { -FLT_MAX, -FLT_MAX, -FLT_MAX, },
+};
+
+void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max)
+{
+  VectorMid(min, max, aabb->origin);
+  VectorSubtract(max, aabb->origin, aabb->extents);
+}
+
+void aabb_clear(aabb_t *aabb)
+{
+  VectorCopy(g_aabb_null.origin, aabb->origin);
+  VectorCopy(g_aabb_null.extents, aabb->extents);
+}
+
+void aabb_extend_by_point(aabb_t *aabb, const vec3_t point)
+{
+#if 1
+  int i;
+  vec_t min, max, displacement;
+  for(i=0; i<3; i++)
+  {
+    displacement = point[i] - aabb->origin[i];
+    if(fabs(displacement) > aabb->extents[i])
+    {
+      if(aabb->extents[i] < 0) // degenerate
+      {
+        min = max = point[i];
+      }
+      else if(displacement > 0)
+      {
+        min = aabb->origin[i] - aabb->extents[i];
+        max = aabb->origin[i] + displacement;
+      }
+      else
+      {
+        max = aabb->origin[i] + aabb->extents[i];
+        min = aabb->origin[i] + displacement;
+      }
+      aabb->origin[i] = (min + max) * 0.5f;
+      aabb->extents[i] = max - aabb->origin[i];
+    }
+  }
+#else
+  unsigned int i;
+  for(i=0; i<3; ++i)
+  {
+    if(aabb->extents[i] < 0) // degenerate
+    {
+      aabb->origin[i] = point[i];
+      aabb->extents[i] = 0;
+    }
+    else
+    {
+      vec_t displacement = point[i] - aabb->origin[i];
+      vec_t increment = (vec_t)fabs(displacement) - aabb->extents[i];
+      if(increment > 0)
+      {
+        increment *= (vec_t)((displacement > 0) ? 0.5 : -0.5);
+        aabb->extents[i] += increment;
+        aabb->origin[i] += increment;
+      }
+    }
+  }
+#endif
+}
+
+void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src)
+{
+  int i;
+  vec_t min, max, displacement, difference;
+  for(i=0; i<3; i++)
+  {
+    displacement = aabb_src->origin[i] - aabb->origin[i];
+    difference = aabb_src->extents[i] - aabb->extents[i];
+    if(aabb->extents[i] < 0
+      || difference >= fabs(displacement))
+    {
+      // 2nd contains 1st
+      aabb->extents[i] = aabb_src->extents[i];
+      aabb->origin[i] = aabb_src->origin[i];
+    }
+    else if(aabb_src->extents[i] < 0
+      || -difference >= fabs(displacement))
+    {
+      // 1st contains 2nd
+      continue;
+    }
+    else
+    {
+      // not contained
+      if(displacement > 0)
+      {
+        min = aabb->origin[i] - aabb->extents[i];
+        max = aabb_src->origin[i] + aabb_src->extents[i];
+      }
+      else
+      {
+        min = aabb_src->origin[i] - aabb_src->extents[i];
+        max = aabb->origin[i] + aabb->extents[i];
+      }
+      aabb->origin[i] = (min + max) * 0.5f;
+      aabb->extents[i] = max - aabb->origin[i];
+    }
+  }
+}
+
+void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension)
+{
+  VectorAdd(aabb->extents, extension, aabb->extents);
+}
+
+int aabb_test_point(const aabb_t *aabb, const vec3_t point)
+{
+  int i;
+  for(i=0; i<3; i++)
+    if(fabs(point[i] - aabb->origin[i]) >= aabb->extents[i])
+      return 0;
+  return 1;
+}
+
+int aabb_test_aabb(const aabb_t *aabb, const aabb_t *aabb_src)
+{
+  int i;
+  for (i=0; i<3; i++)
+    if ( fabs(aabb_src->origin[i] - aabb->origin[i]) > (fabs(aabb->extents[i]) + fabs(aabb_src->extents[i])) )
+      return 0;
+  return 1;
+}
+
+int aabb_test_plane(const aabb_t *aabb, const float *plane)
+{
+  float fDist, fIntersect;
+
+  // calc distance of origin from plane
+  fDist = DotProduct(plane, aabb->origin) + plane[3];
+  
+   // calc extents distance relative to plane normal
+  fIntersect = (vec_t)(fabs(plane[0] * aabb->extents[0]) + fabs(plane[1] * aabb->extents[1]) + fabs(plane[2] * aabb->extents[2]));
+  // accept if origin is less than or equal to this distance
+  if (fabs(fDist) < fIntersect) return 1; // partially inside
+  else if (fDist < 0) return 2; // totally inside
+  return 0; // totally outside
+}
+
+/* 
+Fast Ray-Box Intersection
+by Andrew Woo
+from "Graphics Gems", Academic Press, 1990
+*/
+
+#define NUMDIM 3
+#define RIGHT  0
+#define LEFT   1
+#define MIDDLE 2
+
+int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec3_t intersection)
+{
+       int inside = 1;
+       char quadrant[NUMDIM];
+       register int i;
+       int whichPlane;
+       double maxT[NUMDIM];
+       double candidatePlane[NUMDIM];
+  
+  const float *origin = ray->origin;
+  const float *direction = ray->direction;
+
+       /* Find candidate planes; this loop can be avoided if
+       rays cast all from the eye(assume perpsective view) */
+       for (i=0; i<NUMDIM; i++)
+  {
+               if(origin[i] < (aabb->origin[i] - aabb->extents[i]))
+    {
+                       quadrant[i] = LEFT;
+                       candidatePlane[i] = (aabb->origin[i] - aabb->extents[i]);
+                       inside = 0;
+               }
+    else if (origin[i] > (aabb->origin[i] + aabb->extents[i]))
+    {
+                       quadrant[i] = RIGHT;
+                       candidatePlane[i] = (aabb->origin[i] + aabb->extents[i]);
+                       inside = 0;
+               }
+    else
+    {
+                       quadrant[i] = MIDDLE;
+    }
+  }
+
+       /* Ray origin inside bounding box */
+       if(inside == 1)
+  {
+               VectorCopy(ray->origin, intersection);
+               return 1;
+       }
+
+
+       /* Calculate T distances to candidate planes */
+       for (i = 0; i < NUMDIM; i++)
+  {
+               if (quadrant[i] != MIDDLE && direction[i] !=0.)
+                       maxT[i] = (candidatePlane[i] - origin[i]) / direction[i];
+               else
+                       maxT[i] = -1.;
+  }
+
+       /* Get largest of the maxT's for final choice of intersection */
+       whichPlane = 0;
+       for (i = 1; i < NUMDIM; i++)
+               if (maxT[whichPlane] < maxT[i])
+                       whichPlane = i;
+
+       /* Check final candidate actually inside box */
+       if (maxT[whichPlane] < 0.)
+    return 0;
+       for (i = 0; i < NUMDIM; i++)
+  {
+               if (whichPlane != i)
+    {
+                       intersection[i] = (vec_t)(origin[i] + maxT[whichPlane] * direction[i]);
+                       if (fabs(intersection[i] - aabb->origin[i]) > aabb->extents[i])
+                               return 0;
+               }
+    else
+    {
+                       intersection[i] = (vec_t)candidatePlane[i];
+               }
+  }
+
+       return 1;                               /* ray hits box */
+}
+
+int aabb_test_ray(const aabb_t* aabb, const ray_t* ray)
+{
+ vec3_t displacement, ray_absolute;
+ vec_t f;
+ displacement[0] = ray->origin[0] - aabb->origin[0];
+ if(fabs(displacement[0]) > aabb->extents[0] && displacement[0] * ray->direction[0] >= 0.0f)
+   return 0;
+ displacement[1] = ray->origin[1] - aabb->origin[1];
+ if(fabs(displacement[1]) > aabb->extents[1] && displacement[1] * ray->direction[1] >= 0.0f)
+   return 0;
+ displacement[2] = ray->origin[2] - aabb->origin[2];
+ if(fabs(displacement[2]) > aabb->extents[2] && displacement[2] * ray->direction[2] >= 0.0f)
+   return 0;
+ ray_absolute[0] = (float)fabs(ray->direction[0]);
+ ray_absolute[1] = (float)fabs(ray->direction[1]);
+ ray_absolute[2] = (float)fabs(ray->direction[2]);
+
+ f = ray->direction[1] * displacement[2] - ray->direction[2] * displacement[1];
+ if((float)fabs(f) > aabb->extents[1] * ray_absolute[2] + aabb->extents[2] * ray_absolute[1])
+   return 0;
+
+ f = ray->direction[2] * displacement[0] - ray->direction[0] * displacement[2];
+ if((float)fabs(f) > aabb->extents[0] * ray_absolute[2] + aabb->extents[2] * ray_absolute[0])
+   return 0;
+
+ f = ray->direction[0] * displacement[1] - ray->direction[1] * displacement[0];
+ if((float)fabs(f) > aabb->extents[0] * ray_absolute[1] + aabb->extents[1] * ray_absolute[0])
+   return 0;
+ return 1;
+}
+
+void aabb_orthogonal_transform(aabb_t* dst, const aabb_t* src, const m4x4_t transform)
+{
+  VectorCopy(src->origin, dst->origin);
+  m4x4_transform_point(transform, dst->origin);
+
+  dst->extents[0] = (vec_t)(fabs(transform[0]  * src->extents[0])
+                          + fabs(transform[4]  * src->extents[1])
+                          + fabs(transform[8]  * src->extents[2]));
+  dst->extents[1] = (vec_t)(fabs(transform[1]  * src->extents[0])
+                          + fabs(transform[5]  * src->extents[1])
+                          + fabs(transform[9]  * src->extents[2]));
+  dst->extents[2] = (vec_t)(fabs(transform[2]  * src->extents[0])
+                          + fabs(transform[6]  * src->extents[1])
+                          + fabs(transform[10] * src->extents[2]));
+}
+
+void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox)
+{
+       int i;
+       vec3_t temp[3];
+
+  VectorCopy(bbox->aabb.origin, aabb->origin);
+
+       // calculate the AABB extents in local coord space from the OBB extents and axes
+       VectorScale(bbox->axes[0], bbox->aabb.extents[0], temp[0]);
+       VectorScale(bbox->axes[1], bbox->aabb.extents[1], temp[1]);
+       VectorScale(bbox->axes[2], bbox->aabb.extents[2], temp[2]);
+       for(i=0;i<3;i++) aabb->extents[i] = (vec_t)(fabs(temp[0][i]) + fabs(temp[1][i]) + fabs(temp[2][i]));
+}
+
+void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis)
+{
+  aabb_clear(aabb);
+  aabb->extents[axis] = FLT_MAX;
+  aabb_extend_by_point(aabb, area_tl);
+  aabb_extend_by_point(aabb, area_br);
+}
+
+int aabb_oriented_intersect_plane(const aabb_t *aabb, const m4x4_t transform, const vec_t* plane)
+{
+  vec_t fDist, fIntersect;
+
+  // calc distance of origin from plane
+  fDist = DotProduct(plane, aabb->origin) + plane[3];
+
+  // calc extents distance relative to plane normal
+  fIntersect = (vec_t)(fabs(aabb->extents[0] * DotProduct(plane, transform))
+    + fabs(aabb->extents[1] * DotProduct(plane, transform+4))
+    + fabs(aabb->extents[2] * DotProduct(plane, transform+8)));
+  // accept if origin is less than this distance
+  if (fabs(fDist) < fIntersect) return 1; // partially inside
+  else if (fDist < 0) return 2; // totally inside
+  return 0; // totally outside
+}
+
+void aabb_corners(const aabb_t* aabb, vec3_t corners[8])
+{
+  vec3_t min, max;
+  VectorSubtract(aabb->origin, aabb->extents, min);
+  VectorAdd(aabb->origin, aabb->extents, max);
+  VectorSet(corners[0], min[0], max[1], max[2]);
+  VectorSet(corners[1], max[0], max[1], max[2]);
+  VectorSet(corners[2], max[0], min[1], max[2]);
+  VectorSet(corners[3], min[0], min[1], max[2]);
+  VectorSet(corners[4], min[0], max[1], min[2]);
+  VectorSet(corners[5], max[0], max[1], min[2]);
+  VectorSet(corners[6], max[0], min[1], min[2]);
+  VectorSet(corners[7], min[0], min[1], min[2]);
+}
+
+
+void bbox_update_radius(bbox_t *bbox)
+{
+  bbox->radius = VectorLength(bbox->aabb.extents);
+}
+
+void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform)
+{
+  if(src->extents[0] < 0
+    || src->extents[1] < 0
+    || src->extents[2] < 0)
+  {
+    aabb_clear(dst);
+    return;
+  }
+
+  VectorCopy(src->origin, dst->origin);
+  m4x4_transform_point(transform, dst->origin);
+
+  dst->extents[0] = (vec_t)(fabs(transform[0]  * src->extents[0])
+                          + fabs(transform[4]  * src->extents[1])
+                          + fabs(transform[8]  * src->extents[2]));
+  dst->extents[1] = (vec_t)(fabs(transform[1]  * src->extents[0])
+                          + fabs(transform[5]  * src->extents[1])
+                          + fabs(transform[9]  * src->extents[2]));
+  dst->extents[2] = (vec_t)(fabs(transform[2]  * src->extents[0])
+                          + fabs(transform[6]  * src->extents[1])
+                          + fabs(transform[10] * src->extents[2]));
+}
+
+void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, const m4x4_t matrix, const vec3_t euler, const vec3_t scale)
+{
+       double rad[3];
+       double pi_180 = Q_PI / 180;
+  double A, B, C, D, E, F, AD, BD;
+  
+       VectorCopy(aabb->origin, bbox->aabb.origin);
+       
+  m4x4_transform_point(matrix, bbox->aabb.origin);
+
+       bbox->aabb.extents[0] = aabb->extents[0] * scale[0];
+       bbox->aabb.extents[1] = aabb->extents[1] * scale[1];
+       bbox->aabb.extents[2] = aabb->extents[2] * scale[2];
+
+  rad[0] = euler[0] * pi_180;
+       rad[1] = euler[1] * pi_180;
+       rad[2] = euler[2] * pi_180;
+
+  A       = cos(rad[0]);
+  B       = sin(rad[0]);
+  C       = cos(rad[1]);
+  D       = sin(rad[1]);
+  E       = cos(rad[2]);
+  F       = sin(rad[2]);
+
+  AD      =   A * -D;
+  BD      =   B * -D;
+
+       bbox->axes[0][0] = (vec_t)(C*E);
+       bbox->axes[0][1] = (vec_t)(-BD*E + A*F);
+       bbox->axes[0][2] = (vec_t)(AD*E + B*F);
+       bbox->axes[1][0] = (vec_t)(-C*F);
+       bbox->axes[1][1] = (vec_t)(BD*F + A*E);
+       bbox->axes[1][2] = (vec_t)(-AD*F + B*E);
+       bbox->axes[2][0] = (vec_t)D;
+       bbox->axes[2][1] = (vec_t)(-B*C);
+       bbox->axes[2][2] = (vec_t)(A*C);
+
+  bbox_update_radius(bbox);
+}
+
+int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane)
+{
+  vec_t fDist, fIntersect;
+
+  // calc distance of origin from plane
+  fDist = DotProduct(plane, bbox->aabb.origin) + plane[3];
+
+       // trivial accept/reject using bounding sphere
+       if (fabs(fDist) > bbox->radius)
+       {
+               if (fDist < 0)
+                       return 2; // totally inside
+               else
+                       return 0; // totally outside
+       }
+
+  // calc extents distance relative to plane normal
+  fIntersect = (vec_t)(fabs(bbox->aabb.extents[0] * DotProduct(plane, bbox->axes[0]))
+             + fabs(bbox->aabb.extents[1] * DotProduct(plane, bbox->axes[1]))
+             + fabs(bbox->aabb.extents[2] * DotProduct(plane, bbox->axes[2])));
+  // accept if origin is less than this distance
+  if (fabs(fDist) < fIntersect) return 1; // partially inside
+  else if (fDist < 0) return 2; // totally inside
+  return 0; // totally outside
+}