Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Benchmarks/Google/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(COREI_GOOGLEBENCHMARK_SRC
GoogleBenchmarkMain.cpp
GameEngine/Common/AsciiStringBenchmark.cpp
Libraries/Compression/CompressionManagerBenchmark.cpp
Libraries/WWVegas/WWMath/WWMathBenchmark.cpp
)

add_library(corei_googlebenchmark INTERFACE)
Expand Down
138 changes: 138 additions & 0 deletions Benchmarks/Google/Core/Libraries/WWVegas/WWMath/WWMathBenchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
** Command & Conquer Generals Zero Hour(tm)
** Copyright 2026 TheSuperHackers
**
** 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 <benchmark/benchmark.h>
#include <math.h>

#include "WWMath/wwmath.h"

// Each WWMath function is timed next to the CRT function it replaces.

template <typename T, T (*Function)(T)>
static void BM_Unary(benchmark::State &state)
{
T x = static_cast<T>(0.5);
for (auto _ : state)
{
benchmark::DoNotOptimize(x);
benchmark::DoNotOptimize(Function(x));
}
}

template <typename T, T (*Function)(T, T)>
static void BM_Binary(benchmark::State &state)
{
T x = static_cast<T>(0.4);
T y = static_cast<T>(1.3);
for (auto _ : state)
{
benchmark::DoNotOptimize(x);
benchmark::DoNotOptimize(y);
benchmark::DoNotOptimize(Function(x, y));
}
}

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Sinf);
BENCHMARK_TEMPLATE(BM_Unary, float, sinf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Sin);
BENCHMARK_TEMPLATE(BM_Unary, double, sin);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Cosf);
BENCHMARK_TEMPLATE(BM_Unary, float, cosf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Cos);
BENCHMARK_TEMPLATE(BM_Unary, double, cos);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Tanf);
BENCHMARK_TEMPLATE(BM_Unary, float, tanf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Tan);
BENCHMARK_TEMPLATE(BM_Unary, double, tan);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Asinf);
BENCHMARK_TEMPLATE(BM_Unary, float, asinf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Asin);
BENCHMARK_TEMPLATE(BM_Unary, double, asin);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Acosf);
BENCHMARK_TEMPLATE(BM_Unary, float, acosf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Acos);
BENCHMARK_TEMPLATE(BM_Unary, double, acos);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Atanf);
BENCHMARK_TEMPLATE(BM_Unary, float, atanf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Atan);
BENCHMARK_TEMPLATE(BM_Unary, double, atan);

BENCHMARK_TEMPLATE(BM_Binary, float, WWMath::Atan2f);
BENCHMARK_TEMPLATE(BM_Binary, float, atan2f);
BENCHMARK_TEMPLATE(BM_Binary, double, WWMath::Atan2);
BENCHMARK_TEMPLATE(BM_Binary, double, atan2);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Sinhf);
BENCHMARK_TEMPLATE(BM_Unary, float, sinhf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Sinh);
BENCHMARK_TEMPLATE(BM_Unary, double, sinh);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Coshf);
BENCHMARK_TEMPLATE(BM_Unary, float, coshf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Cosh);
BENCHMARK_TEMPLATE(BM_Unary, double, cosh);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Tanhf);
BENCHMARK_TEMPLATE(BM_Unary, float, tanhf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Tanh);
BENCHMARK_TEMPLATE(BM_Unary, double, tanh);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Expf);
BENCHMARK_TEMPLATE(BM_Unary, float, expf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Exp);
BENCHMARK_TEMPLATE(BM_Unary, double, exp);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Logf);
BENCHMARK_TEMPLATE(BM_Unary, float, logf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Log);
BENCHMARK_TEMPLATE(BM_Unary, double, log);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Log10f);
BENCHMARK_TEMPLATE(BM_Unary, float, log10f);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Log10);
BENCHMARK_TEMPLATE(BM_Unary, double, log10);

BENCHMARK_TEMPLATE(BM_Binary, float, WWMath::Powf);
BENCHMARK_TEMPLATE(BM_Binary, float, powf);
BENCHMARK_TEMPLATE(BM_Binary, double, WWMath::Pow);
BENCHMARK_TEMPLATE(BM_Binary, double, pow);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Sqrtf);
BENCHMARK_TEMPLATE(BM_Unary, float, sqrtf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Sqrt);
BENCHMARK_TEMPLATE(BM_Unary, double, sqrt);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Fabsf);
BENCHMARK_TEMPLATE(BM_Unary, float, fabsf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Fabs);
BENCHMARK_TEMPLATE(BM_Unary, double, fabs);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Ceilf);
BENCHMARK_TEMPLATE(BM_Unary, float, ceilf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Ceil);
BENCHMARK_TEMPLATE(BM_Unary, double, ceil);

BENCHMARK_TEMPLATE(BM_Unary, float, WWMath::Floorf);
BENCHMARK_TEMPLATE(BM_Unary, float, floorf);
BENCHMARK_TEMPLATE(BM_Unary, double, WWMath::Floor);
BENCHMARK_TEMPLATE(BM_Unary, double, floor);
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ endif()

include(cmake/config.cmake)
include(cmake/gamespy.cmake)
if (IS_VS6_BUILD)
add_library(gamemath INTERFACE)
else()
include(cmake/gamemath.cmake)
endif()
include(cmake/lzhl.cmake)
include(cmake/stb.cmake)

Expand Down
27 changes: 27 additions & 0 deletions Core/GameEngine/Include/Common/BezierSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,36 @@

#include <d3dx8math.h>
#include "Common/STLTypedefs.h"
#include "Lib/BaseDefines.h"

#define USUAL_TOLERANCE 1.0f

class BezierMath
Comment thread
Okladnoj marked this conversation as resolved.
Comment thread
Okladnoj marked this conversation as resolved.
{
public:
static void D3DXVec4Transform(D3DXVECTOR4* out, const D3DXVECTOR4* v, const D3DXMATRIX* m)
{
#if USE_DETERMINISTIC_MATH
const float x = v->x, y = v->y, z = v->z, w = v->w;
out->x = ((x * m->m[0][0] + y * m->m[1][0]) + z * m->m[2][0]) + w * m->m[3][0];
out->y = ((x * m->m[0][1] + y * m->m[1][1]) + z * m->m[2][1]) + w * m->m[3][1];
out->z = ((x * m->m[0][2] + y * m->m[1][2]) + z * m->m[2][2]) + w * m->m[3][2];
out->w = ((x * m->m[0][3] + y * m->m[1][3]) + z * m->m[2][3]) + w * m->m[3][3];
#else
::D3DXVec4Transform(out, v, m);
#endif
}

static float D3DXVec4Dot(const D3DXVECTOR4* a, const D3DXVECTOR4* b)
{
#if USE_DETERMINISTIC_MATH
return ((a->x * b->x + a->y * b->y) + a->z * b->z) + a->w * b->w;
#else
return ::D3DXVec4Dot(a, b);
#endif
}
};

class BezierSegment
{
protected:
Expand Down
4 changes: 1 addition & 3 deletions Core/GameEngine/Include/Common/GameDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@
// Note: Retail compatibility must not be broken before this project officially does.
// Use RETAIL_COMPATIBLE_CRC, RETAIL_COMPATIBLE_DATA and RETAIL_COMPATIBLE_XFER_SAVE to guard breaking changes.

#ifndef RETAIL_COMPATIBLE_CRC
#define RETAIL_COMPATIBLE_CRC (1) // Game is expected to be CRC compatible with retail Generals 1.08, Zero Hour 1.04
#endif
// RETAIL_COMPATIBLE_CRC is default defined in BaseDefines.h

#ifndef RETAIL_COMPATIBLE_DATA
#define RETAIL_COMPATIBLE_DATA (1) // Game and tool data files are expected to be compatible with retail Generals 1.08 and Zero Hour 1.04
Expand Down
6 changes: 3 additions & 3 deletions Core/GameEngine/Source/Common/Bezier/BezFwdIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ void BezFwdIterator::start()
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);
BezierMath::D3DXVec4Transform(&cVec[0], &px, &BezierSegment::s_bezBasisMatrix);
BezierMath::D3DXVec4Transform(&cVec[1], &py, &BezierSegment::s_bezBasisMatrix);
BezierMath::D3DXVec4Transform(&cVec[2], &pz, &BezierSegment::s_bezBasisMatrix);

mCurrPoint = mBezSeg.m_controlPoints[0];

Expand Down
8 changes: 4 additions & 4 deletions Core/GameEngine/Source/Common/Bezier/BezierSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ void BezierSegment::evaluateBezSegmentAtT(Real tValue, Coord3D *outResult) const
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);
BezierMath::D3DXVec4Transform(&tResult, &tVec, &BezierSegment::s_bezBasisMatrix);

outResult->x = D3DXVec4Dot(&xCoords, &tResult);
outResult->y = D3DXVec4Dot(&yCoords, &tResult);
outResult->z = D3DXVec4Dot(&zCoords, &tResult);
outResult->x = BezierMath::D3DXVec4Dot(&xCoords, &tResult);
outResult->y = BezierMath::D3DXVec4Dot(&yCoords, &tResult);
outResult->z = BezierMath::D3DXVec4Dot(&zCoords, &tResult);
}

//-------------------------------------------------------------------------------------------------
Expand Down
24 changes: 12 additions & 12 deletions Core/GameEngine/Source/Common/Diagnostic/SimulationMathCrc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ static void appendSimulationMathCrc(XferCRC &xfer)
0.9f, 1.0f, 2.1f, 1.2f);

factorsMatrix.Set(
WWMath::Sin(0.7f) * log10f(2.3f),
WWMath::Cos(1.1f) * powf(1.1f, 2.0f),
tanf(0.3f),
asinf(0.967302263f),
acosf(0.967302263f),
atanf(0.967302263f) * powf(1.1f, 2.0f),
atan2f(0.4f, 1.3f),
sinhf(0.2f),
coshf(0.4f) * tanhf(0.5f),
sqrtf(55788.84375f),
expf(0.1f) * log10f(2.3f),
logf(1.4f));
WWMath::Sinf(0.7f) * WWMath::Log10f(2.3f),
WWMath::Cosf(1.1f) * WWMath::Powf(1.1f, 2.0f),
WWMath::Tanf(0.3f),
WWMath::Asinf(0.967302263f),
WWMath::Acosf(0.967302263f),
WWMath::Atanf(0.967302263f) * WWMath::Powf(1.1f, 2.0f),
WWMath::Atan2f(0.4f, 1.3f),
WWMath::Sinhf(0.2f),
WWMath::Coshf(0.4f) * WWMath::Tanhf(0.5f),
WWMath::Sqrtf(55788.84375f),
WWMath::Expf(0.1f) * WWMath::Log10f(2.3f),
WWMath::Logf(1.4f));

Matrix3D::Multiply(matrix, factorsMatrix, &matrix);
matrix.Get_Inverse(matrix);
Expand Down
4 changes: 2 additions & 2 deletions Core/GameEngine/Source/Common/INI/INI.cpp
Comment thread
xezon marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -1798,15 +1798,15 @@ void INI::parseDurationReal( INI *ini, void * /*instance*/, void *store, const v
void INI::parseDurationUnsignedInt( INI *ini, void * /*instance*/, void *store, const void* /*userData*/ )
{
UnsignedInt val = scanUnsignedInt(ini->getNextToken());
*(UnsignedInt *)store = (UnsignedInt)ceilf(ConvertDurationFromMsecsToFrames((Real)val));
*(UnsignedInt *)store = (UnsignedInt)WWMath::Ceilf(ConvertDurationFromMsecsToFrames((Real)val));
}

// ------------------------------------------------------------------------------------------------
// parse a duration in msec and convert to duration in integral number of frames, (unsignedshort) rounding UP
void INI::parseDurationUnsignedShort( INI *ini, void * /*instance*/, void *store, const void* /*userData*/ )
{
UnsignedInt val = scanUnsignedInt(ini->getNextToken());
*(UnsignedShort *)store = (UnsignedShort)ceilf(ConvertDurationFromMsecsToFrames((Real)val));
*(UnsignedShort *)store = (UnsignedShort)WWMath::Ceilf(ConvertDurationFromMsecsToFrames((Real)val));
}

//-------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
if (TheInGameUI->isInForceAttackMode())
{
const Real snapRadians = DEG_TO_RADF(45);
targetAngle = WWMath::Round(targetAngle / snapRadians) * snapRadians;
targetAngle = WWMath::Roundf(targetAngle / snapRadians) * snapRadians;
}

TheTacticalView->userSetAngle(targetAngle);
Expand Down
12 changes: 6 additions & 6 deletions Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2535,7 +2535,7 @@ Int Pathfinder::examineNeighboringCells(PathfindCell *parentCell, PathfindCell *
toPos.y = newCellCoord.y * PATHFIND_CELL_SIZE_F ;
toPos.z = TheTerrainLogic->getGroundHeight(toPos.x , toPos.y);

if ( fabs(fromPos.z - toPos.z)<PATHFIND_CELL_SIZE_F) {
if ( WWMath::Fabs(fromPos.z - toPos.z)<PATHFIND_CELL_SIZE_F) {
newCostSoFar += 7*COST_DIAGONAL;
}
} else if (newCell->getPinched()) {
Expand All @@ -2560,7 +2560,7 @@ Int Pathfinder::examineNeighboringCells(PathfindCell *parentCell, PathfindCell *
} else {
dx = newCellCoord.x - goalCell->getXIndex();
dy = newCellCoord.y - goalCell->getYIndex();
costRemaining = COST_ORTHOGONAL*sqrt(dx*dx + dy*dy);
costRemaining = COST_ORTHOGONAL*WWMath::Sqrt((float)(dx*dx + dy*dy));
costRemaining -= attackDistance/2;
if (costRemaining<0)
costRemaining=0;
Expand Down Expand Up @@ -2884,7 +2884,7 @@ Path *Pathfinder::internalFindPath( Object *obj, const LocomotorSet& locomotorSe
dx = from->x - to->x;
dy = from->y - to->y;

Int count = sqrt(dx*dx+dy*dy)/(PATHFIND_CELL_SIZE_F/2);
Int count = WWMath::Sqrt(dx*dx+dy*dy)/(PATHFIND_CELL_SIZE_F/2);
if (count<2) count = 2;
Int i;
color.green = 0;
Expand Down Expand Up @@ -3581,7 +3581,7 @@ Path *Pathfinder::findGroundPath( const Coord3D *from,
dx = from->x - to->x;
dy = from->y - to->y;

Int count = sqrt(dx*dx+dy*dy)/(PATHFIND_CELL_SIZE_F/2);
Int count = WWMath::Sqrt(dx*dx+dy*dy)/(PATHFIND_CELL_SIZE_F/2);
if (count<2) count = 2;
Int i;
color.green = 0;
Expand Down Expand Up @@ -4277,7 +4277,7 @@ Path *Pathfinder::internal_findHierarchicalPath( Bool isHuman, const LocomotorSu
dx = from->x - to->x;
dy = from->y - to->y;

Int count = sqrt(dx*dx+dy*dy)/(PATHFIND_CELL_SIZE_F/2);
Int count = WWMath::Sqrt(dx*dx+dy*dy)/(PATHFIND_CELL_SIZE_F/2);
if (count<2) count = 2;
Int i;
color.green = 0;
Expand Down Expand Up @@ -7346,7 +7346,7 @@ Path *Pathfinder::findSafePath( const Object *obj, const LocomotorSet& locomotor
farthestDistanceSqr = distSqr;
if (cellCount > MAX_CELLS) {
#ifdef INTENSE_DEBUG
DEBUG_LOG(("Took intermediate path, dist %f, goal dist %f", sqrt(farthestDistanceSqr), repulsorRadius));
DEBUG_LOG(("Took intermediate path, dist %f, goal dist %f", WWMath::Sqrt(farthestDistanceSqr), repulsorRadius));
#endif
ok = true; // Already a big search, just take this one.
}
Expand Down
14 changes: 7 additions & 7 deletions Core/GameEngine/Source/GameLogic/AI/Pathfinder/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,9 @@ inline Bool isReallyClose(const Coord3D& a, const Coord3D& b)
{
const Real CLOSE_ENOUGH = 0.1f;
return
fabs(a.x-b.x) <= CLOSE_ENOUGH &&
fabs(a.y-b.y) <= CLOSE_ENOUGH &&
fabs(a.z-b.z) <= CLOSE_ENOUGH;
WWMath::Fabs(a.x-b.x) <= CLOSE_ENOUGH &&
WWMath::Fabs(a.y-b.y) <= CLOSE_ENOUGH &&
WWMath::Fabs(a.z-b.z) <= CLOSE_ENOUGH;
}

/**
Expand Down Expand Up @@ -695,14 +695,14 @@ void Path::computePointOnPath(
// compute distance of point from this path segment
Real toDistSqr = sqr(toPos.x) + sqr(toPos.y);
Real offsetDistSq = toDistSqr - sqr(alongPathDist);
Real offsetDist = (offsetDistSq <= 0.0) ? 0.0 : sqrt(offsetDistSq);
Real offsetDist = (offsetDistSq <= 0.0) ? 0.0 : WWMath::Sqrt(offsetDistSq);

// If we are basically on the path, return the next path node as the movement goal.
// However, the farther off the path we get, the movement goal becomes closer to our
// projected position on the path. If we are very far off the path, we will move
// directly towards the nearest point on the path, and not the next path node.
const Real maxPathError = 3.0f * PATHFIND_CELL_SIZE_F;
const Real maxPathErrorInv = 1.0 / maxPathError;
const Real maxPathErrorInv = 1.0f / maxPathError;
Real k = offsetDist * maxPathErrorInv;
if (k > 1.0f)
k = 1.0f;
Expand Down Expand Up @@ -785,8 +785,8 @@ void Path::computePointOnPath(
out.posOnPath.x = closeNodePos->x + alongPathDist * segmentDirNorm.x;
out.posOnPath.y = closeNodePos->y + alongPathDist * segmentDirNorm.y;
out.posOnPath.z = closeNodePos->z;
Real dx = fabs(pos.x - out.posOnPath.x);
Real dy = fabs(pos.y - out.posOnPath.y);
Real dx = WWMath::Fabs(pos.x - out.posOnPath.x);
Real dy = WWMath::Fabs(pos.y - out.posOnPath.y);
if (dx<1 && dy<1 && closeNode->getNextOptimized() && closeNode->getNextOptimized()->getNextOptimized()) {
out.posOnPath = *closeNode->getNextOptimized()->getNextOptimized()->getPosition();
}
Expand Down
Loading
Loading