Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
parent
2e338c00cb
commit
3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions
124
Generals/Code/GameEngine/Source/Common/Bezier/BezFwdIterator.cpp
Normal file
124
Generals/Code/GameEngine/Source/Common/Bezier/BezFwdIterator.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "PreRTS.h"
|
||||
#include "Common/BezFwdIterator.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
BezFwdIterator::BezFwdIterator(): mStep(0), mStepsDesired(0)
|
||||
{
|
||||
// Added by Sadullah Nader
|
||||
mCurrPoint.zero();
|
||||
mDDDq.zero();
|
||||
mDDq.zero();
|
||||
mDq.zero();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
BezFwdIterator::BezFwdIterator(Int stepsDesired, const BezierSegment *bezSeg)
|
||||
{
|
||||
// Added by Sadullah Nader
|
||||
mCurrPoint.zero();
|
||||
mDDDq.zero();
|
||||
mDDq.zero();
|
||||
mDq.zero();
|
||||
//
|
||||
|
||||
mStepsDesired = stepsDesired;
|
||||
mBezSeg = (*bezSeg);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void BezFwdIterator::start(void)
|
||||
{
|
||||
mStep = 0;
|
||||
|
||||
if (mStepsDesired <= 1)
|
||||
return;
|
||||
|
||||
float d = 1.0f / (mStepsDesired - 1);
|
||||
float d2 = d * d;
|
||||
float d3 = d * d2;
|
||||
|
||||
D3DXVECTOR4 px(mBezSeg.m_controlPoints[0].x, mBezSeg.m_controlPoints[1].x, mBezSeg.m_controlPoints[2].x, mBezSeg.m_controlPoints[3].x);
|
||||
D3DXVECTOR4 py(mBezSeg.m_controlPoints[0].y, mBezSeg.m_controlPoints[1].y, mBezSeg.m_controlPoints[2].y, mBezSeg.m_controlPoints[3].y);
|
||||
D3DXVECTOR4 pz(mBezSeg.m_controlPoints[0].z, mBezSeg.m_controlPoints[1].z, mBezSeg.m_controlPoints[2].z, mBezSeg.m_controlPoints[3].z);
|
||||
|
||||
D3DXVECTOR4 cVec[3];
|
||||
D3DXVec4Transform(&cVec[0], &px, &BezierSegment::s_bezBasisMatrix);
|
||||
D3DXVec4Transform(&cVec[1], &py, &BezierSegment::s_bezBasisMatrix);
|
||||
D3DXVec4Transform(&cVec[2], &pz, &BezierSegment::s_bezBasisMatrix);
|
||||
|
||||
mCurrPoint = mBezSeg.m_controlPoints[0];
|
||||
|
||||
int i = 3;
|
||||
while (i--) {
|
||||
float a = cVec[i].x;
|
||||
float b = cVec[i].y;
|
||||
float c = cVec[i].z;
|
||||
|
||||
float *pD, *pDD, *pDDD;
|
||||
|
||||
if (i == 2) {
|
||||
pD = &mDq.z;
|
||||
pDD = &mDDq.z;
|
||||
pDDD = &mDDDq.z;
|
||||
} else if (i == 1) {
|
||||
pD = &mDq.y;
|
||||
pDD = &mDDq.y;
|
||||
pDDD = &mDDDq.y;
|
||||
} else if (i == 0) {
|
||||
pD = &mDq.x;
|
||||
pDD = &mDDq.x;
|
||||
pDDD = &mDDDq.x;
|
||||
}
|
||||
|
||||
(*pD) = a * d3 + b * d2 + c * d;
|
||||
(*pDD) = 6 * a * d3 + 2 * b * d2;
|
||||
(*pDDD) = 6 * a * d3;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
Bool BezFwdIterator::done(void)
|
||||
{
|
||||
return (mStep >= mStepsDesired);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
const Coord3D& BezFwdIterator::getCurrent(void) const
|
||||
{
|
||||
return mCurrPoint;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void BezFwdIterator::next(void)
|
||||
{
|
||||
mCurrPoint.add(&mDq);
|
||||
mDq.add(&mDDq);
|
||||
mDDq.add(&mDDDq);
|
||||
|
||||
++mStep;
|
||||
}
|
||||
|
246
Generals/Code/GameEngine/Source/Common/Bezier/BezierSegment.cpp
Normal file
246
Generals/Code/GameEngine/Source/Common/Bezier/BezierSegment.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
** Command & Conquer Generals(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) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "PreRTS.h"
|
||||
#include "Common/BezierSegment.h"
|
||||
#include "Common/BezFwdIterator.h"
|
||||
|
||||
#include <D3DX8Math.h>
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
BezierSegment::BezierSegment()
|
||||
{
|
||||
for(int i=0; i < 4; i++)
|
||||
m_controlPoints[i].zero();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
BezierSegment::BezierSegment(Real x0, Real y0, Real z0,
|
||||
Real x1, Real y1, Real z1,
|
||||
Real x2, Real y2, Real z2,
|
||||
Real x3, Real y3, Real z3)
|
||||
{
|
||||
m_controlPoints[0].x = x0;
|
||||
m_controlPoints[0].y = y0;
|
||||
m_controlPoints[0].z = z0;
|
||||
|
||||
m_controlPoints[1].x = x1;
|
||||
m_controlPoints[1].y = y1;
|
||||
m_controlPoints[1].z = z1;
|
||||
|
||||
m_controlPoints[2].x = x2;
|
||||
m_controlPoints[2].y = y2;
|
||||
m_controlPoints[2].z = z2;
|
||||
|
||||
m_controlPoints[3].x = x3;
|
||||
m_controlPoints[3].y = y3;
|
||||
m_controlPoints[3].z = z3;
|
||||
}
|
||||
|
||||
BezierSegment::BezierSegment(Real cp[12])
|
||||
{
|
||||
m_controlPoints[0].x = cp[0];
|
||||
m_controlPoints[0].y = cp[1];
|
||||
m_controlPoints[0].z = cp[2];
|
||||
|
||||
m_controlPoints[1].x = cp[3];
|
||||
m_controlPoints[1].y = cp[4];
|
||||
m_controlPoints[1].z = cp[5];
|
||||
|
||||
m_controlPoints[2].x = cp[6];
|
||||
m_controlPoints[2].y = cp[7];
|
||||
m_controlPoints[2].z = cp[8];
|
||||
|
||||
m_controlPoints[3].x = cp[9];
|
||||
m_controlPoints[3].y = cp[10];
|
||||
m_controlPoints[3].z = cp[11];
|
||||
}
|
||||
|
||||
BezierSegment::BezierSegment(const Coord3D& cp0, const Coord3D& cp1, const Coord3D& cp2, const Coord3D& cp3)
|
||||
{
|
||||
m_controlPoints[0] = cp0;
|
||||
m_controlPoints[1] = cp1;
|
||||
m_controlPoints[2] = cp2;
|
||||
m_controlPoints[3] = cp3;
|
||||
}
|
||||
|
||||
BezierSegment::BezierSegment(Coord3D cp[4])
|
||||
{
|
||||
m_controlPoints[0] = cp[0];
|
||||
m_controlPoints[1] = cp[1];
|
||||
m_controlPoints[2] = cp[2];
|
||||
m_controlPoints[3] = cp[3];
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void BezierSegment::evaluateBezSegmentAtT(Real tValue, Coord3D *outResult) const
|
||||
|
||||
{
|
||||
if (!outResult)
|
||||
return;
|
||||
|
||||
D3DXVECTOR4 tVec(tValue * tValue * tValue, tValue * tValue, tValue, 1);
|
||||
|
||||
D3DXVECTOR4 xCoords(m_controlPoints[0].x, m_controlPoints[1].x, m_controlPoints[2].x, m_controlPoints[3].x);
|
||||
D3DXVECTOR4 yCoords(m_controlPoints[0].y, m_controlPoints[1].y, m_controlPoints[2].y, m_controlPoints[3].y);
|
||||
D3DXVECTOR4 zCoords(m_controlPoints[0].z, m_controlPoints[1].z, m_controlPoints[2].z, m_controlPoints[3].z);
|
||||
|
||||
D3DXVECTOR4 tResult;
|
||||
D3DXVec4Transform(&tResult, &tVec, &BezierSegment::s_bezBasisMatrix);
|
||||
|
||||
outResult->x = D3DXVec4Dot(&xCoords, &tResult);
|
||||
outResult->y = D3DXVec4Dot(&yCoords, &tResult);
|
||||
outResult->z = D3DXVec4Dot(&zCoords, &tResult);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void BezierSegment::getSegmentPoints(Int numSegments, VecCoord3D *outResult) const
|
||||
{
|
||||
if (!outResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
outResult->clear();
|
||||
outResult->resize(numSegments);
|
||||
|
||||
BezFwdIterator iter(numSegments, this);
|
||||
iter.start();
|
||||
Int i = 0;
|
||||
while (!iter.done()) {
|
||||
(*outResult)[i] = iter.getCurrent();
|
||||
++i;
|
||||
iter.next();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// This function isn't terribly fast. There are alternatives, and if this is too slow, we can
|
||||
// take a look at the other approximations.
|
||||
// There is no known close-form solution to this problem.
|
||||
Real BezierSegment::getApproximateLength(Real withinTolerance) const
|
||||
{
|
||||
/*
|
||||
How this works:
|
||||
We can determine the approximate length of a bezier segment by
|
||||
L0 = |(P0,P1)| + |(P1,P2)| + |(P2,P3)|
|
||||
L1 = |(P0,P3)|
|
||||
|
||||
The length of the segment is approximately 1/2 L0 + 1/2 L1
|
||||
|
||||
P1__P2
|
||||
/ \
|
||||
P0----P3
|
||||
|
||||
The error in this is L1 - L0. If the error is too much, then we subdivide the curve and
|
||||
try again.
|
||||
*/
|
||||
|
||||
Coord3D p0p1 = { m_controlPoints[1].x - m_controlPoints[0].x,
|
||||
m_controlPoints[1].y - m_controlPoints[0].y,
|
||||
m_controlPoints[1].z - m_controlPoints[0].z, };
|
||||
|
||||
Coord3D p1p2 = { m_controlPoints[2].x - m_controlPoints[1].x,
|
||||
m_controlPoints[2].y - m_controlPoints[1].y,
|
||||
m_controlPoints[2].z - m_controlPoints[1].z, };
|
||||
|
||||
Coord3D p2p3 = { m_controlPoints[3].x - m_controlPoints[2].x,
|
||||
m_controlPoints[3].y - m_controlPoints[2].y,
|
||||
m_controlPoints[3].z - m_controlPoints[2].z, };
|
||||
|
||||
Coord3D p0p3 = { m_controlPoints[3].x - m_controlPoints[0].x,
|
||||
m_controlPoints[3].y - m_controlPoints[0].y,
|
||||
m_controlPoints[3].z - m_controlPoints[0].z, };
|
||||
|
||||
Real length0 = p0p3.length();
|
||||
Real length1 = p0p1.length() + p1p2.length() + p2p3.length();
|
||||
|
||||
if ((length1 - length0) > withinTolerance) {
|
||||
BezierSegment seg1, seg2;
|
||||
splitSegmentAtT(0.5f, seg1, seg2);
|
||||
return (seg1.getApproximateLength(withinTolerance) + seg2.getApproximateLength(withinTolerance));
|
||||
}
|
||||
|
||||
return (INT_TO_REAL(length0 + length1) / 2.0f);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void BezierSegment::splitSegmentAtT(Real tValue, BezierSegment &outSeg1, BezierSegment &outSeg2) const
|
||||
{
|
||||
// I think there are faster ways to do this. Could someone clue me in?
|
||||
|
||||
Coord3D p0p1 = { m_controlPoints[1].x - m_controlPoints[0].x,
|
||||
m_controlPoints[1].y - m_controlPoints[0].y,
|
||||
m_controlPoints[1].z - m_controlPoints[0].z, };
|
||||
|
||||
Coord3D p1p2 = { m_controlPoints[2].x - m_controlPoints[1].x,
|
||||
m_controlPoints[2].y - m_controlPoints[1].y,
|
||||
m_controlPoints[2].z - m_controlPoints[1].z, };
|
||||
|
||||
Coord3D p2p3 = { m_controlPoints[3].x - m_controlPoints[2].x,
|
||||
m_controlPoints[3].y - m_controlPoints[2].y,
|
||||
m_controlPoints[3].z - m_controlPoints[2].z, };
|
||||
|
||||
p0p1.scale(tValue);
|
||||
p1p2.scale(tValue);
|
||||
p2p3.scale(tValue);
|
||||
|
||||
p0p1.add(&m_controlPoints[0]);
|
||||
p1p2.add(&m_controlPoints[1]);
|
||||
p2p3.add(&m_controlPoints[2]);
|
||||
|
||||
Coord3D triLeft = { p1p2.x - p0p1.x,
|
||||
p1p2.y - p0p1.y,
|
||||
p1p2.z - p0p1.z, };
|
||||
|
||||
Coord3D triRight = { p2p3.x - p1p2.x,
|
||||
p2p3.y - p1p2.y,
|
||||
p2p3.z - p1p2.z, };
|
||||
|
||||
triLeft.scale(tValue);
|
||||
triRight.scale(tValue);
|
||||
|
||||
triLeft.add(&p0p1);
|
||||
triRight.add(&p1p2);
|
||||
|
||||
outSeg1.m_controlPoints[0] = m_controlPoints[0];
|
||||
outSeg1.m_controlPoints[1] = p0p1;
|
||||
outSeg1.m_controlPoints[2] = triLeft;
|
||||
evaluateBezSegmentAtT(tValue, &outSeg1.m_controlPoints[3]);
|
||||
|
||||
outSeg2.m_controlPoints[0] = outSeg1.m_controlPoints[3];
|
||||
outSeg2.m_controlPoints[1] = triRight;
|
||||
outSeg2.m_controlPoints[2] = p2p3;
|
||||
outSeg2.m_controlPoints[3] = m_controlPoints[3];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// The Basis Matrix for a bezier segment
|
||||
const D3DXMATRIX BezierSegment::s_bezBasisMatrix(
|
||||
-1.0f, 3.0f, -3.0f, 1.0f,
|
||||
3.0f, -6.0f, 3.0f, 0.0f,
|
||||
-3.0f, 3.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f
|
||||
);
|
Reference in a new issue