Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix GuiTraceRay for radardrift #1764

Merged
7 changes: 6 additions & 1 deletion rts/Game/TraceRay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,12 @@ float GuiTraceRay(
CollisionQuery cq;

QuadFieldQuery qfQuery;
quadField.GetQuadsOnRay(qfQuery, start, dir, length);
if (useRadar) {
const float allyTeamError = losHandler->GetAllyTeamRadarErrorSize(gu->myAllyTeam);
quadField.GetQuadsOnWideRay(qfQuery, start, dir, length, allyTeamError);
} else {
quadField.GetQuadsOnRay(qfQuery, start, dir, length);
}

for (const int quadIdx: *qfQuery.quads) {
const CQuadField::Quad& quad = quadField.GetQuad(quadIdx);
Expand Down
91 changes: 91 additions & 0 deletions rts/Sim/Misc/QuadField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,97 @@ void CQuadField::GetQuadsOnRay(QuadFieldQuery& qfq, const float3& start, const f
}


// Test with wide ray that also extends width at the extremes.
void CQuadField::GetQuadsOnWideRay(QuadFieldQuery& qfq, const float3& start, const float3& dir, float length, float width)
{
RECOIL_DETAILED_TRACY_ZONE;
dir.AssertNaNs();
start.AssertNaNs();

auto& queryQuads = *(qfq.quads = tempQuads[qfq.threadOwner].ReserveVector());

const float3 baseTo = start + (dir * length);

const bool noZdir = (math::floor(start.z * invQuadSize.y) == math::floor(baseTo.z * invQuadSize.y));

// special case, prevent div0.
if (noZdir) {
// Having noZdir will roughly result in a rectangle.
float startX = start.x;
float finalX = baseTo.x;
if (finalX < startX)
std::swap(startX, finalX);

float startZ = start.z;
float finalZ = baseTo.z;
if (finalZ < startZ)
std::swap(startZ, finalZ);

const float3 mins(startX - width, 0, startZ - width);
const float3 maxs(finalX + width, 0, finalZ + width);

return GetQuadsRectangle(qfq, mins, maxs);
}

// iterate z-range; compute which columns (x) are touched for each row (z)
const float3 normDirPlanar = float3(dir.x, 0.0, dir.z).UnsafeNormalize(); // we already checked for unsafe cases before
const float widthFactor = std::abs(normDirPlanar.z / dir.z) * width;

// Start and stop a bit further to account for width
const float3 to = baseTo + dir * widthFactor;
length = (to - start).Length();

// taking normDirPlanar.z since we want perpendicular proportion
const float mapMarginX = std::abs(width * normDirPlanar.z);

// From here on, basically a copy of the same section of GetQuadsOnRay, just here extending
// startX and finalX with mapMarginX before converting to quad indexes and pushing each row.

float startZuc = start.z * invQuadSize.y;
float finalZuc = to.z * invQuadSize.y;

if (finalZuc < startZuc)
std::swap(startZuc, finalZuc);

const int startZ = std::clamp <int> (startZuc, 0, numQuadsZ - 1);
const int finalZ = std::clamp <int> (finalZuc, 0, numQuadsZ - 1);

assert(finalZ < quadSizeZ);

const float invDirZ = 1.0f / dir.z;

for (int z = startZ; z <= finalZ; z++) {
float t0 = ((z ) * quadSizeZ - start.z) * invDirZ;
float t1 = ((z + 1) * quadSizeZ - start.z) * invDirZ;

if ((startZuc < 0 && z == 0) || (startZuc >= numQuadsZ && z == finalZ))
t0 = ((startZuc ) * quadSizeZ - start.z) * invDirZ;

if ((finalZuc < 0 && z == 0) || (finalZuc >= numQuadsZ && z == finalZ))
t1 = ((finalZuc + 1) * quadSizeZ - start.z) * invDirZ;

t0 = std::clamp(t0, 0.0f, length);
t1 = std::clamp(t1, 0.0f, length);

float mapStartX = dir.x * t0 + start.x;
float mapFinalX = dir.x * t1 + start.x;

if (mapFinalX < mapStartX)
std::swap(mapStartX, mapFinalX);

const unsigned startX = std::clamp <int> ((mapStartX - mapMarginX) * invQuadSize.x, 0, numQuadsX - 1);
const unsigned finalX = std::clamp <int> ((mapFinalX + mapMarginX) * invQuadSize.x, 0, numQuadsX - 1);

const int row = std::clamp(z, 0, numQuadsZ - 1) * numQuadsX;

for (unsigned x = startX; x <= finalX; x++) {
queryQuads.push_back(row + x);
assert(static_cast<unsigned>(queryQuads.back()) < baseQuads.size());
}
}
}



#ifndef UNIT_TEST
bool CQuadField::InsertUnitIf(CUnit* unit, const float3& wpos)
Expand Down
1 change: 1 addition & 0 deletions rts/Sim/Misc/QuadField.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class CQuadField : spring::noncopyable
void GetQuads(QuadFieldQuery& qfq, float3 pos, float radius);
void GetQuadsRectangle(QuadFieldQuery& qfq, const float3& mins, const float3& maxs);
void GetQuadsOnRay(QuadFieldQuery& qfq, const float3& start, const float3& dir, float length);
void GetQuadsOnWideRay(QuadFieldQuery& qfq, const float3& start, const float3& dir, float length, float width);

void GetUnitsAndFeaturesColVol(
const float3& pos,
Expand Down