405 lines
11 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Generals Zero Hour(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]);
}
}
}