diff --git a/Core/Libraries/Source/WWVegas/CMakeLists.txt b/Core/Libraries/Source/WWVegas/CMakeLists.txt
index 8b228620b3..78dcb97efd 100644
--- a/Core/Libraries/Source/WWVegas/CMakeLists.txt
+++ b/Core/Libraries/Source/WWVegas/CMakeLists.txt
@@ -52,7 +52,7 @@ target_link_libraries(core_wwvegas INTERFACE
core_wwdebug
# core_wwdownload
core_wwlib
- # core_wwmath
+ core_wwmath
core_wwsaveload
# core_wwshade
# core_wwutil
diff --git a/Core/Libraries/Source/WWVegas/WWMath/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
index 250878a034..d248f6af81 100644
--- a/Core/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
+++ b/Core/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
@@ -4,24 +4,24 @@ set(WWMATH_SRC
aabtreecull.cpp
aabtreecull.h
aaplane.h
- #cardinalspline.cpp # to be moved
+ cardinalspline.cpp
cardinalspline.h
castres.h
catmullromspline.cpp
catmullromspline.h
colmath.cpp
colmath.h
- #colmathaabox.cpp # to be moved
+ colmathaabox.cpp
colmathaabox.h
- #colmathaabtri.cpp # to be moved
+ colmathaabtri.cpp
colmathfrustum.cpp
colmathfrustum.h
colmathinlines.h
colmathline.cpp
colmathline.h
- #colmathobbobb.cpp # to be moved
+ colmathobbobb.cpp
colmathobbox.cpp
- #colmathobbtri.cpp # to be moved
+ colmathobbtri.cpp
colmathplane.cpp
colmathplane.h
colmathsphere.cpp
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp b/Core/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp
similarity index 100%
rename from GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp
rename to Core/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp b/Core/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp
similarity index 100%
rename from GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp
rename to Core/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp b/Core/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
similarity index 100%
rename from GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
rename to Core/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp b/Core/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
similarity index 100%
rename from GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
rename to Core/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp b/Core/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
similarity index 100%
rename from GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
rename to Core/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
diff --git a/Generals/Code/Libraries/Source/WWVegas/CMakeLists.txt b/Generals/Code/Libraries/Source/WWVegas/CMakeLists.txt
index af05669132..f0b47a92c8 100644
--- a/Generals/Code/Libraries/Source/WWVegas/CMakeLists.txt
+++ b/Generals/Code/Libraries/Source/WWVegas/CMakeLists.txt
@@ -18,7 +18,6 @@ target_include_directories(g_wwcommon INTERFACE
)
add_subdirectory(WWAudio)
-add_subdirectory(WWMath)
add_subdirectory(Wwutil)
add_subdirectory(WW3D2)
add_subdirectory(WWDownload)
@@ -38,6 +37,5 @@ target_link_libraries(g_wwvegas INTERFACE
core_wwvegas
g_ww3d2
g_wwdownload
- g_wwmath
g_wwutil
)
diff --git a/Generals/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt b/Generals/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
deleted file mode 100644
index 0e2ac141a8..0000000000
--- a/Generals/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-set(WWMATH_SRC
- cardinalspline.cpp
- colmathaabox.cpp
- colmathaabtri.cpp
- colmathobbobb.cpp
- colmathobbtri.cpp
-)
-
-# Targets to build.
-add_library(g_wwmath STATIC)
-#set_target_properties(g_wwmath PROPERTIES OUTPUT_NAME wwmath)
-
-target_sources(g_wwmath PRIVATE ${WWMATH_SRC})
-
-target_link_libraries(g_wwmath PRIVATE
- core_wwmath
- g_wwcommon
-)
diff --git a/Generals/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp b/Generals/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp
deleted file mode 100644
index 36a6861e86..0000000000
--- a/Generals/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
-** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
-**
-** This program 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 3 of the License, or
-** (at your option) any later version.
-**
-** This program 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 this program. If not, see .
-*/
-
-/***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/wwmath/cardinalspline.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 9/16/01 4:07p $*
- * *
- * $Revision:: 6 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-
-#include "cardinalspline.h"
-#include "wwdebug.h"
-#include "persistfactory.h"
-#include "wwmathids.h"
-#include "wwhack.h"
-
-/*
-** Force-Link this module because the linker can't detect that we actually need it...
-*/
-DECLARE_FORCE_LINK(cardinalspline);
-
-
-/*
-** Save-Load stuff
-*/
-SimplePersistFactoryClass _CardinalSpline3DFactory;
-SimplePersistFactoryClass _CardinalSpline1DFactory;
-
-enum
-{
- // ID's used by CardinalSpline3D
- CARDINAL3D_CHUNK_HERMITE3D = 0x02070957,
- CARDINAL3D_CHUNK_TIGHTNESSKEYS,
-
- // ID's used by CardinalSpline1D
- CARDINAL1D_CHUNK_HERMITE1D = 0x02070959,
- CARDINAL1D_CHUNK_TIGHTNESSKEYS
-};
-
-
-/*
-** CardinalSpline3DClass Implementation
-*/
-int CardinalSpline3DClass::Add_Key(const Vector3 & point,float t)
-{
- int index = HermiteSpline3DClass::Add_Key(point,t);
- float tightness = 0.5f;
- Tightness.Insert(index,tightness);
- return index;
-}
-
-void CardinalSpline3DClass::Remove_Key(int i)
-{
- Tightness.Delete(i);
- HermiteSpline3DClass::Remove_Key(i);
-}
-
-void CardinalSpline3DClass::Clear_Keys(void)
-{
- Tightness.Clear();
- HermiteSpline3DClass::Clear_Keys();
-}
-
-void CardinalSpline3DClass::Set_Tightness(int i,float tightness)
-{
- WWASSERT(i >= 0);
- WWASSERT(i < Tightness.Count());
- Tightness[i] = tightness;
- TangentsDirty = true;
-}
-
-float CardinalSpline3DClass::Get_Tightness(int i)
-{
- return Tightness[i];
-}
-
-void CardinalSpline3DClass::Update_Tangents(void)
-{
- if (Keys.Count() < 2) {
- for (int i=0; i= 0);
- WWASSERT(i < Tightness.Count());
- Tightness[i] = tightness;
- TangentsDirty = true;
-}
-
-float CardinalSpline1DClass::Get_Tightness(int i)
-{
- return Tightness[i];
-}
-
-void CardinalSpline1DClass::Update_Tangents(void)
-{
- if (Keys.Count() < 2) {
- for (int i=0; i.
-*/
-
-/***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/wwmath/colmathaabox.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 8/30/01 7:40p $*
- * *
- * $Revision:: 22 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * CollisionMath::Intersection_Test -- Test intersection between two AABoxes *
- * CollisionMath::Overlap_Test -- Tests overlap between an AABox and a sphere *
- * CollisionMath::Overlap_Test -- Tests overlap between an AABox and a triangle *
- * CollisionMath::Overlap_Test -- Tests overlap between an AABox and a line segment *
- * CollisionMath::Collide -- Collision test for a moving AABox and a plane *
- * aab_separation_test -- tests two AAB's for separation on an axis *
- * CollisionMath::Collide -- Collision test for two moving AABoxes *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-
-#include "colmath.h"
-#include "colmathinlines.h"
-#include "aaplane.h"
-#include "plane.h"
-#include "lineseg.h"
-#include "tri.h"
-#include "sphere.h"
-#include "aabox.h"
-#include "obbox.h"
-#include "wwdebug.h"
-
-
-/***********************************************************************************************
- * CollisionMath::Intersection_Test -- Test intersection between two AABoxes *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-bool CollisionMath::Intersection_Test(const AABoxClass & box,const AABoxClass & box2)
-{
- Vector3 dc = box2.Center - box.Center;
-
- if (box.Extent.X + box2.Extent.X < WWMath::Fabs(dc.X)) return false;
- if (box.Extent.Y + box2.Extent.Y < WWMath::Fabs(dc.Y)) return false;
- if (box.Extent.Z + box2.Extent.Z < WWMath::Fabs(dc.Z)) return false;
- return true;
-}
-
-/***********************************************************************************************
- * CollisionMath::Overlap_Test -- Tests overlap between an AABox and a sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const SphereClass & sphere)
-{
- // TODO: this function seems incorrect. Not currently using it though
- Vector3 dist = sphere.Center - box.Center;
-
- Vector3 extent;
- extent.X = box.Extent.X + sphere.Radius;
- extent.Y = box.Extent.Y + sphere.Radius;
- extent.Z = box.Extent.Z + sphere.Radius;
-
- //
- // Check to see if the sphere is completely outside the box
- //
- if (WWMath::Fabs(dist.X) > extent.X) return OUTSIDE;
- if (WWMath::Fabs(dist.Y) > extent.Y) return OUTSIDE;
- if (WWMath::Fabs(dist.Z) > extent.Z) return OUTSIDE;
-
- return INSIDE;
-}
-
-
-
-/***********************************************************************************************
- * CollisionMath::Overlap_Test -- Tests overlap between an AABox and a line segment *
- * *
- * This function uses separating axes to determine whether an AABox and a line segment overlap *
- * I wrote it when we found that ray-casting was taking a huge amount of time in Renegade. *
- * Here are some statistics comparing this function to the previous function which used the *
- * same algorithm that Collide(box,ray) uses. *
- * *
- * collide algorithm (Gems) separating axis (this one) *
- * ----------------------------------------------------------------------------------------- *
- * number of tests 10000 10000 *
- * avg cycles 641 464 *
- * outside cycles 652 390 *
- * overlap cycles 610 683 *
- * *
- * The idea for this test is that it will early-exit when it can while the old test can't. *
- * When we are passing a ray down our culling trees, it is common to encounter boxes that *
- * are not intersecting the ray. The faster we can reject these, the better! *
- * *
- * INPUT: *
- * box - box to test *
- * line - line to test *
- * *
- * OUTPUT: *
- * overlap status of the line with respect to the box, either INSIDE, OUTSIDE, or OVERLAPPED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const LineSegClass & line)
-{
- // If both endpoints are in, return INSIDE
- // If either was inside, return OVERLAPPED
- int inside_point_count = 0;
- if (CollisionMath::Overlap_Test(box,line.Get_P0()) == INSIDE) inside_point_count++;
- if (CollisionMath::Overlap_Test(box,line.Get_P1()) == INSIDE) inside_point_count++;
-
- if (inside_point_count == 2) {
-
- return INSIDE;
-
- } else if (inside_point_count == 1) {
-
- return OVERLAPPED;
-
- } else {
-
- // Here I'm using the separating axis theorem to test if the line-segment
- // and the box can be separated by a plane. Any two convex objects that are
- // not intersecting can be separated by a plane defined by either a
- // face normal from one of the objects or the cross-product of an edge from
- // each object. In the case of an axis-aligned box and a line-segment, we
- // have to check the three coordinate axes and the cross product between
- // each and the direction vector of the line segment.
- //
- // Here is the general test for an arbitrary axis:
- // -----------------------------------------------
- // box_proj = fabs(extent.X*axis.X) + fabs(extent.Y*axis.Y) + fabs(extent.Z*axis.Z)
- // p0_proj = fabs(dot_product(dp0,axis))
- // dp_proj = fabs(dot_product(dp,axis))
- // if (p0_proj > 0) {
- // if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
- // } else {
- // if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
- // }
- //
- // In practice, there are optimizations you can make on each of the axes that
- // we need to test (see below).
-
- float box_proj,p0_proj,dp_proj;
- Vector3 dp0;
- Vector3::Subtract(line.Get_P0(),box.Center,&dp0);
-
- // Project box and line onto the x-axis
- // Since I know the axis is the x-axis, just take the x components of each
- // vector instead of doing the dot-product. The projection of 'dp' is only
- // counted if it points towards the center of the box (i.e. it decreases the
- // chances of them being separated...)
- box_proj = box.Extent.X;
- p0_proj = dp0.X;
- dp_proj = line.Get_DP().X;
- if (p0_proj > 0) {
- if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
- } else {
- if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
- }
-
- // Project box and line onto the y-axis
- box_proj = box.Extent.Y;
- p0_proj = dp0.Y;
- dp_proj = line.Get_DP().Y;
- if (p0_proj > 0) {
- if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
- } else {
- if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
- }
-
- // Project box and line onto the z-axis
- box_proj = box.Extent.Z;
- p0_proj = dp0.Z;
- dp_proj = line.Get_DP().Z;
- if (p0_proj > 0) {
- if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
- } else {
- if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
- }
-
- // Project box and line onto (x cross line)
- // I'm manually optimizing the cross-product and taking advantage of the fact
- // that 'dp' will always project to zero for this axis.
- Vector3 axis;
- axis.Set(0,-line.Get_Dir().Z,line.Get_Dir().Y); // == (1,0,0) cross (x,y,z)
- box_proj = WWMath::Fabs(axis.Y*box.Extent.Y) + WWMath::Fabs(axis.Z*box.Extent.Z);
- p0_proj = Vector3::Dot_Product(axis,dp0);
- if (WWMath::Fabs(p0_proj) > box_proj) return OUTSIDE;
-
- // Project box and line onto (y cross line)
- axis.Set(line.Get_Dir().Z,0,-line.Get_Dir().X); // == (0,1,0) cross (x,y,z)
- box_proj = WWMath::Fabs(axis.X*box.Extent.X) + WWMath::Fabs(axis.Z*box.Extent.Z);
- p0_proj = Vector3::Dot_Product(axis,dp0);
- if (WWMath::Fabs(p0_proj) > box_proj) return OUTSIDE;
-
- // Project box and line onto (z cross line)
- axis.Set(-line.Get_Dir().Y,line.Get_Dir().X,0); // == (0,0,1) cross (x,y,z)
- box_proj = WWMath::Fabs(axis.X*box.Extent.X) + WWMath::Fabs(axis.Y*box.Extent.Y);
- p0_proj = Vector3::Dot_Product(axis,dp0);
- if (WWMath::Fabs(p0_proj) > box_proj) return OUTSIDE;
-
- }
- return OVERLAPPED;
-}
-
-#if 0 // Alternate Overlap Test for AABox-Ray
-CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const LineSegClass & line)
-{
- // If both endpoints are in, return INSIDE
- // If either was inside, return OVERLAPPED
- int inside_point_count = 0;
- if (CollisionMath::Overlap_Test(box,line.Get_P0()) == INSIDE) inside_point_count++;
- if (CollisionMath::Overlap_Test(box,line.Get_P1()) == INSIDE) inside_point_count++;
-
- if (inside_point_count == 2) {
-
- return INSIDE;
-
- } else if (inside_point_count == 1) {
-
- return OVERLAPPED;
-
- } else {
-
- // Now we know that both points are outside of the box so we
- // have to detect if the ray penetrates the box.
- // I found this algorithm in one of the GEMS books...
- Vector3 boxmin,boxmax;
- Vector3::Subtract(box.Center,box.Extent,&boxmin);
- Vector3::Add(box.Center,box.Extent,&boxmax);
-
- float candidateplane[3]; // candidate intersection plane distance for each axis
- float maxt[3]; // t value along the ray for each axis
- Vector3 coord; // intersection point
-
- const int BOX_SIDE_NEGATIVE = -1;
- const int BOX_SIDE_MIDDLE = 0;
- const int BOX_SIDE_POSITIVE = 1;
-
- int quadrant[3];
- for (int i=0; i<3; i++) {
- if (line.Get_P0()[i] < boxmin[i]) {
- quadrant[i] = BOX_SIDE_NEGATIVE;
- candidateplane[i] = boxmin[i];
- } else if (line.Get_P0()[i] > boxmax[i]) {
- quadrant[i] = BOX_SIDE_POSITIVE;
- candidateplane[i] = boxmax[i];
- } else {
- quadrant[i] = BOX_SIDE_MIDDLE;
- }
- }
-
- // Calculate the 3 distances to the candidate planes
- for (i=0; i<3; i++) {
- if (quadrant[i] != BOX_SIDE_MIDDLE && line.Get_DP()[i] != 0.0f) {
- maxt[i] = (candidateplane[i] - line.Get_P0()[i]) / line.Get_DP()[i];
- } else {
- maxt[i] = -1.0f;
- }
- }
-
- // Get the largest of the maxt's for the final choice of intersection
- int intersection_plane = 0;
- for (i=1; i<3; i++) {
- if (maxt[i] > maxt[intersection_plane]) {
- intersection_plane = i;
- }
- }
-
- // If the ray is "in front" of all of the planes, return
- if (maxt[intersection_plane] < 0.0f) {
- return OUTSIDE;
- }
-
- // If the intersection is beyond the end of the ray, return
- if (maxt[intersection_plane] > 1.0f) {
- return OUTSIDE;
- }
-
- // Check if the ray is inside the box, i.e. on the two planes which
- // are not the intersection planes, the intersection point should
- // be between the min and max of the box.
- for (i=0; i<3; i++) {
-
- if (intersection_plane != i) {
-
- coord[i] = line.Get_P0()[i] + maxt[intersection_plane] * line.Get_DP()[i];
- if ((coord[i] < boxmin[i]) || (coord[i] > boxmax[i])) {
- return OUTSIDE; // ray is outside the box
- }
-
- } else {
-
- coord[i] = candidateplane[i];
-
- }
- }
- }
- return OVERLAPPED;
-}
-#endif // Alternate Overlap Test for AABox-Ray
-
-
-/***********************************************************************************************
- * CollisionMath::Overlap_Test -- Tests overlap between an AABox and a triangle *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const TriClass & tri)
-{
- CastResultStruct res;
- CollisionMath::Collide(box,Vector3(0,0,0),tri,&res);
- return eval_overlap_collision(res);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Collide -- Collision test for a moving AABox and a plane *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide
-(
- const AABoxClass & box,
- const Vector3 & move_vector,
- const PlaneClass & plane,
- CastResultStruct * result
-)
-{
- float frac;
-
- float extent = box.Project_To_Axis(plane.N);
- float dist = Vector3::Dot_Product(plane.N,box.Center) + plane.D;
- float move = Vector3::Dot_Product(plane.N,move_vector);
-
- if (dist > extent) {
- if (dist + move > extent) {
- // entire move ok!
- frac = 1.0f;
- } else {
- // partial move allowed
- frac = (extent - dist) / move;
- }
-
- } else if (dist < -extent) {
- if (dist + move < -extent) {
- // entire move ok!
- frac = 1.0f;
- } else {
- // partial move allowed
- frac = (-extent - dist) / move;
- }
-
- } else {
- result->StartBad = true;
- result->Normal = plane.N;
- return true;
- }
-
- if (frac < result->Fraction) {
- result->Fraction = frac;
- result->Normal = plane.N;
- if (result->ComputeContactPoint) {
- Vector3 move_dir(move_vector);
- move_dir.Normalize();
- float move_extent = Vector3::Dot_Product(box.Extent,move_dir);
- result->ContactPoint = box.Center + result->Fraction * move_vector + move_extent * move_dir;
- }
- return true;
- }
-
- return false;
-}
-
-
-
-
-
-/*
-** AABCollisionStruct
-** Contains all of the intermediate and temporary values used by
-** the set of functions used in detecting collisions for aab's
-*/
-struct AABCollisionStruct
-{
- AABCollisionStruct(const AABoxClass &box0,const Vector3 &move0,const AABoxClass & box1,const Vector3 &move1) :
- StartBad(true), // Startbad is true until one of the axes clears it
- AxisId(-1), // AxisId will be the axis that allowed the longest move
- MaxFrac(0.0f), // MaxFrac is the longest allowed move so far
- Box0(box0),
- Box1(box1)
- {
- Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
- Vector3::Subtract(move1,move0,&M); // move vector relative to stationary box0
- }
-
- bool StartBad; // Inital configuration is intersecting?
- float MaxFrac; // Longest move allowed so far
- int AxisId; // Last separating axis
- int Side; // which side of the interval
-
- Vector3 C; // Vector from the center0 to center1
- Vector3 M; // Move vector relative to stationary box0
-
- const AABoxClass & Box0;
- const AABoxClass & Box1;
-
-private:
-
- //not implemented
- AABCollisionStruct(const AABCollisionStruct&);
- AABCollisionStruct & operator = (const AABCollisionStruct&);
-};
-
-
-/***********************************************************************************************
- * aab_separation_test -- tests two AAB's for separation on an axis *
- * *
- * This function is very similar to the obb_separation_test. If a flaw is found in either, *
- * we should update the other... *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-static inline bool aab_separation_test
-(
- AABCollisionStruct & context,
- int axis
-)
-{
- // ra = box0 projection onto the axis
- // rb = box1 projection onto the axis
- // u0 = projected distance between the box centers at t0
- // u1 = projected distance between the box centers at t1
- float ra = context.Box0.Extent[axis];
- float rb = context.Box1.Extent[axis];
- float u0 = context.C[axis];
- float u1 = u0 + context.M[axis];
-
- float tmp;
- float rsum = ra+rb;
-
- if ( u0 + WWMATH_EPSILON > rsum ) {
- context.StartBad = false;
- if ( u1 > rsum ) {
- context.MaxFrac = 1.0f;
- return true;
- } else {
- tmp = (rsum-u0)/(u1-u0);
- if ( tmp > context.MaxFrac ) {
- context.MaxFrac = tmp;
- context.AxisId = axis;
- context.Side = +1;
- }
- }
- } else if ( u0 - WWMATH_EPSILON < -rsum ) {
- context.StartBad = false;
- if ( u1 < -rsum ) {
- context.MaxFrac = 1.0f;
- return true;
- } else {
- tmp = (-rsum-u0)/(u1-u0);
- if ( tmp > context.MaxFrac ) {
- context.MaxFrac = tmp;
- context.AxisId = axis;
- context.Side = -1;
- }
- }
- }
- return false;
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Collide -- Collision test for two moving AABoxes *
- * *
- * this function sweeps two AABoxes and finds the first time of collision. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * currently there is no parateter for the movement of the second box. the internal code *
- * can handle it though. *
- * *
- * HISTORY: *
- * 11/19/99 gth : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide(const AABoxClass & box,const Vector3 & move,const AABoxClass & box2,CastResultStruct * result)
-{
- /*
- ** Test the X-axis
- ** ra = box projection onto the axis
- ** rb = box2 projection onto the axis
- ** u0 = projected distance between the box centers at t0
- ** u1 = projected distance between the box centers at t1
- */
- AABCollisionStruct context(box,move,box2,Vector3(0,0,0));
-
- if (aab_separation_test(context,0)) {
- goto exit;
- }
-
- if (aab_separation_test(context,1)) {
- goto exit;
- }
-
- if (aab_separation_test(context,2)) {
- goto exit;
- }
-
-exit:
-
- if (context.StartBad) {
- result->StartBad = true;
- result->Fraction = 0.0f;
- return true;
- }
-
- if (context.MaxFrac < result->Fraction) {
-
- result->Fraction = context.MaxFrac;
- result->Normal.Set(0,0,0);
- result->Normal[context.AxisId] = -context.Side;
-
- if (result->ComputeContactPoint) {
- //WWASSERT(0); // TODO
- WWDEBUG_SAY(("AABox-AABox collision does not currently support contact point computation\r\n"));
- }
-
- return true;
- }
- return false;
-}
diff --git a/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp b/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
deleted file mode 100644
index 0d38fd6bed..0000000000
--- a/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
+++ /dev/null
@@ -1,1184 +0,0 @@
-/*
-** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
-**
-** This program 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 3 of the License, or
-** (at your option) any later version.
-**
-** This program 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 this program. If not, see .
-*/
-
-/***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/wwmath/colmathaabtri.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 1/15/02 2:46p $*
- * *
- * $Revision:: 19 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * aabtri_separation_test -- test the projected extents for separation *
- * aabtri_check_axis -- project the aab and tri onto an arbitrary axis *
- * aabtri_check_cross_axis -- projects aab and tri onto a "cross" axis *
- * aabtri_check_basis_axis -- projects the aab and tri onto a basis axis *
- * aabtri_check_normal_axis -- project the box and tri onto the tri-normal *
- * eval_side -- returns -1,0,+1 depending on the sign of val and side *
- * aabtri_compute_contact_normal -- computes the normal of the collision *
- * CollisionMath::Collide -- collide an aabox into a triangle *
- * aabtri_intersect_cross_axis -- intersection check for a "cross-product" axis *
- * aabtri_intersect_basis_axis -- intersection check for a basis axis *
- * aabtri_intersect_normal_axis -- intersection check for the triangle normal *
- * CollisionMath::Intersection_Test -- Intersection check for an AABox and a triangle *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-
-#include "colmath.h"
-#include "aabox.h"
-#include "tri.h"
-#include "wwdebug.h"
-
-
-/*
-** Separating Axes have to be rejected if their length is smaller than some epsilon.
-** Otherwise, erroneous results can be reported.
-*/
-#define AXISLEN_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON // squared length of a separating axis must be larger than this
-
-
-/*
-** Axes used in Box-Tri intersection tests
-** The axes of the box are A0,A1,A2. N is the normal of the triangle,
-** E0,E1,E2 are direction vectors for the edges of the triangle.
-** (the box axes are labeled A0,A1,A2 as a holdover from the obbox-obbox
-** collision code which this was derived from where there are two boxes
-** A and B)
-*/
-enum
-{
- INTERSECTION = 0,
- AXIS_N, // normal of the triangle
- AXIS_A0, // first basis vector of the box
- AXIS_A1, // second basis vector of the box
- AXIS_A2, // third basis vector of the box
-
- AXIS_A0E0, // box0 x edge0...
- AXIS_A1E0,
- AXIS_A2E0,
- AXIS_A0E1,
- AXIS_A1E1,
- AXIS_A2E1,
- AXIS_A0E2,
- AXIS_A1E2,
- AXIS_A2E2
-};
-
-
-/******************************************************************************************
-
- AABox->Triangle collision
-
- This code is basically a special-case optimization of the OBBox->Triangle collision
- detection code. There are many dot and cross products that can be simplified due
- to the fact that we know the axes of the boxes are always the same and are aligned
- with the world coordinate axes.
-
- Each axis test will use the following logic:
- Project D onto the axis being used, it is the separation distance. If the
- projection of the extent of the box + the projection of the extent of the
- tri is greater than D*axis then the two intersect
-
- March 13, 2000 - Modified these routines to all use a static instance of
- the BTCollisionStruct. The compiler was generating lots of extra code for the
- constructor of this object and testing determined that re-using the same static
- struct was slightly faster anyway.
- NOTE: this makes the code not Thread-Safe!!!!
-
-
-******************************************************************************************/
-
-/*
-** BoxTriColStruct
-** Scratchpad variables for the AABox-Triangle collision detection functions. One instance
-** of this structure will be used for all of the local variables and its pointer will be
-** handed of to various inline functions for the axis tests.
-** Note that much of the code needs the un-normalized triangle normal. For this reason,
-** I have to compute N rather than copying it from the triangle. (commenting this to
-** avoid re-generating a difficult to find bug that I had)
-*/
-struct BTCollisionStruct
-{
- BTCollisionStruct(void) {}
-
- void Init(const AABoxClass &box,const Vector3 &move,const TriClass &tri,const Vector3 &trimove)
- {
- StartBad = true; // true until an axis clears it
- MaxFrac = -0.01f; // maximum move allowed so far
- AxisId = INTERSECTION; // axis that allowed the longest move
- Point = 0; // index of triangle point that was closest to the box
- Side = 0; // side of the interval
- Box = &box;
- Tri = &tri;
- BoxMove = &move;
- TriMove = &trimove;
-
- Vector3::Subtract(*tri.V[0],box.Center,&D); // vector from center of box to vertex 0
- Vector3::Subtract(move,trimove,&Move); // move vector relative to stationary triangle
-
- Vector3::Subtract(*tri.V[1],*tri.V[0],&E[0]);
- Vector3::Subtract(*tri.V[2],*tri.V[0],&E[1]);
- Vector3::Subtract(E[1],E[0],&E[2]);
-
- Vector3::Cross_Product(E[0],E[1],&N);
- }
-
- bool StartBad; // Inital configuration is intersecting?
- float MaxFrac; // Longest move allowed so far
-
- int AxisId; // Last separating axis
- int Side; // which side of the interval
- int Point; // Index of the "closest" triangle point (or one of them)
-
- int TestAxisId; // Axis 'id' we're working on
- int TestSide; // Was the axis we're working on flipped
- int TestPoint; // Index of the closest vertex
- Vector3 TestAxis; // Axis we're working on
-
- Vector3 D; // Vector from the center of the box to v0
- Vector3 Move; // Move vector relative to stationary triangle
- float AE[3][3]; // Dot products of the Basis vectors and edges
- float AN[3]; // Dot products of the Basis vectors and the normal
- Vector3 AxE[3][3]; // Cross products of the Basis vectors and edges
-
- Vector3 E[3]; // edge vectors for the triangle
- Vector3 N; // normal (NOT normalized!!!)
- Vector3 FinalD; // Vector from center of box to v0 at end of move
-
- const AABoxClass * Box;
- const TriClass * Tri;
- const Vector3 * BoxMove;
- const Vector3 * TriMove;
-
-private:
-
- // not implemented
- BTCollisionStruct(const BTCollisionStruct &);
- BTCollisionStruct & operator = (const BTCollisionStruct &);
-};
-
-static BTCollisionStruct CollisionContext;
-
-/***********************************************************************************************
- * aabtri_separation_test -- test the projected extents for separation *
- * *
- * Once the extents are projected onto the axis, this function contains *
- * the logic that determines the allowed fraction. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- * 7/12/99 GTH : Converted original OBBox code to AABox *
- *=============================================================================================*/
-static inline bool aabtri_separation_test
-(
- float lp,float leb0,float leb1
-)
-{
- /*
- ** - If (I'm no more than 'EPSILON' embedded in the wall)
- ** - not startbad
- ** - If (I'm moving towards)
- ** - fraction = How far I can move before embedding (can be negative if started embedded)
- ** - If (I can take entire move)
- ** - accept entire move
- ** - Else If (I can move more than I could have before; *negative always fails!)
- ** - update fraction
- ** - Else
- ** - Accept entire move since I'm not moving towards
- */
- float eps = 0.0f;
- if (lp - leb0 <= 0.0f) {
- eps = COLLISION_EPSILON * CollisionContext.TestAxis.Length(); // trying to only compute epsilon if I have to
- }
-
- if (lp - leb0 > -eps) {
- CollisionContext.StartBad = false;
- if (leb1 - leb0 > 0.0f) {
- float frac = (lp-leb0)/(leb1-leb0);
- if (frac >= 1.0f) {
- /* moving toward but not hitting triangle */
- CollisionContext.AxisId = CollisionContext.TestAxisId;
- CollisionContext.MaxFrac = 1.0f;
- return true;
- } else {
- /* moving toward, hitting triangle */
- if (frac > CollisionContext.MaxFrac) {
- CollisionContext.MaxFrac = frac;
- CollisionContext.AxisId = CollisionContext.TestAxisId;
- CollisionContext.Side = CollisionContext.TestSide;
- CollisionContext.Point = CollisionContext.TestPoint;
- }
- }
- } else {
- /* moving away or not moving */
- CollisionContext.AxisId = CollisionContext.TestAxisId;
- CollisionContext.MaxFrac = 1.0f;
- return true;
- }
- }
- return false;
-}
-
-
-/***********************************************************************************************
- * aabtri_check_axis -- project the aab and tri onto an arbitrary axis *
- * *
- * projects the box and the triangle onto the given axis and calls *
- * obbtri_separation_test. return true if separation was detected *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- * 7/12/99 GTH : converted to AABox *
- *=============================================================================================*/
-static inline bool aabtri_check_axis(void)
-{
- float dist; // separation along the axis
- float axismove; // size of the move along the axis.
- float leb0; // initial coordinate of the leading edge of the box
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
- float tmp; // temporary
-
- dist = Vector3::Dot_Product(CollisionContext.D,CollisionContext.TestAxis);
- axismove = Vector3::Dot_Product(CollisionContext.Move,CollisionContext.TestAxis);
-
- // I want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axismove = -axismove;
- CollisionContext.TestAxis = -CollisionContext.TestAxis;
- CollisionContext.TestSide = -1.0f;
- } else {
- CollisionContext.TestSide = 1.0f;
- }
-
- // compute coordinates of the leading edge of the box at t0 and t1
- leb0 = CollisionContext.Box->Extent.X * WWMath::Fabs(CollisionContext.TestAxis.X) +
- CollisionContext.Box->Extent.Y * WWMath::Fabs(CollisionContext.TestAxis.Y) +
- CollisionContext.Box->Extent.Z * WWMath::Fabs(CollisionContext.TestAxis.Z);
- leb1 = leb0 + axismove;
-
- // compute coordinate of "leading edge of the triangle" relative to the box center.
- lp = 0;
- tmp = Vector3::Dot_Product(CollisionContext.E[0],CollisionContext.TestAxis); if (tmp < lp) lp = tmp;
- tmp = Vector3::Dot_Product(CollisionContext.E[1],CollisionContext.TestAxis); if (tmp < lp) lp = tmp;
- lp = dist + lp;
-
- return aabtri_separation_test(/*CollisionContext,*/lp,leb0,leb1);
-}
-
-
-/***********************************************************************************************
- * aabtri_check_cross_axis -- projects aab and tri onto a "cross" axis *
- * *
- * Assumes that the axis given is one generated from a cross product of one of the edge and *
- * basis vectors. In this case, the box extent can be optimized and only two triangle verts *
- * need to be checked. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool aabtri_check_cross_axis
-(
- float dp,
- int dpi,
- float leb0
-)
-{
- float p0; // distance from box center to vertex 0
- float axismove; // size of the move along the axis.
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- p0 = Vector3::Dot_Product(CollisionContext.D,CollisionContext.TestAxis);
- axismove = Vector3::Dot_Product(CollisionContext.Move,CollisionContext.TestAxis);
-
- // I want the axis centered at the box, pointing towards the triangle
- if (p0 < 0) {
- p0 = -p0;
- axismove = -axismove;
- dp = -dp;
- CollisionContext.TestAxis = -CollisionContext.TestAxis;
- CollisionContext.TestSide = -1.0f;
- } else {
- CollisionContext.TestSide = 1.0f;
- }
-
- // compute coordinates of the leading edge of the box at t1
- leb1 = leb0 + axismove;
-
- // compute coordinate of "leading edge of the triangle" relative to the box center.
- lp = 0; CollisionContext.TestPoint = 0;
- if (dp < 0) { lp = dp; CollisionContext.TestPoint = dpi; }
- lp = p0 + lp;
-
- return aabtri_separation_test(/*CollisionContext,*/lp,leb0,leb1);
-}
-
-
-/***********************************************************************************************
- * aabtri_check_basis_axis -- projects the aab and tri onto a basis axis *
- * *
- * Projects the box and triangle onto an axis that is assumed to be a basis *
- * vector from the box. In this case, we can skip a dot-product and use the *
- * corresponding extent of the box (which is passed in as leb0). *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool aabtri_check_basis_axis
-(
- float leb0,
- float dp1,
- float dp2
-)
-{
- float dist; // separation along the axis
- float axismove; // size of the move along the axis.
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(CollisionContext.D,CollisionContext.TestAxis);
- axismove = Vector3::Dot_Product(CollisionContext.Move,CollisionContext.TestAxis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axismove = -axismove;
- dp1 = -dp1;
- dp2 = -dp2;
- CollisionContext.TestAxis = -CollisionContext.TestAxis;
- CollisionContext.TestSide = -1.0f;
- } else {
- CollisionContext.TestSide = 1.0f;
- }
-
- // this is the "optimization", leb0 = one of the extents
- leb1 = leb0 + axismove;
-
- // compute coordinate of "leading edge of the polygon" relative to the box center.
- lp = 0; CollisionContext.TestPoint = 0;
- if (dp1 < lp) { lp = dp1; CollisionContext.TestPoint = 1; }
- if (dp2 < lp) { lp = dp2; CollisionContext.TestPoint = 2; }
- lp = dist + lp;
-
- return aabtri_separation_test(/*CollisionContext,*/lp,leb0,leb1);
-}
-
-
-/***********************************************************************************************
- * aabtri_check_normal_axis -- project the box and tri onto the tri-normal *
- * *
- * Projects the box and triangle onto an axis that is assumed to be the normal *
- * vector from the triangle. In this case, the triangle extents are zero. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool aabtri_check_normal_axis(void)
-{
- float dist; // separation along the axis
- float axismove; // size of the move along the axis.
- float leb0; // initial coordinate of the leading edge of the box
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(CollisionContext.D,CollisionContext.TestAxis);
- axismove = Vector3::Dot_Product(CollisionContext.Move,CollisionContext.TestAxis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axismove = -axismove;
- CollisionContext.TestAxis = -CollisionContext.TestAxis;
- CollisionContext.TestSide = -1.0f;
- } else {
- CollisionContext.TestSide = 1.0f;
- }
-
- leb0 = CollisionContext.Box->Extent.X * WWMath::Fabs(CollisionContext.AN[0]) +
- CollisionContext.Box->Extent.Y * WWMath::Fabs(CollisionContext.AN[1]) +
- CollisionContext.Box->Extent.Z * WWMath::Fabs(CollisionContext.AN[2]);
- leb1 = leb0 + axismove;
- CollisionContext.TestPoint = 0;
- lp = dist; // this is the "optimization", don't have to find lp
-
- return aabtri_separation_test(/*CollisionContext,*/lp,leb0,leb1);
-}
-
-/***********************************************************************************************
- * eval_side -- returns -1,0,+1 depending on the sign of val and side *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline float eval_side(float val,int side)
-{
- if (val > 0.0f) {
- return side;
- } else if (val < 0.0f) {
- return -side;
- } else {
- return 0.0f;
- }
-}
-
-/***********************************************************************************************
- * aabtri_compute_contact_normal -- computes the normal of the collision *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void aabtri_compute_contact_normal
-(
- Vector3 & set_norm
-)
-{
-#if 1
- switch(CollisionContext.AxisId)
- {
- case INTERSECTION:
- set_norm = CollisionContext.N;
- set_norm.Normalize();
- break;
- case AXIS_N:
- set_norm = -CollisionContext.Side * CollisionContext.N;
- set_norm.Normalize();
- break;
- case AXIS_A0:
- set_norm = -CollisionContext.Side * Vector3(1.0f,0.0f,0.0f);
- break;
- case AXIS_A1:
- set_norm = -CollisionContext.Side * Vector3(0.0f,1.0f,0.0f);
- break;
- case AXIS_A2:
- set_norm = -CollisionContext.Side * Vector3(0.0f,0.0f,1.0f);
- break;
- case AXIS_A0E0:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[0][0];
- set_norm.Normalize();
- break;
- case AXIS_A1E0:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[1][0];
- set_norm.Normalize();
- break;
- case AXIS_A2E0:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[2][0];
- set_norm.Normalize();
- break;
- case AXIS_A0E1:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[0][1];
- set_norm.Normalize();
- break;
- case AXIS_A1E1:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[1][1];
- set_norm.Normalize();
- break;
- case AXIS_A2E1:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[2][1];
- set_norm.Normalize();
- break;
- case AXIS_A0E2:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[0][2];
- set_norm.Normalize();
- break;
- case AXIS_A1E2:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[1][2];
- set_norm.Normalize();
- break;
- case AXIS_A2E2:
- set_norm = -CollisionContext.Side * CollisionContext.AxE[2][2];
- set_norm.Normalize();
- break;
- }
-
- WWASSERT(set_norm.Length2() > 0.0f);
-
-#else
- set_norm = *CollisionContext.N;
- set_norm.Normalize();
- if (Vector3::Dot_Product(set_norm,CollisionContext.Move) > 0.0f) {
- set_norm = -(set_norm);
- }
-#endif
-}
-
-inline void VERIFY_CROSS(const Vector3 & a, const Vector3 & b,const Vector3 & cross)
-{
-#ifdef WWDEBUG
- Vector3 tmp_cross;
- Vector3::Cross_Product(a,b,&tmp_cross);
- Vector3 diff = cross - tmp_cross;
- WWASSERT(WWMath::Fabs(diff.Length()) < 0.0001f);
-#endif
-}
-
-/***********************************************************************************************
- * CollisionMath::Collide -- collide an aabox into a triangle *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide
-(
- const AABoxClass & box,
- const Vector3 & move,
- const TriClass & tri,
- CastResultStruct * result
-)
-{
- TRACK_COLLISION_AABOX_TRI;
-
- float dp,leb0;
-
- CollisionContext.Init(box,move,tri,Vector3(0,0,0));
-
- /*
- ** AXIS_N
- */
- CollisionContext.TestAxis = CollisionContext.N;
- CollisionContext.TestAxisId = AXIS_N;
- CollisionContext.AN[0] = CollisionContext.N.X;
- CollisionContext.AN[1] = CollisionContext.N.Y;
- CollisionContext.AN[2] = CollisionContext.N.Z;
- if (aabtri_check_normal_axis()) goto exit;
-
- /*
- ** AXIS_A0
- */
- CollisionContext.TestAxis.Set(1,0,0);
- CollisionContext.TestAxisId = AXIS_A0;
- CollisionContext.AE[0][0] = CollisionContext.E[0].X;
- CollisionContext.AE[0][1] = CollisionContext.E[1].X;
- if (aabtri_check_basis_axis(box.Extent.X,CollisionContext.AE[0][0],CollisionContext.AE[0][1])) goto exit;
-
- /*
- ** AXIS_A1
- */
- CollisionContext.TestAxis.Set(0,1,0);
- CollisionContext.TestAxisId = AXIS_A1;
- CollisionContext.AE[1][0] = CollisionContext.E[0].Y;
- CollisionContext.AE[1][1] = CollisionContext.E[1].Y;
- if (aabtri_check_basis_axis(box.Extent.Y,CollisionContext.AE[1][0],CollisionContext.AE[1][1])) goto exit;
-
- /*
- ** AXIS_A2
- */
- CollisionContext.TestAxis.Set(0,0,1);
- CollisionContext.TestAxisId = AXIS_A2;
- CollisionContext.AE[2][0] = CollisionContext.E[0].Z;
- CollisionContext.AE[2][1] = CollisionContext.E[1].Z;
- if (aabtri_check_basis_axis(box.Extent.Z,CollisionContext.AE[2][0],CollisionContext.AE[2][1])) goto exit;
-
- /*
- ** AXIS_A0xE0
- */
- CollisionContext.AxE[0][0].Set(0,-CollisionContext.E[0].Z,CollisionContext.E[0].Y);
- VERIFY_CROSS(Vector3(1,0,0),CollisionContext.E[0],CollisionContext.AxE[0][0]);
- CollisionContext.TestAxis = CollisionContext.AxE[0][0];
- CollisionContext.TestAxisId = AXIS_A0E0;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = CollisionContext.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(CollisionContext.AE[2][0]) + box.Extent[2]*WWMath::Fabs(CollisionContext.AE[1][0]);
- if (aabtri_check_cross_axis(dp,2,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A0xE1
- */
- CollisionContext.AxE[0][1].Set(0,-CollisionContext.E[1].Z,CollisionContext.E[1].Y);
- VERIFY_CROSS(Vector3(1,0,0),CollisionContext.E[1],CollisionContext.AxE[0][1]);
- CollisionContext.TestAxis = CollisionContext.AxE[0][1];
- CollisionContext.TestAxisId = AXIS_A0E1;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -CollisionContext.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(CollisionContext.AE[2][1]) + box.Extent[2]*WWMath::Fabs(CollisionContext.AE[1][1]);
- if (aabtri_check_cross_axis(dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A0xE2
- */
- CollisionContext.AE[0][2] = CollisionContext.E[2].X;
- CollisionContext.AE[1][2] = CollisionContext.E[2].Y;
- CollisionContext.AE[2][2] = CollisionContext.E[2].Z;
-
- CollisionContext.AxE[0][2].Set(0,-CollisionContext.E[2].Z,CollisionContext.E[2].Y);
- VERIFY_CROSS(Vector3(1,0,0),CollisionContext.E[2],CollisionContext.AxE[0][2]);
- CollisionContext.TestAxis = CollisionContext.AxE[0][2];
- CollisionContext.TestAxisId = AXIS_A0E2;
-
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -CollisionContext.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(CollisionContext.AE[2][2]) + box.Extent[2]*WWMath::Fabs(CollisionContext.AE[1][2]);
- if (aabtri_check_cross_axis(dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A1xE0
- */
- CollisionContext.AxE[1][0].Set(CollisionContext.E[0].Z,0,-CollisionContext.E[0].X);
- VERIFY_CROSS(Vector3(0,1,0),CollisionContext.E[0],CollisionContext.AxE[1][0]);
- CollisionContext.TestAxis = CollisionContext.AxE[1][0];
- CollisionContext.TestAxisId = AXIS_A1E0;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = CollisionContext.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(CollisionContext.AE[2][0]) + box.Extent[2]*WWMath::Fabs(CollisionContext.AE[0][0]);
- if (aabtri_check_cross_axis(dp,2,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A1xE1
- */
- CollisionContext.AxE[1][1].Set(CollisionContext.E[1].Z,0,-CollisionContext.E[1].X);
- VERIFY_CROSS(Vector3(0,1,0),CollisionContext.E[1],CollisionContext.AxE[1][1]);
- CollisionContext.TestAxis = CollisionContext.AxE[1][1];
- CollisionContext.TestAxisId = AXIS_A1E1;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -CollisionContext.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(CollisionContext.AE[2][1]) + box.Extent[2]*WWMath::Fabs(CollisionContext.AE[0][1]);
- if (aabtri_check_cross_axis(dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A1xE2
- */
- CollisionContext.AxE[1][2].Set(CollisionContext.E[2].Z,0,-CollisionContext.E[2].X);
- VERIFY_CROSS(Vector3(0,1,0),CollisionContext.E[2],CollisionContext.AxE[1][2]);
- CollisionContext.TestAxis = CollisionContext.AxE[1][2];
- CollisionContext.TestAxisId = AXIS_A1E2;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -CollisionContext.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(CollisionContext.AE[2][2]) + box.Extent[2]*WWMath::Fabs(CollisionContext.AE[0][2]);
- if (aabtri_check_cross_axis(dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A2xE0
- */
- CollisionContext.AxE[2][0].Set(-CollisionContext.E[0].Y,CollisionContext.E[0].X,0);
- VERIFY_CROSS(Vector3(0,0,1),CollisionContext.E[0],CollisionContext.AxE[2][0]);
- CollisionContext.TestAxis = CollisionContext.AxE[2][0];
- CollisionContext.TestAxisId = AXIS_A2E0;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = CollisionContext.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(CollisionContext.AE[1][0]) + box.Extent[1]*WWMath::Fabs(CollisionContext.AE[0][0]);
- if (aabtri_check_cross_axis(dp,2,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A2xE1
- */
- CollisionContext.AxE[2][1].Set(-CollisionContext.E[1].Y,CollisionContext.E[1].X,0);
- VERIFY_CROSS(Vector3(0,0,1),CollisionContext.E[1],CollisionContext.AxE[2][1]);
- CollisionContext.TestAxis = CollisionContext.AxE[2][1];
- CollisionContext.TestAxisId = AXIS_A2E1;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -CollisionContext.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(CollisionContext.AE[1][1]) + box.Extent[1]*WWMath::Fabs(CollisionContext.AE[0][1]);
- if (aabtri_check_cross_axis(dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A2xE2
- */
- CollisionContext.AxE[2][2].Set(-CollisionContext.E[2].Y,CollisionContext.E[2].X,0);
- VERIFY_CROSS(Vector3(0,0,1),CollisionContext.E[2],CollisionContext.AxE[2][2]);
- CollisionContext.TestAxis = CollisionContext.AxE[2][2];
- CollisionContext.TestAxisId = AXIS_A2E2;
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -CollisionContext.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(CollisionContext.AE[1][2]) + box.Extent[1]*WWMath::Fabs(CollisionContext.AE[0][2]);
- if (aabtri_check_cross_axis(dp,1,leb0)) goto exit;
- }
-
- /*
- ** Last ditch effort, check an axis based on the move vector
- */
- if (!CollisionContext.StartBad) {
- CollisionContext.TestPoint = CollisionContext.Point;
- CollisionContext.TestAxisId = CollisionContext.AxisId;
-
- CollisionContext.TestAxis.Set(0,-CollisionContext.Move.Z,CollisionContext.Move.Y); // A0 X Move
- VERIFY_CROSS(Vector3(1,0,0),CollisionContext.Move,CollisionContext.TestAxis);
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- if (aabtri_check_axis()) goto exit;
- }
- CollisionContext.TestAxis.Set(CollisionContext.Move.Z,0,-CollisionContext.Move.X); // A1 X Move
- VERIFY_CROSS(Vector3(0,1,0),CollisionContext.Move,CollisionContext.TestAxis);
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- if (aabtri_check_axis()) goto exit;
- }
- CollisionContext.TestAxis.Set(-CollisionContext.Move.Y,CollisionContext.Move.X,0); // A2 X Move
- VERIFY_CROSS(Vector3(0,0,1),CollisionContext.Move,CollisionContext.TestAxis);
- if (CollisionContext.TestAxis.Length2() > AXISLEN_EPSILON2) {
- if (aabtri_check_axis()) goto exit;
- }
- }
-
-exit:
-
- /*
- ** If MaxFrac is less than zero, clamp it to zero. Negative fractions can
- ** leak through this routine due to the epsilon in the separation test.
- */
- if (CollisionContext.MaxFrac < 0.0f) {
- CollisionContext.MaxFrac = 0.0f;
- }
-
- /*
- ** If the triangle and box are intersecting before the move, return that
- ** result.
- */
- if (CollisionContext.StartBad) {
- result->StartBad = true;
- result->Fraction = 0.0f;
- result->Normal = *tri.N;
- TRACK_COLLISION_AABOX_TRI_HIT;
- return true;
- }
-
- /*
- ** If the fraction allowed is basically equal to the fraction allowed by
- ** another polygon, try to pick the polygon which is least "edge-on" to the
- ** move.
- */
- if ((CollisionContext.MaxFrac <= result->Fraction) && (CollisionContext.MaxFrac < 1.0f)) {
-
- /*
- ** Reflect the normal if it is pointing the same way as our move
- ** (probably hitting the back side of a polygon)
- */
- Vector3 tmp_norm(0.0f,0.0f,0.0f);
- aabtri_compute_contact_normal(tmp_norm);
-// if (Vector3::Dot_Product(tmp_norm,move) > 0.0f) {
-// tmp_norm = -tmp_norm;
-// }
-
- /*
- ** If this polygon cuts off more of the move -OR- this polygon cuts
- ** of the same amount but has a "better" normal, then use this normal
- */
- if ( (WWMath::Fabs(CollisionContext.MaxFrac - result->Fraction) > WWMATH_EPSILON) ||
- (Vector3::Dot_Product(tmp_norm,move) < Vector3::Dot_Product(result->Normal,move)))
- {
- result->Normal = tmp_norm;
- WWASSERT(WWMath::Fabs(result->Normal.Length() - 1.0f) < WWMATH_EPSILON);
- }
-
- result->Fraction = CollisionContext.MaxFrac;
-
- TRACK_COLLISION_AABOX_TRI_HIT;
- return true;
- }
-
- return false;
-}
-
-
-
-/*
-** AABTIntersectStruct
-** Scratchpad variables for the AABox-Triangle intersection functions. One instance
-** of this structure will be used for all of the local variables and its pointer will be
-** handed of to various inline functions for the axis tests.
-** Note that much of the code needs the un-normalized triangle normal. For this reason,
-** I have to compute N rather than copying it from the triangle. (commenting this to
-** avoid re-generating a difficult to find bug that I had)
-*/
-struct AABTIntersectStruct
-{
- AABTIntersectStruct(void) :
- Box(NULL),
- Tri(NULL)
- {
- }
-
- void Init(const AABoxClass &box,const TriClass &tri)
- {
- Box = &box;
- Tri = &tri;
- Vector3::Subtract(*tri.V[0],box.Center,&D); // vector from center of box to vertex 0
- Vector3::Subtract(*tri.V[1],*tri.V[0],&E[0]);
- Vector3::Subtract(*tri.V[2],*tri.V[0],&E[1]);
- Vector3::Subtract(E[1],E[0],&E[2]);
-
- Vector3::Cross_Product(E[0],E[1],&N);
- }
-
-
- Vector3 D; // Vector from the center of the box to v0
- float AE[3][3]; // Dot products of the Basis vectors and edges
- float AN[3]; // Dot products of the Basis vectors and the normal
- Vector3 AxE[3][3]; // Cross produts of the Basis vectors and edges
-
- Vector3 E[3]; // edge vectors for the triangle
- Vector3 N; // normal (NOT normalized!!!)
-
- const AABoxClass * Box;
- const TriClass * Tri;
-
-private:
-
- // not implemented
- AABTIntersectStruct(const AABTIntersectStruct &);
- AABTIntersectStruct & operator = (const AABTIntersectStruct &);
-};
-
-static AABTIntersectStruct IntersectContext;
-
-
-/***********************************************************************************************
- * aabtri_intersect_cross_axis -- intersection check for a "cross-product" axis *
- * *
- * axis being checked is a cross product between a triangle edge and a box basis vector *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool aabtri_intersect_cross_axis
-(
- Vector3 & axis,
- float dp,
- float leb0
-)
-{
- float p0; // distance from box center to vertex 0
- float lp; // leading edge of the polygon.
-
- p0 = Vector3::Dot_Product(IntersectContext.D,axis);
-
- // I want the axis centered at the box, pointing towards the triangle
- if (p0 < 0) {
- p0 = -p0;
- axis = -axis;
- dp = -dp;
- }
-
- // compute coordinate of "leading edge of the triangle" relative to the box center.
- lp = 0;
- if (dp < 0) { lp = dp; }
- lp = p0 + lp;
-
- return (lp - leb0 > -WWMATH_EPSILON);
-}
-
-
-/***********************************************************************************************
- * aabtri_intersect_basis_axis -- intersection check for a basis axis *
- * *
- * axis being checked is one of the basis vectors for the box *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool aabtri_intersect_basis_axis
-(
- Vector3 & axis,
- float leb0,
- float dp1,
- float dp2
-)
-{
- float dist; // separation along the axis
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(IntersectContext.D,axis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axis = -axis;
- dp1 = -dp1;
- dp2 = -dp2;
- }
-
- // compute coordinate of "leading edge of the polygon" relative to the box center.
- lp = 0;
- if (dp1 < lp) { lp = dp1; }
- if (dp2 < lp) { lp = dp2; }
- lp = dist + lp;
-
- return (lp - leb0 > -WWMATH_EPSILON);
-}
-
-
-/***********************************************************************************************
- * aabtri_intersect_normal_axis -- intersection check for the triangle normal *
- * *
- * axis being checked is the triangle's normal *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool aabtri_intersect_normal_axis
-(
- Vector3 & axis
-)
-{
- float dist; // separation along the axis
- float leb0; // initial coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(IntersectContext.D,axis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axis = -axis;
- }
-
- leb0 = IntersectContext.Box->Extent.X * WWMath::Fabs(IntersectContext.AN[0]) +
- IntersectContext.Box->Extent.Y * WWMath::Fabs(IntersectContext.AN[1]) +
- IntersectContext.Box->Extent.Z * WWMath::Fabs(IntersectContext.AN[2]);
- lp = dist; // this is the "optimization", don't have to find lp
-
- return (lp - leb0 > -WWMATH_EPSILON);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Intersection_Test -- Intersection check for an AABox and a triangle *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/20/00 gth : copied from OBBox version and removed some Dot-products *
- *=============================================================================================*/
-bool CollisionMath::Intersection_Test(const AABoxClass & box,const TriClass & tri)
-{
- Vector3 axis;
- float dp,leb0;
-
- IntersectContext.Init(box,tri);
-
- /*
- ** AXIS_N
- */
- axis = IntersectContext.N;
- IntersectContext.AN[0] = IntersectContext.N.X;
- IntersectContext.AN[1] = IntersectContext.N.Y;
- IntersectContext.AN[2] = IntersectContext.N.Z;
- if (aabtri_intersect_normal_axis(axis)) return false;
-
- /*
- ** AXIS_A0
- */
- axis.Set(1,0,0);
- IntersectContext.AE[0][0] = IntersectContext.E[0].X;
- IntersectContext.AE[0][1] = IntersectContext.E[1].Y;
- if (aabtri_intersect_basis_axis(axis,box.Extent.X,IntersectContext.AE[0][0],IntersectContext.AE[0][1])) return false;
-
- /*
- ** AXIS_A1
- */
- axis.Set(0,1,0);
- IntersectContext.AE[1][0] = IntersectContext.E[0].Y;
- IntersectContext.AE[1][1] = IntersectContext.E[1].Y;
- if (aabtri_intersect_basis_axis(axis,box.Extent.Y,IntersectContext.AE[1][0],IntersectContext.AE[1][1])) return false;
-
- /*
- ** AXIS_A2
- */
- axis.Set(0,0,1);
- IntersectContext.AE[2][0] = IntersectContext.E[0].Z;
- IntersectContext.AE[2][1] = IntersectContext.E[1].Z;
- if (aabtri_intersect_basis_axis(axis,box.Extent.Z,IntersectContext.AE[2][0],IntersectContext.AE[2][1])) return false;
-
- /*
- ** AXIS_A0xE0
- */
- Vector3::Cross_Product(Vector3(1,0,0),IntersectContext.E[0],&IntersectContext.AxE[0][0]);
- axis = IntersectContext.AxE[0][0];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = IntersectContext.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(IntersectContext.AE[2][0]) + box.Extent[2]*WWMath::Fabs(IntersectContext.AE[1][0]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A0xE1
- */
- Vector3::Cross_Product(Vector3(1,0,0),IntersectContext.E[1],&IntersectContext.AxE[0][1]);
- axis = IntersectContext.AxE[0][1];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = -IntersectContext.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(IntersectContext.AE[2][1]) + box.Extent[2]*WWMath::Fabs(IntersectContext.AE[1][1]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A0xE2
- */
- Vector3::Cross_Product(Vector3(1,0,0),IntersectContext.E[2],&IntersectContext.AxE[0][2]);
- axis = IntersectContext.AxE[0][2];
- IntersectContext.AE[1][2] = IntersectContext.E[2].Y;
- IntersectContext.AE[2][2] = IntersectContext.E[2].Z;
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = -IntersectContext.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(IntersectContext.AE[2][2]) + box.Extent[2]*WWMath::Fabs(IntersectContext.AE[1][2]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A1xE0
- */
- Vector3::Cross_Product(Vector3(0,1,0),IntersectContext.E[0],&IntersectContext.AxE[1][0]);
- axis = IntersectContext.AxE[1][0];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = IntersectContext.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(IntersectContext.AE[2][0]) + box.Extent[2]*WWMath::Fabs(IntersectContext.AE[0][0]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A1xE1
- */
- Vector3::Cross_Product(Vector3(0,1,0),IntersectContext.E[1],&IntersectContext.AxE[1][1]);
- axis = IntersectContext.AxE[1][1];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = -IntersectContext.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(IntersectContext.AE[2][1]) + box.Extent[2]*WWMath::Fabs(IntersectContext.AE[0][1]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A1xE2
- */
- Vector3::Cross_Product(Vector3(0,1,0),IntersectContext.E[2],&IntersectContext.AxE[1][2]);
- axis = IntersectContext.AxE[1][2];
- IntersectContext.AE[0][2] = IntersectContext.E[2].X;
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = -IntersectContext.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(IntersectContext.AE[2][2]) + box.Extent[2]*WWMath::Fabs(IntersectContext.AE[0][2]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A2xE0
- */
- Vector3::Cross_Product(Vector3(0,0,1),IntersectContext.E[0],&IntersectContext.AxE[2][0]);
- axis = IntersectContext.AxE[2][0];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = IntersectContext.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(IntersectContext.AE[1][0]) + box.Extent[1]*WWMath::Fabs(IntersectContext.AE[0][0]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A2xE1
- */
- Vector3::Cross_Product(Vector3(0,0,1),IntersectContext.E[1],&IntersectContext.AxE[2][1]);
- axis = IntersectContext.AxE[2][1];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = -IntersectContext.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(IntersectContext.AE[1][1]) + box.Extent[1]*WWMath::Fabs(IntersectContext.AE[0][1]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A2xE2
- */
- Vector3::Cross_Product(Vector3(0,0,1),IntersectContext.E[2],&IntersectContext.AxE[2][2]);
- axis = IntersectContext.AxE[2][2];
- if (axis.Length2() > AXISLEN_EPSILON2) {
- dp = -IntersectContext.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(IntersectContext.AE[1][2]) + box.Extent[1]*WWMath::Fabs(IntersectContext.AE[0][2]);
- if (aabtri_intersect_cross_axis(axis,dp,leb0)) return false;
- }
-
- return true;
-}
diff --git a/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp b/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
deleted file mode 100644
index 0ddbbdf8d7..0000000000
--- a/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
+++ /dev/null
@@ -1,1409 +0,0 @@
-/*
-** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
-**
-** This program 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 3 of the License, or
-** (at your option) any later version.
-**
-** This program 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 this program. If not, see .
-*/
-
-/***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/wwmath/colmathobbobb.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 1/04/02 6:29p $*
- * *
- * $Revision:: 15 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * obb_intersect_box0_basis -- intersection test for a basis vector from box0 *
- * obb_intersect_box1_basis -- intersection test for a basis vector from box1 *
- * obb_intersect_axis -- intersection test for a axis *
- * intersect_obb_obb -- test two OBBoxes for intersection *
- * CollisionMath::Intersection_Test -- test two obb's for intersection *
- * CollisionMath::Intersection_Test -- test an OBB for intersection with an AAB *
- * CollisionMath::Intersection_Test -- Test an AAB for intersection with an OBB *
- * obb_separation_test -- test the projections of two obb's for separation *
- * obb_check_box0_basis -- projects the boxes onto a basis vector from box0 *
- * obb_check_box1_basis -- projects the two obbs onto a basis vector from box1 *
- * obb_check_axis -- projects the obbs onto an arbitrary axis *
- * obb_compute_projections -- computes projections of two boxes onto an arbitrary axis *
- * compute_contact_normal -- computes the contact normal (after contact is detected) *
- * eval_side -- returns -1,0,1 depending on ab and side *
- * compute_contact_point -- computes the contact point (after contact is detected) *
- * collide_obb_obb -- test two obb's for collision *
- * CollisionMath::Collide -- collide two OBB's *
- * CollisionMath::Collide -- collide an OBB with an AAB *
- * CollisionMath::Collide -- collide an AAB with an OBB *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-#include "colmath.h"
-#include "obbox.h"
-#include "aabox.h"
-#include "wwdebug.h"
-
-
-/*
-** Separating Axes have to be rejected if their length is smaller than some epsilon.
-** Otherwise, erroneous results can be reported.
-*/
-#define AXISLEN_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON // squared length of a separating axis must be larger than this
-
-
-enum
-{
- /* Axes used in Box-Box intersection tests */
- INTERSECTION = 0,
- AXIS_A0,
- AXIS_A1,
- AXIS_A2,
- AXIS_B0,
- AXIS_B1,
- AXIS_B2,
- AXIS_A0B0,
- AXIS_A0B1,
- AXIS_A0B2,
- AXIS_A1B0,
- AXIS_A1B1,
- AXIS_A1B2,
- AXIS_A2B0,
- AXIS_A2B1,
- AXIS_A2B2
-};
-
-
-
-/********************************************************************************
-
- OBBox-OBBox intersection detection
-
- As with most of the collision detection functions, this code is based on the theorem
- that given any two non-intersecting convex polyhedra, a separating plane/axis
- can be found that will be defined by one of the face normals of one of the polyhedra
- or the cross product of an edge from each polyhedra.
-
- In the case of two oriented 3D boxes, 15 separating axes must be tested.
- Each of the basis vectors from box A, each of the basis vectors from box B, and
- the cross products of any combination of a basis vector from A and a basis vector
- from B. Some of these separating axis tests can be optimized. For example, if
- the axis being tested is a basis vector from the first box, then that box's
- extent does not need to be projected onto the axis...
-
- The first batch of functions in this module implement a intersection test.
- A boolean is returned indicating whether the two boxes intersect each other
- in any way.
-
- The OBB-ABB and ABB-OBB functions are also implemented in a way that re-uses
- the OBB-OBB code.
-
-********************************************************************************/
-
-
-/**
-** ObbIntersectionStruct
-** Contains all of the intermediate and temporary values used by
-** the set of functions used in detecting intersection for obb's
-*/
-struct ObbIntersectionStruct
-{
- ObbIntersectionStruct(const OBBoxClass &box0,const OBBoxClass & box1) :
- Box0(box0),
- Box1(box1)
- {
- Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
-
- A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
- A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
- A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
-
- B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
- B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
- B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
- }
-
- Vector3 C; // Vector from the center0 to center1
- Vector3 A[3]; // basis vectors for box0
- Vector3 B[3]; // basis vectors for box1
- float AB[3][3]; // dot products of the basis vectors
-
- const OBBoxClass & Box0;
- const OBBoxClass & Box1;
-
-private:
- //not implemented
- ObbIntersectionStruct(const ObbIntersectionStruct&);
- ObbIntersectionStruct & operator = (const ObbIntersectionStruct&);
-};
-
-
-
-/***********************************************************************************************
- * obb_intersect_box0_basis -- intersection test for a basis vector from box0 *
- * *
- * The optimization here is that the projection of the first box is known since the axis is *
- * one of its basis vectors. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static bool obb_intersect_box0_basis
-(
- ObbIntersectionStruct & context,
- int axis_index
-)
-{
- // ra = box0 projection onto the axis
- // rb = box1 projection onto the axis
- float ra = context.Box0.Extent[axis_index];
- float rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[axis_index][0]) +
- WWMath::Fabs(context.Box1.Extent[1]*context.AB[axis_index][1]) +
- WWMath::Fabs(context.Box1.Extent[2]*context.AB[axis_index][2]);
- float rsum = ra+rb;
-
- // u = projected distance between the box centers
- float u = Vector3::Dot_Product(context.C,context.A[axis_index]);
-
- // (gth) the epsilon here was not scaled to the length of the axis so it
- // caused problems when the axis being tested became very small
- return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
-}
-
-
-/***********************************************************************************************
- * obb_intersect_box1_basis -- intersection test for a basis vector from box1 *
- * *
- * The "optimization" here is that the extent for the second box is known since the axis is *
- * one of its basis vectors. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static bool obb_intersect_box1_basis
-(
- ObbIntersectionStruct & context,
- int axis_index
-)
-{
- // ra = box0 projection onto the axis
- // rb = box1 projection onto the axis
- float ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[0][axis_index]) +
- WWMath::Fabs(context.Box0.Extent[1]*context.AB[1][axis_index]) +
- WWMath::Fabs(context.Box0.Extent[2]*context.AB[2][axis_index]);
- float rb = context.Box1.Extent[axis_index];
- float rsum = ra+rb;
-
- // u = projected distance between the box centers
- float u = Vector3::Dot_Product(context.C,context.B[axis_index]);
-
- // (gth) the epsilon here was not scaled to the length of the axis so it
- // caused problems when the axis being tested became very small
- return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
-}
-
-
-/***********************************************************************************************
- * obb_intersect_axis -- intersection test for a axis *
- * *
- * Checks intersection on an arbitrary axis where you've already computed the projectsions. *
- * Many of the later tests in the OBB-OBB algorigthm fall into here since there are *
- * optimizations in computing the projections but they are all specific to the axis being used *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obb_intersect_axis
-(
- ObbIntersectionStruct & context,
- const Vector3 & axis,
- float ra,
- float rb
-)
-{
- float rsum = ra+rb;
- float u = Vector3::Dot_Product(context.C,axis);
-
- // (gth) the epsilon here was not scaled to the length of the axis so it
- // caused problems when the axis being tested became very small
- return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
-}
-
-
-/***********************************************************************************************
- * intersect_obb_obb -- test two OBBoxes for intersection *
- * *
- * This function works in a very similar (but simplified) way as the Collide function. See *
- * the comments in that function for more clues regarding the math involved... *
- * *
- * Due to the re-usage of intermediate calculations, this function is ~2x faster than the *
- * equivalent Oriented_Boxes_Intersect. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-bool intersect_obb_obb
-(
- ObbIntersectionStruct & context
-)
-{
- Vector3 axis;
- float ra,rb;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0
- /////////////////////////////////////////////////////////////////////////
- context.AB[0][0] = Vector3::Dot_Product(context.A[0],context.B[0]);
- context.AB[0][1] = Vector3::Dot_Product(context.A[0],context.B[1]);
- context.AB[0][2] = Vector3::Dot_Product(context.A[0],context.B[2]);
- if (context.Box0.Extent[0] > 0.0f) {
- if (obb_intersect_box0_basis(context,0)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axsis A1
- /////////////////////////////////////////////////////////////////////////
- context.AB[1][0] = Vector3::Dot_Product(context.A[1],context.B[0]);
- context.AB[1][1] = Vector3::Dot_Product(context.A[1],context.B[1]);
- context.AB[1][2] = Vector3::Dot_Product(context.A[1],context.B[2]);
- if (context.Box0.Extent[1] > 0.0f) {
- if (obb_intersect_box0_basis(context,1)) return false;
- }
-
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2
- /////////////////////////////////////////////////////////////////////////
- context.AB[2][0] = Vector3::Dot_Product(context.A[2],context.B[0]);
- context.AB[2][1] = Vector3::Dot_Product(context.A[2],context.B[1]);
- context.AB[2][2] = Vector3::Dot_Product(context.A[2],context.B[2]);
- if (context.Box0.Extent[2] > 0.0f) {
- if (obb_intersect_box0_basis(context,2)) return false;
- }
-
-
- /////////////////////////////////////////////////////////////////////////
- // Axis B0,B1,B2
- /////////////////////////////////////////////////////////////////////////
- if (context.Box1.Extent[0] > 0.0f) {
- if (obb_intersect_box1_basis(context,0)) return false;
- }
-
- if (context.Box1.Extent[1] > 0.0f) {
- if (obb_intersect_box1_basis(context,1)) return false;
- }
-
- if (context.Box1.Extent[2] > 0.0f) {
- if (obb_intersect_box1_basis(context,2)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0xB0
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.B[0],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][0]);
- rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][1]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0xB1
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.B[1],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][1]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][0]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0xB2
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.B[2],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][2]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][0]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xB0
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.B[0],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][0]);
- rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][1]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xB1
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.B[1],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][1]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][0]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xB2
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.B[2],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][2]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][0]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xB0
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.B[0],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][0])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][0]);
- rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][1]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xB1
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.B[1],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][1]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][0]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xB2
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.B[2],&axis);
- if (axis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][2]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][0]);
- if (obb_intersect_axis(context,axis,ra,rb)) return false;
- }
-
- return true;
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Intersection_Test -- test two obb's for intersection *
- * *
- * Simply sets up the context and calls intersect_obb_obb *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/25/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Intersection_Test(const OBBoxClass & box0,const OBBoxClass & box1)
-{
- ObbIntersectionStruct context(box0,box1);
- return intersect_obb_obb(context);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Intersection_Test -- test an OBB for intersection with an AAB *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/25/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Intersection_Test(const OBBoxClass & box0,const AABoxClass & box1)
-{
- OBBoxClass obbox1(box1.Center,box1.Extent);
- ObbIntersectionStruct context(box0,obbox1);
- return intersect_obb_obb(context);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Intersection_Test -- Test an AAB for intersection with an OBB *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/25/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Intersection_Test(const AABoxClass & box0,const OBBoxClass & box1)
-{
- OBBoxClass obbox0(box0.Center,box0.Extent);
- ObbIntersectionStruct context(obbox0,box1);
- return intersect_obb_obb(context);
-}
-
-
-/********************************************************************************
-
- OBBox-OBBox collision detection
-
- This batch of functions implement collision detection for moving oriented
- boxes. Assuming that the two arbitrarily oriented boxes are moving at a constant
- velocity along a path and not rotating, the time of collision can be found.
- The OBB-ABB and ABB-OBB functions are also implemented in a way that re-uses
- the OBB-OBB code.
-
- For the code which computes the point of collision and collision normal, you'll
- have to refer to the paper by Dave Eberly on oriented bounding boxes. The
- formulas for the collision point are the only part of this I was unable to
- derive myself (they are pretty nasty...)
-
-********************************************************************************/
-
-
-/**
-** ObbCollisionStruct
-** Contains all of the intermediate and temporary values used by
-** the set of functions used in detecting collisions for obb's
-*/
-struct ObbCollisionStruct
-{
- ObbCollisionStruct(const OBBoxClass &box0,const Vector3 &move0,const OBBoxClass & box1,const Vector3 &move1) :
- StartBad(true), // Startbad is true until one of the axes clears it
- AxisId(INTERSECTION), // AxisId will be the axis that allowed the longest move
- MaxFrac(0.0f), // MaxFrac is the longest allowed move so far
- Box0(box0),
- Move0(move0),
- Box1(box1),
- Move1(move1)
- {
- Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
- Vector3::Subtract(move1,move0,&M); // move vector relative to stationary box0
-
- A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
- A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
- A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
-
- B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
- B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
- B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
- }
-
- bool StartBad; // Inital configuration is intersecting?
- float MaxFrac; // Longest move allowed so far
- int AxisId; // Last separating axis
- int Side; // which side of the interval
-
- int TestAxisId; // Axis 'id' we're working on
- Vector3 TestAxis; // Axis that we're working on
-
- Vector3 C; // Vector from the center0 to center1
- Vector3 M; // Move vector relative to stationary box0
-
- Vector3 A[3]; // basis vectors for box0
- Vector3 B[3]; // basis vectors for box1
- float AB[3][3]; // dot products of the basis vectors
-
- const OBBoxClass & Box0;
- const Vector3 & Move0;
- const OBBoxClass & Box1;
- const Vector3 & Move1;
-
-private:
- //not implemented
- ObbCollisionStruct(const ObbCollisionStruct&);
- ObbCollisionStruct & operator = (const ObbCollisionStruct&);
-};
-
-
-
-/***********************************************************************************************
- * obb_separation_test -- test the projections of two obb's for separation *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obb_separation_test
-(
- ObbCollisionStruct & context,
- float ra,
- float rb,
- float u0,
- float u1
-)
-{
- float tmp;
- float rsum = ra+rb;
-
- if ( u0 + WWMATH_EPSILON > rsum ) {
- context.StartBad = false;
- if ( u1 > rsum ) {
- context.MaxFrac = 1.0f;
- return true;
- } else if (WWMath::Fabs(u1-u0) > 0.0f) {
- tmp = (rsum-u0)/(u1-u0);
- if ( tmp > context.MaxFrac ) {
- context.MaxFrac = tmp;
- context.AxisId = context.TestAxisId;
- context.Side = +1;
- }
- }
- } else if ( u0 - WWMATH_EPSILON < -rsum ) {
- context.StartBad = false;
- if ( u1 < -rsum ) {
- context.MaxFrac = 1.0f;
- return true;
- } else if (WWMath::Fabs(u1-u0) > 0.0f) {
- tmp = (-rsum-u0)/(u1-u0);
- if ( tmp > context.MaxFrac ) {
- context.MaxFrac = tmp;
- context.AxisId = context.TestAxisId;
- context.Side = -1;
- }
- }
- }
- return false;
-}
-
-
-/***********************************************************************************************
- * obb_check_box0_basis -- projects the boxes onto a basis vector from box0 *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static bool obb_check_box0_basis
-(
- ObbCollisionStruct & context,
- int axis_index
-)
-{
- // ra = box0 projection onto the axis
- // rb = box1 projection onto the axis
- float ra = context.Box0.Extent[axis_index];
- float rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[axis_index][0]) +
- WWMath::Fabs(context.Box1.Extent[1]*context.AB[axis_index][1]) +
- WWMath::Fabs(context.Box1.Extent[2]*context.AB[axis_index][2]);
-
- // u0 = projected distance between the box centers at t0
- // u1 = projected distance between the box centers at t1
- float u0 = Vector3::Dot_Product(context.C,context.A[axis_index]);
- float u1 = u0 + Vector3::Dot_Product(context.M,context.A[axis_index]);
-
- return obb_separation_test(context,ra,rb,u0,u1);
-}
-
-
-/***********************************************************************************************
- * obb_check_box1_basis -- projects the two obbs onto a basis vector from box1 *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static bool obb_check_box1_basis
-(
- ObbCollisionStruct & context,
- int axis_index
-)
-{
- // ra = box0 projection onto the axis
- // rb = box1 projection onto the axis
- float ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[0][axis_index]) +
- WWMath::Fabs(context.Box0.Extent[1]*context.AB[1][axis_index]) +
- WWMath::Fabs(context.Box0.Extent[2]*context.AB[2][axis_index]);
- float rb = context.Box1.Extent[axis_index];
-
- // u0 = projected distance between the box centers at t0
- // u1 = projected distance between the box centers at t1
- float u0 = Vector3::Dot_Product(context.C,context.B[axis_index]);
- float u1 = u0 + Vector3::Dot_Product(context.M,context.B[axis_index]);
- return obb_separation_test(context,ra,rb,u0,u1);
-}
-
-
-/***********************************************************************************************
- * obb_check_axis -- projects the obbs onto an arbitrary axis *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obb_check_axis
-(
- ObbCollisionStruct & context,
- float ra,
- float rb
-)
-{
- float u0 = Vector3::Dot_Product(context.C,context.TestAxis);
- float u1 = u0 + Vector3::Dot_Product(context.M,context.TestAxis);
- return obb_separation_test(context,ra,rb,u0,u1);
-}
-
-
-/***********************************************************************************************
- * obb_compute_projections -- computes projections of two boxes onto an arbitrary axis *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void obb_compute_projections
-(
- const ObbCollisionStruct & context,
- float * ra,
- float * rb
-)
-{
- *ra = context.Box0.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.A[0],context.TestAxis)) +
- context.Box0.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.A[1],context.TestAxis)) +
- context.Box0.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.A[2],context.TestAxis));
-
- *rb = context.Box1.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.B[0],context.TestAxis)) +
- context.Box1.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.B[1],context.TestAxis)) +
- context.Box1.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.B[2],context.TestAxis));
-}
-
-
-/***********************************************************************************************
- * compute_contact_normal -- computes the contact normal (after contact is detected) *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void compute_contact_normal(ObbCollisionStruct & context,CastResultStruct * result)
-{
- switch(context.AxisId)
- {
- case INTERSECTION:
-#pragma message("Fatal assert disabled for demo, obb-obb collision")
-// WWASSERT(0);
-// break;
-
- case AXIS_A0:
- result->Normal = context.A[0];
- break;
-
- case AXIS_A1:
- result->Normal = context.A[1];
- break;
-
- case AXIS_A2:
- result->Normal = context.A[2];
- break;
-
- case AXIS_B0:
- result->Normal = context.B[0];
- break;
-
- case AXIS_B1:
- result->Normal = context.B[1];
- break;
-
- case AXIS_B2:
- result->Normal = context.B[2];
- break;
-
- case AXIS_A0B0:
- Vector3::Cross_Product(context.A[0],context.B[0],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A0B1:
- Vector3::Cross_Product(context.A[0],context.B[1],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A0B2:
- Vector3::Cross_Product(context.A[0],context.B[2],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A1B0:
- Vector3::Cross_Product(context.A[1],context.B[0],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A1B1:
- Vector3::Cross_Product(context.A[1],context.B[1],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A1B2:
- Vector3::Cross_Product(context.A[1],context.B[2],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A2B0:
- Vector3::Cross_Product(context.A[2],context.B[0],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A2B1:
- Vector3::Cross_Product(context.A[2],context.B[1],&result->Normal);
- result->Normal.Normalize();
- break;
-
- case AXIS_A2B2:
- Vector3::Cross_Product(context.A[2],context.B[2],&result->Normal);
- result->Normal.Normalize();
- break;
- }
-
- result->Normal *= -context.Side;
-}
-
-
-/***********************************************************************************************
- * eval_side -- returns -1,0,1 depending on ab and side *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline float eval_side(float ab,float side)
-{
- if (ab > 0.0f) {
- return side;
- } else if (ab < 0.0f) {
- return -side;
- } else {
- return 0.0f;
- }
-}
-
-
-/***********************************************************************************************
- * compute_contact_point -- computes the contact point (after contact is detected) *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void compute_contact_point(ObbCollisionStruct & context,CastResultStruct * result)
-{
- int i,j;
- float x[3]; // box0 parameters
- float y[3]; // box1 parameters
- float den;
- Vector3 dcnew(0,0,0);
-
-//again:
-
- if (context.AxisId >= AXIS_A0B0) {
- Vector3 cnew0;
- Vector3 cnew1;
- Vector3::Add(context.Box0.Center,context.MaxFrac * context.Move0,&cnew0);
- Vector3::Add(context.Box1.Center,context.MaxFrac * context.Move1,&cnew1);
- Vector3::Subtract(cnew1,cnew0,&dcnew);
- }
-
- //PROBLEMS:
- //in case of edge-face or face-face or perfectly aligned edge-edge this
- //routine is only computing a single point.
- switch(context.AxisId)
- {
- case AXIS_A0:
- case AXIS_A1:
- case AXIS_A2:
- i = context.AxisId - AXIS_A0;
- for (j=0; j<3; j++) {
- y[j] = -eval_side(context.AB[i][j],context.Side);
- }
- context.Box1.Compute_Point(y,&(result->ContactPoint));
- result->ContactPoint += result->Fraction * context.Move1;
- return;
-
- case AXIS_B0:
- case AXIS_B1:
- case AXIS_B2:
- j = context.AxisId - AXIS_B0;
- for (i=0; i<3; i++) {
- x[i] = eval_side(context.AB[i][j],context.Side);
- }
- context.Box0.Compute_Point(x,&(result->ContactPoint));
- result->ContactPoint += result->Fraction * context.Move0;
- return;
-
- case AXIS_A0B0:
- x[1] = -eval_side(context.AB[2][0],context.Side) * context.Box0.Extent[1];
- x[2] = eval_side(context.AB[1][0],context.Side) * context.Box0.Extent[2];
- y[1] = -eval_side(context.AB[0][2],context.Side) * context.Box1.Extent[1];
- y[2] = eval_side(context.AB[0][1],context.Side) * context.Box1.Extent[2];
-
- den = (1.0f - context.AB[0][0] * context.AB[0][0]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[0] = Vector3::Dot_Product(context.A[0],dcnew);
- x[0] += context.AB[0][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[1][0]*x[1] + context.AB[2][0]*x[2]);
- x[0] += context.AB[0][1] * y[1] + context.AB[0][2] * y[2];
- x[0] /= den;
- } else {
- x[0] = 0.0f;
- }
- break;
-
- case AXIS_A0B1:
- x[1] = -eval_side(context.AB[2][1],context.Side) * context.Box0.Extent[1];
- x[2] = eval_side(context.AB[1][1],context.Side) * context.Box0.Extent[2];
- y[0] = eval_side(context.AB[0][2],context.Side) * context.Box1.Extent[0];
- y[2] = -eval_side(context.AB[0][0],context.Side) * context.Box1.Extent[2];
-
- den = (1.0f - context.AB[0][1] * context.AB[0][1]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[0] = Vector3::Dot_Product(context.A[0],dcnew);
- x[0] += context.AB[0][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[1][1]*x[1] + context.AB[2][1]*x[2]);
- x[0] += context.AB[0][0] * y[0] + context.AB[0][2] * y[2];
- x[0] /= den;
- } else {
- x[0] = 0.0f;
- }
- break;
-
- case AXIS_A0B2:
- x[1] = -eval_side(context.AB[2][2],context.Side) * context.Box0.Extent[1];
- x[2] = eval_side(context.AB[1][2],context.Side) * context.Box0.Extent[2];
- y[0] = -eval_side(context.AB[0][1],context.Side) * context.Box1.Extent[0];
- y[1] = eval_side(context.AB[0][0],context.Side) * context.Box1.Extent[1];
-
- den = (1.0f - context.AB[0][2] * context.AB[0][2]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[0] = Vector3::Dot_Product(context.A[0],dcnew);
- x[0] += context.AB[0][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[1][2]*x[1] + context.AB[2][2]*x[2]);
- x[0] += context.AB[0][0] * y[0] + context.AB[0][1] * y[1];
- x[0] /= den;
- } else {
- x[0] = 0.0f;
- }
- break;
-
- case AXIS_A1B0:
- x[0] = eval_side(context.AB[2][0],context.Side) * context.Box0.Extent[0];
- x[2] = -eval_side(context.AB[0][0],context.Side) * context.Box0.Extent[2];
- y[1] = -eval_side(context.AB[1][2],context.Side) * context.Box1.Extent[1];
- y[2] = eval_side(context.AB[1][1],context.Side) * context.Box1.Extent[2];
-
- den = (1.0f - context.AB[1][0] * context.AB[1][0]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[1] = Vector3::Dot_Product(context.A[1],dcnew);
- x[1] += context.AB[1][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[0][0]*x[0] + context.AB[2][0]*x[2]);
- x[1] += context.AB[1][1] * y[1] + context.AB[1][2] * y[2];
- x[1] /= den;
- } else {
- x[1] = 0.0f;
- }
- break;
-
- case AXIS_A1B1:
- x[0] = eval_side(context.AB[2][1],context.Side) * context.Box0.Extent[0];
- x[2] = -eval_side(context.AB[0][1],context.Side) * context.Box0.Extent[2];
- y[0] = eval_side(context.AB[1][2],context.Side) * context.Box1.Extent[0];
- y[2] = -eval_side(context.AB[1][0],context.Side) * context.Box1.Extent[2];
-
- den = 1.0f / (1.0f - context.AB[1][1] * context.AB[1][1]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[1] = Vector3::Dot_Product(context.A[1],dcnew);
- x[1] += context.AB[1][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[0][1]*x[0] + context.AB[2][1]*x[2]);
- x[1] += context.AB[1][0] * y[0] + context.AB[1][2] * y[2];
- x[1] /= den;
- } else {
- x[1] = 0.0f;
- }
- break;
-
- case AXIS_A1B2:
- x[0] = eval_side(context.AB[2][2],context.Side) * context.Box0.Extent[0];
- x[2] = -eval_side(context.AB[0][2],context.Side) * context.Box0.Extent[2];
- y[0] = -eval_side(context.AB[1][1],context.Side) * context.Box1.Extent[0];
- y[1] = eval_side(context.AB[1][0],context.Side) * context.Box1.Extent[1];
-
- den = (1.0f - context.AB[1][2] * context.AB[1][2]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[1] = Vector3::Dot_Product(context.A[1],dcnew);
- x[1] += context.AB[1][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[0][2]*x[0] + context.AB[2][2]*x[2]);
- x[1] += context.AB[1][0] * y[0] + context.AB[1][1] * y[1];
- x[1] /= den;
- } else {
- x[1] = 0.0f;
- }
- break;
-
- case AXIS_A2B0:
- x[0] = -eval_side(context.AB[1][0],context.Side) * context.Box0.Extent[0];
- x[1] = eval_side(context.AB[0][0],context.Side) * context.Box0.Extent[1];
- y[1] = -eval_side(context.AB[2][2],context.Side) * context.Box1.Extent[1];
- y[2] = eval_side(context.AB[2][1],context.Side) * context.Box1.Extent[2];
-
- den = (1.0f - context.AB[2][0] * context.AB[2][0]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[2] = Vector3::Dot_Product(context.A[2],dcnew);
- x[2] += context.AB[2][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[0][0]*x[0] + context.AB[1][0]*x[1]);
- x[2] += context.AB[2][1] * y[1] + context.AB[2][2] * y[2];
- x[2] /= den;
- } else {
- x[2] = 0.0f;
- }
- break;
-
- case AXIS_A2B1:
- x[0] = -eval_side(context.AB[1][1],context.Side) * context.Box0.Extent[0];
- x[1] = eval_side(context.AB[0][1],context.Side) * context.Box0.Extent[1];
- y[0] = eval_side(context.AB[2][2],context.Side) * context.Box1.Extent[0];
- y[2] = -eval_side(context.AB[2][0],context.Side) * context.Box1.Extent[2];
-
- den = (1.0f - context.AB[2][1] * context.AB[2][1]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[2] = Vector3::Dot_Product(context.A[2],dcnew);
- x[2] += context.AB[2][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[0][1]*x[0] + context.AB[1][1]*x[1]);
- x[2] += context.AB[2][0] * y[0] + context.AB[2][2] * y[2];
- x[2] /= den;
- } else {
- x[2] = 0.0f;
- }
- break;
-
- case AXIS_A2B2:
- x[0] = -eval_side(context.AB[1][2],context.Side) * context.Box0.Extent[0];
- x[1] = eval_side(context.AB[0][2],context.Side) * context.Box0.Extent[1];
- y[0] = -eval_side(context.AB[2][1],context.Side) * context.Box1.Extent[0];
- y[1] = eval_side(context.AB[2][0],context.Side) * context.Box1.Extent[1];
-
- den = (1.0f - context.AB[2][2] * context.AB[2][2]);
- if (WWMath::Fabs(den) > 0.0f) {
- x[2] = Vector3::Dot_Product(context.A[2],dcnew);
- x[2] += context.AB[2][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[0][2]*x[0] + context.AB[1][2]*x[1]);
- x[2] += context.AB[2][0] * y[0] + context.AB[2][1] * y[1];
- x[2] /= den;
- } else {
- x[2] = 0.0f;
- }
- break;
- }
-
- // all but the first two cases fall through to here
- result->ContactPoint.X = context.Box0.Center.X +
- x[0]*context.A[0].X +
- x[1]*context.A[1].X +
- x[2]*context.A[2].X;
-
- result->ContactPoint.Y = context.Box0.Center.Y +
- x[0]*context.A[0].Y +
- x[1]*context.A[1].Y +
- x[2]*context.A[2].Y;
-
- result->ContactPoint.Z = context.Box0.Center.Z +
- x[0]*context.A[0].Z +
- x[1]*context.A[1].Z +
- x[2]*context.A[2].Z;
-
- Vector3::Add(result->ContactPoint,result->Fraction * context.Move0,&(result->ContactPoint));
-
-}
-
-
-/***********************************************************************************************
- * collide_obb_obb -- test two obb's for collision *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/25/99 GTH : Created. *
- *=============================================================================================*/
-bool collide_obb_obb
-(
- ObbCollisionStruct & context,
- CastResultStruct * result
-)
-{
- Vector3 axis;
- float ra,rb;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0
- // Projecting the two boxes onto Box0's X axis. If their intervals
- // on this line do not intersect, the boxes are not intersecting!
- // Each of the tests in this function work in a similar way.
- // For this function I compute the AB's that are needed. The first
- // three tests compute all of these constants.
- /////////////////////////////////////////////////////////////////////////
- context.TestAxisId = AXIS_A0;
- context.AB[0][0] = Vector3::Dot_Product(context.A[0],context.B[0]);
- context.AB[0][1] = Vector3::Dot_Product(context.A[0],context.B[1]);
- context.AB[0][2] = Vector3::Dot_Product(context.A[0],context.B[2]);
- if (obb_check_box0_basis(context,0)) goto exit;
-
- /////////////////////////////////////////////////////////////////////////
- // Axsis A1
- /////////////////////////////////////////////////////////////////////////
- context.TestAxisId = AXIS_A1;
- context.AB[1][0] = Vector3::Dot_Product(context.A[1],context.B[0]);
- context.AB[1][1] = Vector3::Dot_Product(context.A[1],context.B[1]);
- context.AB[1][2] = Vector3::Dot_Product(context.A[1],context.B[2]);
- if (obb_check_box0_basis(context,1)) goto exit;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2
- /////////////////////////////////////////////////////////////////////////
- context.TestAxisId = AXIS_A2;
- context.AB[2][0] = Vector3::Dot_Product(context.A[2],context.B[0]);
- context.AB[2][1] = Vector3::Dot_Product(context.A[2],context.B[1]);
- context.AB[2][2] = Vector3::Dot_Product(context.A[2],context.B[2]);
- if (obb_check_box0_basis(context,2)) goto exit;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = B0
- /////////////////////////////////////////////////////////////////////////
- context.TestAxisId = AXIS_B0;
- if (obb_check_box1_basis(context,0)) goto exit;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = B1
- /////////////////////////////////////////////////////////////////////////
- context.TestAxisId = AXIS_B1;
- if (obb_check_box1_basis(context,1)) goto exit;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = B2
- /////////////////////////////////////////////////////////////////////////
- context.TestAxisId = AXIS_B2;
- if (obb_check_box1_basis(context,2)) goto exit;
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0xB0
- // The axes defined by the cross product between the boxes' basis
- // vectors are optimized in a similar way to this one:
- //
- // ra = |ex*A0*(A0xB0)| + |ey*A1*(A0xB0)| + |ez*A2*(A0xB0)|
- // = |ey*A1*(A0xB0)| + |ez*A2*(A0xB0)| A0*(A0xB0)=0
- // = |ey*B0*(A1xA0)| + |ez*B0*(A2xA0)| A*(BxC)=B*(CxA)=C*(AxB)
- // = |-ey*A2*B0| + |ez*A1*B0| A0xA1=A2
- // = |ey*AB[2][0]| + |ez*AB[1][0]| already computed these dot products!
- //
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.B[0],&context.TestAxis);
- context.TestAxisId = AXIS_A0B0;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][0]);
- rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][1]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0xB1
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.B[1],&context.TestAxis);
- context.TestAxisId = AXIS_A0B1;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][1]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][0]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A0xB2
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.B[2],&context.TestAxis);
- context.TestAxisId = AXIS_A0B2;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][2]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][0]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xB0
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.B[0],&context.TestAxis);
- context.TestAxisId = AXIS_A1B0;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][0]);
- rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][1]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xB1
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.B[1],&context.TestAxis);
- context.TestAxisId = AXIS_A1B1;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][1]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][0]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xB2
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.B[2],&context.TestAxis);
- context.TestAxisId = AXIS_A1B2;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][2]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][0]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xB0
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.B[0],&context.TestAxis);
- context.TestAxisId = AXIS_A2B0;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][0])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][0]);
- rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][1]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xB1
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.B[1],&context.TestAxis);
- context.TestAxisId = AXIS_A2B1;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][1]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][0]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xB2
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.B[2],&context.TestAxis);
- context.TestAxisId = AXIS_A2B2;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][2]);
- rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][0]);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- if (!result->StartBad) {
-
- context.TestAxisId = context.AxisId;
-
- /////////////////////////////////////////////////////////////////////////
- // Final three checks are for eliminating false collisions
- // Axis = A0xMove
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[0],context.Move0,&context.TestAxis);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- obb_compute_projections(context,&ra,&rb);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A1xMove
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[1],context.Move0,&context.TestAxis);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- obb_compute_projections(context,&ra,&rb);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Axis = A2xMove
- /////////////////////////////////////////////////////////////////////////
- Vector3::Cross_Product(context.A[2],context.Move0,&context.TestAxis);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- obb_compute_projections(context,&ra,&rb);
- if (obb_check_axis(context,ra,rb)) goto exit;
- }
- }
-
-exit:
-
- if (context.StartBad) {
- result->StartBad = true;
- result->Fraction = 0.0f;
- return true;
- }
-
-
- /*
- ** If our fraction is smaller, override the previous
- ** values because our collision occured first.
- */
- if (context.MaxFrac < result->Fraction) {
-
- result->Fraction = context.MaxFrac;
-
- compute_contact_normal(context,result);
- if (result->ComputeContactPoint) {
- compute_contact_point(context,result);
- }
- return true;
- }
- return false;
-}
-
-/***********************************************************************************************
- * CollisionMath::Collide -- collide two obb's *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide
-(
- const OBBoxClass & box0,
- const Vector3 & move0,
- const OBBoxClass & box1,
- const Vector3 & move1,
- CastResultStruct * result
-)
-{
- ObbCollisionStruct context(box0,move0,box1,move1);
- return collide_obb_obb(context,result);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Collide -- collide an OBB with an AAB *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/25/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide
-(
- const OBBoxClass & box0,
- const Vector3 & move0,
- const AABoxClass & box1,
- const Vector3 & move1,
- CastResultStruct * result
-)
-{
- OBBoxClass obbox1(box1.Center,box1.Extent);
- ObbCollisionStruct context(box0,move0,obbox1,move1);
- return collide_obb_obb(context,result);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Collide -- collide an AAB with an OBB *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/25/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide
-(
- const AABoxClass & box0,
- const Vector3 & move0,
- const OBBoxClass & box1,
- const Vector3 & move1,
- CastResultStruct * result
-)
-{
- OBBoxClass obbox0(box0.Center,box0.Extent);
- ObbCollisionStruct context(obbox0,move0,box1,move1);
- return collide_obb_obb(context,result);
-}
diff --git a/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp b/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
deleted file mode 100644
index 70171d5d46..0000000000
--- a/Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
+++ /dev/null
@@ -1,1510 +0,0 @@
-/*
-** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
-**
-** This program 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 3 of the License, or
-** (at your option) any later version.
-**
-** This program 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 this program. If not, see .
-*/
-
-/***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/wwmath/colmathobbtri.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 11/28/01 5:56p $*
- * *
- * $Revision:: 16 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * obbtri_collision_separation_test -- test the projected extents for separation *
- * obbtri_check_collision_axis -- project the obb and tri onto an arbitrary axis *
- * obbtri_check_collision_cross_axis -- intersection check for a "cross-product" axis *
- * obbtri_check_collision_basis_axis -- intersection check for a basis axis *
- * obbtri_check_collision_normal_axis -- intersection check for the triangle normal *
- * eval_side -- returns -1,0,+1 depending on the signe of val and side *
- * obbtri_compute_contact_normal -- computes the normal of the collision *
- * eval_A0_point -- contact point parameters for A0xEx *
- * eval_A1_point -- contact point parameters for A1xEx *
- * eval_A2_point -- contact point parameters for A2xEx *
- * obbtri_compute_contact_point -- compute the contact point *
- * CollisionMath::Collide -- collide an obbox into a triangle *
- * obbtri_intersection_separation_test -- test the projected extents for intersection *
- * obbtri_check_intersection_cross_axis -- intersection check for a "cross-product" axis *
- * obbtri_check_intersection_basis_axis -- intersection check for a basis axis *
- * obbtri_check_intersection_normal_axis -- intersection check for the triangle normal *
- * CollisionMath::Intersection_Test -- Intersection check for an OBBox and a triangle *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-#include "colmath.h"
-#include "obbox.h"
-#include "tri.h"
-#include "wwdebug.h"
-
-
-/*
-** Separating Axes have to be rejected if their length is smaller than some epsilon.
-** Otherwise, erroneous results can be reported.
-*/
-#define AXISLEN_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON // squared length of a separating axis must be larger than this
-
-/*
-** Axes used in Box-Tri intersection tests
-** The axes of the box are A0,A1,A2. N is the normal of the triangle,
-** E0,E1,E2 are direction vectors for the edges of the triangle.
-** (the box axes are labeled A0,A1,A2 as a holdover from the obbox-obbox
-** collision code which this was derived from where there are two boxes
-** A and B)
-*/
-enum
-{
- INTERSECTION = 0,
- AXIS_N, // normal of the triangle
- AXIS_A0, // first basis vector of the box
- AXIS_A1, // second basis vector of the box
- AXIS_A2, // third basis vector of the box
-
- AXIS_A0E0, // box0 x edge0...
- AXIS_A1E0,
- AXIS_A2E0,
- AXIS_A0E1,
- AXIS_A1E1,
- AXIS_A2E1,
- AXIS_A0E2,
- AXIS_A1E2,
- AXIS_A2E2
-};
-
-
-/******************************************************************************************
-
- OBBox->Triangle collision
-
- As with most of the collision detection functions, this code is based on the theorem
- that given any two non-intersecting convex polyhedra, a separating plane/axis
- can be found that will be defined by one of the face normals of one of the polyhedra
- or the cross product of an edge from each polyhedra. The key optimization for
- boxes is that many of these axes are the same. The normal to a face is the same
- as the axis for four of the edges of the box, etc.
-
- This test must be done using the tri normal, the three basis vectors
- for the box, and three vectors defined by the cross products of the basis
- and edge vectors. When testing the basis vectors, there will be two extents for
- the tri (the other two vectors projected onto the axis being tested).
- The appropriate extent must be used in the test (largest value which is pointing
- towards the direction of the box). In addition, I've found that I must test axes
- defined by the cross products of the move vector and the box axes. These tests
- catch "false collisions" where the box passes very close to the triangle but does
- not actually hit it.
-
- Each axis test will use the following logic:
- Project D onto the axis being used, it is the separation distance. If the
- projection of the extent of the box + the projection of the extent of the
- tri is greater than D*axis then the two intersect
-
-******************************************************************************************/
-
-/**
-** BoxTriColStruct
-** Scratchpad variables for the OBBox-Triangle collision detection functions. One instance
-** of this structure will be used for all of the local variables and its pointer will be
-** handed of to various inline functions for the axis tests.
-** Note that much of the code needs the un-normalized triangle normal. For this reason,
-** I have to compute N rather than copying it from the triangle. (commenting this to
-** avoid re-generating a difficult to find bug that I had)
-**
-** Note that the MaxFrac variable starts negative so that we can accept slightly negative
-** fractions (interpenetrations). But we clamp the returned result to 0.0 so that we never
-** allow an object to get more embedded, just to possibly break itself free if it is within
-** the epsilon. This is important because sometimes objects seem to intersect simply due to
-** floating point roundoff error...
-*/
-struct BTCollisionStruct
-{
- BTCollisionStruct(const OBBoxClass &box,const Vector3 &move,const TriClass &tri,const Vector3 &trimove) :
- Box(box),
- Tri(tri),
- BoxMove(move),
- TriMove(trimove)
- {
- Reset();
- }
-
- void Reset(void)
- {
- StartBad = true; // true until an axis clears it
- MaxFrac = -1.0f; // maximum move allowed so far (accept slightly negative but clamp to zero at end)
- AxisId = INTERSECTION; // axis that allowed the longest move
- Point = 0; // index of triangle point that was closest to the box
- Side = 0; // side of the interval
-
- Vector3::Subtract(*Tri.V[0],Box.Center,&D); // vector from center of box to vertex 0
- Vector3::Subtract(BoxMove,TriMove,&Move); // move vector relative to stationary triangle
-
- Vector3::Subtract(*Tri.V[1],*Tri.V[0],&E[0]);
- Vector3::Subtract(*Tri.V[2],*Tri.V[0],&E[1]);
- Vector3::Subtract(E[1],E[0],&E[2]);
-
- A[0].Set(Box.Basis[0][0],Box.Basis[1][0],Box.Basis[2][0]);
- A[1].Set(Box.Basis[0][1],Box.Basis[1][1],Box.Basis[2][1]);
- A[2].Set(Box.Basis[0][2],Box.Basis[1][2],Box.Basis[2][2]);
-
- Vector3::Cross_Product(E[0],E[1],&N);
- }
-
- bool StartBad; // Inital configuration is intersecting?
- float MaxFrac; // Longest move allowed so far
- int AxisId; // Last separating axis
- int Point; // Index of the "closest" triangle point (or one of them)
- int Side; // which side of the interval
-
- int TestSide; // Was the axis we're working on flipped
- int TestAxisId; // Axis 'id' we're working on
- int TestPoint; // Index of the closest vertex
- Vector3 TestAxis; // Axis we're working on
-
- Vector3 D; // Vector from the center of the box to v0
- Vector3 Move; // Move vector relative to stationary triangle
- float AE[3][3]; // Dot products of the Basis vectors and edges
- float AN[3]; // Dot products of the Basis vectors and the normal
- Vector3 AxE[3][3]; // Cross produts of the Basis vectors and edges
-
- Vector3 A[3]; // basis vectors for the box
- Vector3 E[3]; // edge vectors for the triangle
- Vector3 N; // normal (NOT normalized!!!)
- Vector3 FinalD; // Vector from center of box to v0 at end of move
-
- const OBBoxClass & Box;
- const TriClass & Tri;
- const Vector3 & BoxMove;
- const Vector3 & TriMove;
-
-private:
-
- // not implemented
- BTCollisionStruct(const BTCollisionStruct &);
- BTCollisionStruct & operator = (const BTCollisionStruct &);
-};
-
-
-
-
-
-/***********************************************************************************************
- * obbtri_collision_separation_test -- test the projected extents for separation *
- * *
- * Once the extents are projected onto the axis, this function contains *
- * the logic that determines the allowed fraction. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_collision_separation_test
-(
- BTCollisionStruct & context,
- float lp,float leb0,float leb1
-)
-{
- /*
- ** - compute 'EPSILON' normalized to the length of the axis
- ** - If (I'm no more than 'EPSILON' embedded in the polygon)
- ** - not startbad
- ** - If (I'm moving towards)
- ** - fraction = How far I can move before embedding (can be negative if started embedded)
- ** - If (I can take entire move)
- ** - accept entire move
- ** - Else If (I can move more than I could have before; *negative always fails!)
- ** - update fraction
- ** - Else
- ** - Accept entire move since I'm not moving towards the polygon
- */
- float eps = 0.0f;
- if (lp - leb0 <= 0.0f) {
- eps = COLLISION_EPSILON * context.TestAxis.Length(); // trying to only compute epsilon if I have to
- }
-
- if (lp - leb0 > -eps) {
- context.StartBad = false;
- if (leb1 - leb0 > 0.0f) {
- float frac = (lp-leb0)/(leb1-leb0);
- if (frac >= 1.0f) {
- /* moving toward but not hitting triangle */
- context.AxisId = context.TestAxisId;
- context.MaxFrac = 1.0f;
- return true;
- } else {
- /* moving toward, hitting triangle */
- if (frac > context.MaxFrac) {
- context.MaxFrac = frac;
- context.AxisId = context.TestAxisId;
- context.Side = context.TestSide;
- context.Point = context.TestPoint;
- }
- }
- } else {
- /* moving away or not moving */
- context.AxisId = context.TestAxisId;
- context.MaxFrac = 1.0f;
- return true;
- }
- }
- return false;
-}
-
-
-/***********************************************************************************************
- * obbtri_check_collision_axis -- project the obb and tri onto an arbitrary axis *
- * *
- * projects the box and the triangle onto the given axis and calls *
- * obbtri_separation_test. return true if separation was detected *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_collision_axis(BTCollisionStruct & context)
-{
- float dist; // separation along the axis
- float axismove; // size of the move along the axis.
- float leb0; // initial coordinate of the leading edge of the box
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
- float tmp; // temporary
-
- dist = Vector3::Dot_Product(context.D,context.TestAxis);
- axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
-
- // I want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axismove = -axismove;
- context.TestAxis = -context.TestAxis;
- context.TestSide = -1.0f;
- } else {
- context.TestSide = 1.0f;
- }
-
- // compute coordinates of the leading edge of the box at t0 and t1
- leb0 = context.Box.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.TestAxis,context.A[0])) +
- context.Box.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.TestAxis,context.A[1])) +
- context.Box.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.TestAxis,context.A[2]));
- leb1 = leb0 + axismove;
-
- // compute coordinate of "leading edge of the triangle" relative to the box center.
- lp = 0;
- tmp = Vector3::Dot_Product(context.E[0],context.TestAxis); if (tmp < lp) lp = tmp;
- tmp = Vector3::Dot_Product(context.E[1],context.TestAxis); if (tmp < lp) lp = tmp;
- lp = dist + lp;
-
- return obbtri_collision_separation_test(context,lp,leb0,leb1);
-}
-
-
-/***********************************************************************************************
- * obbtri_check_collision_cross_axis -- projects obb and tri onto a "cross" axis *
- * *
- * Assumes that the axis given is one generated from a cross product of one of the edge and *
- * basis vectors. In this case, the box extent can be optimized and only two triangle verts *
- * need to be checked. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_collision_cross_axis
-(
- BTCollisionStruct & context,
- float dp,
- int dpi,
- float leb0
-)
-{
- float p0; // distance from box center to vertex 0
- float axismove; // size of the move along the axis.
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- p0 = Vector3::Dot_Product(context.D,context.TestAxis);
- axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
-
- // I want the axis centered at the box, pointing towards the triangle
- if (p0 < 0) {
- p0 = -p0;
- axismove = -axismove;
- dp = -dp;
- context.TestAxis = -context.TestAxis;
- context.TestSide = -1.0f;
- } else {
- context.TestSide = 1.0f;
- }
-
- // compute coordinates of the leading edge of the box at t1
- leb1 = leb0 + axismove;
-
- // compute coordinate of "leading edge of the triangle" relative to the box center.
- lp = 0; context.TestPoint = 0;
- if (dp < 0) { lp = dp; context.TestPoint = dpi; }
- lp = p0 + lp;
-
- return obbtri_collision_separation_test(context,lp,leb0,leb1);
-}
-
-
-/***********************************************************************************************
- * obbtri_check_collision_basis_axis -- projects the obb and tri onto a basis axis *
- * *
- * Projects the box and triangle onto an axis that is assumed to be a basis *
- * vector from the box. In this case, we can skip a dot-product and use the *
- * corresponding extent of the box (which is passed in as leb0). *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_collision_basis_axis
-(
- BTCollisionStruct & context,
- float leb0,
- float dp1,
- float dp2
-)
-{
- float dist; // separation along the axis
- float axismove; // size of the move along the axis.
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(context.D,context.TestAxis);
- axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axismove = -axismove;
- dp1 = -dp1;
- dp2 = -dp2;
- context.TestAxis = -context.TestAxis;
- context.TestSide = -1.0f;
- } else {
- context.TestSide = 1.0f;
- }
-
- // this is the "optimization", leb0 = one of the extents
- leb1 = leb0 + axismove;
-
- // compute coordinate of "leading edge of the polygon" relative to the box center.
- lp = 0; context.TestPoint = 0;
- if (dp1 < lp) { lp = dp1; context.TestPoint = 1; }
- if (dp2 < lp) { lp = dp2; context.TestPoint = 2; }
- lp = dist + lp;
-
- return obbtri_collision_separation_test(context,lp,leb0,leb1);
-}
-
-
-/***********************************************************************************************
- * obbtri_check_collision_normal_axis -- project the box and tri onto the tri-normal *
- * *
- * Projects the box and triangle onto an axis that is assumed to be the normal *
- * vector from the triangle. In this case, the triangle extents are zero. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_collision_normal_axis(BTCollisionStruct & context)
-{
- float dist; // separation along the axis
- float axismove; // size of the move along the axis.
- float leb0; // initial coordinate of the leading edge of the box
- float leb1; // final coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(context.D,context.TestAxis);
- axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- dist = -dist;
- axismove = -axismove;
- context.TestAxis = -context.TestAxis;
- context.TestSide = -1.0f;
- } else {
- context.TestSide = 1.0f;
- }
-
- leb0 = context.Box.Extent.X * WWMath::Fabs(context.AN[0]) +
- context.Box.Extent.Y * WWMath::Fabs(context.AN[1]) +
- context.Box.Extent.Z * WWMath::Fabs(context.AN[2]);
- leb1 = leb0 + axismove;
- context.TestPoint = 0;
- lp = dist; // this is the "optimization", don't have to find lp
-
- return obbtri_collision_separation_test(context,lp,leb0,leb1);
-}
-
-/***********************************************************************************************
- * eval_side -- returns -1,0,+1 depending on the sign of val and side *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline float eval_side(float val,int side)
-{
- if (val > 0.0f) {
- return side;
- } else if (val < 0.0f) {
- return -side;
- } else {
- return 0.0f;
- }
-}
-
-/***********************************************************************************************
- * obbtri_compute_contact_normal -- computes the normal of the collision *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void obbtri_compute_contact_normal
-(
- const BTCollisionStruct & context,
- Vector3 * set_normal
-)
-{
- switch(context.AxisId)
- {
- case INTERSECTION:
-// WWASSERT(0);
- break;
- case AXIS_N:
- *set_normal = -context.Side * *context.Tri.N;
- break;
- case AXIS_A0:
- *set_normal = -context.Side * context.A[0];
- break;
- case AXIS_A1:
- *set_normal = -context.Side * context.A[1];
- break;
- case AXIS_A2:
- *set_normal = -context.Side * context.A[2];
- break;
- case AXIS_A0E0:
- *set_normal = -context.Side * context.AxE[0][0];
- set_normal->Normalize();
- break;
- case AXIS_A1E0:
- *set_normal = -context.Side * context.AxE[1][0];
- set_normal->Normalize();
- break;
- case AXIS_A2E0:
- *set_normal = -context.Side * context.AxE[2][0];
- set_normal->Normalize();
- break;
- case AXIS_A0E1:
- *set_normal = -context.Side * context.AxE[0][1];
- set_normal->Normalize();
- break;
- case AXIS_A1E1:
- *set_normal = -context.Side * context.AxE[1][1];
- set_normal->Normalize();
- break;
- case AXIS_A2E1:
- *set_normal = -context.Side * context.AxE[2][1];
- set_normal->Normalize();
- break;
- case AXIS_A0E2:
- *set_normal = -context.Side * context.AxE[0][2];
- set_normal->Normalize();
- break;
- case AXIS_A1E2:
- *set_normal = -context.Side * context.AxE[1][2];
- set_normal->Normalize();
- break;
- case AXIS_A2E2:
- *set_normal = -context.Side * context.AxE[2][2];
- set_normal->Normalize();
- break;
- }
- WWASSERT(set_normal->Length2() > 0.0f);
-}
-
-
-/***********************************************************************************************
- * eval_A0_point -- contact point parameters for A0xEx *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void eval_A0_point(const BTCollisionStruct & context,float * x,int edge)
-{
- float yval,den;
- Vector3 DxE;
-
- x[1] = -eval_side(context.AE[2][edge],context.Side) * context.Box.Extent[1];
- x[2] = eval_side(context.AE[1][edge],context.Side) * context.Box.Extent[2];
- if (context.Point == 0) { yval = 0.0f; } else { yval = 1.0f; }
-
- den = Vector3::Dot_Product(context.N,context.AxE[0][edge]);
- if (WWMath::Fabs(den) > 0.0f) {
-
- Vector3::Cross_Product(context.FinalD,context.E[edge],&DxE);
- x[0] = Vector3::Dot_Product(context.N,DxE);
- if (edge == 0) {
- x[0] -= context.N.Length2() * yval;
- } else {
- x[0] += context.N.Length2() * yval;
- }
- x[0] -= Vector3::Dot_Product(context.N,context.AxE[1][edge]) * x[1];
- x[0] -= Vector3::Dot_Product(context.N,context.AxE[2][edge]) * x[2];
- x[0] /= den;
-
- } else {
-
- x[0] = 0.0f;
-
- }
-}
-
-
-/***********************************************************************************************
- * eval_A1_point -- contact point parameters for A1xEx *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void eval_A1_point(const BTCollisionStruct & context,float * x,int edge)
-{
- float yval,den;
- Vector3 DxE;
-
- x[0] = eval_side(context.AE[2][edge],context.Side) * context.Box.Extent[0];
- x[2] = -eval_side(context.AE[0][edge],context.Side) * context.Box.Extent[2];
- if (context.Point == 0) { yval = 0.0f; } else { yval = 1.0f; }
-
- den = Vector3::Dot_Product(context.N,context.AxE[1][edge]);
- if (WWMath::Fabs(den) > 0.0f) {
-
- Vector3::Cross_Product(context.FinalD,context.E[edge],&DxE);
- x[1] = Vector3::Dot_Product(context.N,DxE);
- if (edge == 0) {
- x[1] -= context.N.Length2() * yval;
- } else {
- x[1] += context.N.Length2() * yval;
- }
- x[1] -= Vector3::Dot_Product(context.N,context.AxE[0][edge]) * x[0];
- x[1] -= Vector3::Dot_Product(context.N,context.AxE[2][edge]) * x[2];
- x[1] /= den;
-
- } else {
-
- x[1] = 0.0f;
-
- }
-}
-
-/***********************************************************************************************
- * eval_A2_point -- contact point parameters for A2xEx *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void eval_A2_point(const BTCollisionStruct & context,float * x,int edge)
-{
- float yval,den;
- Vector3 DxE;
-
- x[0] = -eval_side(context.AE[1][edge],context.Side) * context.Box.Extent[0];
- x[1] = eval_side(context.AE[0][edge],context.Side) * context.Box.Extent[1];
- if (context.Point == 0) { yval = 0.0f; } else { yval = 1.0f; }
-
- den = Vector3::Dot_Product(context.N,context.AxE[2][edge]);
- if (WWMath::Fabs(den) > 0.0f) {
-
- Vector3::Cross_Product(context.FinalD,context.E[edge],&DxE);
- x[2] = Vector3::Dot_Product(context.N,DxE);
- if (edge == 0) {
- x[2] -= context.N.Length2() * yval;
- } else {
- x[2] += context.N.Length2() * yval;
- }
- x[2] -= Vector3::Dot_Product(context.N,context.AxE[0][edge]) * x[0];
- x[2] -= Vector3::Dot_Product(context.N,context.AxE[1][edge]) * x[1];
- x[2] /= den;
-
- } else {
-
- x[2] = 0.0f;
-
- }
-}
-
-
-/***********************************************************************************************
- * obbtri_compute_contact_point -- compute the contact point *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-static inline void obbtri_compute_contact_point
-(
- BTCollisionStruct & context,
- CastResultStruct * result
-)
-{
- int i;
- float x[3];
-
- if (context.AxisId >= AXIS_A0E0) {
- Vector3 newc = context.Box.Center + result->Fraction * context.BoxMove;
- Vector3 newv0 = *context.Tri.V[0] + result->Fraction * context.TriMove;
- context.FinalD = newv0 - newc;
- }
-
- switch (context.AxisId)
- {
-
- case INTERSECTION:
- WWASSERT(0);
- return;
-
- case AXIS_N: // part of the box is touching the face of the triangle
-
- for (i = 0; i < 3; i++) {
- x[i] = eval_side(context.AN[i],context.Side) * context.Box.Extent[i];
- }
- break;
-
- case AXIS_A0: // part of the triangle is touching a face of the box
- case AXIS_A1:
- case AXIS_A2:
-
- if (context.Point == 0) {
- result->ContactPoint = *context.Tri.V[0];
- } else if (context.Point == 1) {
- result->ContactPoint = *context.Tri.V[1];
- } else {
- result->ContactPoint = *context.Tri.V[2];
- }
- Vector3::Add(result->ContactPoint,result->Fraction * context.TriMove,&(result->ContactPoint));
- return;
-
- case AXIS_A0E0: // one of the x-aligned edges of the box is contacting edge0
- eval_A0_point(context,x,0);
- break;
-
- case AXIS_A0E1: // one of the x-aligned edges of the box is contacting edge1
- eval_A0_point(context,x,1);
- break;
-
- case AXIS_A0E2: // one of the x-aligned edges of the box is contacting edge2
- eval_A0_point(context,x,2);
- break;
-
- case AXIS_A1E0: // one of the y-aligned edges of the box is contacting edge0
- eval_A1_point(context,x,0);
- break;
-
- case AXIS_A1E1: // one of the y-aligned edges of the box is contacting edge1
- eval_A1_point(context,x,1);
- break;
-
- case AXIS_A1E2: // one of the y-aligned edges of the box is contacting edge2
- eval_A1_point(context,x,2);
- break;
-
- case AXIS_A2E0: // one of the z-aligned edges of the box is contacting edge0
- eval_A2_point(context,x,0);
- break;
-
- case AXIS_A2E1: // one of the z-aligned edges of the box is contacting edge1
- eval_A2_point(context,x,1);
- break;
-
- case AXIS_A2E2: // one of the z-aligned edges of the box is contacting edge3
- eval_A2_point(context,x,2);
- break;
-
- }
-
- /*
- ** In certain circumstances, the x's computed above are outside the size of
- ** the box. I have tracked at least one of these cases to a situation where the
- ** separating axis is the triangle normal but one of the AxE axes also lines up
- ** with the normal. In this case, the Normal was 0,0,25 and the A0xE0 axis
- ** was 0,0,5. When the fraction was calculated for both of these, they were
- ** the same up to the six decimal places that MSVC will show me in the debugger.
- ** However, the fraction computed for the 0,0,5 axis was larger by some very small
- ** amount. This causes it to be used as the "separating axis". Looks like floating
- ** point roundoff error to me. The problem is that since the axis was perpendicular
- ** to the triangle, the "nearest-point" logic chose V0 which resulted in the
- ** calculation for x[0] being way off. The equations for finding the contact point
- ** in the AxE axis case assume that the axis is not normal to the triangle since
- ** that should be handled in the simpler routine for the N separating axis...
- ** Since I am at a loss for how to deal with this problem, I'm going to clamp all
- ** of the x's to be within the box here...
- */
- if (x[0] > context.Box.Extent.X) {
- x[0] = context.Box.Extent.X;
- } else if (x[0] < -context.Box.Extent.X) {
- x[0] = -context.Box.Extent.X;
- }
-
- if (x[1] > context.Box.Extent.Y) {
- x[1] = context.Box.Extent.Y;
- } else if (x[1] < -context.Box.Extent.Y) {
- x[1] = -context.Box.Extent.Y;
- }
-
- if (x[2] > context.Box.Extent.Z) {
- x[2] = context.Box.Extent.Z;
- } else if (x[2] < -context.Box.Extent.Z) {
- x[2] = -context.Box.Extent.Z;
- }
-
- /*
- ** Now, compute the point
- */
- result->ContactPoint.X = context.Box.Center.X +
- x[0]*context.A[0].X +
- x[1]*context.A[1].X +
- x[2]*context.A[2].X;
-
- result->ContactPoint.Y = context.Box.Center.Y +
- x[0]*context.A[0].Y +
- x[1]*context.A[1].Y +
- x[2]*context.A[2].Y;
-
- result->ContactPoint.Z = context.Box.Center.Z +
- x[0]*context.A[0].Z +
- x[1]*context.A[1].Z +
- x[2]*context.A[2].Z;
-
- Vector3::Add(result->ContactPoint,result->Fraction * context.BoxMove,&(result->ContactPoint));
-}
-
-
-
-/***********************************************************************************************
- * CollisionMath::Collide -- collide an obbox into a triangle *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Collide
-(
- const OBBoxClass & box,
- const Vector3 & move,
- const TriClass & tri,
- const Vector3 & trimove,
- CastResultStruct * result
-)
-{
- TRACK_COLLISION_OBBOX_TRI;
- float dp,leb0;
- BTCollisionStruct context(box,move,tri,trimove);
-
- /*
- ** AXIS_N
- */
- context.TestAxis = context.N;
- context.TestAxisId = AXIS_N;
- context.AN[0] = Vector3::Dot_Product(context.A[0],context.N);
- context.AN[1] = Vector3::Dot_Product(context.A[1],context.N);
- context.AN[2] = Vector3::Dot_Product(context.A[2],context.N);
- if (obbtri_check_collision_normal_axis(context)) goto exit;
-
- /*
- ** AXIS_A0
- */
- context.TestAxis = context.A[0];
- context.TestAxisId = AXIS_A0;
- context.AE[0][0] = Vector3::Dot_Product(context.A[0],context.E[0]);
- context.AE[0][1] = Vector3::Dot_Product(context.A[0],context.E[1]);
- if (obbtri_check_collision_basis_axis(context,box.Extent.X,context.AE[0][0],context.AE[0][1])) goto exit;
-
- /*
- ** AXIS_A1
- */
- context.TestAxis = context.A[1];
- context.TestAxisId = AXIS_A1;
- context.AE[1][0] = Vector3::Dot_Product(context.A[1],context.E[0]);
- context.AE[1][1] = Vector3::Dot_Product(context.A[1],context.E[1]);
- if (obbtri_check_collision_basis_axis(context,box.Extent.Y,context.AE[1][0],context.AE[1][1])) goto exit;
-
- /*
- ** AXIS_A2
- */
- context.TestAxis = context.A[2];
- context.TestAxisId = AXIS_A2;
- context.AE[2][0] = Vector3::Dot_Product(context.A[2],context.E[0]);
- context.AE[2][1] = Vector3::Dot_Product(context.A[2],context.E[1]);
- if (obbtri_check_collision_basis_axis(context,box.Extent.Z,context.AE[2][0],context.AE[2][1])) goto exit;
-
- /*
- ** AXIS_A0xE0
- */
- Vector3::Cross_Product(context.A[0],context.E[0],&context.AxE[0][0]);
- context.TestAxis = context.AxE[0][0];
- context.TestAxisId = AXIS_A0E0;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = context.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[1][0]);
- if (obbtri_check_collision_cross_axis(context,dp,2,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A0xE1
- */
- Vector3::Cross_Product(context.A[0],context.E[1],&context.AxE[0][1]);
- context.TestAxis = context.AxE[0][1];
- context.TestAxisId = AXIS_A0E1;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[1][1]);
- if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A0xE2
- */
- Vector3::Cross_Product(context.A[0],context.E[2],&context.AxE[0][2]);
- context.TestAxis = context.AxE[0][2];
- context.TestAxisId = AXIS_A0E2;
- context.AE[1][2] = Vector3::Dot_Product(context.A[1],context.E[2]);
- context.AE[2][2] = Vector3::Dot_Product(context.A[2],context.E[2]);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[1][2]);
- if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A1xE0
- */
- Vector3::Cross_Product(context.A[1],context.E[0],&context.AxE[1][0]);
- context.TestAxis = context.AxE[1][0];
- context.TestAxisId = AXIS_A1E0;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = context.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[0][0]);
- if (obbtri_check_collision_cross_axis(context,dp,2,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A1xE1
- */
- Vector3::Cross_Product(context.A[1],context.E[1],&context.AxE[1][1]);
- context.TestAxis = context.AxE[1][1];
- context.TestAxisId = AXIS_A1E1;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[0][1]);
- if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A1xE2
- */
- Vector3::Cross_Product(context.A[1],context.E[2],&context.AxE[1][2]);
- context.TestAxis = context.AxE[1][2];
- context.TestAxisId = AXIS_A1E2;
- context.AE[0][2] = Vector3::Dot_Product(context.A[0],context.E[2]);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[0][2]);
- if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A2xE0
- */
- Vector3::Cross_Product(context.A[2],context.E[0],&context.AxE[2][0]);
- context.TestAxis = context.AxE[2][0];
- context.TestAxisId = AXIS_A2E0;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = context.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][0]) + box.Extent[1]*WWMath::Fabs(context.AE[0][0]);
- if (obbtri_check_collision_cross_axis(context,dp,2,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A2xE1
- */
- Vector3::Cross_Product(context.A[2],context.E[1],&context.AxE[2][1]);
- context.TestAxis = context.AxE[2][1];
- context.TestAxisId = AXIS_A2E1;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][1]) + box.Extent[1]*WWMath::Fabs(context.AE[0][1]);
- if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
- }
-
- /*
- ** AXIS_A2xE2
- */
- Vector3::Cross_Product(context.A[2],context.E[2],&context.AxE[2][2]);
- context.TestAxis = context.AxE[2][2];
- context.TestAxisId = AXIS_A2E2;
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][2]) + box.Extent[1]*WWMath::Fabs(context.AE[0][2]);
- if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
- }
-
- /*
- ** Last ditch effort, check an axis based on the move vector
- */
- if (!context.StartBad) {
- context.TestPoint = context.Point;
- context.TestAxisId = context.AxisId;
-
- Vector3::Cross_Product(context.Move,context.A[0],&context.TestAxis);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- if (obbtri_check_collision_axis(context)) goto exit;
- }
- Vector3::Cross_Product(context.Move,context.A[1],&context.TestAxis);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- if (obbtri_check_collision_axis(context)) goto exit;
- }
- Vector3::Cross_Product(context.Move,context.A[2],&context.TestAxis);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- if (obbtri_check_collision_axis(context)) goto exit;
- }
- }
-
-exit:
-
-#pragma message ("(gth) disabling an assert in obb->tri collision, investigate later\n")
-#if 0
- WWASSERT((context.AxisId != INTERSECTION) || (context.StartBad));
-#else
- if (context.AxisId == INTERSECTION) {
- context.StartBad = true;
- }
-#endif
-
- /*
- ** If the triangle and box are intersecting before the move, return that
- ** result.
- */
- if (context.StartBad) {
- result->StartBad = true;
- result->Fraction = 0.0f;
- result->Normal = *tri.N;
- TRACK_COLLISION_OBBOX_TRI_HIT;
- return true;
- }
-
- /*
- ** If the fraction allowed is basically equal to the fraction allowed by
- ** another polygon, try to pick the polygon which is least "edge-on" to the
- ** move.
- */
- if (context.MaxFrac < 0.0f) {
- context.MaxFrac = 0.0f;
- }
-
- if ((context.MaxFrac < 1.0f) && (context.MaxFrac <= result->Fraction)) {
-
- Vector3 normal;
- obbtri_compute_contact_normal(context,&normal);
-
- if ( (WWMath::Fabs(context.MaxFrac - result->Fraction) > WWMATH_EPSILON) ||
- (Vector3::Dot_Product(normal,move) < Vector3::Dot_Product(result->Normal,move)) )
- {
- result->Normal = normal; //obbtri_compute_contact_normal(context,result);
- }
-
- result->Fraction = context.MaxFrac;
-
- if (result->ComputeContactPoint) {
- obbtri_compute_contact_point(context,result);
- }
- TRACK_COLLISION_OBBOX_TRI_HIT;
- return true;
- }
-
- return false;
-}
-
-
-/***********************************************************************************************
-
- OBBox-Triangle Intersection
-
- The following code implements a simple boolean intersection check. It uses the same
- algorithm as the collision function but can avoid some of the calculations. For a very
- simple implementation of this algorithm, see Oriented_Box_Intersects_Tri in obbox.h
-
-***********************************************************************************************/
-
-/**
-** BTIntersectStruct
-** Scratchpad variables for the OBBox-Triangle intersection functions. One instance
-** of this structure will be used for all of the local variables and its pointer will be
-** handed of to various inline functions for the axis tests.
-** Note that much of the code needs the un-normalized triangle normal. For this reason,
-** I have to compute N rather than copying it from the triangle. (commenting this to
-** avoid re-generating a difficult to find bug that I had)
-*/
-struct BTIntersectStruct
-{
- BTIntersectStruct(const OBBoxClass &box,const TriClass &tri) :
- Box(box),
- Tri(tri)
- {
- Vector3::Subtract(*tri.V[0],box.Center,&D); // vector from center of box to vertex 0
- Vector3::Subtract(*tri.V[1],*tri.V[0],&E[0]);
- Vector3::Subtract(*tri.V[2],*tri.V[0],&E[1]);
- Vector3::Subtract(E[1],E[0],&E[2]);
-
- A[0].Set(box.Basis[0][0],box.Basis[1][0],box.Basis[2][0]);
- A[1].Set(box.Basis[0][1],box.Basis[1][1],box.Basis[2][1]);
- A[2].Set(box.Basis[0][2],box.Basis[1][2],box.Basis[2][2]);
-
- Vector3::Cross_Product(E[0],E[1],&N);
- }
-
- Vector3 D; // Vector from the center of the box to v0
- float AE[3][3]; // Dot products of the Basis vectors and edges
- float AN[3]; // Dot products of the Basis vectors and the normal
- Vector3 AxE[3][3]; // Cross produts of the Basis vectors and edges
-
- Vector3 A[3]; // basis vectors for the box
- Vector3 E[3]; // edge vectors for the triangle
- Vector3 N; // normal (NOT normalized!!!)
-
- Vector3 TestAxis; // separating axis currently being tested
-
- const OBBoxClass & Box;
- const TriClass & Tri;
-
-private:
-
- // not implemented
- BTIntersectStruct(const BTIntersectStruct &);
- BTIntersectStruct & operator = (const BTIntersectStruct &);
-};
-
-
-/***********************************************************************************************
- * obbtri_intersection_separation_test -- test the projected extents for intersection *
- * *
- * Once the extents are projected onto the axis, this function contains *
- * the logic that determines whether the box and triangle intersect. *
- * *
- * INPUT: *
- * context - the BTIntersectStruct containing the data for this intersection test *
- * lp - the leading edge of the polygon projected onto the axis *
- * leb0 - the leading edge of the box projected onto the axis *
- * *
- * OUTPUT: *
- * true = objects are separated *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 2/3/2000 gth : Created. *
- *=============================================================================================*/
-static inline bool obbtri_intersection_separation_test
-(
- BTIntersectStruct & context,
- float lp,
- float leb0
-)
-{
- /*
- ** Only compute the normalized epsilon if we need to.
- ** - compute 'EPSILON' normalized to the length of the axis
- ** - If (I'm no more than 'EPSILON' embedded in the polygon) then the box and tri are separated
- */
- float eps = 0.0f;
- if (lp - leb0 <= 0.0f) {
- eps = COLLISION_EPSILON * context.TestAxis.Length(); // trying to only compute epsilon if I have to
- }
-
- return (lp - leb0 > -eps);
-}
-
-
-/***********************************************************************************************
- * obbtri_check_intersection_cross_axis -- intersection check for a "cross-product" axis *
- * *
- * axis being checked is a cross product between a triangle edge and a box basis vector *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * true = the objects are SEPARATED *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_intersection_cross_axis
-(
- BTIntersectStruct & context,
- float dp,
- float leb0
-)
-{
- float p0; // distance from box center to vertex 0
- float lp; // leading edge of the polygon.
-
- p0 = Vector3::Dot_Product(context.D,context.TestAxis);
-
- // I want the axis centered at the box, pointing towards the triangle
- if (p0 < 0) {
- context.TestAxis = -context.TestAxis;
- p0 = -p0;
- dp = -dp;
- }
-
- // compute coordinate of "leading edge of the triangle" relative to the box center.
- lp = 0;
- if (dp < 0) { lp = dp; }
- lp = p0 + lp;
-
- return obbtri_intersection_separation_test(context,lp,leb0);
-}
-
-
-/***********************************************************************************************
- * obbtri_check_intersection_basis_axis -- intersection check for a basis axis *
- * *
- * axis being checked is one of the basis vectors for the box *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = the objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_intersection_basis_axis
-(
- BTIntersectStruct & context,
- float leb0,
- float dp1,
- float dp2
-)
-{
- float dist; // separation along the axis
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(context.D,context.TestAxis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- context.TestAxis = -context.TestAxis;
- dist = -dist;
- dp1 = -dp1;
- dp2 = -dp2;
- }
-
- // compute coordinate of "leading edge of the polygon" relative to the box center.
- lp = 0;
- if (dp1 < lp) { lp = dp1; }
- if (dp2 < lp) { lp = dp2; }
- lp = dist + lp;
-
- return obbtri_intersection_separation_test(context,lp,leb0);
-}
-
-
-/***********************************************************************************************
- * obbtri_check_intersection_normal_axis -- intersection check for the triangle normal *
- * *
- * axis being checked is the triangle's normal *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * true = the objects are SEPARATED *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-static inline bool obbtri_check_intersection_normal_axis
-(
- BTIntersectStruct & context
-)
-{
- float dist; // separation along the axis
- float leb0; // initial coordinate of the leading edge of the box
- float lp; // leading edge of the polygon.
-
- dist = Vector3::Dot_Product(context.D,context.TestAxis);
-
- // we want the axis centered at the box, pointing towards the triangle
- if (dist < 0) {
- context.TestAxis = -context.TestAxis;
- dist = -dist;
- }
-
- leb0 = context.Box.Extent.X * WWMath::Fabs(context.AN[0]) +
- context.Box.Extent.Y * WWMath::Fabs(context.AN[1]) +
- context.Box.Extent.Z * WWMath::Fabs(context.AN[2]);
- lp = dist; // this is the "optimization", don't have to find lp
-
- return obbtri_intersection_separation_test(context,lp,leb0);
-}
-
-
-/***********************************************************************************************
- * CollisionMath::Intersection_Test -- Intersection check for an OBBox and a triangle *
- * *
- * INPUT: *
- * box - obbox to be tested *
- * tri - triangle to be tested *
- * *
- * OUTPUT: *
- * true = objects INTERSECT *
- * *
- * WARNINGS: *
- * note that the other inline functions are "quick-reject" functions which return true when *
- * the objects are separated. *
- * *
- * HISTORY: *
- * 5/4/99 GTH : Created. *
- *=============================================================================================*/
-bool CollisionMath::Intersection_Test(const OBBoxClass & box,const TriClass & tri)
-{
- float dp,leb0;
- BTIntersectStruct context(box,tri);
-
- /*
- ** AXIS_N
- */
- context.TestAxis = context.N;
- context.AN[0] = Vector3::Dot_Product(context.A[0],context.N);
- context.AN[1] = Vector3::Dot_Product(context.A[1],context.N);
- context.AN[2] = Vector3::Dot_Product(context.A[2],context.N);
- if (obbtri_check_intersection_normal_axis(context)) return false;
-
- /*
- ** AXIS_A0
- */
- context.TestAxis = context.A[0];
- context.AE[0][0] = Vector3::Dot_Product(context.A[0],context.E[0]);
- context.AE[0][1] = Vector3::Dot_Product(context.A[0],context.E[1]);
- if (obbtri_check_intersection_basis_axis(context,box.Extent.X,context.AE[0][0],context.AE[0][1])) return false;
-
- /*
- ** AXIS_A1
- */
- context.TestAxis = context.A[1];
- context.AE[1][0] = Vector3::Dot_Product(context.A[1],context.E[0]);
- context.AE[1][1] = Vector3::Dot_Product(context.A[1],context.E[1]);
- if (obbtri_check_intersection_basis_axis(context,box.Extent.Y,context.AE[1][0],context.AE[1][1])) return false;
-
- /*
- ** AXIS_A2
- */
- context.TestAxis = context.A[2];
- context.AE[2][0] = Vector3::Dot_Product(context.A[2],context.E[0]);
- context.AE[2][1] = Vector3::Dot_Product(context.A[2],context.E[1]);
- if (obbtri_check_intersection_basis_axis(context,box.Extent.Z,context.AE[2][0],context.AE[2][1])) return false;
-
- /*
- ** AXIS_A0xE0
- */
- Vector3::Cross_Product(context.A[0],context.E[0],&context.AxE[0][0]);
- context.TestAxis = context.AxE[0][0];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = context.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[1][0]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A0xE1
- */
- Vector3::Cross_Product(context.A[0],context.E[1],&context.AxE[0][1]);
- context.TestAxis = context.AxE[0][1];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[1][1]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A0xE2
- */
- Vector3::Cross_Product(context.A[0],context.E[2],&context.AxE[0][2]);
- context.TestAxis = context.AxE[0][2];
- context.AE[1][2] = Vector3::Dot_Product(context.A[1],context.E[2]);
- context.AE[2][2] = Vector3::Dot_Product(context.A[2],context.E[2]);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[0];
- leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[1][2]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A1xE0
- */
- Vector3::Cross_Product(context.A[1],context.E[0],&context.AxE[1][0]);
- context.TestAxis = context.AxE[1][0];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = context.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[0][0]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A1xE1
- */
- Vector3::Cross_Product(context.A[1],context.E[1],&context.AxE[1][1]);
- context.TestAxis = context.AxE[1][1];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[0][1]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A1xE2
- */
- Vector3::Cross_Product(context.A[1],context.E[2],&context.AxE[1][2]);
- context.TestAxis = context.AxE[1][2];
- context.AE[0][2] = Vector3::Dot_Product(context.A[0],context.E[2]);
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[1];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[0][2]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A2xE0
- */
- Vector3::Cross_Product(context.A[2],context.E[0],&context.AxE[2][0]);
- context.TestAxis = context.AxE[2][0];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = context.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][0]) + box.Extent[1]*WWMath::Fabs(context.AE[0][0]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A2xE1
- */
- Vector3::Cross_Product(context.A[2],context.E[1],&context.AxE[2][1]);
- context.TestAxis = context.AxE[2][1];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][1]) + box.Extent[1]*WWMath::Fabs(context.AE[0][1]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- /*
- ** AXIS_A2xE2
- */
- Vector3::Cross_Product(context.A[2],context.E[2],&context.AxE[2][2]);
- context.TestAxis = context.AxE[2][2];
- if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
- dp = -context.AN[2];
- leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][2]) + box.Extent[1]*WWMath::Fabs(context.AE[0][2]);
- if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
- }
-
- return true;
-}
-
-
-
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/CMakeLists.txt b/GeneralsMD/Code/Libraries/Source/WWVegas/CMakeLists.txt
index 9598eea489..4980ead157 100644
--- a/GeneralsMD/Code/Libraries/Source/WWVegas/CMakeLists.txt
+++ b/GeneralsMD/Code/Libraries/Source/WWVegas/CMakeLists.txt
@@ -18,7 +18,6 @@ target_include_directories(z_wwcommon INTERFACE
)
add_subdirectory(WWAudio)
-add_subdirectory(WWMath)
add_subdirectory(Wwutil)
add_subdirectory(WW3D2)
add_subdirectory(WWDownload)
@@ -38,6 +37,5 @@ target_link_libraries(z_wwvegas INTERFACE
core_wwvegas
z_ww3d2
z_wwdownload
- z_wwmath
z_wwutil
)
diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt b/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
deleted file mode 100644
index 83f9571a21..0000000000
--- a/GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-set(WWMATH_SRC
- cardinalspline.cpp
- colmathaabox.cpp
- colmathaabtri.cpp
- colmathobbobb.cpp
- colmathobbtri.cpp
-)
-
-# Targets to build.
-add_library(z_wwmath STATIC)
-#set_target_properties(z_wwmath PROPERTIES OUTPUT_NAME wwmath)
-
-target_sources(z_wwmath PRIVATE ${WWMATH_SRC})
-
-target_link_libraries(z_wwmath PRIVATE
- core_wwmath
- z_wwcommon
-)