From e9384a45cb6b330776a26c9cf447d9749ea8004a Mon Sep 17 00:00:00 2001 From: Stephan Vedder Date: Tue, 22 Apr 2025 13:38:46 +0200 Subject: [PATCH] [CORE] Unify remaining WWMath --- Core/Libraries/Source/WWVegas/CMakeLists.txt | 2 +- .../Source/WWVegas/WWMath/CMakeLists.txt | 10 +- .../Source/WWVegas/WWMath/cardinalspline.cpp | 0 .../Source/WWVegas/WWMath/colmathaabox.cpp | 0 .../Source/WWVegas/WWMath/colmathaabtri.cpp | 0 .../Source/WWVegas/WWMath/colmathobbobb.cpp | 0 .../Source/WWVegas/WWMath/colmathobbtri.cpp | 0 .../Libraries/Source/WWVegas/CMakeLists.txt | 2 - .../Source/WWVegas/WWMath/CMakeLists.txt | 18 - .../Source/WWVegas/WWMath/cardinalspline.cpp | 356 ---- .../Source/WWVegas/WWMath/colmathaabox.cpp | 596 ------- .../Source/WWVegas/WWMath/colmathaabtri.cpp | 1184 ------------- .../Source/WWVegas/WWMath/colmathobbobb.cpp | 1409 --------------- .../Source/WWVegas/WWMath/colmathobbtri.cpp | 1510 ----------------- .../Libraries/Source/WWVegas/CMakeLists.txt | 2 - .../Source/WWVegas/WWMath/CMakeLists.txt | 18 - 16 files changed, 6 insertions(+), 5101 deletions(-) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp (100%) delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp delete mode 100644 GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/CMakeLists.txt 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 -)