Initial commit of Command & Conquer Renegade source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:39:46 +00:00
parent 74ab8fa5e0
commit 58ed459113
4918 changed files with 1366710 additions and 0 deletions

View File

@@ -0,0 +1,316 @@
/*
** Command & Conquer Renegade(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 <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include "matrix3d.h"
#include "vector3.h"
#include "col.h"
#include "cvec.h"
#include "mpu.h"
void benchmark_transformations(void);
//---------------------------------------------------------------------------
#include <fstream.h>
#include <stdlib.h>
#define FRAND (-1.0f+2.0f*rand()/float(RAND_MAX))
ofstream ostr("data1.txt");
void Rotate3D (float line[3], float angle, float rotate[3][3])
{
int row, col, mid;
float I[3][3], A[3][3], A2[3][3];
float sn, omcs;
/* identity matrix */
I[0][0] = 1; I[0][1] = 0; I[0][2] = 0;
I[1][0] = 0; I[1][1] = 1; I[1][2] = 0;
I[2][0] = 0; I[2][1] = 0; I[2][2] = 1;
/* infinitesimal rotation about line */
A[0][0] = 0; A[0][1] = +line[2]; A[0][2] = -line[1];
A[1][0] = -line[2]; A[1][1] = 0; A[1][2] = +line[0];
A[2][0] = +line[1]; A[2][1] = -line[0]; A[2][2] = 0;
/* A2 = A*A */
for (row = 0; row < 3; row++)
for (col = 0; col < 3; col++) {
A2[row][col] = 0;
for (mid = 0; mid < 3; mid++)
A2[row][col] += A[row][mid]*A[mid][col];
}
sn = float(sin(angle));
omcs = float(1.0-cos(angle));
/* rotation is I+sin(angle)*A+[1-cos(angle)]*A*A */
for (row = 0; row < 3; row++)
for (col = 0; col < 3; col++)
rotate[row][col] = I[row][col]+sn*A[row][col]+omcs*A2[row][col];
}
void main ()
{
Box box0, box1;
// create box0
box0.center[0] = 0.0f;
box0.center[1] = 0.0f;
box0.center[2] = 0.0f;
box0.basis[0][0] = 1.0f;
box0.basis[0][1] = 0.0f;
box0.basis[0][2] = 0.0f;
box0.basis[1][0] = 0.0f;
box0.basis[1][1] = 1.0f;
box0.basis[1][2] = 0.0f;
box0.basis[2][0] = 0.0f;
box0.basis[2][1] = 0.0f;
box0.basis[2][2] = 1.0f;
box0.extent[0] = 4.0f;
box0.extent[1] = 4.0f;
box0.extent[2] = 4.0f;
box0.velocity[0] = 0.0f;
box0.velocity[1] = 0.0f;
box0.velocity[2] = 0.0f;
// create box1
box1.center[0] = 0.0f;
box1.center[1] = -10.0f;
box1.center[2] = 20.0f;
float line[3] = { 0.0f, 0.707f, 0.707f };
float length = float(sqrt(line[0]*line[0]+line[1]*line[1]+line[2]*line[2]));
line[0] /= length;
line[1] /= length;
line[2] /= length;
float angle = (float)DEG_TO_RAD(45.0f);
Rotate3D(line,angle,box1.basis);
/*
box1.basis[0][0] = 1.0f;
box1.basis[0][1] = 0.0f;
box1.basis[0][2] = 0.0f;
box1.basis[1][0] = 0.0f;
box1.basis[1][1] = 1.0f;
box1.basis[1][2] = 0.0f;
box1.basis[2][0] = 0.0f;
box1.basis[2][1] = 0.0f;
box1.basis[2][2] = 1.0f;
*/
box1.extent[0] = 10.0f;
box1.extent[1] = 4.0f;
box1.extent[2] = 4.0f;
box1.velocity[0] = 0.0f;
box1.velocity[1] = 0.0f;
box1.velocity[2] = 0.0f;
BoxClass mybox0(box0);
BoxClass mybox1(box1);
unsigned long high;
unsigned long cycles0;
unsigned long cycles1;
unsigned long cycles2;
while (box1.center[2] > -20.0f) {
cycles0 = Get_CPU_Clock(high);
IntersectType type = BoxesIntersect(1.0f,box0,box1);
cycles0 = Get_CPU_Clock(high) - cycles0;
cycles1 = Get_CPU_Clock(high);
IntersectType mytype = Boxes_Intersect(mybox0,mybox1,1.0f);
cycles1 = Get_CPU_Clock(high) - cycles1;
cycles2 = Get_CPU_Clock(high);
IntersectType mytype2 = Boxes_Intersect(mybox0,mybox1);
cycles2 = Get_CPU_Clock(high) - cycles2;
cout << cycles0 << " "<< cycles1 << " " << cycles2 << " " << type << " " << mytype<< " " << mytype2 << endl;
box1.center[2] -= 1.0f;
mybox1.Center[2] -= 1.0f;
}
// if (type == itIntersects) {
// ostr << "type = " << type << endl;
// }
benchmark_transformations();
#if 0
float line[3] = { FRAND, FRAND, FRAND };
float length = float(sqrt(line[0]*line[0]+line[1]*line[1]+line[2]*line[2]));
line[0] /= length;
line[1] /= length;
line[2] /= length;
float angle = FRAND;
Rotate3D(line,angle,box0.basis);
box0.extent[0] = 1.0f;
box0.extent[1] = 1.0f;
box0.extent[2] = 1.0f;
box0.velocity[0] = 0.0f;
box0.velocity[1] = 0.0f;
box0.velocity[2] = 0.0f;
for (int i = 0; i < 100; i++)
{
box1.center[0] = 2.0f;
box1.center[1] = 0.0f;
box1.center[2] = 0.0f;
line[0] = FRAND;
line[1] = FRAND;
line[2] = FRAND;
length = float(sqrt(line[0]*line[0]+line[1]*line[1]+line[2]*line[2]));
line[0] /= length;
line[1] /= length;
line[2] /= length;
angle = FRAND;
Rotate3D(line,angle,box1.basis);
box1.extent[0] = 1.0f;
box1.extent[1] = 1.0f;
box1.extent[2] = 1.0f;
box1.velocity[0] = 0.0f;
box1.velocity[1] = 0.0f;
box1.velocity[2] = 0.0f;
IntersectType type = BoxesIntersect(1.0f,box0,box1);
ostr << "i = " << i << ' ' << "type = " << type << endl;
}
#endif
/*
** box0
*/
box0.center[0] = 6.1978f;
box0.center[1] = 2.6640f;
box0.center[2] = 0.840f;
box0.extent[0] = 0.1341f;
box0.extent[1] = 0.320672f;
box0.extent[2] = 0.840f;
box0.velocity[0] = box0.velocity[1] = box0.velocity[2] = 0.0f;
box0.basis[0][0] = 0.857709f;
box0.basis[0][1] = -0.514136f;
box0.basis[0][2] = 0.0f;
box0.basis[1][0] = 0.514136f;
box0.basis[1][1] = 0.857709f;
box0.basis[1][2] = 0.0f;
box0.basis[2][0] = 0.0f;
box0.basis[2][1] = 0.0f;
box0.basis[2][2] = 1.0f;
/*
** box1
*/
box1.center[0] = 10.0f;
box1.center[1] = 4.0f;
box1.center[2] = 2.8f;
box1.extent[0] = 4.5f;
box1.extent[1] = 1.966f;
box1.extent[2] = 2.868f;
box1.velocity[0] = box1.velocity[1] = box1.velocity[2] = 0.0f;
box1.basis[0][0] = 1.0f;
box1.basis[0][1] = 0.0f;
box1.basis[0][2] = 0.0f;
box1.basis[1][0] = 0.0f;
box1.basis[1][1] = 1.0f;
box1.basis[1][2] = 0.0f;
box1.basis[2][0] = 0.0f;
box1.basis[2][1] = 0.0f;
box1.basis[2][2] = 1.0f;
IntersectType type = BoxesIntersect(1.0f,box0,box1);
}
void benchmark_transformations(void)
{
unsigned long high;
unsigned long cycles0;
unsigned long cycles1;
/*
** Testing speed of the matrix library...
*/
Vector v = { 4.0f, -2.5f, 100.4f };
float mat[3][3];
float line[3] = { 0.0f, 0.0f, 1.0f };
float length = float(sqrt(line[0]*line[0]+line[1]*line[1]+line[2]*line[2]));
line[0] /= length;
line[1] /= length;
line[2] /= length;
float angle = (float)DEG_TO_RAD(45.0f);
Rotate3D(line,angle,mat);
Vector3 myv(4.0,-2.5,100.4);
Matrix3 mymat;
mymat[0][0] = mat[0][0];
mymat[0][1] = mat[0][1];
mymat[0][2] = mat[0][2];
mymat[1][0] = mat[1][0];
mymat[1][1] = mat[1][1];
mymat[1][2] = mat[1][2];
mymat[2][0] = mat[2][0];
mymat[2][1] = mat[2][1];
mymat[2][2] = mat[2][2];
Vector res;
Vector3 myres;
cycles0 = Get_CPU_Clock(high);
MultiplyVM (v,mat,res);
cycles0 = Get_CPU_Clock(high) - cycles0;
cycles1 = Get_CPU_Clock(high);
myres = mymat * myv;
cycles1 = Get_CPU_Clock(high) - cycles1;
cout << "c cycles = " << cycles0 << endl;
cout << "c++ cycles = " << cycles1 << endl;
}

531
Code/Tests/collide/col.cpp Normal file
View File

@@ -0,0 +1,531 @@
/*
** Command & Conquer Renegade(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 <http://www.gnu.org/licenses/>.
*/
#include "col.h"
#include "matrix3.h"
#include "vector3.h"
BoxClass::BoxClass(Box box)
{
Center.X = box.center[0];
Center.Y = box.center[1];
Center.Z = box.center[2];
Extent.X = box.extent[0];
Extent.Y = box.extent[1];
Extent.Z = box.extent[2];
Velocity.X = box.velocity[0];
Velocity.Y = box.velocity[1];
Velocity.Z = box.velocity[2];
Basis[0][0] = box.basis[0][0];
Basis[0][1] = box.basis[0][1];
Basis[0][2] = box.basis[0][2];
Basis[1][0] = box.basis[1][0];
Basis[1][1] = box.basis[1][1];
Basis[1][2] = box.basis[1][2];
Basis[2][0] = box.basis[2][0];
Basis[2][1] = box.basis[2][1];
Basis[2][2] = box.basis[2][2];
}
//---------------------------------------------------------------------------
IntersectType Boxes_Intersect(const BoxClass & box0, const BoxClass & box1,float dt)
{
// memoized values for Dot_Product(box0.Basis[i],box1.Basis[j]),
Matrix3 AB;
// calculate difference of centers
Vector3 C = box1.Center - box0.Center;
Vector3 V = box1.Velocity - box0.Velocity;
float ra, rb, rsum, u0, u1;
/////////////////////////////////////////////////////////////////////////
// L = 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.
/////////////////////////////////////////////////////////////////////////
AB[0][0] = Dot_Product(box0.Basis[0],box1.Basis[0]);
AB[0][1] = Dot_Product(box0.Basis[0],box1.Basis[1]);
AB[0][2] = Dot_Product(box0.Basis[0],box1.Basis[2]);
ra = FABS(box0.Extent[0]);
rb = FABS(box1.Extent[0]*AB[0][0])+FABS(box1.Extent[1]*AB[0][1])+FABS(box1.Extent[2]*AB[0][2]);
rsum = ra+rb;
// u0 = projected distance between the box centers at t0
// u1 = projected distance between the box centers at t1
u0 = Dot_Product(C,box0.Basis[0]);
u1 = u0+dt*Dot_Product(V,box0.Basis[0]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0;
/////////////////////////////////////////////////////////////////////////
// L = A1
// Separating Axis is Box0's Y axis
/////////////////////////////////////////////////////////////////////////
AB[1][0] = Dot_Product(box0.Basis[1],box1.Basis[0]);
AB[1][1] = Dot_Product(box0.Basis[1],box1.Basis[1]);
AB[1][2] = Dot_Product(box0.Basis[1],box1.Basis[2]);
ra = FABS(box0.Extent[1]);
rb = FABS(box1.Extent[0]*AB[1][0])+FABS(box1.Extent[1]*AB[1][1])+FABS(box1.Extent[2]*AB[1][2]);
rsum = ra+rb;
u0 = Dot_Product(C,box0.Basis[1]);
u1 = u0+dt*Dot_Product(V,box0.Basis[1]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1;
/////////////////////////////////////////////////////////////////////////
// L = A2
// Separating Axis is Box0's Y axis
/////////////////////////////////////////////////////////////////////////
AB[2][0] = Dot_Product(box0.Basis[2],box1.Basis[0]);
AB[2][1] = Dot_Product(box0.Basis[2],box1.Basis[1]);
AB[2][2] = Dot_Product(box0.Basis[2],box1.Basis[2]);
ra = FABS(box0.Extent[2]);
rb = FABS(box1.Extent[0]*AB[2][0])+FABS(box1.Extent[1]*AB[2][1])+FABS(box1.Extent[2]*AB[2][2]);
rsum = ra+rb;
u0 = Dot_Product(C,box0.Basis[2]);
u1 = u0+dt*Dot_Product(V,box0.Basis[2]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2;
/////////////////////////////////////////////////////////////////////////
// L = B0
// Separating Axis is Box1's X axis
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*AB[0][0])+FABS(box0.Extent[1]*AB[1][0])+FABS(box0.Extent[2]*AB[2][0]);
rb = FABS(box1.Extent[0]);
rsum = ra+rb;
u0 = Dot_Product(C,box1.Basis[0]);
u1 = u0+dt*Dot_Product(V,box1.Basis[0]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itB0;
/////////////////////////////////////////////////////////////////////////
// L = B1
// Separating Axis is Box1's Y axis
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*AB[0][1])+FABS(box0.Extent[1]*AB[1][1])+FABS(box0.Extent[2]*AB[2][1]);
rb = FABS(box1.Extent[1]);
rsum = ra+rb;
u0 = Dot_Product(C,box1.Basis[1]);
u1 = u0+dt*Dot_Product(V,box1.Basis[1]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itB1;
/////////////////////////////////////////////////////////////////////////
// L = B2
// Separating Axis is Box1's Z axis
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*AB[0][2])+FABS(box0.Extent[1]*AB[1][2])+FABS(box0.Extent[2]*AB[2][2]);
rb = FABS(box1.Extent[2]);
rsum = ra+rb;
u0 = Dot_Product(C,box1.Basis[2]);
u1 = u0+dt*Dot_Product(V,box1.Basis[2]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itB2;
/////////////////////////////////////////////////////////////////////////
// None of the aligned axes turned out to be separating axes. Now
// we check all combinations of cross products of the two boxes axes.
/////////////////////////////////////////////////////////////////////////
Matrix3 Ainv = box0.Basis.Transpose();
Matrix3 coeff = AB.Transpose();
// difference of centers in box0's-basis
Vector3 d0, d1, product;
d0 = Ainv * C;
d1 = Ainv * V;
product = dt*d1;
d1 = d0 + product;
/////////////////////////////////////////////////////////////////////////
// L = A0xB0
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[1]*coeff[0][2])+FABS(box0.Extent[2]*coeff[0][1]);
rb = FABS(box1.Extent[1]*coeff[2][0])+FABS(box1.Extent[2]*coeff[1][0]);
rsum = ra+rb;
u0 = d0[2]*coeff[1][0]-d0[1]*coeff[2][0];
u1 = d1[2]*coeff[1][0]-d1[1]*coeff[2][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0B0;
/////////////////////////////////////////////////////////////////////////
// L = A0xB1
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[1]*coeff[1][2])+FABS(box0.Extent[2]*coeff[1][1]);
rb = FABS(box1.Extent[0]*coeff[2][0])+FABS(box1.Extent[2]*coeff[0][0]);
rsum = ra+rb;
u0 = d0[2]*coeff[1][1]-d0[1]*coeff[1][2];
u1 = d1[2]*coeff[1][1]-d1[1]*coeff[1][2];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0B1;
/////////////////////////////////////////////////////////////////////////
// L = A0xB2
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[1]*coeff[2][2])+FABS(box0.Extent[2]*coeff[2][1]);
rb = FABS(box1.Extent[0]*coeff[1][0])+FABS(box1.Extent[1]*coeff[0][0]);
rsum = ra+rb;
u0 = d0[2]*coeff[2][1]-d0[1]*coeff[2][2];
u1 = d1[2]*coeff[2][1]-d1[1]*coeff[2][2];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0B2;
/////////////////////////////////////////////////////////////////////////
// L = A1xB0
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[0][2])+FABS(box0.Extent[2]*coeff[0][0]);
rb = FABS(box1.Extent[1]*coeff[2][1])+FABS(box1.Extent[2]*coeff[1][1]);
rsum = ra+rb;
u0 = d0[0]*coeff[0][2]-d0[2]*coeff[0][0];
u1 = d1[0]*coeff[0][2]-d1[2]*coeff[0][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1B0;
/////////////////////////////////////////////////////////////////////////
// L = A1xB1
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[1][2])+FABS(box0.Extent[2]*coeff[1][0]);
rb = FABS(box1.Extent[0]*coeff[2][1])+FABS(box1.Extent[2]*coeff[0][1]);
rsum = ra+rb;
u0 = d0[0]*coeff[1][2]-d0[2]*coeff[1][0];
u1 = d1[0]*coeff[1][2]-d1[2]*coeff[1][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1B1;
/////////////////////////////////////////////////////////////////////////
// L = A1xB2
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[2][2])+FABS(box0.Extent[2]*coeff[2][0]);
rb = FABS(box1.Extent[0]*coeff[1][1])+FABS(box1.Extent[1]*coeff[0][1]);
rsum = ra+rb;
u0 = d0[0]*coeff[2][2]-d0[2]*coeff[2][0];
u1 = d1[0]*coeff[2][2]-d1[2]*coeff[2][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1B2;
/////////////////////////////////////////////////////////////////////////
// L = A2xB0
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[0][1])+FABS(box0.Extent[1]*coeff[0][0]);
rb = FABS(box1.Extent[1]*coeff[2][2])+FABS(box1.Extent[2]*coeff[1][2]);
rsum = ra+rb;
u0 = d0[1]*coeff[0][0]-d0[0]*coeff[0][1];
u1 = d1[1]*coeff[0][0]-d1[0]*coeff[0][1];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2B0;
/////////////////////////////////////////////////////////////////////////
// L = A2xB1
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[1][1])+FABS(box0.Extent[1]*coeff[1][0]);
rb = FABS(box1.Extent[0]*coeff[2][2])+FABS(box1.Extent[2]*coeff[0][2]);
rsum = ra+rb;
u0 = d0[1]*coeff[1][0]-d0[0]*coeff[1][1];
u1 = d1[1]*coeff[1][0]-d1[0]*coeff[1][1];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2B1;
/////////////////////////////////////////////////////////////////////////
// L = A2xB2
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[2][1])+FABS(box0.Extent[1]*coeff[2][0]);
rb = FABS(box1.Extent[0]*coeff[1][2])+FABS(box1.Extent[1]*coeff[0][2]);
rsum = ra+rb;
u0 = d0[1]*coeff[2][0]-d0[0]*coeff[2][1];
u1 = d1[1]*coeff[2][0]-d1[0]*coeff[2][1];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2B2;
return itIntersects;
}
//---------------------------------------------------------------------------
IntersectType Boxes_Intersect(const BoxClass & box0, const BoxClass & box1)
{
// memoized values for Dot_Product(box0.Basis[i],box1.Basis[j]),
Matrix3 AB;
// calculate difference of centers
Vector3 C = box1.Center - box0.Center;
float ra, rb, rsum, u0;
/////////////////////////////////////////////////////////////////////////
// L = 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.
/////////////////////////////////////////////////////////////////////////
AB[0][0] = Dot_Product(box0.Basis[0],box1.Basis[0]);
AB[0][1] = Dot_Product(box0.Basis[0],box1.Basis[1]);
AB[0][2] = Dot_Product(box0.Basis[0],box1.Basis[2]);
ra = FABS(box0.Extent[0]);
rb = FABS(box1.Extent[0]*AB[0][0])+FABS(box1.Extent[1]*AB[0][1])+FABS(box1.Extent[2]*AB[0][2]);
rsum = ra+rb;
// u0 = projected distance between the box centers at t0
// u1 = projected distance between the box centers at t1
u0 = Dot_Product(C,box0.Basis[0]);
if ((u0 > rsum) || (u0 < -rsum))
return itA0;
/////////////////////////////////////////////////////////////////////////
// L = A1
// Separating Axis is Box0's Y axis
/////////////////////////////////////////////////////////////////////////
AB[1][0] = Dot_Product(box0.Basis[1],box1.Basis[0]);
AB[1][1] = Dot_Product(box0.Basis[1],box1.Basis[1]);
AB[1][2] = Dot_Product(box0.Basis[1],box1.Basis[2]);
ra = FABS(box0.Extent[1]);
rb = FABS(box1.Extent[0]*AB[1][0])+FABS(box1.Extent[1]*AB[1][1])+FABS(box1.Extent[2]*AB[1][2]);
rsum = ra+rb;
u0 = Dot_Product(C,box0.Basis[1]);
if ((u0 > rsum) || (u0 < -rsum))
return itA1;
/////////////////////////////////////////////////////////////////////////
// L = A2
// Separating Axis is Box0's Y axis
/////////////////////////////////////////////////////////////////////////
AB[2][0] = Dot_Product(box0.Basis[2],box1.Basis[0]);
AB[2][1] = Dot_Product(box0.Basis[2],box1.Basis[1]);
AB[2][2] = Dot_Product(box0.Basis[2],box1.Basis[2]);
ra = FABS(box0.Extent[2]);
rb = FABS(box1.Extent[0]*AB[2][0])+FABS(box1.Extent[1]*AB[2][1])+FABS(box1.Extent[2]*AB[2][2]);
rsum = ra+rb;
u0 = Dot_Product(C,box0.Basis[2]);
if ((u0 > rsum) || (u0 < -rsum))
return itA2;
/////////////////////////////////////////////////////////////////////////
// L = B0
// Separating Axis is Box1's X axis
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*AB[0][0])+FABS(box0.Extent[1]*AB[1][0])+FABS(box0.Extent[2]*AB[2][0]);
rb = FABS(box1.Extent[0]);
rsum = ra+rb;
u0 = Dot_Product(C,box1.Basis[0]);
if ((u0 > rsum) || (u0 < -rsum))
return itB0;
/////////////////////////////////////////////////////////////////////////
// L = B1
// Separating Axis is Box1's Y axis
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*AB[0][1])+FABS(box0.Extent[1]*AB[1][1])+FABS(box0.Extent[2]*AB[2][1]);
rb = FABS(box1.Extent[1]);
rsum = ra+rb;
u0 = Dot_Product(C,box1.Basis[1]);
if ((u0 > rsum) || (u0 < -rsum))
return itB1;
/////////////////////////////////////////////////////////////////////////
// L = B2
// Separating Axis is Box1's Z axis
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*AB[0][2])+FABS(box0.Extent[1]*AB[1][2])+FABS(box0.Extent[2]*AB[2][2]);
rb = FABS(box1.Extent[2]);
rsum = ra+rb;
u0 = Dot_Product(C,box1.Basis[2]);
if ((u0 > rsum) || (u0 < -rsum))
return itB2;
/////////////////////////////////////////////////////////////////////////
// None of the aligned axes turned out to be separating axes. Now
// we check all combinations of cross products of the two boxes axes.
/////////////////////////////////////////////////////////////////////////
Matrix3 Ainv = box0.Basis.Transpose();
Matrix3 coeff = AB.Transpose();
// difference of centers in box0's-basis
Vector3 d0, d1, product;
d0 = Ainv * C;
/////////////////////////////////////////////////////////////////////////
// L = A0xB0
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[1]*coeff[0][2])+FABS(box0.Extent[2]*coeff[0][1]);
rb = FABS(box1.Extent[1]*coeff[2][0])+FABS(box1.Extent[2]*coeff[1][0]);
rsum = ra+rb;
u0 = d0[2]*coeff[1][0]-d0[1]*coeff[2][0];
if ((u0 > rsum) || (u0 < -rsum))
return itA0B0;
/////////////////////////////////////////////////////////////////////////
// L = A0xB1
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[1]*coeff[1][2])+FABS(box0.Extent[2]*coeff[1][1]);
rb = FABS(box1.Extent[0]*coeff[2][0])+FABS(box1.Extent[2]*coeff[0][0]);
rsum = ra+rb;
u0 = d0[2]*coeff[1][1]-d0[1]*coeff[1][2];
if ((u0 > rsum) || (u0 < -rsum))
return itA0B1;
/////////////////////////////////////////////////////////////////////////
// L = A0xB2
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[1]*coeff[2][2])+FABS(box0.Extent[2]*coeff[2][1]);
rb = FABS(box1.Extent[0]*coeff[1][0])+FABS(box1.Extent[1]*coeff[0][0]);
rsum = ra+rb;
u0 = d0[2]*coeff[2][1]-d0[1]*coeff[2][2];
if ((u0 > rsum) || (u0 < -rsum))
return itA0B2;
/////////////////////////////////////////////////////////////////////////
// L = A1xB0
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[0][2])+FABS(box0.Extent[2]*coeff[0][0]);
rb = FABS(box1.Extent[1]*coeff[2][1])+FABS(box1.Extent[2]*coeff[1][1]);
rsum = ra+rb;
u0 = d0[0]*coeff[0][2]-d0[2]*coeff[0][0];
if ((u0 > rsum) || (u0 < -rsum))
return itA1B0;
/////////////////////////////////////////////////////////////////////////
// L = A1xB1
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[1][2])+FABS(box0.Extent[2]*coeff[1][0]);
rb = FABS(box1.Extent[0]*coeff[2][1])+FABS(box1.Extent[2]*coeff[0][1]);
rsum = ra+rb;
u0 = d0[0]*coeff[1][2]-d0[2]*coeff[1][0];
if ((u0 > rsum) || (u0 < -rsum))
return itA1B1;
/////////////////////////////////////////////////////////////////////////
// L = A1xB2
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[2][2])+FABS(box0.Extent[2]*coeff[2][0]);
rb = FABS(box1.Extent[0]*coeff[1][1])+FABS(box1.Extent[1]*coeff[0][1]);
rsum = ra+rb;
u0 = d0[0]*coeff[2][2]-d0[2]*coeff[2][0];
if ((u0 > rsum) || (u0 < -rsum))
return itA1B2;
/////////////////////////////////////////////////////////////////////////
// L = A2xB0
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[0][1])+FABS(box0.Extent[1]*coeff[0][0]);
rb = FABS(box1.Extent[1]*coeff[2][2])+FABS(box1.Extent[2]*coeff[1][2]);
rsum = ra+rb;
u0 = d0[1]*coeff[0][0]-d0[0]*coeff[0][1];
if ((u0 > rsum) || (u0 < -rsum))
return itA2B0;
/////////////////////////////////////////////////////////////////////////
// L = A2xB1
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[1][1])+FABS(box0.Extent[1]*coeff[1][0]);
rb = FABS(box1.Extent[0]*coeff[2][2])+FABS(box1.Extent[2]*coeff[0][2]);
rsum = ra+rb;
u0 = d0[1]*coeff[1][0]-d0[0]*coeff[1][1];
if ((u0 > rsum) || (u0 < -rsum))
return itA2B1;
/////////////////////////////////////////////////////////////////////////
// L = A2xB2
/////////////////////////////////////////////////////////////////////////
ra = FABS(box0.Extent[0]*coeff[2][1])+FABS(box0.Extent[1]*coeff[2][0]);
rb = FABS(box1.Extent[0]*coeff[1][2])+FABS(box1.Extent[1]*coeff[0][2]);
rsum = ra+rb;
u0 = d0[1]*coeff[2][0]-d0[0]*coeff[2][1];
if ((u0 > rsum) || (u0 < -rsum))
return itA2B2;
return itIntersects;
}

59
Code/Tests/collide/col.h Normal file
View File

@@ -0,0 +1,59 @@
/*
** Command & Conquer Renegade(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 <http://www.gnu.org/licenses/>.
*/
#include "matrix3.h"
#include "vector3.h"
#include "cvec.h"
typedef enum
{
itIntersects,
itA0, itA1, itA2,
itB0, itB1, itB2,
itA0B0, itA0B1, itA0B2,
itA1B0, itA1B1, itA1B2,
itA2B0, itA2B1, itA2B2
}
IntersectType;
typedef struct
{
Vector center;
Vector basis[3];
Vector extent;
Vector velocity;
}
Box;
class BoxClass
{
public:
BoxClass(Box box);
Vector3 Center;
Vector3 Extent;
Vector3 Velocity;
Matrix3 Basis;
};
IntersectType Boxes_Intersect(const BoxClass & box0, const BoxClass & box1);
IntersectType Boxes_Intersect(const BoxClass & box0, const BoxClass & box1,float dt);
IntersectType BoxesIntersect(float dt, const Box & box0, const Box & box1);

View File

@@ -0,0 +1,113 @@
# Microsoft Developer Studio Project File - Name="collide" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 5.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=collide - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "collide.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "collide.mak" CFG="collide - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "collide - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "collide - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP Scc_ProjName ""$/Commando/Code/Tests/collide", NWHAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "collide - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\wwmath" /I "..\..\Library" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib library.lib wwmath.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "collide - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\wwmath" /I "..\..\Library" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib libraryd.lib wwmathd.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "collide - Win32 Release"
# Name "collide - Win32 Debug"
# Begin Group "source files"
# PROP Default_Filter "cpp;c"
# Begin Source File
SOURCE=.\col.cpp
# End Source File
# Begin Source File
SOURCE=.\Collide.cpp
# End Source File
# Begin Source File
SOURCE=.\oldcol.cpp
# End Source File
# End Group
# Begin Group "Header files"
# PROP Default_Filter "h"
# Begin Source File
SOURCE=.\col.h
# End Source File
# Begin Source File
SOURCE=.\cvec.h
# End Source File
# End Group
# End Target
# End Project

102
Code/Tests/collide/cvec.h Normal file
View File

@@ -0,0 +1,102 @@
/*
** Command & Conquer Renegade(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 <http://www.gnu.org/licenses/>.
*/
#ifndef CVEC_H
#define CVEC_H
typedef float Vector[3];
#define FABS(f) (float(fabs(f)))
//---------------------------------------------------------------------------
inline void Add (const Vector u, const Vector v, Vector sum)
{
sum[0] = u[0] + v[0];
sum[1] = u[1] + v[1];
sum[2] = u[2] + v[2];
}
//---------------------------------------------------------------------------
inline void Sub (const Vector u, const Vector v, Vector diff)
{
diff[0] = u[0] - v[0];
diff[1] = u[1] - v[1];
diff[2] = u[2] - v[2];
}
//---------------------------------------------------------------------------
inline float Dot (const Vector u, const Vector v)
{
return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
}
//---------------------------------------------------------------------------
inline void ScalarMult (const float scalar, const Vector u, Vector product)
{
product[0] = scalar*u[0];
product[1] = scalar*u[1];
product[2] = scalar*u[2];
}
//---------------------------------------------------------------------------
inline int Invert3x3 (const float a[3][3], float ainv[3][3])
{
// Invert a 3x3 using cofactors. This is about 8 times faster than
// the Numerical Recipes code which uses Gaussian elimination.
ainv[0][0] = a[1][1]*a[2][2]-a[1][2]*a[2][1];
ainv[0][1] = a[0][2]*a[2][1]-a[0][1]*a[2][2];
ainv[0][2] = a[0][1]*a[1][2]-a[0][2]*a[1][1];
ainv[1][0] = a[1][2]*a[2][0]-a[1][0]*a[2][2];
ainv[1][1] = a[0][0]*a[2][2]-a[0][2]*a[2][0];
ainv[1][2] = a[0][2]*a[1][0]-a[0][0]*a[1][2];
ainv[2][0] = a[1][0]*a[2][1]-a[1][1]*a[2][0];
ainv[2][1] = a[0][1]*a[2][0]-a[0][0]*a[2][1];
ainv[2][2] = a[0][0]*a[1][1]-a[0][1]*a[1][0];
float det = a[0][0]*ainv[0][0]+a[0][1]*ainv[1][0]+a[0][2]*ainv[2][0];
if (FABS(det) <= 1e-06f )
return 0;
float invdet = 1.0f/det;
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++)
ainv[row][col] *= invdet;
return 1;
}
//---------------------------------------------------------------------------
inline void MultiplyVM (Vector input, float m[3][3], Vector output)
{
output[0] = input[0]*m[0][0] + input[1]*m[1][0] + input[2]*m[2][0];
output[1] = input[0]*m[0][1] + input[1]*m[1][1] + input[2]*m[2][1];
output[2] = input[0]*m[0][2] + input[1]*m[1][2] + input[2]*m[2][2];
}
//---------------------------------------------------------------------------
inline void MultiplyMM (const float A[3][3], const float B[3][3], float AB[3][3])
{
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 3; col++)
{
AB[row][col] = 0.0f;
for (int mid = 0; mid < 3; mid++)
AB[row][col] += A[row][mid]*B[mid][col];
}
}
}
#endif

View File

@@ -0,0 +1,261 @@
/*
** Command & Conquer Renegade(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 <http://www.gnu.org/licenses/>.
*/
#include "col.h"
// The eight box vertices of the box at time zero are
// center+extent[i]*basis[i]
// center-extent[i]*basis[i]
// for i = 0,1,2,3. The vertices after a time step of dt are
// center+dt*velocity+extent[i]*basis[i]
// center+dt*velocity-extent[i]*basis[i]
// for i = 0,1,2,3.
//---------------------------------------------------------------------------
IntersectType BoxesIntersect (float dt, const Box& box0, const Box& box1)
{
// Comments indicate where additional speed is gained for orthonormal bases
// for both boxes. If a box is known to be flat (a[i] = 0 for some i OR
// b[j] = 0 for some j), then more terms can be eliminated.
const Vector* A = box0.basis;
const Vector* B = box1.basis;
const float* a = box0.extent;
const float* b = box1.extent;
// memoized values for Dot(A[i],A[j]), Dot(A[i],B[j]), Dot(B[i],B[j])
float AA[3][3], AB[3][3], BB[3][3];
// calculate difference of centers
Vector C, V;
Sub(box1.center,box0.center,C);
Sub(box1.velocity,box0.velocity,V);
float ra, rb, rsum, u0, u1;
// L = A0
AA[0][0] = Dot(A[0],A[0]); // = 1 for orthonormal basis
AA[0][1] = Dot(A[0],A[1]); // = 0 for orthonormal basis
AA[0][2] = Dot(A[0],A[2]); // = 0 for orthonormal basis
AB[0][0] = Dot(A[0],B[0]);
AB[0][1] = Dot(A[0],B[1]);
AB[0][2] = Dot(A[0],B[2]);
ra = FABS(a[0]*AA[0][0])+FABS(a[1]*AA[0][1])+FABS(a[2]*AA[0][2]);
// = FABS(a[0]) for orthonormal basis
rb = FABS(b[0]*AB[0][0])+FABS(b[1]*AB[0][1])+FABS(b[2]*AB[0][2]);
rsum = ra+rb;
u0 = Dot(C,A[0]);
u1 = u0+dt*Dot(V,A[0]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0;
// L = A1
AA[1][1] = Dot(A[1],A[1]); // = 1 for orthonormal basis
AA[1][2] = Dot(A[1],A[2]); // = 0 for orthonormal basis
AB[1][0] = Dot(A[1],B[0]);
AB[1][1] = Dot(A[1],B[1]);
AB[1][2] = Dot(A[1],B[2]);
ra = FABS(a[0]*AA[0][1])+FABS(a[1]*AA[1][1])+FABS(a[2]*AA[1][2]);
// = FABS(a[1]) for orthonormal basis
rb = FABS(b[0]*AB[1][0])+FABS(b[1]*AB[1][1])+FABS(b[2]*AB[1][2]);
rsum = ra+rb;
u0 = Dot(C,A[1]);
u1 = u0+dt*Dot(V,A[1]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1;
// L = A2
AA[2][2] = Dot(A[2],A[2]); // = 1 for orthonormal basis
AB[2][0] = Dot(A[2],B[0]);
AB[2][1] = Dot(A[2],B[1]);
AB[2][2] = Dot(A[2],B[2]);
ra = FABS(a[0]*AA[0][2])+FABS(a[1]*AA[1][2])+FABS(a[2]*AA[2][2]);
// = FABS(a[2]) for orthonormal basis
rb = FABS(b[0]*AB[2][0])+FABS(b[1]*AB[2][1])+FABS(b[2]*AB[2][2]);
rsum = ra+rb;
u0 = Dot(C,A[2]);
u1 = u0+dt*Dot(V,A[2]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2;
// L = B0
BB[0][0] = Dot(B[0],B[0]); // = 1 for orthonormal basis
BB[0][1] = Dot(B[0],B[1]); // = 0 for orthonormal basis
BB[0][2] = Dot(B[0],B[2]); // = 0 for orthonormal basis
ra = FABS(a[0]*AB[0][0])+FABS(a[1]*AB[1][0])+FABS(a[2]*AB[2][0]);
rb = FABS(b[0]*BB[0][0])+FABS(b[1]*BB[0][1])+FABS(b[2]*BB[0][2]);
// = FABS(b[0]) for orthonormal basis
rsum = ra+rb;
u0 = Dot(C,B[0]);
u1 = u0+dt*Dot(V,B[0]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itB0;
// L = B1
BB[1][1] = Dot(B[1],B[1]); // = 1 for orthonormal basis
BB[1][2] = Dot(B[1],B[2]); // = 0 for orthonormal basis
ra = FABS(a[0]*AB[0][1])+FABS(a[1]*AB[1][1])+FABS(a[2]*AB[2][1]);
rb = FABS(b[0]*BB[0][1])+FABS(b[1]*BB[1][1])+FABS(b[2]*BB[1][2]);
// = FABS(b[1]) for orthonormal basis
rsum = ra+rb;
u0 = Dot(C,B[1]);
u1 = u0+dt*Dot(V,B[1]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itB1;
// L = B2
BB[2][2] = Dot(B[2],B[2]); // = 1 for orthonormal basis
ra = FABS(a[0]*AB[0][2])+FABS(a[1]*AB[1][2])+FABS(a[2]*AB[2][2]);
rb = FABS(b[0]*BB[0][2])+FABS(b[1]*BB[1][2])+FABS(b[2]*BB[2][2]);
// = FABS(b[2]) for orthonormal basis
rsum = ra+rb;
u0 = Dot(C,B[2]);
u1 = u0+dt*Dot(V,B[2]);
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itB2;
// check separating axes which are cross products of box edges
float Ainv[3][3], coeff[3][3];
Invert3x3(A,Ainv);
// Ainv = Transpose(A) for orthonormal basis, no need to invert
MultiplyMM(B,Ainv,coeff);
// coeff[i][j] = AB[j][i] for orthonormal basis, no need to multiply
// memoize minors of coefficient matrix
float minor[3][3];
// difference of centers in A-basis
Vector d0, d1, product;
MultiplyVM(C,Ainv,d0); // Ainv = Transpose(A) for orthonormal basis
MultiplyVM(V,Ainv,d1); // Ainv = Transpose(A) for orthonormal basis
ScalarMult(dt,d1,product);
Add(d0,product,d1);
// L = A0xB0
minor[0][1] = coeff[0][1]*coeff[2][2]-coeff[2][1]*coeff[0][2];
// = -coeff[1][0] for orthonormal bases
minor[0][2] = coeff[0][1]*coeff[1][2]-coeff[1][1]*coeff[0][2];
// = +coeff[2][0] for orthonormal bases
ra = FABS(a[1]*coeff[0][2])+FABS(a[2]*coeff[0][1]);
rb = FABS(b[1]*minor[0][2])+FABS(b[2]*minor[0][1]);
// = FABS(b[1]*coeff[2][0])+FABS(b[2]*coeff[1][0]) for orthonormal bases
rsum = ra+rb;
u0 = d0[2]*coeff[1][0]-d0[1]*coeff[2][0];
u1 = d1[2]*coeff[1][0]-d1[1]*coeff[2][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0B0;
// L = A0xB1
minor[0][0] = coeff[1][1]*coeff[2][2]-coeff[2][1]*coeff[1][2];
// = +coeff[0][0] for orthonormal bases
ra = FABS(a[1]*coeff[1][2])+FABS(a[2]*coeff[1][1]);
rb = FABS(b[0]*minor[0][2])+FABS(b[2]*minor[0][0]);
// = FABS(b[0]*coeff[2][0])+FABS(b[2]*coeff[0][0]) for orthonormal bases
rsum = ra+rb;
u0 = d0[2]*coeff[1][1]-d0[1]*coeff[1][2];
u1 = d1[2]*coeff[1][1]-d1[1]*coeff[1][2];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0B1;
// L = A0xB2
ra = FABS(a[1]*coeff[2][2])+FABS(a[2]*coeff[2][1]);
rb = FABS(b[0]*minor[0][1])+FABS(b[1]*minor[0][0]);
// = FABS(b[0]*coeff[1][0])+FABS(b[1]*coeff[0][0]) for orthonormal bases
rsum = ra+rb;
u0 = d0[2]*coeff[2][1]-d0[1]*coeff[2][2];
u1 = d1[2]*coeff[2][1]-d1[1]*coeff[2][2];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA0B2;
// L = A1xB0
minor[1][1] = coeff[0][0]*coeff[2][2]-coeff[2][0]*coeff[0][2];
// = +coeff[1][1] for orthonormal bases
minor[1][2] = coeff[0][0]*coeff[1][2]-coeff[1][0]*coeff[0][2];
// = -coeff[2][1] for orthonormal bases
ra = FABS(a[0]*coeff[0][2])+FABS(a[2]*coeff[0][0]);
rb = FABS(b[1]*minor[1][2])+FABS(b[2]*minor[1][1]);
// = FABS(b[1]*coeff[2][1])+FABS(b[2]*coeff[1][1]) for orthonormal bases
rsum = ra+rb;
u0 = d0[0]*coeff[0][2]-d0[2]*coeff[0][0];
u1 = d1[0]*coeff[0][2]-d1[2]*coeff[0][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1B0;
// L = A1xB1
minor[1][0] = coeff[1][0]*coeff[2][2]-coeff[2][0]*coeff[1][2];
// = -coeff[0][1] for orthonormal bases
ra = FABS(a[0]*coeff[1][2])+FABS(a[2]*coeff[1][0]);
rb = FABS(b[0]*minor[1][2])+FABS(b[2]*minor[1][0]);
// = FABS(b[0]*coeff[2][1])+FABS(b[2]*coeff[0][1]) for orthonormal bases
rsum = ra+rb;
u0 = d0[0]*coeff[1][2]-d0[2]*coeff[1][0];
u1 = d1[0]*coeff[1][2]-d1[2]*coeff[1][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1B1;
// L = A1xB2
ra = FABS(a[0]*coeff[2][2])+FABS(a[2]*coeff[2][0]);
rb = FABS(b[0]*minor[1][1])+FABS(b[1]*minor[1][0]);
// = FABS(b[0]*coeff[1][1])+FABS(b[1]*coeff[0][1]) for orthonormal bases
rsum = ra+rb;
u0 = d0[0]*coeff[2][2]-d0[2]*coeff[2][0];
u1 = d1[0]*coeff[2][2]-d1[2]*coeff[2][0];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA1B2;
// L = A2xB0
minor[2][1] = coeff[0][0]*coeff[2][1]-coeff[2][0]*coeff[0][1];
// = -coeff[2][1] for orthonormal bases
minor[2][2] = coeff[0][0]*coeff[1][1]-coeff[1][0]*coeff[0][1];
// = +coeff[2][2] for orthonormal bases
ra = FABS(a[0]*coeff[0][1])+FABS(a[1]*coeff[0][0]);
rb = FABS(b[1]*minor[2][2])+FABS(b[2]*minor[2][1]);
// = FABS(b[1]*coeff[2][2])+FABS(b[2]*coeff[1][2]) for orthonormal bases
rsum = ra+rb;
u0 = d0[1]*coeff[0][0]-d0[0]*coeff[0][1];
u1 = d1[1]*coeff[0][0]-d1[0]*coeff[0][1];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2B0;
// L = A2xB1
minor[2][0] = coeff[1][0]*coeff[2][1]-coeff[2][0]*coeff[1][1];
// = +coeff[0][2] for orthonormal bases
ra = FABS(a[0]*coeff[1][1])+FABS(a[1]*coeff[1][0]);
rb = FABS(b[0]*minor[2][2])+FABS(b[2]*minor[2][0]);
// = FABS(b[0]*coeff[2][2])+FABS(b[2]*coeff[0][2]) for orthonormal bases
rsum = ra+rb;
u0 = d0[1]*coeff[1][0]-d0[0]*coeff[1][1];
u1 = d1[1]*coeff[1][0]-d1[0]*coeff[1][1];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2B1;
// L = A2xB2
ra = FABS(a[0]*coeff[2][1])+FABS(a[1]*coeff[2][0]);
rb = FABS(b[0]*minor[2][1])+FABS(b[1]*minor[2][0]);
// = FABS(b[0]*coeff[1][2])+FABS(b[1]*coeff[0][2]) for orthonormal bases
rsum = ra+rb;
u0 = d0[1]*coeff[2][0]-d0[0]*coeff[2][1];
u1 = d1[1]*coeff[2][0]-d1[0]*coeff[2][1];
if ((u0 > rsum && u1 > rsum) || (u0 < -rsum && u1 < -rsum) )
return itA2B2;
return itIntersects;
}