405 lines
11 KiB
C++
405 lines
11 KiB
C++
|
/*
|
||
|
** 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/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** 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/Tools/max2w3d/WWmatrix3.cpp $*
|
||
|
* *
|
||
|
* Author:: Greg_h *
|
||
|
* *
|
||
|
* $Modtime:: 2/02/00 2:05p $*
|
||
|
* *
|
||
|
* $Revision:: 17 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
|
||
|
#include "wwmatrix3.h"
|
||
|
#include "matrix3d.h"
|
||
|
#include "matrix4.h"
|
||
|
#include "w3dquat.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Some pre-initialized Matrix3's
|
||
|
*/
|
||
|
const Matrix3 Matrix3::Identity
|
||
|
(
|
||
|
1.0, 0.0, 0.0,
|
||
|
0.0, 1.0, 0.0,
|
||
|
0.0, 0.0, 1.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateX90
|
||
|
(
|
||
|
1.0, 0.0, 0.0,
|
||
|
0.0, 0.0, -1.0,
|
||
|
0.0, 1.0, 0.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateX180
|
||
|
(
|
||
|
1.0, 0.0, 0.0,
|
||
|
0.0, -1.0, 0.0,
|
||
|
0.0, 0.0, -1.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateX270
|
||
|
(
|
||
|
1.0, 0.0, 0.0,
|
||
|
0.0, 0.0, 1.0,
|
||
|
0.0, -1.0, 0.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateY90
|
||
|
(
|
||
|
0.0, 0.0, 1.0,
|
||
|
0.0, 1.0, 0.0,
|
||
|
-1.0, 0.0, 0.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateY180
|
||
|
(
|
||
|
-1.0, 0.0, 0.0,
|
||
|
0.0, 1.0, 0.0,
|
||
|
0.0, 0.0, -1.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateY270
|
||
|
(
|
||
|
0.0, 0.0, -1.0,
|
||
|
0.0, 1.0, 0.0,
|
||
|
1.0, 0.0, 0.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateZ90
|
||
|
(
|
||
|
0.0, -1.0, 0.0,
|
||
|
1.0, 0.0, 0.0,
|
||
|
0.0, 0.0, 1.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateZ180
|
||
|
(
|
||
|
-1.0, 0.0, 0.0,
|
||
|
0.0, -1.0, 0.0,
|
||
|
0.0, 0.0, 1.0
|
||
|
);
|
||
|
|
||
|
const Matrix3 Matrix3::RotateZ270
|
||
|
(
|
||
|
0.0, 1.0, 0.0,
|
||
|
-1.0, 0.0, 0.0,
|
||
|
0.0, 0.0, 1.0
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Matrix3::Matrix3 -- Convert a Matrix3D (fake 4x4) to a Matrix3 *
|
||
|
* *
|
||
|
* INPUT: *
|
||
|
* *
|
||
|
* OUTPUT: *
|
||
|
* *
|
||
|
* WARNINGS: *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 06/02/1997 GH : Created. *
|
||
|
*=============================================================================================*/
|
||
|
Matrix3::Matrix3(const Matrix3D & m)
|
||
|
{
|
||
|
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||
|
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||
|
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||
|
}
|
||
|
|
||
|
Matrix3::Matrix3(const Matrix4 & m)
|
||
|
{
|
||
|
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||
|
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||
|
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||
|
}
|
||
|
|
||
|
void Matrix3::Set(const Matrix3D & m)
|
||
|
{
|
||
|
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||
|
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||
|
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||
|
}
|
||
|
|
||
|
void Matrix3::Set(const Matrix4 & m)
|
||
|
{
|
||
|
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||
|
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||
|
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||
|
}
|
||
|
|
||
|
void Matrix3::Set(const Quaternion & q)
|
||
|
{
|
||
|
Row[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
|
||
|
Row[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
|
||
|
Row[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
|
||
|
|
||
|
Row[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
|
||
|
Row[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
|
||
|
Row[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
|
||
|
|
||
|
Row[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
|
||
|
Row[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
|
||
|
Row[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
|
||
|
}
|
||
|
|
||
|
|
||
|
Matrix3 & Matrix3::operator = (const Matrix3D & m)
|
||
|
{
|
||
|
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||
|
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||
|
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
Matrix3 & Matrix3::operator = (const Matrix4 & m)
|
||
|
{
|
||
|
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||
|
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||
|
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
void Matrix3::Multiply(const Matrix3D & a, const Matrix3 & b,Matrix3 * res)
|
||
|
{
|
||
|
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||
|
|
||
|
(*res)[0][0] = ROWCOL(0,0);
|
||
|
(*res)[0][1] = ROWCOL(0,1);
|
||
|
(*res)[0][2] = ROWCOL(0,2);
|
||
|
|
||
|
(*res)[1][0] = ROWCOL(1,0);
|
||
|
(*res)[1][1] = ROWCOL(1,1);
|
||
|
(*res)[1][2] = ROWCOL(1,2);
|
||
|
|
||
|
(*res)[2][0] = ROWCOL(2,0);
|
||
|
(*res)[2][1] = ROWCOL(2,1);
|
||
|
(*res)[2][2] = ROWCOL(2,2);
|
||
|
|
||
|
#undef ROWCOL
|
||
|
}
|
||
|
|
||
|
void Matrix3::Multiply(const Matrix3 & a, const Matrix3D & b,Matrix3 * res)
|
||
|
{
|
||
|
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||
|
|
||
|
(*res)[0][0] = ROWCOL(0,0);
|
||
|
(*res)[0][1] = ROWCOL(0,1);
|
||
|
(*res)[0][2] = ROWCOL(0,2);
|
||
|
|
||
|
(*res)[1][0] = ROWCOL(1,0);
|
||
|
(*res)[1][1] = ROWCOL(1,1);
|
||
|
(*res)[1][2] = ROWCOL(1,2);
|
||
|
|
||
|
(*res)[2][0] = ROWCOL(2,0);
|
||
|
(*res)[2][1] = ROWCOL(2,1);
|
||
|
(*res)[2][2] = ROWCOL(2,2);
|
||
|
|
||
|
#undef ROWCOL
|
||
|
}
|
||
|
|
||
|
Matrix3 operator * (const Matrix3D & a, const Matrix3 & b)
|
||
|
{
|
||
|
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||
|
|
||
|
return Matrix3(
|
||
|
Vector3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2) ),
|
||
|
Vector3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2) ),
|
||
|
Vector3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2) )
|
||
|
);
|
||
|
|
||
|
#undef ROWCOL
|
||
|
}
|
||
|
|
||
|
Matrix3 operator * (const Matrix3 & a, const Matrix3D & b)
|
||
|
{
|
||
|
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||
|
|
||
|
return Matrix3(
|
||
|
Vector3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2) ),
|
||
|
Vector3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2) ),
|
||
|
Vector3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2) )
|
||
|
);
|
||
|
|
||
|
#undef ROWCOL
|
||
|
}
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
void Matrix3::Compute_Jacobi_Rotation(int i,int j,Matrix3 * r,Matrix3 * rinv)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void Matrix3::Symmetric_Eigen_Solve(void)
|
||
|
{
|
||
|
Matrix3 eigen_vals = *this;
|
||
|
Matrix3 eigen_vecs(1);
|
||
|
|
||
|
Matrix3 jr,jrinv;
|
||
|
|
||
|
while (!done) {
|
||
|
eigen_vals.Compute_Jacobi_Rotation(i,j,&jr,&jrinv);
|
||
|
eigen_vals = jr * (eigenvals) * jrinv;
|
||
|
eigen_vecs = eigen_vecs * jr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Done! Eigen values are the diagonals of
|
||
|
** the eigen_vals matrix and the eigen vectors
|
||
|
** are the columns of the eigen_vecs matrix
|
||
|
*/
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void Matrix3::Multiply(const Matrix3 & A,const Matrix3 & B,Matrix3 * set_res)
|
||
|
{
|
||
|
Matrix3 tmp;
|
||
|
Matrix3 * Aptr;
|
||
|
float tmp1,tmp2,tmp3;
|
||
|
|
||
|
// Check for aliased parameters, copy the 'A' matrix into a temporary if the
|
||
|
// result is going into 'A'. (in this case, this function is no better than
|
||
|
// the overloaded C++ operator...)
|
||
|
if (set_res == &A) {
|
||
|
tmp = A;
|
||
|
Aptr = &tmp;
|
||
|
} else {
|
||
|
Aptr = (Matrix3 *)&A;
|
||
|
}
|
||
|
|
||
|
tmp1 = B[0][0];
|
||
|
tmp2 = B[1][0];
|
||
|
tmp3 = B[2][0];
|
||
|
|
||
|
(*set_res)[0][0] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3);
|
||
|
(*set_res)[1][0] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3);
|
||
|
(*set_res)[2][0] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3);
|
||
|
|
||
|
tmp1 = B[0][1];
|
||
|
tmp2 = B[1][1];
|
||
|
tmp3 = B[2][1];
|
||
|
|
||
|
(*set_res)[0][1] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3);
|
||
|
(*set_res)[1][1] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3);
|
||
|
(*set_res)[2][1] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3);
|
||
|
|
||
|
tmp1 = B[0][2];
|
||
|
tmp2 = B[1][2];
|
||
|
tmp3 = B[2][2];
|
||
|
|
||
|
(*set_res)[0][2] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3);
|
||
|
(*set_res)[1][2] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3);
|
||
|
(*set_res)[2][2] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3);
|
||
|
}
|
||
|
|
||
|
int Matrix3::Is_Orthogonal(void) const
|
||
|
{
|
||
|
Vector3 x(Row[0].X,Row[0].Y,Row[0].Z);
|
||
|
Vector3 y(Row[1].X,Row[1].Y,Row[1].Z);
|
||
|
Vector3 z(Row[2].X,Row[2].Y,Row[2].Z);
|
||
|
|
||
|
if (Vector3::Dot_Product(x,y) > WWMATH_EPSILON) return 0;
|
||
|
if (Vector3::Dot_Product(y,z) > WWMATH_EPSILON) return 0;
|
||
|
if (Vector3::Dot_Product(z,x) > WWMATH_EPSILON) return 0;
|
||
|
|
||
|
if (WWMath::Fabs(x.Length() - 1.0f) > WWMATH_EPSILON) return 0;
|
||
|
if (WWMath::Fabs(y.Length() - 1.0f) > WWMATH_EPSILON) return 0;
|
||
|
if (WWMath::Fabs(z.Length() - 1.0f) > WWMATH_EPSILON) return 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void Matrix3::Re_Orthogonalize(void)
|
||
|
{
|
||
|
Vector3 x(Row[0][0],Row[0][1],Row[0][2]);
|
||
|
Vector3 y(Row[1][0],Row[1][1],Row[1][2]);
|
||
|
Vector3 z;
|
||
|
|
||
|
Vector3::Cross_Product(x,y,&z);
|
||
|
Vector3::Cross_Product(z,x,&y);
|
||
|
|
||
|
float len = x.Length();
|
||
|
if (len < WWMATH_EPSILON) {
|
||
|
Make_Identity();
|
||
|
return;
|
||
|
} else {
|
||
|
x /= len;
|
||
|
}
|
||
|
|
||
|
len = y.Length();
|
||
|
if (len < WWMATH_EPSILON) {
|
||
|
Make_Identity();
|
||
|
return;
|
||
|
} else {
|
||
|
y /= len;
|
||
|
}
|
||
|
|
||
|
len = z.Length();
|
||
|
if (len < WWMATH_EPSILON) {
|
||
|
Make_Identity();
|
||
|
return;
|
||
|
} else {
|
||
|
z /= len;
|
||
|
}
|
||
|
|
||
|
Row[0][0] = x.X;
|
||
|
Row[0][1] = x.Y;
|
||
|
Row[0][2] = x.Z;
|
||
|
|
||
|
Row[1][0] = y.X;
|
||
|
Row[1][1] = y.Y;
|
||
|
Row[1][2] = y.Z;
|
||
|
|
||
|
Row[2][0] = z.X;
|
||
|
Row[2][1] = z.Y;
|
||
|
Row[2][2] = z.Z;
|
||
|
}
|
||
|
|
||
|
void Matrix3::Rotate_AABox_Extent(const Vector3 & extent,Vector3 * set_extent)
|
||
|
{
|
||
|
// push each extent out to the projections of the original extents
|
||
|
for (int i=0; i<3; i++) {
|
||
|
|
||
|
// start the center out at the translation portion of the matrix
|
||
|
// and the extent at zero
|
||
|
(*set_extent)[i] = 0.0f;
|
||
|
|
||
|
for (int j=0; j<3; j++) {
|
||
|
(*set_extent)[i] += WWMath::Fabs(Row[i][j] * extent[j]);
|
||
|
}
|
||
|
}
|
||
|
}
|