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,88 @@
/*
** 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/>.
*/
// FindDialog.cpp : implementation file
//
#include "stdafx.h"
#include "wdump.h"
#include "FindDialog.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Static data.
char FindDialog::_FindString [MAX_FIND_STRING_LENGTH + 1] = "";
bool FindDialog::_Found;
/////////////////////////////////////////////////////////////////////////////
// FindDialog dialog
FindDialog::FindDialog(CWnd* pParent /*=NULL*/)
: CDialog(FindDialog::IDD, pParent)
{
//{{AFX_DATA_INIT(FindDialog)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void FindDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(FindDialog)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(FindDialog, CDialog)
//{{AFX_MSG_MAP(FindDialog)
ON_EN_CHANGE(IDC_FIND_STRING, OnChangeFindString)
ON_EN_UPDATE(IDC_FIND_STRING, OnUpdateFindString)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// FindDialog message handlers
BOOL FindDialog::OnInitDialog()
{
CDialog::OnInitDialog();
((CEdit*) GetDlgItem (IDC_FIND_STRING))->SetLimitText (MAX_FIND_STRING_LENGTH);
GetDlgItem (IDC_FIND_STRING)->SetWindowText (_FindString);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void FindDialog::OnChangeFindString()
{
GetDlgItem (IDC_FIND_STRING)->GetWindowText (_FindString, MAX_FIND_STRING_LENGTH);
}
void FindDialog::OnUpdateFindString()
{
GetDlgItem (IDOK)->EnableWindow (GetDlgItem (IDC_FIND_STRING)->GetWindowTextLength() > 0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,379 @@
/*
** 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 : WW3D PS2 *
* *
* $Archive:: /Commando/Code/Tools/W3DShellExt/External/matrix3.cpp $*
* *
* Programmer : Kenny Mitchell *
* *
* Start Date : 11/16/99 *
* *
* Last Update : 11/16/99 *
* *
*---------------------------------------------------------------------------------------------*
* Based on Greg Hjelstrom 97 *
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "matrix3.h"
#include "matrix3d.h"
#include "matrix4.h"
#include "quat.h"
/*
** Some pre-initialized Matrix3's
*/
const Matrix3 Matrix3::Identity
(
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
);
const Matrix3 Matrix3::RotateX90
(
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f,
0.0f, 1.0f, 0.0f
);
const Matrix3 Matrix3::RotateX180
(
1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, 0.0f, -1.0f
);
const Matrix3 Matrix3::RotateX270
(
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, -1.0f, 0.0f
);
const Matrix3 Matrix3::RotateY90
(
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f
);
const Matrix3 Matrix3::RotateY180
(
-1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, -1.0f
);
const Matrix3 Matrix3::RotateY270
(
0.0f, 0.0f, -1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f
);
const Matrix3 Matrix3::RotateZ90
(
0.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f
);
const Matrix3 Matrix3::RotateZ180
(
-1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f
);
const Matrix3 Matrix3::RotateZ270
(
0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f
);
/***********************************************************************************************
* 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.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
Row[0][1] = (float)(2.0f * (q[0] * q[1] - q[2] * q[3]));
Row[0][2] = (float)(2.0f * (q[2] * q[0] + q[1] * q[3]));
Row[1][0] = (float)(2.0f * (q[0] * q[1] + q[2] * q[3]));
Row[1][1] = (float)(1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
Row[1][2] = (float)(2.0f * (q[1] * q[2] - q[0] * q[3]));
Row[2][0] = (float)(2.0f * (q[2] * q[0] - q[1] * q[3]));
Row[2][1] = (float)(2.0f * (q[1] * q[2] + q[0] * q[3]));
Row[2][2] =(float)(1.0f - 2.0f * (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 0
if (Vector3::Dot_Product(x,y) > EPSILON) return 0;
if (Vector3::Dot_Product(y,z) > EPSILON) return 0;
if (Vector3::Dot_Product(z,x) > EPSILON) return 0;
if (Get_Float_ABS(x.Length() - 1.0f) > EPSILON) return 0;
if (Get_Float_ABS(y.Length() - 1.0f) > EPSILON) return 0;
if (Get_Float_ABS(z.Length() - 1.0f) > EPSILON) return 0;
#endif
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);
#if 0
x*=Inv_Sqrt(x.Length2());
y*=Inv_Sqrt(y.Length2());
z*=Inv_Sqrt(z.Length2());
#endif
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;
}

View File

@@ -0,0 +1,910 @@
/*
** 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/>.
*/
/* $Header: /Commando/Code/Tools/W3DShellExt/External/matrix3d.cpp 1 1/02/02 1:18p Moumine_ballo $ */
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : WW3D PS2 *
* *
* File Name : MATRIX3D.CPP *
* *
* Programmer : Kenny Mitchell *
* *
* Start Date : 11/16/99 *
* *
* Last Update : 11/16/99 *
* *
*---------------------------------------------------------------------------------------------*
* Based on Greg Hjelstrom 97 *
* Functions: *
* Matrix3D::Set_Rotation -- Sets the rotation part of the matrix *
* Matrix3D::Set_Rotation -- Sets the rotation part of the matrix *
* Matrix3D::Set -- Init a matrix3D from a matrix3 and a position *
* Matrix3D::Set -- Init a matrix3D from a quaternion and a position *
* Matrix3D::Get_X_Rotation -- approximates the rotation about the X axis *
* Matrix3D::Get_Y_Rotation -- approximates the rotation about the Y axis *
* Matrix3D::Get_Z_Rotation -- approximates the rotation about the Z axis *
* Matrix3D::Multiply -- matrix multiplication without temporaries. *
* Matrix3D::Inverse_Rotate_Vector -- rotates a vector by the inverse of the 3x3 sub-matrix *
* Matrix3D::Transform_Min_Max_AABox -- compute transformed axis-aligned box *
* Matrix3D::Transform_Center_Extent_AABox -- compute transformed axis-aligned box *
* Matrix3D::Get_Inverse -- calculate the inverse of this matrix *
* Matrix3D::Get_Orthogonal_Inverse -- Returns the inverse of the matrix *
* Matrix3D::Re_Orthogonalize -- makes this matrix orthogonal. *
* Matrix3D::Is_Orthogonal -- checks whether this matrix is orthogonal *
* Lerp - linearly interpolate matrices (orientation is slerped) *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "matrix3d.h"
#include <math.h>
#include <stdlib.h>
#include "vector3.h"
#include "matrix3.h"
#include "matrix4.h"
#include "quat.h"
// some static matrices which are sometimes useful
const Matrix3D Matrix3D::Identity
(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f
);
const Matrix3D Matrix3D::RotateX90
(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f,0.0f,
0.0f, 1.0f, 0.0f, 0.0f
);
const Matrix3D Matrix3D::RotateX180
(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f,0.0f, 0.0f,
0.0f, 0.0f,-1.0f, 0.0f
);
const Matrix3D Matrix3D::RotateX270
(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, -1.0f,0.0f, 0.0f
);
const Matrix3D Matrix3D::RotateY90
(
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f
);
const Matrix3D Matrix3D::RotateY180
(
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f,0.0f
);
const Matrix3D Matrix3D::RotateY270
(
0.0f, 0.0f, -1.0f,0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f
);
const Matrix3D Matrix3D::RotateZ90
(
0.0f, -1.0f,0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f
);
const Matrix3D Matrix3D::RotateZ180
(
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f,0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f
);
const Matrix3D Matrix3D::RotateZ270
(
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f
);
/***********************************************************************************************
* Matrix3D::Set -- Init a matrix3D from a matrix3 and a position *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
*=============================================================================================*/
void Matrix3D::Set(const Matrix3 & rot,const Vector3 & pos)
{
Row[0].Set( rot[0][0], rot[0][1], rot[0][2], pos[0]);
Row[1].Set( rot[1][0], rot[1][1], rot[1][2], pos[1]);
Row[2].Set( rot[2][0], rot[2][1], rot[2][2], pos[2]);
}
/***********************************************************************************************
* Matrix3D::Set -- Init a matrix3D from a quaternion and a position *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
*=============================================================================================*/
void Matrix3D::Set(const Quaternion & rot,const Vector3 & pos)
{
Set_Rotation(rot);
Set_Translation(pos);
}
/***********************************************************************************************
* Matrix3D::Set_Rotation -- Sets the rotation part of the matrix *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 5/11/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::Set_Rotation(const Matrix3 & m)
{
Row[0][0] = m[0][0];
Row[0][1] = m[0][1];
Row[0][2] = m[0][2];
Row[1][0] = m[1][0];
Row[1][1] = m[1][1];
Row[1][2] = m[1][2];
Row[2][0] = m[2][0];
Row[2][1] = m[2][1];
Row[2][2] = m[2][2];
}
/***********************************************************************************************
* Matrix3D::Set_Rotation -- Sets the rotation part of the matrix *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 5/11/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::Set_Rotation(const Quaternion & q)
{
Row[0][0] = (float)(1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
Row[0][1] = (float)(2.0f * (q[0] * q[1] - q[2] * q[3]));
Row[0][2] = (float)(2.0f * (q[2] * q[0] + q[1] * q[3]));
Row[1][0] = (float)(2.0f * (q[0] * q[1] + q[2] * q[3]));
Row[1][1] = (float)(1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
Row[1][2] = (float)(2.0f * (q[1] * q[2] - q[0] * q[3]));
Row[2][0] = (float)(2.0f * (q[2] * q[0] - q[1] * q[3]));
Row[2][1] = (float)(2.0f * (q[1] * q[2] + q[0] * q[3]));
Row[2][2] =(float)(1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
}
/***********************************************************************************************
* Matrix3D::Get_X_Rotation -- approximates the rotation about the X axis *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/11/1997 GH : Created. *
*=============================================================================================*/
float Matrix3D::Get_X_Rotation(void) const
{
return atan2f(Row[2][1], Row[1][1]);
}
/***********************************************************************************************
* Matrix3D::Get_Y_Rotation -- approximates the rotation about the Y axis *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/11/1997 GH : Created. *
*=============================================================================================*/
float Matrix3D::Get_Y_Rotation(void) const
{
return atan2f(Row[0][2], Row[2][2]);
}
/***********************************************************************************************
* Matrix3D::Get_Z_Rotation -- approximates the rotation about the Z axis *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/11/1997 GH : Created. *
*=============================================================================================*/
float Matrix3D::Get_Z_Rotation(void) const
{
return atan2f(Row[1][0], Row[0][0]);
}
/***********************************************************************************************
* M3DC::Rotate_Vector -- Uses the 3x3 sub-matrix to rotate a vector *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
*=============================================================================================*/
Vector3 Matrix3D::Rotate_Vector(const Vector3 &vect) const
{
return Vector3(
(Row[0][0]*vect[0] + Row[0][1]*vect[1] + Row[0][2]*vect[2]),
(Row[1][0]*vect[0] + Row[1][1]*vect[1] + Row[1][2]*vect[2]),
(Row[2][0]*vect[0] + Row[2][1]*vect[1] + Row[2][2]*vect[2])
);
}
/***********************************************************************************************
* Matrix3D::Inverse_Rotate_Vector -- rotates a vector by the inverse of the 3x3 sub-matrix *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 4/27/98 GTH : Created. *
*=============================================================================================*/
Vector3 Matrix3D::Inverse_Rotate_Vector(const Vector3 &vect) const
{
return Vector3(
(Row[0][0]*vect[0] + Row[1][0]*vect[1] + Row[2][0]*vect[2]),
(Row[0][1]*vect[0] + Row[1][1]*vect[1] + Row[2][1]*vect[2]),
(Row[0][2]*vect[0] + Row[1][2]*vect[1] + Row[2][2]*vect[2])
);
}
/***********************************************************************************************
* M3DC::Look_At -- Creates a "look at" transformation. *
* *
* Builds a transformation matrix which positions the origin at p, *
* points the negative z-axis towards a target t, and rolls about the z-axis *
* by the angle specified by roll. *
* *
* This can be useful for creating a camera matrix, just invert *
* the matrix after initializing it with this function... *
* *
* INPUT: *
* p - position of the coordinate system *
* t - target of the coordinate system *
* roll - roll angle (in radians) *
* *
* OUTPUT: *
* *
* WARNINGS: *
* This function is written assuming the convention that the "ground" is the X-Y plane and *
* Z is altitude. *
* *
* HISTORY: *
*=============================================================================================*/
void Matrix3D::Look_At(const Vector3 &p,const Vector3 &t,float roll)
{
float dx,dy,dz; //vector from p to t
float len1,len2;
float sinp,cosp; //sine and cosine of the pitch ("up-down" tilt about x)
float siny,cosy; //sine and cosine of the yaw ("left-right"tilt about z)
dx = (t[0] - p[0]);
dy = (t[1] - p[1]);
dz = (t[2] - p[2]);
len1 = 1.0f / (float)sqrt(dx*dx + dy*dy + dz*dz);
len2 = 1.0f / (float)sqrt(dx*dx + dy*dy);
sinp = dz*len1;
cosp = len2*len1;
// sinp = 0.0f;
// cosp = 1.0f;
siny = dy*len2;
cosy = dx*len2;
// siny = 0.0f;
// cosy = 1.0f;
// init the matrix with position p and -z pointing down +x and +y up
Row[0].X = 0.0f; Row[0].Y = 0.0f; Row[0].Z = -1.0f;
Row[1].X = -1.0f; Row[1].Y = 0.0f; Row[1].Z = 0.0f;
Row[2].X = 0.0f; Row[2].Y = 1.0f; Row[2].Z = 0.0f;
Row[0].W = p.X;
Row[1].W = p.Y;
Row[2].W = p.Z;
// Yaw rotation to make the matrix look at the projection of the target
// into the x-y plane
Rotate_Y(siny,cosy);
// rotate about local x axis to pitch up to the targets position
Rotate_X(sinp,cosp);
// roll about the local z axis (negate since we look down -z)
Rotate_Z(-roll);
}
/***********************************************************************************************
* M3DC::Obj_Look_At -- Commando Object "look at" transformation. *
* *
* Builds a transformation matrix which positions the origin at p, *
* points the positive X axis towards a target t, and rolls about the X axis *
* by the angle specified by roll. *
* *
* The object convention used by Commando and G is Forward = +X, Left = +Y, Up = +Z. The *
* world is basically the x-y plane with z as altitude and +x is the default "forward". *
* *
* INPUT: *
* p - position of the coordinate system *
* t - target of the coordinate system *
* roll - roll angle (in radians) *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
*=============================================================================================*/
void Matrix3D::Obj_Look_At(const Vector3 &p,const Vector3 &t,float roll)
{
float dx,dy,dz; //vector from p to t
float len1,len2;
float sinp,cosp; //sine and cosine of the pitch ("up-down" tilt about y)
float siny,cosy; //sine and cosine of the yaw ("left-right"tilt about z)
dx = (t[0] - p[0]);
dy = (t[1] - p[1]);
dz = (t[2] - p[2]);
len1 = 1.0f / (float)sqrt(dx*dx + dy*dy + dz*dz);
len2 = 1.0f / (float)sqrt(dx*dx + dy*dy);
sinp = dz*len1;
cosp = len2*len1;
siny = dy*len2;
cosy = dx*len2;
Make_Identity();
Translate(p);
// Yaw rotation to projection of target in x-y plane
Rotate_Z(siny,cosy);
// Pitch rotation
Rotate_Y(-sinp,cosp);
// Roll rotation
Rotate_X(roll);
}
/***********************************************************************************************
* Matrix3D::Get_Inverse -- calculate the inverse of this matrix *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 8/7/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::Get_Inverse(Matrix3D & inv) const
{
// TODO: Implement the general purpose inverse function here (once we need it :-)
Get_Orthogonal_Inverse(inv);
}
/***********************************************************************************************
* Matrix3D::Get_Orthogonal_Inverse -- Returns the inverse of the matrix *
* *
* NOTE!!! This only works if the matrix is really ORTHOGONAL!!! *
* *
***********************************************************************************************
* Inverting an orthogonal Matrix3D *
* *
* M is the original transform, *
* R is rotation submatrix, *
* T is translation vector in M. *
* *
* To build MINV *
* *
* R' = transpose of R (inverse of orthogonal 3x3 matrix is transpose) *
* T' = -R'T *
* *
* Build MINV with R'and T' *
* MINV is the inverse of M *
* *
***********************************************************************************************
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
*=============================================================================================*/
void Matrix3D::Get_Orthogonal_Inverse(Matrix3D & inv) const
{
// Transposing the rotation submatrix
inv.Row[0][0] = Row[0][0];
inv.Row[0][1] = Row[1][0];
inv.Row[0][2] = Row[2][0];
inv.Row[1][0] = Row[0][1];
inv.Row[1][1] = Row[1][1];
inv.Row[1][2] = Row[2][1];
inv.Row[2][0] = Row[0][2];
inv.Row[2][1] = Row[1][2];
inv.Row[2][2] = Row[2][2];
// Now, calculate translation portion of matrix:
// T' = -R'T
Vector3 trans = Get_Translation();
trans = inv.Rotate_Vector(trans);
trans = -trans;
inv.Row[0][3] = trans[0];
inv.Row[1][3] = trans[1];
inv.Row[2][3] = trans[2];
}
/***********************************************************************************************
* Copy_3x3_Matrix(float *matrix) -- Copies a 3x3 (float[9]) matrix into this matrix *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 1/16/98 EHC : Created. *
*=============================================================================================*/
void Matrix3D::Copy_3x3_Matrix(float matrix[3][3])
{
Row[0][0] = matrix[0][0];
Row[0][1] = matrix[0][1];
Row[0][2] = matrix[0][2];
Row[0][3] = 0;
Row[1][0] = matrix[1][0];
Row[1][1] = matrix[1][1];
Row[1][2] = matrix[1][2];
Row[1][3] = 0;
Row[2][0] = matrix[2][0];
Row[2][1] = matrix[2][1];
Row[2][2] = matrix[2][2];
Row[2][3] = 0;
}
/***********************************************************************************************
* Matrix3D::Multiply -- matrix multiplication without temporaries. *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 4/22/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::Multiply(const Matrix3D & A,const Matrix3D & B,Matrix3D * set_res)
{
assert(set_res );
Matrix3D tmp;
Matrix3D * 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 = (Matrix3D *)&A;
}
tmp1 = B[0][0];
tmp2 = B[1][0];
tmp3 = B[2][0];
(*set_res)[0][0] = (*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3;
(*set_res)[1][0] = (*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3;
(*set_res)[2][0] = (*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] = (*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3;
(*set_res)[1][1] = (*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3;
(*set_res)[2][1] = (*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] = (*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3;
(*set_res)[1][2] = (*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3;
(*set_res)[2][2] = (*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3;
tmp1 = B[0][3];
tmp2 = B[1][3];
tmp3 = B[2][3];
(*set_res)[0][3] = (*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3 + (*Aptr)[0][3];
(*set_res)[1][3] = (*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3 + (*Aptr)[1][3];
(*set_res)[2][3] = (*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3 + (*Aptr)[2][3];
}
/***********************************************************************************************
* Matrix3D::Transform_Min_Max_AABox -- compute transformed axis-aligned box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/17/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::Transform_Min_Max_AABox
(
const Vector3 & min,
const Vector3 & max,
Vector3 * set_min,
Vector3 * set_max
) const
{
assert(set_min != &min);
assert(set_max != &max);
float tmp0,tmp1;
// init the min and max to the translation of the transform
set_min->X = set_max->X = Row[0][3];
set_min->Y = set_max->Y = Row[1][3];
set_min->Z = set_max->Z = Row[2][3];
// now push them both out by the projections of the original intervals
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
tmp0 = Row[i][j] * min[j];
tmp1 = Row[i][j] * max[j];
if (tmp0 < tmp1)
{
(*set_min)[i] += tmp0;
(*set_max)[i] += tmp1;
}
else
{
(*set_min)[i] += tmp1;
(*set_max)[i] += tmp0;
}
}
}
}
/***********************************************************************************************
* Matrix3D::Transform_Center_Extent_AABox -- compute transformed axis-aligned box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/17/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::Transform_Center_Extent_AABox
(
const Vector3 & center,
const Vector3 & extent,
Vector3 * set_center,
Vector3 * set_extent
) const
{
assert(set_center != &center);
assert(set_extent != &extent);
float tmp;
// now push them both out by the projections of the original intervals
for (int i=0; i<3; i++)
{
// start the center out at the translation portion of the matrix
// and the extent at zero
(*set_center)[i] = Row[i][3];
(*set_extent)[i] = 0.0f;
for (int j=0; j<3; j++)
{
(*set_center)[i] += Row[i][j] * center[j];
tmp = Row[i][j] * extent[j];
if (tmp > 0.0f)
{
(*set_extent)[i] += tmp;
}
else
{
(*set_extent)[i] -= tmp;
}
}
}
}
/***********************************************************************************************
* Matrix3D::Is_Orthogonal -- checks whether this matrix is orthogonal *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 9/16/98 GTH : Created. *
*=============================================================================================*/
int Matrix3D::Is_Orthogonal(void) const
{
#if 0
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) > EPSILON) return 0;
if (Vector3::Dot_Product(y,z) > EPSILON) return 0;
if (Vector3::Dot_Product(z,x) > EPSILON) return 0;
if (Get_Float_ABS(x.Length() - 1.0f) > EPSILON) return 0;
if (Get_Float_ABS(y.Length() - 1.0f) > EPSILON) return 0;
if (Get_Float_ABS(z.Length() - 1.0f) > EPSILON) return 0;
#endif
return 1;
}
/***********************************************************************************************
* Matrix3D::Re_Orthogonalize -- makes this matrix orthogonal. *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* This function is rather expensive, should only be used if you *know* numerical error is *
* killing you. *
* *
* HISTORY: *
* 9/16/98 GTH : Created. *
*=============================================================================================*/
void Matrix3D::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);
x*=1.0f / (float)sqrt(x.Length2());
y*=1.0f / (float)sqrt(y.Length2());
z*=1.0f / (float)sqrt(z.Length2());
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;
}
#if 0
void Matrix3D::Multiply(const Matrix3D & A,const Matrix3D & B,Matrix3D * set_res)
{
assert(set_res );
#if 0
Matrix3D tmpa = A;
Matrix3D tmpb = B;
*set_res = tmpa * tmpb;
#else
Matrix3D tmp;
Matrix3D * 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 = (Matrix3D *)&A;
}
tmp1 = B[0][0];
tmp2 = B[1][0];
tmp3 = B[2][0];
#if 1
(*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);
#else
(*set_res)[0][0] = (float)(Aptr->Row[0].X*tmp1 + Aptr->Row[0].Y*tmp2 + Aptr->Row[0].Z*tmp3);
(*set_res)[1][0] = (float)(Aptr->Row[1].X*tmp1 + Aptr->Row[1].Y*tmp2 + Aptr->Row[1].Z*tmp3);
(*set_res)[2][0] = (float)(Aptr->Row[2].X*tmp1 + Aptr->Row[2].Y*tmp2 + Aptr->Row[2].Z*tmp3);
#endif
// printf("tmp1 = %f\n",tmp1);
// printf("B[0][0] = %f\n",B[0][0]);
// printf("Row A: %f %f %f\n",Aptr->Row[0].X,Aptr->Row[0].Y,Aptr->Row[0].Z);
// printf("Col B: %f %f %f\n",tmp1,tmp2,tmp3);
// printf("tmp1 = %f\n",tmp1);
// printf("B[0][0] = %f\n",B[0][0]);
// (*set_res)[0][0] = Aptr->Row[0].X * tmp1 + Aptr->Row[0].Y * tmp2 + Aptr->Row[0].Z * tmp3;
// printf("result: %f\n",(*set_res)[0][0]);
//print_matrix(*set_res);
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);
//print_matrix(*set_res);
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);
//print_matrix(*set_res);
tmp1 = B[0][3];
tmp2 = B[1][3];
tmp3 = B[2][3];
(*set_res)[0][3] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3 + (*Aptr)[0][3]);
(*set_res)[1][3] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3 + (*Aptr)[1][3]);
(*set_res)[2][3] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3 + (*Aptr)[2][3]);
//print_matrix(*set_res);
#endif
}
#endif
/***********************************************************************************************
* Lerp - linearly interpolate matrices (orientation is slerped) *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 10/05/1998 NH : Created. *
*=============================================================================================*/
Matrix3D Lerp(const Matrix3D &A, const Matrix3D &B, float factor)
{
assert(factor >= 0.0f);
assert(factor <= 1.0f);
// Lerp position
Vector3 pos = Lerp(A.Get_Translation(), B.Get_Translation(), factor);
Quaternion rot = Slerp(Build_Quaternion(A), Build_Quaternion(B), factor);
return Matrix3D(rot, pos);
}

View File

@@ -0,0 +1,288 @@
/*
** 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 : WW3D PS2 *
* *
* $Archive:: /Commando/Code/Tools/W3DShellExt/External/matrix4.cpp $*
* *
* Programmer : Kenny Mitchell *
* *
* Start Date : 11/16/99 *
* *
* Last Update : 11/16/99 *
* *
*---------------------------------------------------------------------------------------------*
* Based on Greg Hjelstrom 97 *
* Functions: *
* Matrix4::Multiply -- Multiply two Matrix4's together *
* Matrix4::Multiply -- Multiply a Matrix3D * Matrix4 *
* Matrix4::Multiply -- Multiply a Matrix4 * Matrix3D *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <assert.h>
#include "matrix4.h"
#if 0
/***********************************************************************************************
* Matrix4::Multiply -- Multiply two Matrix4's together *
* *
* INPUT: *
* a - first operand *
* b - second operand *
* res - pointer to matrix to store the result in (must not point to a or b) *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/13/99 gth : Created. *
*=============================================================================================*/
void Matrix4::Multiply(const Matrix4 &a,const Matrix4 &b,Matrix4 * res)
{
assert(res != &a);
assert(res != &b);
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j]
(*res)[0][0] = ROWCOL(0,0);
(*res)[0][1] = ROWCOL(0,1);
(*res)[0][2] = ROWCOL(0,2);
(*res)[0][3] = ROWCOL(0,3);
(*res)[1][0] = ROWCOL(1,0);
(*res)[1][1] = ROWCOL(1,1);
(*res)[1][2] = ROWCOL(1,2);
(*res)[1][3] = ROWCOL(1,3);
(*res)[2][0] = ROWCOL(2,0);
(*res)[2][1] = ROWCOL(2,1);
(*res)[2][2] = ROWCOL(2,2);
(*res)[2][3] = ROWCOL(2,3);
(*res)[3][0] = ROWCOL(3,0);
(*res)[3][1] = ROWCOL(3,1);
(*res)[3][2] = ROWCOL(3,2);
(*res)[3][3] = ROWCOL(3,3);
#undef ROWCOL
}
/***********************************************************************************************
* Matrix4::Multiply -- Multiply a Matrix3D * Matrix4 *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/13/99 gth : Created. *
*=============================================================================================*/
void Matrix4::Multiply(const Matrix3D &a,const Matrix4 &b,Matrix4 * res)
{
assert(res != &b);
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j]
(*res)[0][0] = ROWCOL(0,0);
(*res)[0][1] = ROWCOL(0,1);
(*res)[0][2] = ROWCOL(0,2);
(*res)[0][3] = ROWCOL(0,3);
(*res)[1][0] = ROWCOL(1,0);
(*res)[1][1] = ROWCOL(1,1);
(*res)[1][2] = ROWCOL(1,2);
(*res)[1][3] = ROWCOL(1,3);
(*res)[2][0] = ROWCOL(2,0);
(*res)[2][1] = ROWCOL(2,1);
(*res)[2][2] = ROWCOL(2,2);
(*res)[2][3] = ROWCOL(2,3);
(*res)[3][0] = b[3][0]; // last row of a is 0,0,0,1
(*res)[3][1] = b[3][1]; // this leaves the last row of b unchanged
(*res)[3][2] = b[3][2];
(*res)[3][3] = b[3][3];
#undef ROWCOL
}
/***********************************************************************************************
* Matrix4::Multiply -- Multiply a Matrix4 * Matrix3D *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
*=============================================================================================*/
void Matrix4::Multiply(const Matrix4 & a,const Matrix3D & b,Matrix4 * res)
{
assert(res != &a);
// ROWCOL multiplies a row of 'a' by one of the first three columns of 'b' (4th entry in b is zero)
// ROWCOL4 multiplies a row of 'a' by the fourth column of 'b' (4th entry in b is one)
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
#define ROWCOL4(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]
(*res)[0][0] = ROWCOL(0,0);
(*res)[0][1] = ROWCOL(0,1);
(*res)[0][2] = ROWCOL(0,2);
(*res)[0][3] = ROWCOL4(0,3);
(*res)[1][0] = ROWCOL(1,0);
(*res)[1][1] = ROWCOL(1,1);
(*res)[1][2] = ROWCOL(1,2);
(*res)[1][3] = ROWCOL4(1,3);
(*res)[2][0] = ROWCOL(2,0);
(*res)[2][1] = ROWCOL(2,1);
(*res)[2][2] = ROWCOL(2,2);
(*res)[2][3] = ROWCOL4(2,3);
(*res)[3][0] = ROWCOL(3,0);
(*res)[3][1] = ROWCOL(3,1);
(*res)[3][2] = ROWCOL(3,2);
(*res)[3][3] = ROWCOL4(3,3);
#undef ROWCOL
#undef ROWCOL4
}
/***********************************************************************************************
* Set_Perspective -- Sets perspective matrix *
// Desc: Sets the passed in 4x4 matrix to a perpsective projection matrix built
// from the field-of-view (fov, in y), aspect ratio, near plane (D),
// and far plane (F).
* *
* HISTORY: *
* 11/16/99 KJM: Created. *
*=============================================================================================*/
void Matrix4::Set_Perspective
(
Matrix4* m,
float fFOV,
float ScreenWidth,
float ScreenHeight,
float fNearPlane,
float fFarPlane
)
{
float w;
float h;
float Q,Q2;
Q=DEGTORAD*0.5f;
float c = cosf(fFOV*Q);
float s = sinf(fFOV*Q);
//printf("sincos %f %f\n",c,s);
Q=0.000244140625f; // 1/4096
w = (ScreenWidth*Q);
h = (ScreenHeight*Q);
Q = s/(1.0f - (fNearPlane/fFarPlane));
Q2 = -Q*fNearPlane;
m->Make_Identity();
m->Row[0][0]= c*w;
m->Row[1][1]= -c*h;
m->Row[2][2]= Q;
m->Row[2][3]= s;//1.0f;
m->Row[3][2]= Q2;
}
void Matrix4::Set_View_Matrix
(
Matrix4* m,
Vector3& vFrom,
Vector3& vAt,
Vector3& vWorldUp
)
{
Vector3 vView;
Vector3 vUp;
Vector3 vRight;
float inv_length;
float dot_product;
// Get the z basis vector, which points straight ahead. This is the
// difference from the eyepoint to the lookat point.
vView=vAt-vFrom;
inv_length=Inv_Sqrt(vView.Length2());
// Normalize the z basis vector
vView*=inv_length;
// Get the dot product, and calculate the projection of the z basis
// vector onto the up vector. The projection is the y basis vector.
dot_product=Vector3::Dot_Product(vWorldUp,vView);
// vUp = vWorldUp - fDotProduct * vView
vUp=vWorldUp-(dot_product*vView);
inv_length=Inv_Sqrt(vUp.Length2());
// Normalize the y basis vector
vUp*=inv_length;
// The x basis vector is found simply with the cross product of the y
// and z basis vectors
Vector3::Cross_Product(vUp,vView,&vRight);
// Start building the matrix. The first three rows contains the basis
// vectors used to rotate the view to point at the lookat point
m->Row[0][0] = vRight.x; m->Row[0][1] = vUp.x; m->Row[0][2] = vView.x; m->Row[0][3] = 0.0f;
m->Row[1][0] = vRight.y; m->Row[1][1] = vUp.y; m->Row[1][2] = vView.y; m->Row[1][3] = 0.0f;
m->Row[2][0] = vRight.z; m->Row[2][1] = vUp.z; m->Row[2][2] = vView.z; m->Row[2][3] = 0.0f;
// Do the translation values (rotations are still about the eyepoint)
m->Row[3][0] = - (vFrom * vRight);
m->Row[3][1] = - (vFrom * vUp);
m->Row[3][2] = - (vFrom * vView);
m->Row[3][3] = 1.0f;
}
void Matrix4::Print_Matrix() const
{
printf("%f %f %f %f\n",Row[0][0],Row[0][1],Row[0][2],Row[0][3]);
printf("%f %f %f %f\n",Row[1][0],Row[1][1],Row[1][2],Row[1][3]);
printf("%f %f %f %f\n",Row[2][0],Row[2][1],Row[2][2],Row[2][3]);
printf("%f %f %f %f\n",Row[3][0],Row[3][1],Row[3][2],Row[3][3]);
}
#endif

756
Code/Tools/W3DShellExt/External/quat.cpp vendored Normal file
View File

@@ -0,0 +1,756 @@
/*
** 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/>.
*/
/* $Header: /Commando/Code/Tools/W3DShellExt/External/quat.cpp 1 1/02/02 1:18p Moumine_ballo $ */
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Voxel Technology *
* *
* File Name : QUAT.CPP *
* *
* Programmer : Greg Hjelstrom *
* *
* Start Date : 02/24/97 *
* *
* Last Update : February 28, 1997 [GH] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Quaternion::Quaternion -- constructor *
* Quaternion::Set -- Set the quaternion *
* Quaternion::operator= -- Assignment operator *
* Quaternion::Make_Closest -- Use nearest representation to the given quaternion. *
* Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
* Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
* Slerp -- Spherical Linear interpolation! *
* Build_Quaternion -- Creates a quaternion from a Matrix *
* Build_Matrix -- Creates a Matrix from a Quaternion *
* Normalize -- normalizes a quaternion *
* Quaternion::Quaternion -- constructor *
* Slerp_Setup -- Get ready to call "Cached_Slerp" *
* Cached_Slerp -- Quaternion slerping, optimized with cached values *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <stdio.h>
//#include <iostream.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
//#include "math_util.h"
#include "quat.h"
#include "matrix3d.h"
#include "matrix4.h"
#define SLERP_EPSILON 0.001f
static int _nxt[3] = { 1 , 2, 0 };
// ------------------------------------------------------------
// local functions
// ------------------------------------------------------------
static float Project_To_Sphere(float, float, float);
/***********************************************************************************************
* Quaternion::Quaternion -- constructor *
* *
* constructs a quaternion from the given axis and angle of rotation (in RADIANS of course) *
* *
* INPUT: *
* axis - axis of the rotation *
* angle - rotation angle *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/10/97 GTH : Created. *
*=============================================================================================*/
Quaternion::Quaternion(const Vector3 & axis,float angle)
{
float s = sinf(angle/2);
float c = cosf(angle/2);
X = s * axis.X;
Y = s * axis.Y;
Z = s * axis.Z;
W = c;
}
/***********************************************************************************************
* Quaternion::Normalize -- Normalize to a unit quaternion *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/24/1997 GH : Created. *
*=============================================================================================*/
void Quaternion::Normalize()
{
float mag = 1.0f / (float)sqrt(X * X + Y * Y + Z * Z + W * W);
X *= mag;
Y *= mag;
Z *= mag;
W *= mag;
}
/***********************************************************************************************
* Quaternion::operator= -- Assignment operator *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/24/1997 GH : Created. *
*=============================================================================================*/
Quaternion & Quaternion::operator = (const Quaternion & source)
{
X = source[0];
Y = source[1];
Z = source[2];
W = source[3];
return *this;
}
/***********************************************************************************************
* Q::Make_Closest -- Use nearest representation to the given quaternion. *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/28/1997 GH : Created. *
*=============================================================================================*/
Quaternion & Quaternion::Make_Closest(const Quaternion & qto)
{
float cos_t = qto.X * X + qto.Y * Y + qto.Z * Z + qto.W * W;
// if we are on opposite hemisphere from qto, negate ourselves
if (cos_t < 0.0f)
{
X = -X;
Y = -Y;
Z = -Z;
W = -W;
}
return *this;
}
/***********************************************************************************************
* Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
* *
* INPUT: *
* x0,y0 - x1,y1 - "normalized" mouse coordinates for the mouse movement *
* sphsize - size of the trackball sphere *
* *
* OUTPUT: *
* a quaternion representing the rotation of a trackball *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/28/1997 GH : Created. *
*=============================================================================================*/
Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize)
{
Vector3 a;
Vector3 p1;
Vector3 p2;
Vector3 d;
float phi,t;
if ((x0 == x1) && (y0 == y1))
{
return Quaternion(0.0f, 0.0f, 0.0f, 1.0f); // Zero rotation
}
// Compute z coordinates for projection of p1 and p2 to
// deformed sphere
p1[0] = x0;
p1[1] = y0;
p1[2] = Project_To_Sphere(sphsize, x0, y0);
p2[0] = x1;
p2[1] = y1;
p2[2] = Project_To_Sphere(sphsize, x1, y1);
// Find their cross product
Vector3::Cross_Product(p2,p1,&a);
// Compute how much to rotate
d = p1 - p2;
t = d.Length() / (2.0f * sphsize);
// Avoid problems with out of control values
if (t > 1.0f) t = 1.0f;
if (t < -1.0f) t = -1.0f;
phi = 2.0f * asinf(t);
return Axis_To_Quat(a, phi);
}
/***********************************************************************************************
* Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/28/1997 GH : Created. *
*=============================================================================================*/
Quaternion Axis_To_Quat(const Vector3 &a, float phi)
{
Quaternion q;
Vector3 tmp = a;
tmp.Normalize();
q[0] = tmp[0];
q[1] = tmp[1];
q[2] = tmp[2];
q.Scale(sinf(phi / 2.0f));
q[3] = cosf(phi / 2.0f);
return q;
}
/***********************************************************************************************
* Slerp -- Spherical Linear interpolation! *
* *
* INPUT: *
* p - start quaternion *
* q - end quaternion *
* alpha - interpolating parameter *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/28/1997 GH : Created. *
*=============================================================================================*/
Quaternion Slerp(const Quaternion & p,const Quaternion & q,float alpha)
{
float beta; // complementary interploation parameter
float theta; // angle between p and q
float sin_t,cos_t; // sine, cosine of theta
float oo_sin_t;
int qflip; // use flip of q?
// cos theta = dot product of p and q
cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
// if q is on opposite hemisphere from A, use -B instead
if (cos_t < 0.0f)
{
cos_t = -cos_t;
qflip = true;
}
else
{
qflip = false;
}
if (1.0f - cos_t < SLERP_EPSILON)
{
// if q is very close to p, just linearly interpolate
// between the two.
beta = 1.0f - (float)alpha;
}
else
{
// normal slerp!
theta = acosf(cos_t);
sin_t = sinf(theta);
oo_sin_t = 1.0f / sin_t;
beta = sinf(theta - alpha*theta) * oo_sin_t;
alpha = sinf(alpha*theta) * oo_sin_t;
}
if (qflip)
{
alpha = -alpha;
}
Quaternion res;
res.X = beta*p.X + alpha*q.X;
res.Y = beta*p.Y + alpha*q.Y;
res.Z = beta*p.Z + alpha*q.Z;
res.W = beta*p.W + alpha*q.W;
return res;
}
/***********************************************************************************************
* Slerp_Setup -- Get ready to call "Cached_Slerp" *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/27/98 GTH : Created. *
*=============================================================================================*/
void Slerp_Setup(
const Quaternion & p,
const Quaternion & q,
SlerpInfoStruct* slerpinfo)
{
float cos_t;
assert(!slerpinfo);
// cos theta = dot product of p and q
cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
// if q is on opposite hemisphere from A, use -B instead
if (cos_t < 0.0f)
{
cos_t = -cos_t;
slerpinfo->Flip = true;
}
else
{
slerpinfo->Flip = false;
}
if (1.0 - cos_t < SLERP_EPSILON)
{
slerpinfo->Linear = true;
slerpinfo->Theta = 0.0f;
slerpinfo->SinT = 0.0f;
}
else
{
slerpinfo->Linear = false;
slerpinfo->Theta = acosf(cos_t);
slerpinfo->SinT = sinf(slerpinfo->Theta);
}
}
/***********************************************************************************************
* Cached_Slerp -- Quaternion slerping, optimized with cached values *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/27/98 GTH : Created. *
*=============================================================================================*/
Quaternion Cached_Slerp(
const Quaternion & p,
const Quaternion & q,
float alpha,
SlerpInfoStruct * slerpinfo)
{
float beta; // complementary interploation parameter
float oo_sin_t;
if (slerpinfo->Linear)
{
// if q is very close to p, just linearly interpolate
// between the two.
beta = 1.0f - alpha;
}
else
{
// normal slerp!
oo_sin_t = 1.0f / slerpinfo->Theta;
beta = sinf(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
alpha = sinf(alpha*slerpinfo->Theta) * oo_sin_t;
}
if (slerpinfo->Flip)
{
alpha = -alpha;
}
Quaternion res;
res.X = beta*p.X + alpha*q.X;
res.Y = beta*p.Y + alpha*q.Y;
res.Z = beta*p.Z + alpha*q.Z;
res.W = beta*p.W + alpha*q.W;
return res;
}
void Cached_Slerp(
const Quaternion & p,
const Quaternion & q,
float alpha,SlerpInfoStruct * slerpinfo,
Quaternion * set_q)
{
float beta; // complementary interploation parameter
float oo_sin_t;
if (slerpinfo->Linear)
{
// if q is very close to p, just linearly interpolate
// between the two.
beta = 1.0f - alpha;
}
else
{
// normal slerp!
oo_sin_t = 1.0f / slerpinfo->Theta;
beta = sinf(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
alpha = sinf(alpha*slerpinfo->Theta) * oo_sin_t;
}
if (slerpinfo->Flip)
{
alpha = -alpha;
}
set_q->X = beta*p.X + alpha*q.X;
set_q->Y = beta*p.Y + alpha*q.Y;
set_q->Z = beta*p.Z + alpha*q.Z;
set_q->W = beta*p.W + alpha*q.W;
}
/***********************************************************************************************
* Build_Quaternion -- Creates a quaternion from a Matrix *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* Matrix MUST NOT have scaling! *
* *
* HISTORY: *
* 02/28/1997 GH : Created. *
*=============================================================================================*/
Quaternion Build_Quaternion(const Matrix3D & mat)
{
float tr,s;
int i,j,k;
Quaternion q;
// sum the diagonal of the rotation matrix
tr = mat[0][0] + mat[1][1] + mat[2][2];
if (tr > 0.0f)
{
s = (float)sqrt(tr + 1.0f);
q[3] = s * 0.5f;
s = 0.5f / s;
q[0] = (mat[2][1] - mat[1][2]) * s;
q[1] = (mat[0][2] - mat[2][0]) * s;
q[2] = (mat[1][0] - mat[0][1]) * s;
}
else
{
i=0;
if (mat[1][1] > mat[0][0]) i = 1;
if (mat[2][2] > mat[i][i]) i = 2;
j = _nxt[i];
k = _nxt[j];
s = (float)sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1.0f);
q[i] = s * 0.5f;
if (s != 0.0f)
{
s = 0.5f / s;
}
q[3] = ( mat[k][j] - mat[j][k] ) * s;
q[j] = ( mat[j][i] + mat[i][j] ) * s;
q[k] = ( mat[k][i] + mat[i][k] ) * s;
}
return q;
}
Quaternion Build_Quaternion(const Matrix3 & mat)
{
float tr,s;
int i,j,k;
Quaternion q;
// sum the diagonal of the rotation matrix
tr = mat[0][0] + mat[1][1] + mat[2][2];
if (tr > 0.0f)
{
s = (float)sqrt(tr + 1.0f);
q[3] = s * 0.5f;
s = 0.5f / s;
q[0] = (mat[2][1] - mat[1][2]) * s;
q[1] = (mat[0][2] - mat[2][0]) * s;
q[2] = (mat[1][0] - mat[0][1]) * s;
}
else
{
i = 0;
if (mat[1][1] > mat[0][0]) i = 1;
if (mat[2][2] > mat[i][i]) i = 2;
j = _nxt[i];
k = _nxt[j];
s = (float)sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0f);
q[i] = s * 0.5f;
if (s != 0.0f)
{
s = 0.5f/s;
}
q[3] = ( mat[k][j] - mat[j][k] ) * s;
q[j] = ( mat[j][i] + mat[i][j] ) * s;
q[k] = ( mat[k][i] + mat[i][k] ) * s;
}
return q;
}
Quaternion Build_Quaternion(const Matrix4 & mat)
{
float tr,s;
int i,j,k;
Quaternion q;
// sum the diagonal of the rotation matrix
tr = mat[0][0] + mat[1][1] + mat[2][2];
if (tr > 0.0f)
{
s = (float)sqrt(tr + 1.0f);
q[3] = s * 0.5f;
s = 0.5f / s;
q[0] = (mat[2][1] - mat[1][2]) * s;
q[1] = (mat[0][2] - mat[2][0]) * s;
q[2] = (mat[1][0] - mat[0][1]) * s;
}
else
{
i = 0;
if (mat[1][1] > mat[0][0]) i = 1;
if (mat[2][2] > mat[i][i]) i = 2;
j = _nxt[i];
k = _nxt[j];
s = (float)sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0f);
q[i] = s * 0.5f;
if (s != 0.0f)
{
s = 0.5f/s;
}
q[3] = ( mat[k][j] - mat[j][k] ) * s;
q[j] = ( mat[j][i] + mat[i][j] ) * s;
q[k] = ( mat[k][i] + mat[i][k] ) * s;
}
return q;
}
/***********************************************************************************************
* Build_Matrix -- Creates a Matrix from a Quaternion *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/28/1997 GH : Created. *
*=============================================================================================*/
Matrix3 Build_Matrix3(const Quaternion & q)
{
Matrix3 m;
m[0][0] = (1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
m[0][1] = (2.0f * (q[0] * q[1] - q[2] * q[3]));
m[0][2] = (2.0f * (q[2] * q[0] + q[1] * q[3]));
m[1][0] = (2.0f * (q[0] * q[1] + q[2] * q[3]));
m[1][1] = (1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
m[1][2] = (2.0f * (q[1] * q[2] - q[0] * q[3]));
m[2][0] = (2.0f * (q[2] * q[0] - q[1] * q[3]));
m[2][1] = (2.0f * (q[1] * q[2] + q[0] * q[3]));
m[2][2] =(1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
return m;
}
Matrix3D Build_Matrix3D(const Quaternion & q)
{
Matrix3D m;
// initialize the rotation sub-matrix
m[0][0] = (1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
m[0][1] = (2.0f * (q[0] * q[1] - q[2] * q[3]));
m[0][2] = (2.0f * (q[2] * q[0] + q[1] * q[3]));
m[1][0] = (2.0f * (q[0] * q[1] + q[2] * q[3]));
m[1][1] = (1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
m[1][2] = (2.0f * (q[1] * q[2] - q[0] * q[3]));
m[2][0] = (2.0f * (q[2] * q[0] - q[1] * q[3]));
m[2][1] = (2.0f * (q[1] * q[2] + q[0] * q[3]));
m[2][2] =(1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
// no translation
m[0][3] = m[1][3] = m[2][3] = 0.0f;
return m;
}
// JAC - Modified to create matrix already transposed
Matrix4 Build_Matrix4(const Quaternion & q)
{
Matrix4 m;
// initialize the rotation sub-matrix
m[0][0] = (1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
m[0][1] = (2.0f * (q[0] * q[1] - q[2] * q[3]));
m[0][2] = (2.0f * (q[2] * q[0] + q[1] * q[3]));
m[1][0] = (2.0f * (q[0] * q[1] + q[2] * q[3]));
m[1][1] = (1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
m[1][2] = (2.0f * (q[1] * q[2] - q[0] * q[3]));
m[2][0] = (2.0f * (q[2] * q[0] - q[1] * q[3]));
m[2][1] = (2.0f * (q[1] * q[2] + q[0] * q[3]));
m[2][2] = (1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
// no translation
m[0][3] = m[1][3] = m[2][3] = 0.0f;
// last row
m[3][0] = m[3][1] = m[3][2] = 0.0f;
m[3][3] = 1.0f;
return m;
}
void Quaternion::Rotate_X(float theta)
{
// TODO: optimize this
*this = (*this) * Quaternion(Vector3(1,0,0),theta);
}
void Quaternion::Rotate_Y(float theta)
{
// TODO: optimize this
*this = (*this) * Quaternion(Vector3(0,1,0),theta);
}
void Quaternion::Rotate_Z(float theta)
{
// TODO: optimize this
*this = (*this) * Quaternion(Vector3(0,0,1),theta);
}
float Project_To_Sphere(float r, float x, float y)
{
float t, z;
float d = (float)sqrt(x * x + y * y);
// Commented out code to get it to compile. Kludge but this code shouldn't be needed here
if (d < r * ((float)sqrt(2.0f)/(2.0f))) // inside sphere
{
z = (float)sqrt(r * r - d * d);
}
else
{ // on hyperbola
t = r / (float)sqrt(2.0f);
z = t * t / d;
}
return z;
}
void Quaternion::Randomize(void)
{
X = ((float) (rand() & 0xFFFF)) / 65536.0f;
Y = ((float) (rand() & 0xFFFF)) / 65536.0f;
Z = ((float) (rand() & 0xFFFF)) / 65536.0f;
W = ((float) (rand() & 0xFFFF)) / 65536.0f;
Normalize();
}

261
Code/Tools/W3DShellExt/External/quat.h vendored Normal file
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/>.
*/
/* $Header: /Commando/Code/Tools/W3DShellExt/External/quat.h 1 1/02/02 1:18p Moumine_ballo $ */
/***************************************************************************
*** Confidential - Westwood Studios ***
***************************************************************************
* *
* Project Name : WW3D PS2 *
* *
* File Name : QUAT.H *
* *
* Programmer : Kenny Mitchell *
* *
* Start Date : 11/16/99 *
* *
* Last Update : 11/16/99 *
* *
*-------------------------------------------------------------------------*
* Based on Greg Hjelstrom 97 *
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef QUAT_H
#define QUAT_H
#include "matrix3.h"
#include "vector3.h"
class Quaternion
{
private:
public:
// X,Y,Z are the imaginary parts of the quaterion
// W is the real part
float X;
float Y;
float Z;
float W;
public:
Quaternion(void) {};
explicit Quaternion(bool init) { if (init) { X = 0.0f; Y = 0.0f; Z = 0.0f; W = 1.0f; } }
explicit Quaternion(float a, float b, float c, float d) { X=a; Y=b; Z=c; W=d; }
explicit Quaternion(const Vector3 & axis,float angle);
Quaternion & operator=(const Quaternion & source);
void Set(float a = 0.0f, float b = 0.0f, float c = 0.0f, float d = 1.0f) { X = a; Y = b; Z = c; W = d; }
void Make_Identity(void) { Set(); };
void Scale(float s) { X = (float)(s*X); Y = (float)(s*Y); Z = (float)(s*Z); W = (float)(s*W); }
// Array access
float & operator [](int i) { return (&X)[i]; }
const float & operator [](int i) const { return (&X)[i]; }
// Unary operators.
// Remember that q and -q represent the same 3D rotation.
Quaternion operator-() const { return(Quaternion(-X,-Y,-Z,-W)); }
Quaternion operator+() const { return *this; }
// Every 3D rotation can be expressed by two different quaternions, This
// function makes the current quaternion convert itself to the representation
// which is closer on the 4D unit-hypersphere to the given quaternion.
Quaternion & Make_Closest(const Quaternion & qto);
// Square of the magnitude of the quaternion
float Length2(void) const { return(X*X + Y*Y + Z*Z + W*W); }
// Magnitude of the quaternion
float Length(void) const { return (float)sqrt(Length2()); }
// Make the quaternion unit length
void Normalize(void);
// post-concatenate rotations about the coordinate axes
void Rotate_X(float theta);
void Rotate_Y(float theta);
void Rotate_Z(float theta);
// initialize this quaternion randomly (creates a random *unit* quaternion)
void Randomize(void);
// transform (rotate) a vector with this quaternion
Vector3 Rotate_Vector(const Vector3 & v) const;
void Rotate_Vector(const Vector3 & v,Vector3 * set_result) const;
// verify that none of the members of this quaternion are invalid floats
bool Is_Valid(void) const;
};
// Inverse of the quaternion (1/q)
inline Quaternion Inverse(const Quaternion & a)
{
return Quaternion(-a[0],-a[1],-a[2],a[3]);
}
// Conjugate of the quaternion
inline Quaternion Conjugate(const Quaternion & a)
{
return Quaternion(-a[0],-a[1],-a[2],a[3]);
}
// Add two quaternions
inline Quaternion operator + (const Quaternion & a,const Quaternion & b)
{
return Quaternion(a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]);
}
// Subract two quaternions
inline Quaternion operator - (const Quaternion & a,const Quaternion & b)
{
return Quaternion(a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]);
}
// Multiply a quaternion by a scalar:
inline Quaternion operator * (float scl, const Quaternion & a)
{
return Quaternion(scl*a[0], scl*a[1], scl*a[2], scl*a[3]);
}
// Multiply a quaternion by a scalar
inline Quaternion operator * (const Quaternion & a, float scl)
{
return scl*a;
}
// Multiply two quaternions
inline Quaternion operator * (const Quaternion & a,const Quaternion & b)
{
return Quaternion
(
a.W*b.X + b.W*a.X + (a.Y*b.Z - b.Y*a.Z),
a.W*b.Y + b.W*a.Y - (a.X*b.Z - b.X*a.Z),
a.W*b.Z + b.W*a.Z + (a.X*b.Y - b.X*a.Y),
a.W * b.W - (a.X * b.X + a.Y * b.Y + a.Z * b.Z)
);
}
// Divide two quaternions
inline Quaternion operator / (const Quaternion & a,const Quaternion & b)
{
return a * Inverse(b);
}
// Normalized version of the quaternion
inline Quaternion Normalize(const Quaternion & a)
{
float mag = a.Length();
if (0.0f == mag) {
return a;
} else {
float oomag = 1.0f / mag;
return Quaternion(a[0] * oomag, a[1] * oomag, a[2] * oomag, a[3] * oomag);
}
}
// This function computes a quaternion based on an axis
// (defined by the given Vector a) and an angle about
// which to rotate. The angle is expressed in radians.
Quaternion Axis_To_Quat(const Vector3 &a, float angle);
// Pass the x and y coordinates of the last and current position
// of the mouse, scaled so they are from -1.0 to 1.0
// The quaternion is the computed as the rotation of a trackball
// between the two points projected onto a sphere. This can
// be used to implement an intuitive viewing control system.
Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize);
// Spherical Linear interpolation of quaternions
Quaternion Slerp(const Quaternion & a,const Quaternion & b,float t);
// Convert a rotation matrix into a quaternion
Quaternion Build_Quaternion(const Matrix3 & matrix);
Quaternion Build_Quaternion(const Matrix3D & matrix);
Quaternion Build_Quaternion(const Matrix4 & matrix);
// Convert a quaternion into a rotation matrix
Matrix3 Build_Matrix3(const Quaternion & quat);
Matrix3D Build_Matrix3D(const Quaternion & quat);
Matrix4 Build_Matrix4(const Quaternion & quat);
// Some values can be cached if you are performing multiple slerps
// between the same two quaternions...
struct SlerpInfoStruct
{
float SinT;
float Theta;
bool Flip;
bool Linear;
};
// Cached slerp implementation
void Slerp_Setup(const Quaternion & p,const Quaternion & q,SlerpInfoStruct * slerpinfo);
void Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo,Quaternion * set_q);
Quaternion Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo);
inline Vector3 Quaternion::Rotate_Vector(const Vector3 & v) const
{
float x = W*v.X + (Y*v.Z - v.Y*Z);
float y = W*v.Y - (X*v.Z - v.X*Z);
float z = W*v.Z + (X*v.Y - v.X*Y);
float w = -(X*v.X + Y*v.Y + Z*v.Z);
return Vector3
(
w*(-X) + W*x + (y*(-Z) - (-Y)*z),
w*(-Y) + W*y - (x*(-Z) - (-X)*z),
w*(-Z) + W*z + (x*(-Y) - (-X)*y)
);
}
inline void Quaternion::Rotate_Vector(const Vector3 & v,Vector3 * result) const
{
assert(result != NULL);
float x = W*v.X + (Y*v.Z - v.Y*Z);
float y = W*v.Y - (X*v.Z - v.X*Z);
float z = W*v.Z + (X*v.Y - v.X*Y);
float w = -(X*v.X + Y*v.Y + Z*v.Z);
result->X = w*(-X) + W*x + (y*(-Z) - (-Y)*z);
result->Y = w*(-Y) + W*y - (x*(-Z) - (-X)*z);
result->Z = w*(-Z) + W*z + (x*(-Y) - (-X)*y);
}
inline bool Quaternion::Is_Valid(void) const
{
#if 1
return (1);
#else
return ( Is_Valid_Float(X) &&
Is_Valid_Float(Y) &&
Is_Valid_Float(Z) &&
Is_Valid_Float(W) );
#endif
}
#endif /* QUAT_H */

View File

@@ -0,0 +1,924 @@
/*
** 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 : G *
* *
* $Archive:: /G/wdump/RAWFILEM.CPP $*
* *
* $Author:: Eric_c $*
* *
* $Modtime:: 7/28/97 3:36p $*
* *
* $Revision:: 3 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* RawFileMClass::Bias -- Bias a file with a specific starting position and length. *
* RawFileMClass::Close -- Perform a closure of the file. *
* RawFileMClass::Create -- Creates an empty file. *
* RawFileMClass::Delete -- Deletes the file object from the disk. *
* RawFileMClass::Error -- Handles displaying a file error message. *
* RawFileMClass::Get_Date_Time -- Gets the date and time the file was last modified. *
* RawFileMClass::Is_Available -- Checks to see if the specified file is available to open. *
* RawFileMClass::Open -- Assigns name and opens file in one operation. *
* RawFileMClass::Open -- Opens the file object with the rights specified. *
* RawFileMClass::RawFileMClass -- Simple constructor for a file object. *
* RawFileMClass::Raw_Seek -- Performs a seek on the unbiased file *
* RawFileMClass::Read -- Reads the specified number of bytes into a memory buffer. *
* RawFileMClass::Seek -- Reposition the file pointer as indicated. *
* RawFileMClass::Set_Date_Time -- Sets the date and time the file was last modified. *
* RawFileMClass::Set_Name -- Manually sets the name for a file object. *
* RawFileMClass::Size -- Determines size of file (in bytes). *
* RawFileMClass::Write -- Writes the specified data to the buffer specified. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "always.h"
#include "rawfilem.h"
#include <direct.h>
#include <share.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/***********************************************************************************************
* RawFileMClass::Error -- Handles displaying a file error message. *
* *
* Display an error message as indicated. If it is allowed to retry, then pressing a key *
* will return from this function. Otherwise, it will exit the program with "exit()". *
* *
* INPUT: error -- The error number (same as the DOSERR.H error numbers). *
* *
* canretry -- Can this routine exit normally so that retrying can occur? If this is *
* false, then the program WILL exit in this routine. *
* *
* filename -- Optional filename to report with this error. If no filename is *
* supplied, then no filename is listed in the error message. *
* *
* OUTPUT: none, but this routine might not return at all if the "canretry" parameter is *
* false or the player pressed ESC. *
* *
* WARNINGS: This routine may not return at all. It handles being in text mode as well as *
* if in a graphic mode. *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
void RawFileMClass::Error(int, int, char const * )
{
}
/***********************************************************************************************
* RawFileMClass::RawFileMClass -- Simple constructor for a file object. *
* *
* This constructor is called when a file object is created with a supplied filename, but *
* not opened at the same time. In this case, an assumption is made that the supplied *
* filename is a constant string. A duplicate of the filename string is not created since *
* it would be wasteful in that case. *
* *
* INPUT: filename -- The filename to assign to this file object. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
RawFileMClass::RawFileMClass(char const * filename) :
Rights(0),
BiasStart(0),
BiasLength(-1),
Handle(NULL_HANDLE),
Filename(filename),
Date(0),
Time(0),
Allocated(false)
{
}
/***********************************************************************************************
* RawFileMClass::Set_Name -- Manually sets the name for a file object. *
* *
* This routine will set the name for the file object to the name specified. This name is *
* duplicated in free store. This allows the supplied name to be a temporarily constructed *
* text string. Setting the name in this fashion doesn't affect the closed or opened state *
* of the file. *
* *
* INPUT: filename -- The filename to assign to this file object. *
* *
* OUTPUT: Returns with a pointer to the allocated copy of this filename. This pointer is *
* guaranteed to remain valid for the duration of this file object or until the name *
* is changed -- whichever is sooner. *
* *
* WARNINGS: Because of the allocation this routine must perform, memory could become *
* fragmented. *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
char const * RawFileMClass::Set_Name(char const * filename)
{
if (Filename != NULL && Allocated) {
free((char *)Filename);
Filename = NULL;
Allocated = false;
}
if (filename == NULL) return(NULL);
Bias(0);
Filename = strdup(filename);
if (Filename == NULL) {
Error(ENOMEM, false, filename);
}
Allocated = true;
return(Filename);
}
/***********************************************************************************************
* RawFileMClass::Open -- Assigns name and opens file in one operation. *
* *
* This routine will assign the specified filename to the file object and open it at the *
* same time. If the file object was already open, then it will be closed first. If the *
* file object was previously assigned a filename, then it will be replaced with the new *
* name. Typically, this routine is used when an anonymous file object has been crated and *
* now it needs to be assigned a name and opened. *
* *
* INPUT: filename -- The filename to assign to this file object. *
* *
* rights -- The open file access rights to use. *
* *
* OUTPUT: bool; Was the file opened? The return value of this is moot, since the open file *
* is designed to never return unless it succeeded. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Open(char const * filename, int rights)
{
Set_Name(filename);
return(Open(rights));
}
/***********************************************************************************************
* RawFileMClass::Open -- Opens the file object with the rights specified. *
* *
* This routine is used to open the specified file object with the access rights indicated. *
* This only works if the file has already been assigned a filename. It is guaranteed, by *
* the error handler, that this routine will always return with success. *
* *
* INPUT: rights -- The file access rights to use when opening this file. This is a *
* combination of READ and/or WRITE bit flags. *
* *
* OUTPUT: bool; Was the file opened successfully? This will always return true by reason of *
* the error handler. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/17/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Open(int rights)
{
Close();
/*
** Verify that there is a filename associated with this file object. If not, then this is a
** big error condition.
*/
if (Filename == NULL) {
Error(ENOENT, false);
}
/*
** Record the access rights used for this open call. These rights will be used if the
** file object is duplicated.
*/
Rights = rights;
/*
** Repetitively try to open the file. Abort if a fatal error condition occurs.
*/
for (;;) {
/*
** Try to open the file according to the access rights specified.
*/
switch (rights) {
/*
** If the access rights are not recognized, then report this as
** an invalid access code.
*/
default:
Error_Number = EINVAL;
break;
case READ:
Handle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
break;
case WRITE:
Handle = CreateFileA(Filename, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
break;
case READ|WRITE:
Handle = CreateFileA(Filename, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
/*
** Biased files must be positioned past the bias start position.
*/
if (BiasStart != 0 || BiasLength != -1) {
Seek(0, SEEK_SET);
}
/*
** If the handle indicates the file is not open, then this is an error condition.
** For the case of the file cannot be found, then allow a retry. All other cases
** are fatal.
*/
if (Handle == NULL_HANDLE) {
return(false);
// Error(GetLastError(), false, Filename);
// continue;
}
break;
}
return(true);
}
/***********************************************************************************************
* RawFileMClass::Is_Available -- Checks to see if the specified file is available to open. *
* *
* This routine will examine the disk system to see if the specified file can be opened *
* or not. Use this routine before opening a file in order to make sure that is available *
* or to perform other necessary actions. *
* *
* INPUT: force -- Should this routine keep retrying until the file becomes available? If *
* in this case it doesn't become available, then the program will abort. *
* *
* OUTPUT: bool; Is the file available to be opened? *
* *
* WARNINGS: Depending on the parameter passed in, this routine may never return. *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
bool RawFileMClass::Is_Available(int forced)
{
if (Filename == NULL) return(false);
/*
** If the file is already open, then is must have already passed the availability check.
** Return true in this case.
*/
if (Is_Open()) return(true);
/*
** If this is a forced check, then go through the normal open channels, since those
** channels ensure that the file must exist.
*/
if (forced) {
RawFileMClass::Open(READ);
RawFileMClass::Close();
return(true);
}
/*
** Perform a raw open of the file. If this open fails for ANY REASON, including a missing
** CD-ROM, this routine will return a failure condition. In all but the missing file
** condition, go through the normal error recover channels.
*/
for (;;) {
Handle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (Handle == NULL_HANDLE) {
return(false);
}
break;
}
/*
** Since the file could be opened, then close it and return that the file exists.
*/
if (!CloseHandle(Handle)) {
Error(GetLastError(), false, Filename);
}
Handle = NULL_HANDLE;
return(true);
}
/***********************************************************************************************
* RawFileMClass::Close -- Perform a closure of the file. *
* *
* Close the file object. In the rare case of an error, handle it as appropriate. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: Some rare error conditions may cause this routine to abort the program. *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
void RawFileMClass::Close(void)
{
/*
** If the file is open, then close it. If the file is already closed, then just return. This
** isn't considered an error condition.
*/
if (Is_Open()) {
/*
** Try to close the file. If there was an error (who knows what that could be), then
** call the error routine.
*/
if (!CloseHandle(Handle)) {
Error(GetLastError(), false, Filename);
}
/*
** At this point the file must have been closed. Mark the file as empty and return.
*/
Handle = NULL_HANDLE;
}
}
/***********************************************************************************************
* RawFileMClass::Read -- Reads the specified number of bytes into a memory buffer. *
* *
* This routine will read the specified number of bytes and place the data into the buffer *
* indicated. It is legal to call this routine with a request for more bytes than are in *
* the file. This condition can result in fewer bytes being read than requested. Determine *
* this by examining the return value. *
* *
* INPUT: buffer -- Pointer to the buffer to read data into. If NULL is passed, no read *
* is performed. *
* *
* size -- The number of bytes to read. If NULL is passed, then no read is *
* performed. *
* *
* OUTPUT: Returns with the number of bytes read into the buffer. If this number is less *
* than requested, it indicates that the file has been exhausted. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Read(void * buffer, int size)
{
long bytesread = 0; // Running count of the number of bytes read into the buffer.
int opened = false; // Was the file opened by this routine?
/*
** If the file isn't opened, open it. This serves as a convenience
** for the programmer.
*/
if (!Is_Open()) {
/*
** The error check here is moot. Open will never return unless it succeeded.
*/
if (!Open(READ)) {
return(0);
}
opened = true;
}
/*
** A biased file has the requested read length limited to the bias length of
** the file.
*/
if (BiasLength != -1) {
int remainder = BiasLength - Seek(0);
size = size < remainder ? size : remainder;
}
long total = 0;
while (size > 0) {
bytesread = 0;
if (!ReadFile(Handle, buffer, size, &(unsigned long&)bytesread, NULL)) {
size -= bytesread;
total += bytesread;
Error(GetLastError(), true, Filename);
continue;
}
size -= bytesread;
total += bytesread;
if (bytesread == 0) break;
}
bytesread = total;
/*
** Close the file if it was opened by this routine and return
** the actual number of bytes read into the buffer.
*/
if (opened) Close();
return(bytesread);
}
/***********************************************************************************************
* RawFileMClass::Write -- Writes the specified data to the buffer specified. *
* *
* This routine will write the data specified to the file. *
* *
* INPUT: buffer -- The buffer that holds the data to write. *
* *
* size -- The number of bytes to write to the file. *
* *
* OUTPUT: Returns with the number of bytes written to the file. This routine catches the *
* case of a disk full condition, so this routine will always return with the number *
* matching the size request. *
* *
* WARNINGS: A fatal file condition could cause this routine to never return. *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Write(void const * buffer, int size)
{
long bytesread = 0;
int opened = false; // Was the file manually opened?
/*
** Check to open status of the file. If the file is open, then merely write to
** it. Otherwise, open the file for writing and then close the file when the
** output is finished.
*/
if (!Is_Open()) {
if (!Open(WRITE)) {
return(0);
}
opened = true;
}
if (!WriteFile(Handle, buffer, size, &(unsigned long&)bytesread, NULL)) {
Error(GetLastError(), false, Filename);
}
/*
** Fixup the bias length if necessary.
*/
if (BiasLength != -1) {
if (Raw_Seek(0) > BiasStart+BiasLength) {
BiasLength = Raw_Seek(0) - BiasStart;
}
}
/*
** If this routine had to open the file, then close it before returning.
*/
if (opened) {
Close();
}
/*
** Return with the number of bytes written. This will always be the number of bytes
** requested, since the case of the disk being full is caught by this routine.
*/
return(bytesread);
}
/***********************************************************************************************
* RawFileMClass::Seek -- Reposition the file pointer as indicated. *
* *
* Use this routine to move the filepointer to the position indicated. It can move either *
* relative to current position or absolute from the beginning or ending of the file. This *
* routine will only return if it successfully performed the seek. *
* *
* INPUT: pos -- The position to seek to. This is interpreted as relative to the position *
* indicated by the "dir" parameter. *
* *
* dir -- The relative position to relate the seek to. This can be either SEEK_SET *
* for the beginning of the file, SEEK_CUR for the current position, or *
* SEEK_END for the end of the file. *
* *
* OUTPUT: This routine returns the position that the seek ended up at. *
* *
* WARNINGS: If there was a file error, then this routine might never return. *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Seek(int pos, int dir)
{
/*
** A file that is biased will have a seek operation modified so that the file appears to
** exist only within the bias range. All bytes outside of this range appear to be
** non-existant.
*/
if (BiasLength != -1) {
switch (dir) {
case SEEK_SET:
if (pos > BiasLength) {
pos = BiasLength;
}
pos += BiasStart;
break;
case SEEK_CUR:
break;
case SEEK_END:
dir = SEEK_SET;
pos += BiasStart + BiasLength;
// pos = (pos <= BiasStart+BiasLength) ? pos : BiasStart+BiasLength;
// pos = (pos >= BiasStart) ? pos : BiasStart;
break;
}
/*
** Perform the modified raw seek into the file.
*/
long newpos = Raw_Seek(pos, dir) - BiasStart;
/*
** Perform a final double check to make sure the file position fits with the bias range.
*/
if (newpos < 0) {
newpos = Raw_Seek(BiasStart, SEEK_SET) - BiasStart;
}
if (newpos > BiasLength) {
newpos = Raw_Seek(BiasStart+BiasLength, SEEK_SET) - BiasStart;
}
return(newpos);
}
/*
** If the file is not biased in any fashion, then the normal seek logic will
** work just fine.
*/
return(Raw_Seek(pos, dir));
}
/***********************************************************************************************
* RawFileMClass::Size -- Determines size of file (in bytes). *
* *
* Use this routine to determine the size of the file. The file must exist or this is an *
* error condition. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the number of bytes in the file. *
* *
* WARNINGS: This routine handles error conditions and will not return unless the file *
* exists and can successfully be queried for file length. *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Size(void)
{
int size = 0;
/*
** A biased file already has its length determined.
*/
if (BiasLength != -1) {
return(BiasLength);
}
/*
** If the file is open, then proceed normally.
*/
if (Is_Open()) {
size = GetFileSize(Handle, NULL);
/*
** If there was in internal error, then call the error function.
*/
if (size == 0xFFFFFFFF) {
Error(GetLastError(), false, Filename);
}
} else {
/*
** If the file wasn't open, then open the file and call this routine again. Count on
** the fact that the open function must succeed.
*/
if (Open()) {
size = Size();
/*
** Since we needed to open the file we must remember to close the file when the
** size has been determined.
*/
Close();
}
}
BiasLength = size-BiasStart;
return(BiasLength);
}
/***********************************************************************************************
* RawFileMClass::Create -- Creates an empty file. *
* *
* This routine will create an empty file from the file object. The file object's filename *
* must already have been assigned before this routine will function. *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the file successfully created? This routine will always return true. *
* *
* WARNINGS: A fatal error condition could occur with this routine. Especially if the disk *
* is full or a read-only media was selected. *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Create(void)
{
Close();
if (Open(WRITE)) {
/*
** A biased file must be at least as long as the bias offset. Seeking to the
** appropriate start offset has the effect of lengthening the file to the
** correct length.
*/
if (BiasLength != -1) {
Seek(0, SEEK_SET);
}
Close();
return(true);
}
return(false);
}
/***********************************************************************************************
* RawFileMClass::Delete -- Deletes the file object from the disk. *
* *
* This routine will delete the file object from the disk. If the file object doesn't *
* exist, then this routine will return as if it had succeeded (since the effect is the *
* same). *
* *
* INPUT: none *
* *
* OUTPUT: bool; Was the file deleted? If the file was already missing, the this value will *
* be false. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 10/18/1994 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Delete(void)
{
/*
** If the file was open, then it must be closed first.
*/
Close();
/*
** If there is no filename associated with this object, then this indicates a fatal error
** condition. Report this and abort.
*/
if (!Filename) {
Error(ENOENT, false);
}
/*
** Repetitively try to delete the file if possible. Either return with success, or
** abort the program with an error.
*/
for (;;) {
/*
** If the file is already missing, then return with this fact. No action is necessary.
** This can occur as this section loops if the file exists on a floppy and the floppy
** was removed, the file deleted on another machine, and then the floppy was
** reinserted. Admittedly, this is a rare case, but is handled here.
*/
if (!Is_Available()) {
return(false);
}
if (!DeleteFile(Filename)) {
Error(GetLastError(), false, Filename);
return(false);
}
break;
}
/*
** DOS reports that the file was successfully deleted. Return with this fact.
*/
return(true);
}
/***********************************************************************************************
* RawFileMClass::Get_Date_Time -- Gets the date and time the file was last modified. *
* *
* Use this routine to get the date and time of the file. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the file date and time as a long. *
* Use the YEAR(long), MONTH(),.... *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
* 07/13/1996 JLB : Handles win32 method. *
*=============================================================================================*/
unsigned long RawFileMClass::Get_Date_Time(void)
{
BY_HANDLE_FILE_INFORMATION info;
if (GetFileInformationByHandle(Handle, &info)) {
WORD dosdate;
WORD dostime;
FileTimeToDosDateTime(&info.ftLastWriteTime, &dosdate, &dostime);
return((dosdate << 16) | dostime);
}
return(0);
}
/***********************************************************************************************
* RawFileMClass::Set_Date_Time -- Sets the date and time the file was last modified. *
* *
* Use this routine to set the date and time of the file. *
* *
* INPUT: the file date and time as a long *
* *
* OUTPUT: successful or not if the file date and time was changed. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 11/14/1995 DRD : Created. *
* 07/13/1996 JLB : Handles win 32 method *
*=============================================================================================*/
bool RawFileMClass::Set_Date_Time(unsigned long datetime)
{
if (RawFileMClass::Is_Open()) {
BY_HANDLE_FILE_INFORMATION info;
if (GetFileInformationByHandle(Handle, &info)) {
FILETIME filetime;
if (DosDateTimeToFileTime((WORD)(datetime >> 16), (WORD)(datetime & 0x0FFFF), &filetime)) {
return(SetFileTime(Handle, &info.ftCreationTime, &filetime, &filetime) != 0);
}
}
}
return(false);
}
/***********************************************************************************************
* RawFileMClass::Bias -- Bias a file with a specific starting position and length. *
* *
* This will bias a file by giving it an artificial starting position and length. By *
* using this routine, it is possible to 'fool' the file into ignoring a header and *
* trailing extra data. An example of this would be a file inside of a mixfile. *
* *
* INPUT: start -- The starting offset that will now be considered the start of the *
* file. *
* *
* length -- The forced length of the file. For files that are opened for write, *
* this serves as the artificial constraint on the file's length. For *
* files opened for read, this limits the usable file size. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/02/1996 JLB : Created. *
*=============================================================================================*/
void RawFileMClass::Bias(int start, int length)
{
if (start == 0) {
BiasStart = 0;
BiasLength = -1;
return;
}
BiasLength = RawFileMClass::Size();
BiasStart += start;
if (length != -1) {
BiasLength = BiasLength < length ? BiasLength : length;
}
BiasLength = BiasLength > 0 ? BiasLength : 0;
/*
** Move the current file offset to a legal position if necessary and the
** file was open.
*/
if (Is_Open()) {
RawFileMClass::Seek(0, SEEK_SET);
}
}
/***********************************************************************************************
* RawFileMClass::Raw_Seek -- Performs a seek on the unbiased file *
* *
* This will perform a seek on the file as if it were unbiased. This is in spite of any *
* bias setting the file may have. The ability to perform a raw seek in this fasion is *
* necessary to maintain the bias ability. *
* *
* INPUT: pos -- The position to seek the file relative to the "dir" parameter. *
* *
* dir -- The origin of the seek operation. *
* *
* OUTPUT: Returns with the new position of the seek operation. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/04/1996 JLB : Created. *
*=============================================================================================*/
int RawFileMClass::Raw_Seek(int pos, int dir)
{
/*
** If the file isn't opened, then this is a fatal error condition.
*/
if (!Is_Open()) {
Error(EBADF, false, Filename);
}
switch (dir) {
case SEEK_SET:
dir = FILE_BEGIN;
break;
case SEEK_CUR:
dir = FILE_CURRENT;
break;
case SEEK_END:
dir = FILE_END;
break;
}
pos = SetFilePointer(Handle, pos, NULL, dir);
/*
** If there was an error in the seek, then bail with an error condition.
*/
if (pos == 0xFFFFFFFF) {
Error(GetLastError(), false, Filename);
}
/*
** Return with the new position of the file. This will range between zero and the number of
** bytes the file contains.
*/
return(pos);
}

View File

@@ -0,0 +1,135 @@
/*
** 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/>.
*/
// wdumpDoc.cpp : implementation of the CWdumpDoc class
//
#include "stdafx.h"
#include "wdump.h"
#include "wdumpDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CWdumpDoc
IMPLEMENT_DYNCREATE(CWdumpDoc, CDocument)
BEGIN_MESSAGE_MAP(CWdumpDoc, CDocument)
//{{AFX_MSG_MAP(CWdumpDoc)
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWdumpDoc construction/destruction
CWdumpDoc::CWdumpDoc()
{
// TODO: add one-time construction code here
m_ChunkItem = 0;
}
CWdumpDoc::~CWdumpDoc()
{
}
BOOL CWdumpDoc::OnNewDocument()
{
m_ChunkItem = 0;
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CWdumpDoc serialization
void CWdumpDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
Read_File(ar.m_strFileName);
}
}
/////////////////////////////////////////////////////////////////////////////
// CWdumpDoc diagnostics
#ifdef _DEBUG
void CWdumpDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CWdumpDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CWdumpDoc commands
void CWdumpDoc::OnFileOpen()
{
static char szFilter[] = "W3D Files (*.w3d)|*.w3d|WLT Files (*.wlt)|*.wlt|WHT Files (*.wht)|*.wht|WHA Files (*.wha)|*.wha|WTM Files (*.wtm)|*.wtm|All Files (*.*)|*.*||";
CFileDialog f( true,
NULL,
NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
szFilter);
if(f.DoModal() != IDOK) return;
// Add this filename to recent file list (MRU).
// NOTE: This call is not made by the framework.
//Moumine 1/2/2002 1:10:02 PM -- Project W3DShellExt needs to leave this out
#if ! defined _W3DSHELLEXT
theApp.AddToRecentFileList (f.m_ofn.lpstrFile);
#endif
m_ChunkItem = 0;
UpdateAllViews(0);
Read_File(f.m_ofn.lpstrFile);
}
void CWdumpDoc::Read_File(const char *filename)
{
m_ChunkData.Load(filename);
m_ChunkItem = 0;
UpdateAllViews(0);
}