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);
}

View File

@@ -0,0 +1,55 @@
/*
** 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/>.
*/
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__E3D529E9_7881_4733_91CE_310F49A15696__INCLUDED_)
#define AFX_STDAFX_H__E3D529E9_7881_4733_91CE_310F49A15696__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#include <afxcview.h> // treeview class
#include <afxtempl.h> // CList class
#include <afxdlgs.h> // FileDialog class
#include <CdErr.h>
//#include <AfxRes.h>
#endif // _AFX_NO_AFXCMN_SUPPORT
#include "chunkio.h"
#include "BitType.h"
#include "vector3i.h"
#include "w3d_file.h"
#include "IOStruct.h"
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__E3D529E9_7881_4733_91CE_310F49A15696__INCLUDED_)

View File

@@ -0,0 +1,9 @@
; W3DShellExt.def : Declares the module parameters for the DLL.
LIBRARY "W3DShellExt"
DESCRIPTION 'W3DShell Windows Dynamic Link Library'
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
; DllRegisterServer PRIVATE

View File

@@ -0,0 +1,202 @@
# Microsoft Developer Studio Project File - Name="W3DShellExt" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=W3DShellExt - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "W3DShellExt.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "W3DShellExt.mak" CFG="W3DShellExt - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "W3DShellExt - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "W3DShellExt - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/BAY/Tools/W3DShellExt", SIKEAAAA"
# PROP Scc_LocalPath "."
CPP=snCl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "W3DShellExt - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 1
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\wwdebug" /I "..\..\WWLib" /I "..\..\WW3D2" /I "..\..\WWMath" /I "..\WDump" /I "..\W3d2P3D" /I "external" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=snLink.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 comctl32.lib wwlib.lib wwdebug.lib Winmm.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"LIBCMTD.LIB" /libpath:"..\..\libs\Release"
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "W3DShellExt - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 2
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\wwdebug" /I "..\..\WWLib" /I "..\..\WW3D2" /I "..\..\WWMath" /I "..\WDump" /I "..\W3d2P3D" /I "external" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_W3DSHELLEXT" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=snLink.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
# ADD LINK32 comctl32.lib wwlib.lib wwdebug.lib Winmm.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"LIBCMTD.LIB" /libpath:"..\..\libs\debug"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to system dir
PostBuild_Cmds=Dll_Copy W3DSellExt.dll
# End Special Build Tool
!ENDIF
# Begin Target
# Name "W3DShellExt - Win32 Release"
# Name "W3DShellExt - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\copyhook.cpp
# End Source File
# Begin Source File
SOURCE=.\ctxmenu.cpp
# End Source File
# Begin Source File
SOURCE=.\iconhdlr.cpp
# End Source File
# Begin Source File
SOURCE=.\propshet.cpp
# End Source File
# Begin Source File
SOURCE=.\shellext.cpp
# End Source File
# Begin Source File
SOURCE=.\shexinit.cpp
# End Source File
# Begin Source File
SOURCE=.\W3DShellExt.def
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\resource.h
# End Source File
# Begin Source File
SOURCE=.\shellext.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\gak.ico
# End Source File
# Begin Source File
SOURCE=.\gak2.ico
# End Source File
# Begin Source File
SOURCE=.\gak3.ico
# End Source File
# Begin Source File
SOURCE=.\shellext.RC
# End Source File
# Begin Source File
SOURCE=.\W3DView.ico
# End Source File
# End Group
# Begin Group "External"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\External\chunk_d.cpp
# End Source File
# Begin Source File
SOURCE=.\External\FindDialog.cpp
# End Source File
# Begin Source File
SOURCE=.\external\matrix3.cpp
# End Source File
# Begin Source File
SOURCE=.\external\matrix3d.cpp
# End Source File
# Begin Source File
SOURCE=.\external\matrix4.cpp
# End Source File
# Begin Source File
SOURCE=.\External\quat.cpp
# End Source File
# Begin Source File
SOURCE=.\external\rawfilem.cpp
# End Source File
# Begin Source File
SOURCE=.\external\wdumpdoc.cpp
# End Source File
# End Group
# End Target
# End Project

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,81 @@
/*
** 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/>.
*/
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993-1997 Microsoft Corporation. All Rights Reserved.
//
// MODULE: copyhook.cpp
//
// PURPOSE: Implements the ICopyHook member functions necessary to support
// the copy hook portioins of this shell extension.
// Copy hook handlers are called each time a folder is copied, moved,
// renamed, etc. in the system. Note that the CopyCallback is NOT
// called for each file, but only for entire folders.
//
#include "StdAfx.h"
#include "priv.h"
#include "shellext.h"
//
// FUNCTION: CShellExt::CopyCallback(HWND,
// UINT,
// UINT,
// LPCSTR,
// DWORD,
// LPCSTR,
// DWORD)
//
// PURPOSE: Called by the shell when a folder is being manipulated.
//
// PARAMETERS:
// hwnd - Window handle to use for any UI stuff
// wFunc - what operation is being done
// wFlags - and flags (FOF_*) set in the initial call
// to the file operation
// pszSrcFile - name of the source file
// dwSrcAttribs - file attributes of the source file
// pszDestFile - name of the destiation file (for move and renames)
// dwDestAttribs - file attributes of the destination file
//
// RETURN VALUE:
//
// IDYES - allow the operation
// IDNO - disallow the operation on this file, but continue with
// any other operations (eg. batch copy)
// IDCANCEL - disallow the current operation and cancel any pending
// operations
//
// COMMENTS:
//
STDMETHODIMP_(UINT) CShellExt::CopyCallback(HWND hwnd,
UINT wFunc,
UINT wFlags,
LPCSTR pszSrcFile,
DWORD dwSrcAttribs,
LPCSTR pszDestFile,
DWORD dwDestAttribs)
{
ODS("CShellExt::CopyCallback\r\n");
return IDYES;
}

View File

@@ -0,0 +1,136 @@
/*
** 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/>.
*/
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993-1997 Microsoft Corporation. All Rights Reserved.
//
// MODULE: ctxmenu.cpp
//
// PURPOSE: Implements the IContextMenu member functions necessary to support
// the context menu portioins of this shell extension. Context menu
// shell extensions are called when the user right clicks on a file
// (of the type registered for the shell extension--see SHELLEXT.REG
// for details on the registry entries. In this sample, the relevant
// files are of type .W3D) in the Explorer, or selects the File menu
// item.
//
#include "Stdafx.h"
#include "priv.h"
#include "shellext.h"
//
// FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
//
// PURPOSE: Called by the shell just before the context menu is displayed.
// This is where you add your specific menu items.
//
// PARAMETERS:
// hMenu - Handle to the context menu
// indexMenu - Index of where to begin inserting menu items
// idCmdFirst - Lowest value for new menu ID's
// idCmtLast - Highest value for new menu ID's
// uFlags - Specifies the context of the menu event
//
// RETURN VALUE:
//
//
// COMMENTS:
//
STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags){
UINT idCmd = idCmdFirst;
char szMenuText[64];
BOOL bAppendItems=TRUE;
if ((uFlags & 0x000F) == CMF_NORMAL){ //Check == here, since CMF_NORMAL=0
lstrcpy(szMenuText, "&Convert to P3D");
} else{
if (uFlags & CMF_VERBSONLY){
lstrcpy(szMenuText, "&Convert to P3D");
}else{
if (uFlags & CMF_EXPLORE){
lstrcpy(szMenuText, "&Convert to P3D");
}else{
if (uFlags & CMF_DEFAULTONLY){
bAppendItems = FALSE;
}else{
char szTemp[32];
wsprintf(szTemp, "uFlags==>%d\r\n", uFlags);
bAppendItems = FALSE;
}
}
}
}
if (bAppendItems){
InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
InsertMenu(hMenu, indexMenu,MF_STRING|MF_BYPOSITION,idCmd++, szMenuText);
return ResultFromShort(idCmd-idCmdFirst); //Must return number of menu items we added.
}
return NOERROR;
}
STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
HRESULT hr = E_INVALIDARG;
//If HIWORD(lpcmi->lpVerb) then we have been called programmatically
//and lpVerb is a command that should be invoked. Otherwise, the shell
//has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has
//selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu().
if (!HIWORD(lpcmi->lpVerb)){
UINT idCmd = LOWORD(lpcmi->lpVerb);
switch (idCmd){
case 0:{
hr = DoW3DMenu1(lpcmi->hwnd,lpcmi->lpDirectory,lpcmi->lpVerb,lpcmi->lpParameters, lpcmi->nShow);
break;
}
}
}
return hr;
}
STDMETHODIMP CShellExt::GetCommandString(UINT idCmd,
UINT uFlags,
UINT FAR *reserved,
LPSTR pszName,
UINT cchMax){
switch (idCmd){
case 0:
lstrcpy(pszName, "New menu item number 1");
break;
}
return NOERROR;
}
STDMETHODIMP CShellExt::DoW3DMenu1(HWND hParent,
LPCSTR pszWorkingDir,
LPCSTR pszCmd,
LPCSTR pszParam,
int iShowCmd){
MessageBox(hParent, "Not Implemented !", "Sorry !", MB_OK);
return NOERROR;
}

View File

@@ -0,0 +1,93 @@
/*
** 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/>.
*/
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993-1997 Microsoft Corporation. All Rights Reserved.
//
// Modudule: ICONHDLR.CPP
//
// Purpose: Implements the IExtractIcon and IPersistFile member
// functions necessary to support the icon handler portion
// of this shell extension.
//
#include "Stdafx.h"
#include "priv.h"
#include "shellext.h"
extern HINSTANCE g_DllInstance; // Handle to this DLL itself.
// *********************** IExtractIcon Implementation *************************
STDMETHODIMP CShellExt::GetIconLocation(UINT uFlags,
LPSTR szIconFile,
UINT cchMax,
int *piIndex,
UINT *pwFlags)
{
GetModuleFileName(g_DllInstance, szIconFile, cchMax);
*piIndex = (int)GetPrivateProfileInt("IconImage", "Index", 0, m_szFileUserClickedOn);
return S_OK;
}
STDMETHODIMP CShellExt::Extract(LPCSTR pszFile,UINT nIconIndex,HICON *phiconLarge,HICON *phiconSmall,UINT nIconSize)
{
return S_FALSE;
}
// *********************** IPersistFile Implementation ******************
STDMETHODIMP CShellExt::GetClassID(LPCLSID lpClassID)
{
return E_FAIL;
}
STDMETHODIMP CShellExt::IsDirty()
{
return S_FALSE;
}
STDMETHODIMP CShellExt::Load(LPCOLESTR lpszFileName, DWORD grfMode)
{
WideCharToMultiByte(CP_ACP,0,lpszFileName,-1,m_szFileUserClickedOn, sizeof(m_szFileUserClickedOn), NULL,NULL);
return NOERROR;
}
STDMETHODIMP CShellExt::Save(LPCOLESTR lpszFileName, BOOL fRemember)
{
ODS("CShellExt::Save()\r\n");
return E_FAIL;
}
STDMETHODIMP CShellExt::SaveCompleted(LPCOLESTR lpszFileName)
{
ODS("CShellExt::SaveCompleted()\r\n");
return E_FAIL;
}
STDMETHODIMP CShellExt::GetCurFile(LPOLESTR FAR* lplpszFileName)
{
ODS("CShellExt::GetCurFile()\r\n");
return E_FAIL;
}

View File

@@ -0,0 +1,36 @@
/*
** 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/>.
*/
//--------------------------------------------------------------
// common user interface routines
//
//
//--------------------------------------------------------------
#ifndef STRICT
#define STRICT
#endif
#define INC_OLE2 // WIN32, get ole2 from windows.h
#include <windows.h>
#include <windowsx.h>
#include <shlobj.h>
#define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))

View File

@@ -0,0 +1,430 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "StdAfx.h"
#include "priv.h"
#include "shellext.h"
#include "resource.h"
#include <stdio.h>
#include "wdump.h"
#include "WdumpDoc.h"
#include "W3D_File.h"
#include <commctrl.h>
//===============================================================
// *********** G L O B A L S ************************
extern UINT g_DllRefCount; // Reference count of this DLL.
extern HINSTANCE g_DllInstance; // Handle to this DLL itself.
//===============================================================
// *********** F U N C T I O N S *********************
///////////////////////////////////////
UINT CALLBACK W3DPageCallback(HWND hWnd,
UINT uMessage,
LPPROPSHEETPAGE ppsp){
switch(uMessage){
case PSPCB_CREATE:
return TRUE;
case PSPCB_RELEASE:{
if (ppsp->lParam){
((LPCSHELLEXT)(ppsp->lParam))->Release();
}
return TRUE;
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ShowHideControls(HWND hDlg, bool show){
HWND hControl = GetWindow(hDlg, GW_CHILD);
while(hControl != NULL){
ShowWindow(hControl,show?SW_SHOW:SW_HIDE);
hControl = GetWindow(hControl, GW_HWNDNEXT);
}
ShowWindow(GetDlgItem(hDlg, IDC_NODATA),show?SW_HIDE:SW_SHOW );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void GetItemName(ChunkItem *pItem, int id_of_interest, void* pInfo, int sizeof_struct, int& found ){
if(pItem->ID == id_of_interest){
BYTE *byte_ptr = (BYTE*) pInfo;
byte_ptr += sizeof_struct* found;
memcpy(byte_ptr,pItem->Data,pItem->Length);
found ++;
}
//Get all Sibitems for this item
POSITION p = pItem->Chunks.GetHeadPosition();
while(p != 0) {
ChunkItem *subitem = pItem->Chunks.GetNext(p);
GetItemName(subitem, id_of_interest, pInfo, sizeof_struct,found);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK AnimPageDlgProc(HWND hDlg,UINT uMessage, WPARAM wParam, LPARAM lParam){
LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
UINT iIndex=0;
LPCSHELLEXT lpcs;
char buf[MAX_PATH];
switch (uMessage){
case WM_INITDIALOG:{
SetWindowLong(hDlg, DWL_USER, lParam);
psp = (LPPROPSHEETPAGE)lParam;
lpcs = (LPCSHELLEXT)psp->lParam;
if(!lpcs->m_FileInMemory){
lpcs->Read_SelectedFile();
}
ChunkData* pData = &(lpcs->m_WdumpDocument.m_ChunkData);
assert(pData);
POSITION ptr = pData->Chunks.GetHeadPosition();;
ASSERT(ptr);
W3dAnimHeaderStruct* pAnim = lpcs->m_AnimInfos;
int id_of_interest = W3D_CHUNK_ANIMATION_HEADER;
int sizeof_struct = sizeof W3dAnimHeaderStruct;
int found_animations(0);
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
GetItemName(pItem, id_of_interest, (void*)lpcs->m_AnimInfos, sizeof_struct, found_animations );
}
if(found_animations){
//So far assuming only one animation per file
SetDlgItemText(hDlg, IDC_ANIMNAME, pAnim->Name);
SetDlgItemText(hDlg, IDC_HNAME, pAnim->HierarchyName);
SetDlgItemInt(hDlg, IDC_NUMFRAMES, pAnim->NumFrames,FALSE);
//FrameRate
sprintf(buf,"%i fps",pAnim->FrameRate,FALSE);
SetDlgItemText(hDlg, IDC_FRAMERATE, buf);
//SetDlgItemInt(hDlg, IDC_FRAMERATE, pAnim->FrameRate,FALSE);
//version
sprintf(buf,"%d.%d",W3D_GET_MAJOR_VERSION(pAnim->Version),W3D_GET_MINOR_VERSION(pAnim->Version));
SetDlgItemText(hDlg, IDC_ANIMVERSION, buf);
}
//Hierarchies
ptr = pData->Chunks.GetHeadPosition();;
ASSERT(ptr);
id_of_interest = W3D_CHUNK_HIERARCHY_HEADER;
//So far assuming only one hierarchy per file
W3dHierarchyStruct* pHInfo = lpcs->m_Hierarchies;
ASSERT(pHInfo);
sizeof_struct = sizeof W3dHierarchyStruct;
int found_hierarchies(0);
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
GetItemName(pItem, id_of_interest, (void*)pHInfo, sizeof_struct, found_hierarchies );
}
if(found_hierarchies){
SetDlgItemText(hDlg, IDC_HIERARCHYNAME, pHInfo->Name);
SetDlgItemInt(hDlg, IDC_NUMPIVOTS, pHInfo->NumPivots,FALSE);
sprintf(buf,"%d.%d",W3D_GET_MAJOR_VERSION(pHInfo->Version),W3D_GET_MINOR_VERSION(pHInfo->Version));
SetDlgItemText(hDlg, IDC_HIERARCHYVERSION, buf);
sprintf(buf, "(%.3f, %.3f, %.3f)", pHInfo->Center.X, pHInfo->Center.Y, pHInfo->Center.Z);
SetDlgItemText(hDlg, IDC_HCENTER, buf);
}
ShowHideControls(hDlg, (found_animations + found_hierarchies)!= 0);
break;
}
case WM_DESTROY:{
RemoveProp(hDlg, "ID");
break;
}
case WM_COMMAND:
switch (LOWORD(wParam)){
case IDC_TOP3D:
//SetProp(hDlg, "ID", (HANDLE)lParam);
break;
default:
break;
}
break;
case WM_NOTIFY:
switch (((NMHDR FAR *)lParam)->code){
case PSN_SETACTIVE:
break;
case PSN_APPLY:
//User has clicked the OK or Apply button so we'll
//update the icon information in the .W3D file
lpcs = (LPCSHELLEXT)psp->lParam;
//Ask the shell to refresh the icon list...
//SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, 0, 0);
break;
default:
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//=====================================================================================================
void SetDlgMeshParams(HWND hDlg, W3dMeshHeader3Struct*pInfo){
SetDlgItemText(hDlg,IDC_MESHNAME,pInfo->MeshName);
SetDlgItemText(hDlg,IDC_CONTAINER,pInfo->ContainerName);
SetDlgItemInt(hDlg,IDC_NUM_MATERIALS, pInfo->NumMaterials,FALSE);
SetDlgItemInt(hDlg,IDC_NUM_POLYS, pInfo->NumTris,FALSE);
SetDlgItemInt(hDlg,IDC_NUM_VERTICES, pInfo->NumVertices, FALSE);
SetDlgItemInt(hDlg,IDC_NUM_MATERIALS, pInfo->NumMaterials,FALSE);
char msg[MAX_PATH];
sprintf(msg, "%.3f", pInfo->SphRadius);
SetDlgItemText(hDlg,IDC_SPHERERADIUS,msg);
//3D Coords
//Center
sprintf(msg, "(%.3f, %.3f, %.3f)", pInfo->SphCenter.X, pInfo->SphCenter.Y, pInfo->SphCenter.Z);
SetDlgItemText(hDlg, IDC_SPHERECENTER, msg);
//Min
sprintf(msg, "(%.3f, %.3f, %.3f)", pInfo->Min.X, pInfo->Min.Y, pInfo->Min.Z);
SetDlgItemText(hDlg, IDC_MINDIM, msg);
//Max
sprintf(msg, "(%.3f, %.3f, %.3f)", pInfo->Max.X, pInfo->Max.Y, pInfo->Max.Z);
SetDlgItemText(hDlg, IDC_MAXDIM, msg);
sprintf(msg,"%d.%d",W3D_GET_MAJOR_VERSION(pInfo->Version),W3D_GET_MINOR_VERSION(pInfo->Version));
SetDlgItemText(hDlg, IDC_VERSION, msg);
}
//==========================================================================================================
BOOL CALLBACK MeshPageDlgProc(HWND hDlg,UINT uMessage, WPARAM wParam, LPARAM lParam){
LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
UINT iIndex=0;
LPCSHELLEXT lpcs;
switch (uMessage){
case WM_INITDIALOG:{
SetWindowLong(hDlg, DWL_USER, lParam);
psp = (LPPROPSHEETPAGE)lParam;
lpcs = (LPCSHELLEXT)psp->lParam;
if(!lpcs->m_FileInMemory){
lpcs->Read_SelectedFile();
}
ChunkData* pData = &(lpcs->m_WdumpDocument.m_ChunkData);
assert(pData);
POSITION ptr = pData->Chunks.GetHeadPosition();
ASSERT(ptr);
//Look for mesh headers
W3dMeshHeader3Struct* pInfo = lpcs->m_Meshes;
int id_of_interest = W3D_CHUNK_MESH_HEADER3;
int sizeof_struct = sizeof W3dMeshHeader3Struct;
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
ASSERT(lpcs->m_FoundMeshes < MAX_MESH);
GetItemName(pItem, id_of_interest, (void*)(pInfo),sizeof_struct, lpcs->m_FoundMeshes );
}
if(lpcs->m_FoundMeshes){
SetDlgItemInt(hDlg,IDC_MESHNUMBER, 0,FALSE);
//Look for Textures
char pTextureInfo[MAX_TEXUTRE_NAME_LEN * MAX_MESH];
id_of_interest = W3D_CHUNK_TEXTURE_NAME;
int found_textures(0);
int sizeof_struct = MAX_TEXUTRE_NAME_LEN;
ptr = pData->Chunks.GetHeadPosition();
while(ptr){
ChunkItem *pItem = pData->Chunks.GetNext(ptr);
GetItemName(pItem, id_of_interest, (void*)pTextureInfo, sizeof_struct, found_textures );
}
for(int t_count(0); t_count < found_textures; t_count ++){
if(lpcs->NotAdded(&(pTextureInfo[t_count*MAX_TEXUTRE_NAME_LEN]))){
char* text = lpcs->m_Textures[lpcs->m_NumAdded-1].LockBuffer();
SendDlgItemMessage(hDlg, IDC_TEXTURELIST, LB_ADDSTRING,(WPARAM) 0L, (LPARAM)text);//(pTextureInfo[t_count].name)) ;
lpcs->m_Textures[lpcs->m_NumAdded-1].ReleaseBuffer();
}
}
SetDlgItemInt(hDlg,IDC_NUM_MESHES, lpcs->m_FoundMeshes,FALSE);
SetDlgMeshParams(hDlg, pInfo);
//Set Spin range
SendDlgItemMessage(hDlg, IDC_MESHSPIN, UDM_SETRANGE, (WPARAM)0L, (LPARAM)MAKELONG(lpcs->m_FoundMeshes-1,0));
}
ShowHideControls(hDlg, lpcs->m_FoundMeshes != 0);
break;
}
case WM_DESTROY:
RemoveProp(hDlg, "ID");
break;
case WM_COMMAND:
switch (LOWORD(wParam)){
case IDC_TOP3D:
//SetProp(hDlg, "ID", (HANDLE)lParam);
break;
default:
break;
}
break;
case WM_NOTIFY:
lpcs = (LPCSHELLEXT)psp->lParam;
switch (((NMHDR FAR *)lParam)->code){
case PSN_SETACTIVE:
break;
case PSN_APPLY:
//Ask the shell to refresh the icon list...
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, 0, 0);
break;
case UDN_DELTAPOS:{
lpcs = (LPCSHELLEXT)psp->lParam;
W3dMeshHeader3Struct* pInfo = lpcs->m_Meshes;
LPNMUPDOWN lpUD = (LPNMUPDOWN) lParam;
int mesh_num = lpUD->iDelta + lpUD->iPos;
if(mesh_num >= 0 && mesh_num < lpcs->m_FoundMeshes){
SetDlgMeshParams(hDlg, pInfo+mesh_num);
}
break;
}
default:
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
/////////////////////////////////////////////////////////////
BOOL CALLBACK PreviewPageDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam){
LPPROPSHEETPAGE psp=(LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
UINT iIndex(0);
LPCSHELLEXT lpcs;
switch (uMessage){
case WM_INITDIALOG:{
SetWindowLong(hDlg, DWL_USER, lParam);
psp = (LPPROPSHEETPAGE)lParam;
lpcs = (LPCSHELLEXT)psp->lParam;
if(!lpcs->m_FileInMemory){
lpcs->Read_SelectedFile();
}
break;
}
case WM_DESTROY:{
RemoveProp(hDlg, "ID");
break;
}
case WM_COMMAND:
switch (LOWORD(wParam)){
case IDC_TOP3D:
//SetProp(hDlg, "ID", (HANDLE)lParam);
break;
default:
break;
}
break;
case WM_NOTIFY:
switch (((NMHDR FAR *)lParam)->code){
case PSN_SETACTIVE:
break;
case PSN_APPLY:
//User has clicked the OK or Apply button so we'll
//update the icon information in the .W3D file
lpcs = (LPCSHELLEXT)psp->lParam;
//Ask the shell to refresh the icon list...
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, 0, 0);
break;
default:
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
// PURPOSE: Called by the shell just before the property sheet is displayed.
STDMETHODIMP CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, //Pointer to the Shell's AddPage function
LPARAM lParam){ //Passed as second parameter to lpfnAddPage
m_FileInMemory = false;
PROPSHEETPAGE psp;
HPROPSHEETPAGE hpage;
FORMATETC fmte = {CF_HDROP,(DVTARGETDEVICE FAR *)NULL,DVASPECT_CONTENT,-1, TYMED_HGLOBAL };
STGMEDIUM medium;
HRESULT hres = 0;
// char buf[MAX_PATH];
if (m_pDataObj){ //Paranoid check, m_pDataObj should have something by now...
hres = m_pDataObj->GetData(&fmte, &medium);
}
if (SUCCEEDED(hres)){
//Find out how many files the user has selected...
UINT cbFiles = 0;
LPCSHELLEXT lpcsext = this;
if (medium.hGlobal){
cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0);
}
if (cbFiles < 2){
if (cbFiles){
DragQueryFile((HDROP)medium.hGlobal,0, m_SelectedFile, sizeof(m_SelectedFile));
}
psp.dwSize = sizeof(psp); // no extra data.
psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
psp.hInstance = g_DllInstance;
psp.pszTemplate = MAKEINTRESOURCE(IDD_MESH);
psp.hIcon = 0;
psp.pszTitle = " Meshes ";
psp.pfnDlgProc = MeshPageDlgProc;
psp.pcRefParent = &g_DllRefCount;
psp.pfnCallback = W3DPageCallback;
psp.lParam = (LPARAM)lpcsext;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if(hpage){
if (!lpfnAddPage(hpage, lParam)){
DestroyPropertySheetPage(hpage);
Release();
}
}
//Animation Page
psp.pszTemplate = MAKEINTRESOURCE(IDD_ANIMPAGE);
psp.pszTitle = "Animations";
psp.pfnDlgProc = AnimPageDlgProc;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if(hpage){
if (!lpfnAddPage(hpage, lParam)){
DestroyPropertySheetPage(hpage);
Release();
}
}
//Preview Page
psp.pszTemplate = MAKEINTRESOURCE(IDD_PREVIEW);
psp.pszTitle = " Preview ";
psp.pfnDlgProc = PreviewPageDlgProc;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if(hpage){
if (!lpfnAddPage(hpage, lParam)){
DestroyPropertySheetPage(hpage);
Release();
}
}
}
}
return NOERROR;
}
// PURPOSE: Called by the shell only for Control Panel property sheet
STDMETHODIMP CShellExt::ReplacePage(UINT uPageID, //ID of page to be replaced
LPFNADDPROPSHEETPAGE lpfnReplaceWith, //Pointer to the Shell's Replace function
LPARAM lParam){ //Passed as second parameter to lpfnReplaceWith
return E_FAIL;//we don't support this function. It should never be
}

View File

@@ -0,0 +1,73 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by shellext.RC
//
#define IDD_TOOLS_FIND 130
#define IDD_MESHPAGE 132
#define IDD_PREVIEW 132
#define IDI_W3D 136
#define IDD_ANIMPAGE 138
#define IDD_MESH 139
#define IDD_ANIMPAGE1 140
#define IDC_NUM_POLYS 1000
#define IDC_FIND_STRING 1000
#define IDC_NUM_VERTICES 1001
#define IDC_NUM_MESHES 1002
#define IDC_NUM_MATERIALS 1003
#define IDC_PREVIEW 1004
#define IDC_CONTAINER 1004
#define IDC_TOP3D 1005
#define IDC_MESHNAME 1006
#define IDC_MESHNUMBER 1007
#define IDC_MINDIM 1009
#define IDC_MAXDIM 1010
#define IDC_SPHERECENTER 1011
#define IDC_SPHERERADIUS 1012
#define IDC_NUMFRAMES 1013
#define IDC_VERSION 1013
#define IDC_FRAMERATE 1014
#define IDC_NUMANIMCHANNELS 1015
#define IDC_ANIMVERSION 1015
#define IDC_NUMBITCHANNELS 1016
#define IDC_NUMPIVOTS 1016
#define IDC_ZMOTION 1017
#define IDC_HCENTER 1017
#define IDC_HNAME 1018
#define IDC_ANIMNAME 1019
#define IDC_ANIMNAME_STATIC 1020
#define IDC_HNAME_STATIC 1021
#define IDC_NUMFRAMES_STATIC 1022
#define IDC_FRAMERATE_STATIC 1023
#define IDC_NUM_MESHES_STATIC 1024
#define IDC_FRAMERATE_STATIC2 1024
#define IDC_ANIMATIONCHANNELS 1025
#define IDC_NUMPIVOTRS_STATIC 1025
#define IDC_ANIMATIONCHANNELS_STATIC 1026
#define IDC_CENTER_STATIC 1026
#define IDC_NUMBITCHANNELS_STATIC 1027
#define IDC_HNAME_STATIC2 1027
#define IDC_ZMOTION_STATIC 1028
#define IDC_HIERARCHYNAME 1028
#define IDC_NUM_POLYS_STATIC 1029
#define IDC_NUM_VERTICES_STATIC 1030
#define IDC_NUM_MATERIALS_STATIC 1031
#define IDC_HVERSION_STATIC 1031
#define IDC_SPHERERADIUS_STATIC 1032
#define IDC_HIERARCHYVERSION 1032
#define IDC_SPHERECENTER_STATIC 1033
#define IDC_MINDIM_STATIC 1034
#define IDC_MAXDIM_STATIC 1035
#define IDC_NODATA 1036
#define IDC_MESHSPIN 1040
#define IDC_TEXTURELIST 1042
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 139
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1044
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,230 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "Programmer: Moumine Ballo\0"
VALUE "CompanyName", "Westwood Studios\0"
VALUE "FileDescription", "Shell Extension DLL\0"
VALUE "FileVersion", "1, 0, 0, 1\0"
VALUE "InternalName", "W3DShellExt\0"
VALUE "LegalCopyright", "Copyright <20> Westwwod Studios 1985-2001\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "W3DShellExt\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "W3DShellExt Dynamic Link Library\0"
VALUE "ProductVersion", "1, 0, 0, 1\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PREVIEW DIALOG DISCARDABLE 0, 0, 238, 218
STYLE WS_CHILD | WS_VISIBLE | WS_BORDER
FONT 8, "MS Shell Dlg"
BEGIN
ICON IDI_W3D,IDC_STATIC,6,7,20,20
PUSHBUTTON "Convert to P3D",IDC_TOP3D,175,13,59,14
PUSHBUTTON "Coming soon",IDC_PREVIEW,5,32,229,175,BS_FLAT
END
IDD_ANIMPAGE DIALOG DISCARDABLE 0, 0, 238, 218
STYLE WS_CHILD | WS_VISIBLE | WS_BORDER
FONT 8, "MS Shell Dlg"
BEGIN
RTEXT "Number of Frames : ",IDC_NUMFRAMES_STATIC,51,66,59,8
LTEXT "",IDC_NUMFRAMES,117,66,35,9
RTEXT "Frame Rate : ",IDC_FRAMERATE_STATIC,51,78,59,8
LTEXT "",IDC_FRAMERATE,117,78,35,9
RTEXT "Hierarchy Name : ",IDC_HNAME_STATIC,51,54,59,8
LTEXT "",IDC_HNAME,117,54,70,9
ICON IDI_W3D,IDC_STATIC,6,7,20,20
PUSHBUTTON "Convert to P3D",IDC_TOP3D,174,201,59,14
RTEXT "Animationn Name : ",IDC_ANIMNAME_STATIC,51,42,59,8
LTEXT "",IDC_ANIMNAME,117,42,70,9
LTEXT "NO DATA TO DISPLAY",IDC_NODATA,88,99,84,9
GROUPBOX "Animation :",IDC_STATIC,33,29,173,78
RTEXT "Version :",IDC_FRAMERATE_STATIC2,52,90,59,8
LTEXT "",IDC_ANIMVERSION,118,90,35,9
RTEXT "Number of Pivots : ",IDC_NUMPIVOTRS_STATIC,50,141,59,8
LTEXT "",IDC_NUMPIVOTS,116,141,35,9
RTEXT "Center : ",IDC_CENTER_STATIC,50,154,59,8
LTEXT "",IDC_HCENTER,116,154,86,9
RTEXT "Hierarchy Name :",IDC_HNAME_STATIC2,50,128,59,8
LTEXT "",IDC_HIERARCHYNAME,116,128,70,9
GROUPBOX "Hierarchy",IDC_STATIC,33,111,173,78
RTEXT "Version :",IDC_HVERSION_STATIC,51,167,59,8
LTEXT "",IDC_HIERARCHYVERSION,117,167,35,9
END
IDD_MESH DIALOGEX 0, 0, 238, 218
STYLE WS_CHILD | WS_VISIBLE | WS_BORDER
FONT 8, "MS Shell Dlg"
BEGIN
RTEXT "Mesh Number :",IDC_STATIC,13,55,62,8
CTEXT "",IDC_MESHNUMBER,84,55,9,9
CONTROL "Spin1",IDC_MESHSPIN,"msctls_updown32",UDS_SETBUDDYINT |
UDS_AUTOBUDDY | UDS_ARROWKEYS,96,54,11,10
RTEXT "Number of Polygons :",IDC_STATIC,10,94,65,8
LTEXT "",IDC_NUM_POLYS,98,94,125,9
RTEXT "Number of Vertices :",IDC_STATIC,13,106,62,8
RTEXT "Number of Meshes",IDC_STATIC,32,24,60,8
RTEXT "Number of Materials :",IDC_STATIC,13,118,75,8
LTEXT "",IDC_NUM_VERTICES,98,106,125,9
LTEXT "",IDC_NUM_MESHES,99,23,11,9
LTEXT "",IDC_NUM_MATERIALS,98,118,125,9
RTEXT "Dimensions Min.:",IDC_STATIC,13,166,62,8
RTEXT "Dimensions Max :",IDC_STATIC,13,154,62,8
LTEXT "",IDC_MINDIM,98,166,125,9
LTEXT "",IDC_MAXDIM,98,154,125,9
RTEXT "Sphere Center :",IDC_STATIC,13,142,62,8
RTEXT "Sphere Radius :",IDC_STATIC,13,130,62,8
LTEXT "",IDC_SPHERECENTER,98,142,125,9
LTEXT "",IDC_SPHERERADIUS,98,130,125,9
ICON IDI_W3D,IDC_STATIC,5,7,20,20
PUSHBUTTON "Convert to P3D",IDC_TOP3D,174,201,59,14
RTEXT "Container Name",IDC_STATIC,13,82,62,8
LTEXT "",IDC_CONTAINER,98,82,125,9
RTEXT "Mesh Name :",IDC_STATIC,13,70,62,8
LTEXT "",IDC_MESHNAME,98,70,125,9
RTEXT "Version Number :",IDC_STATIC,13,178,62,8
LTEXT "",IDC_VERSION,98,178,125,9
GROUPBOX "Mesh Description",IDC_STATIC,9,39,225,159
RTEXT "Textures :",IDC_STATIC,132,8,30,8
LISTBOX IDC_TEXTURELIST,132,16,89,25,NOT LBS_NOTIFY | LBS_SORT |
LBS_NOINTEGRALHEIGHT | NOT WS_BORDER | WS_VSCROLL |
WS_TABSTOP,WS_EX_STATICEDGE
LTEXT "NO DATA TO DISPLAY",IDC_NODATA,77,105,84,9
END
IDD_ANIMPAGE1 DIALOG DISCARDABLE 0, 0, 238, 211
STYLE WS_CHILD | WS_VISIBLE | WS_BORDER
FONT 8, "MS Shell Dlg"
BEGIN
RTEXT "Number of Frames",IDC_NUMFRAMES_STATIC,5,58,94,8
LTEXT "",IDC_NUMFRAMES,106,58,35,9
RTEXT "Frame Rate",IDC_FRAMERATE_STATIC,5,71,94,8
RTEXT "Animation Channels",IDC_NUM_MESHES_STATIC,5,84,94,8
LTEXT "",IDC_FRAMERATE,106,71,35,9
LTEXT "",IDC_ANIMATIONCHANNELS,106,84,35,9
LTEXT "",IDC_NUM_MATERIALS,108,97,35,9
RTEXT "Number of Bit Channels",IDC_NUMBITCHANNELS_STATIC,5,123,
94,8
RTEXT "ZMotion",IDC_ZMOTION_STATIC,5,136,94,8
LTEXT "",IDC_NUMBITCHANNELS,106,123,70,9
LTEXT "",IDC_ZMOTION,106,136,70,9
RTEXT "Hierarchy Name",IDC_HNAME_STATIC,5,43,94,8
RTEXT "Number of Animation Channels",
IDC_ANIMATIONCHANNELS_STATIC,5,110,94,8
LTEXT "",IDC_HNAME,106,43,70,9
LTEXT "",IDC_NUMANIMCHANNELS,106,110,35,9
ICON IDI_W3D,IDC_STATIC,6,7,20,20
PUSHBUTTON "Convert to P3D",IDC_TOP3D,174,190,50,14
RTEXT "Animationn Name",IDC_ANIMNAME_STATIC,5,31,94,8
LTEXT "",IDC_ANIMNAME,106,31,70,9
LTEXT "NO DATA TO DISPLAY",IDC_NODATA,77,101,84,9
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_W3D ICON DISCARDABLE "W3DView.ico"
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,209 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stdAfx.h"
#include "priv.h"
#include "Chunkio.h"
#include "io.h"
#include "wdump.h"
#include "WdumpDoc.h"
//#include "w3d2dat.h" /// LFeenanEA: Header file missing, perhaps this tool is outdated?
//
// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
//
#pragma data_seg(".text")
#define INITGUID
#include <initguid.h>
#include <shlguid.h>
#include "shellext.h"
#pragma data_seg()
// Global variables
//
UINT g_DllRefCount = 0; // Reference count of this DLL.
HINSTANCE g_DllInstance = NULL; // Handle to this DLL itself.
//===============================================================
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved){
if (dwReason == DLL_PROCESS_ATTACH){
g_DllInstance = hInstance;
}else
if (dwReason == DLL_PROCESS_DETACH){
ODS3("Detaching Process");
}
return 1; // ok
}
//---------------------------------------------------------------------------
// DllCanUnloadNow
//---------------------------------------------------------------------------
STDAPI DllCanUnloadNow(void)
{
return (g_DllRefCount == 0 ? S_OK : S_FALSE);
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
{
*ppvOut = NULL;
if (IsEqualIID(rclsid, CLSID_ShellExtension)) {
CShellExtClassFactory* pcf = new CShellExtClassFactory;
return pcf->QueryInterface(riid, ppvOut);
}
return CLASS_E_CLASSNOTAVAILABLE;
}
//======================================================================================
CShellExtClassFactory::CShellExtClassFactory()
{
m_cRef = 0L;
g_DllRefCount++;
}
//======================================================================================
CShellExtClassFactory::~CShellExtClassFactory(){
g_DllRefCount--;
}
//======================================================================================
STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid, LPVOID FAR *ppv){
*ppv = NULL;
// Any interface on this object is the object pointer
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)){
*ppv = (LPCLASSFACTORY)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
//======================================================================================
STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CShellExtClassFactory::Release()
{
if (--m_cRef)
return m_cRef;
delete this;
return 0L;
}
STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,LPVOID *ppvObj){
*ppvObj = NULL;
// Shell extensions typically don't support aggregation (inheritance)
if (pUnkOuter)
return CLASS_E_NOAGGREGATION;
// Create the main shell extension object. The shell will then call
// QueryInterface with IID_IShellExtInit--this is how shell extensions are
// initialized.
LPCSHELLEXT pShellExt = new CShellExt(); //Create the CShellExt object
if (NULL == pShellExt)
return E_OUTOFMEMORY;
return pShellExt->QueryInterface(riid, ppvObj);
}
STDMETHODIMP CShellExtClassFactory::LockServer(BOOL fLock)
{
return NOERROR;
}
// *********************** CShellExt *************************
CShellExt::CShellExt(): m_FileInMemory(false),
m_NumAdded(0),
m_FoundMeshes(0){
m_cRef = 0L;
m_pDataObj = NULL;
g_DllRefCount++;
}
CShellExt::~CShellExt()
{
if (m_pDataObj)
m_pDataObj->Release();
g_DllRefCount--;
}
STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) {
*ppv = (LPSHELLEXTINIT)this;
}else {
if (IsEqualIID(riid, IID_IContextMenu)) {
*ppv = (LPCONTEXTMENU)this;
}else{
if (IsEqualIID(riid, IID_IExtractIcon)){
*ppv = (LPEXTRACTICON)this;
}else {
if (IsEqualIID(riid, IID_IPersistFile)){
*ppv = (LPPERSISTFILE)this;
}else {
if (IsEqualIID(riid, IID_IShellPropSheetExt)){
*ppv = (LPSHELLPROPSHEETEXT)this;
}else {
if (IsEqualIID(riid, IID_IShellCopyHook)){
*ppv = (LPCOPYHOOK)this;
}
}
}
}
}
}
if (*ppv){
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CShellExt::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CShellExt::Release()
{
if (--m_cRef){
return m_cRef;
}
delete this;
return 0L;
}
void CShellExt::Read_SelectedFile(){
m_WdumpDocument.Read_File(m_SelectedFile);
m_FileInMemory = true;
}
bool CShellExt::NotAdded(char* name){
CString str = name;
for(int pos(0); pos < m_NumAdded; pos ++){
if(str == m_Textures[pos]){
return false;
}
}
m_Textures[m_NumAdded ++ ] = str;
return true;
}
/////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,138 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SHELLEXT_H
#define _SHELLEXT_H
#define MAX_TEXTURES_INFILE 32
#define MAX_TEXUTRE_NAME_LEN 32
#define MAX_MESH 128
#define MAX_ANIMS_INFILE 16
//#define ODS(sz) OutputDebugString(sz)
//#define ENABLE_MSG2
//#define ENABLE_MSG
//#define ENABLE_MSG3
#if defined ENABLE_MSG
#define ODS(sz) MessageBox(NULL, sz, "Debug Message", MB_OK)
#else
#define ODS(sz)
#endif
#if defined ENABLE_MSG2
#define ODS2(sz) MessageBox(NULL, sz, "Debug Message", MB_OK)
#else
#define ODS2(sz)
#endif
#if defined ENABLE_MSG3
#define ODS3(sz) MessageBox(NULL, sz, "Debug Message", MB_OK)
#else
#define ODS3(sz)
#endif
#include "W3D_File.h"
#include "wdump.h"
#include "WdumpDoc.h"
//#include "w3d2dat.h" /// LFeenanEA: Header file missing, perhaps this tool is outdated?
class CWdumpDoc;
// {556F8779-49C4-4e88-9CEF-0AC2CFD6B763}
DEFINE_GUID(CLSID_ShellExtension, 0x556f8779L, 0x49c4, 0x4e88, 0x9c, 0xef, 0x0a, 0xc2, 0xcf, 0xd6, 0xb7, 0x63 );
class CShellExtClassFactory : public IClassFactory
{
protected:
ULONG m_cRef;
public:
CShellExtClassFactory();
~CShellExtClassFactory();
//IUnknown members
STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
//IClassFactory members
STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
STDMETHODIMP LockServer(BOOL);
};
typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY;
class CShellExt : public IContextMenu,
IShellExtInit,
IExtractIcon,
IPersistFile,
IShellPropSheetExt,
ICopyHook{
public:
char m_SelectedFile[MAX_PATH];
void Read_SelectedFile();
protected:
// ITEMIDLIST m_idFolder;
ULONG m_cRef;
LPDATAOBJECT m_pDataObj;
char m_szFileUserClickedOn[MAX_PATH];
STDMETHODIMP DoW3DMenu1(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd,LPCSTR pszParam, int iShowCmd);
public:
bool NotAdded(char* name);
void Read_Selection(W3dMeshHeader3Struct&, W3D_HTree&, W3D_HAnim** );
CShellExt();
~CShellExt();
//IUnknown members
STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
//IShell members
STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
STDMETHODIMP GetCommandString(UINT idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax);
//IShellExtInit methods
STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);
//IExtractIcon methods
STDMETHODIMP GetIconLocation(UINT uFlags,LPSTR szIconFile,UINT cchMax,int *piIndex,UINT *pwFlags);
STDMETHODIMP Extract(LPCSTR pszFile,UINT nIconIndex,HICON *phiconLarge,HICON *phiconSmall,UINT nIconSize);
//IPersistFile methods
STDMETHODIMP GetClassID(LPCLSID lpClassID);
STDMETHODIMP IsDirty();
STDMETHODIMP Load(LPCOLESTR lpszFileName, DWORD grfMode);
STDMETHODIMP Save(LPCOLESTR lpszFileName, BOOL fRemember);
STDMETHODIMP SaveCompleted(LPCOLESTR lpszFileName);
STDMETHODIMP GetCurFile(LPOLESTR FAR* lplpszFileName);
//IShellPropSheetExt methods
STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
STDMETHODIMP ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam);
//ICopyHook method
STDMETHODIMP_(UINT) CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags, LPCSTR pszSrcFile, DWORD dwSrcAttribs,LPCSTR pszDestFile, DWORD dwDestAttribs);
public:
W3dAnimHeaderStruct m_AnimInfos[MAX_ANIMS_INFILE];
W3dHierarchyStruct m_Hierarchies[MAX_ANIMS_INFILE];
CString m_Textures[MAX_TEXTURES_INFILE];
int m_NumAdded;
bool m_FileInMemory;
CWdumpDoc m_WdumpDocument;
int m_FoundMeshes;
W3dMeshHeader3Struct m_Meshes[MAX_MESH];
};
typedef CShellExt *LPCSHELLEXT;
#endif // _SHELLEXT_H

View File

@@ -0,0 +1,37 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "StdAfx.h"
#include "priv.h"
#include "shellext.h"
STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder,
LPDATAOBJECT pDataObj,
HKEY hRegKey){
// Initialize can be called more than once
if(m_pDataObj){
m_pDataObj->Release();
}
// duplicate the object pointer and registry handle
if (pDataObj){
m_pDataObj = pDataObj;
pDataObj->AddRef();
}
// m_idFolder = *pIDFolder;
ODS("Initialized");
return NOERROR;
}