Skip to content
Merged
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
4 changes: 4 additions & 0 deletions Core/GameEngine/Include/Common/GameDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
#define RETAIL_COMPATIBLE_PATHFINDING_ALLOCATION (1)
#endif

#ifndef RETAIL_COMPATIBLE_CIRCLE_FILL_ALGORITHM
#define RETAIL_COMPATIBLE_CIRCLE_FILL_ALGORITHM (1) // Use the original circle fill algorithm, which is more efficient but less accurate
#endif

// Disable non retail fixes in the networking, such as putting more data per UDP packet
#ifndef RETAIL_COMPATIBLE_NETWORKING
#define RETAIL_COMPATIBLE_NETWORKING (1)
Expand Down
5 changes: 5 additions & 0 deletions Generals/Code/GameEngine/Include/GameLogic/PartitionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,11 @@ class PartitionData : public MemoryPoolObject
Real radius
);

/**
A more advanced implementation of doCircleFill that is 100% accurate.
*/
void doCircleFillPrecise(Real centerX, Real centerY, Real radius);

/**
fill in the pixels covered by the given rectangular shape with the given
center, dimensions, and rotation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ static Bool distCalcProc_BoundaryAndBoundary_2D(const Coord3D *posA, const Objec
static Bool distCalcProc_CenterAndCenter_3D(const Coord3D *posA, const Object *objA, const Coord3D *posB, const Object *objB, Real& abDistSqr, Coord3D& abVec, Real maxDistSqr);
static Bool distCalcProc_BoundaryAndBoundary_3D(const Coord3D *posA, const Object *objA, const Coord3D *posB, const Object *objB, Real& abDistSqr, Coord3D& abVec, Real maxDistSqr);

static Bool doesCircleOverlapCell(Real centerX, Real centerY, Real radius, Real cellX, Real cellY, Real cellSize);

//-----------------------------------------------------------------------------
inline void projectCoord3D(Coord3D *coord, const Coord3D *unitDir, Real dist)
{
Expand Down Expand Up @@ -1878,6 +1880,43 @@ void PartitionData::doCircleFill(
}
}

static Bool doesCircleOverlapCell(Real centerX, Real centerY, Real radius, Real cellX, Real cellY, Real cellSize)
{
Real closestX = std::max(cellX, std::min(centerX, cellX + cellSize));
Real closestY = std::max(cellY, std::min(centerY, cellY + cellSize));
Real distX = centerX - closestX;
Real distY = centerY - closestY;

return (sqr(distX) + sqr(distY)) < sqr(radius);
}

void PartitionData::doCircleFillPrecise(Real centerX, Real centerY, Real radius)
{
Int minCellX, minCellY, maxCellX, maxCellY;
ThePartitionManager->worldToCell(centerX - radius, centerY - radius, &minCellX, &minCellY);
ThePartitionManager->worldToCell(centerX + radius, centerY + radius, &maxCellX, &maxCellY);

Real cellSize = ThePartitionManager->getCellSize();

for (Int x = minCellX; x <= maxCellX; ++x)
{
for (Int y = minCellY; y <= maxCellY; ++y)
{
Real cellWorldX = x * cellSize;
Real cellWorldY = y * cellSize;

if (doesCircleOverlapCell(centerX, centerY, radius, cellWorldX, cellWorldY, cellSize))
{
PartitionCell* cell = ThePartitionManager->getCellAt(x, y);
if (cell)
{
addSubPixToCoverage(cell);
}
}
}
}
}

// -----------------------------------------------------------------------------
void PartitionData::doSmallFill(
Real centerX,
Expand Down Expand Up @@ -2079,7 +2118,13 @@ void PartitionData::updateCellsTouched()
case GEOMETRY_SPHERE:
case GEOMETRY_CYLINDER:
{
#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_CIRCLE_FILL_ALGORITHM
doCircleFill(pos.x, pos.y, majorRadius);
#else
// TheSuperHackers @bugfix Stubbjax 29/01/2026 Use precise circle fill to improve
// collision accuracy, most notably for objects with geometry radii >= 20 and < 40.
doCircleFillPrecise(pos.x, pos.y, majorRadius);
#endif
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@ class PartitionData : public MemoryPoolObject
Real radius
);

/**
A more advanced implementation of doCircleFill that is 100% accurate.
*/
void doCircleFillPrecise(Real centerX, Real centerY, Real radius);

/**
fill in the pixels covered by the given rectangular shape with the given
center, dimensions, and rotation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ static Bool distCalcProc_BoundaryAndBoundary_2D(const Coord3D *posA, const Objec
static Bool distCalcProc_CenterAndCenter_3D(const Coord3D *posA, const Object *objA, const Coord3D *posB, const Object *objB, Real& abDistSqr, Coord3D& abVec, Real maxDistSqr);
static Bool distCalcProc_BoundaryAndBoundary_3D(const Coord3D *posA, const Object *objA, const Coord3D *posB, const Object *objB, Real& abDistSqr, Coord3D& abVec, Real maxDistSqr);

static Bool doesCircleOverlapCell(Real centerX, Real centerY, Real radius, Real cellX, Real cellY, Real cellSize);

//-----------------------------------------------------------------------------
inline void projectCoord3D(Coord3D *coord, const Coord3D *unitDir, Real dist)
{
Expand Down Expand Up @@ -1882,6 +1884,43 @@ void PartitionData::doCircleFill(
}
}

static Bool doesCircleOverlapCell(Real centerX, Real centerY, Real radius, Real cellX, Real cellY, Real cellSize)
{
Real closestX = std::max(cellX, std::min(centerX, cellX + cellSize));
Real closestY = std::max(cellY, std::min(centerY, cellY + cellSize));
Real distX = centerX - closestX;
Real distY = centerY - closestY;

return (sqr(distX) + sqr(distY)) < sqr(radius);
}

void PartitionData::doCircleFillPrecise(Real centerX, Real centerY, Real radius)
{
Int minCellX, minCellY, maxCellX, maxCellY;
ThePartitionManager->worldToCell(centerX - radius, centerY - radius, &minCellX, &minCellY);
ThePartitionManager->worldToCell(centerX + radius, centerY + radius, &maxCellX, &maxCellY);

Real cellSize = ThePartitionManager->getCellSize();

for (Int x = minCellX; x <= maxCellX; ++x)
{
for (Int y = minCellY; y <= maxCellY; ++y)
{
Real cellWorldX = x * cellSize;
Real cellWorldY = y * cellSize;

if (doesCircleOverlapCell(centerX, centerY, radius, cellWorldX, cellWorldY, cellSize))
{
PartitionCell* cell = ThePartitionManager->getCellAt(x, y);
if (cell)
{
addSubPixToCoverage(cell);
}
}
}
}
}

// -----------------------------------------------------------------------------
void PartitionData::doSmallFill(
Real centerX,
Expand Down Expand Up @@ -2083,7 +2122,13 @@ void PartitionData::updateCellsTouched()
case GEOMETRY_SPHERE:
case GEOMETRY_CYLINDER:
{
#if RETAIL_COMPATIBLE_CRC || RETAIL_COMPATIBLE_CIRCLE_FILL_ALGORITHM
doCircleFill(pos.x, pos.y, majorRadius);
#else
// TheSuperHackers @bugfix Stubbjax 29/01/2026 Use precise circle fill to improve
// collision accuracy, most notably for objects with geometry radii >= 20 and < 40.
doCircleFillPrecise(pos.x, pos.y, majorRadius);
#endif
break;
}

Expand Down
Loading