Skip to content

Commit 6801348

Browse files
authored
Merge pull request #46 from cortex-command-community/terrainpenetrationray
Added CastTerrainPenetrationRay to SceneMan
2 parents 2b73f43 + 6085af9 commit 6801348

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
126126

127127
- Exposed `FrameMan` properties `ScreenCount` and `ResolutionMultiplier` to Lua (R).
128128

129+
- New `SceneMan` Lua function `CastTerrainPenetrationRay(Vector start, Vector ray, Vector endPos, int strengthLimit, int skip)`, which adds up the material strength of the terrain pixels encountered along the way, and stops when the accumulated value meets or exceeds `strengthLimit`. `endPos` is filled out with the ending position of the ray, returns `true` or `false` depending on whether the ray was stopped early or not.
130+
129131
</details>
130132

131133
<details><summary><b>Changed</b></summary>

Source/Lua/LuaBindingsManagers.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) {
314314
.def("CastMORay", &SceneMan::CastMORay)
315315
.def("CastFindMORay", &SceneMan::CastFindMORay)
316316
.def("CastObstacleRay", &SceneMan::CastObstacleRay)
317+
.def("CastTerrainPenetrationRay", &SceneMan::CastTerrainPenetrationRay)
317318
.def("GetLastRayHitPos", &SceneMan::GetLastRayHitPos)
318319
.def("FindAltitude", (float(SceneMan::*)(const Vector&, int, int)) & SceneMan::FindAltitude)
319320
.def("FindAltitude", (float(SceneMan::*)(const Vector&, int, int, bool)) & SceneMan::FindAltitude)

Source/Managers/SceneMan.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,94 @@ void SceneMan::RestoreUnseenBox(const int posX, const int posY, const int width,
10771077
}
10781078
}
10791079

1080+
bool SceneMan::CastTerrainPenetrationRay(const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip) {
1081+
int hitCount = 0, error, dom, sub, domSteps, skipped = skip;
1082+
int intPos[2], delta[2], delta2[2], increment[2];
1083+
bool stopped = false;
1084+
unsigned char materialID;
1085+
Material const* foundMaterial;
1086+
int totalStrength = 0;
1087+
// Save the projected end of the ray pos
1088+
endPos = start + ray;
1089+
1090+
intPos[X] = std::floor(start.m_X);
1091+
intPos[Y] = std::floor(start.m_Y);
1092+
delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X];
1093+
delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y];
1094+
1095+
if (delta[X] == 0 && delta[Y] == 0)
1096+
return false;
1097+
1098+
/////////////////////////////////////////////////////
1099+
// Bresenham's line drawing algorithm preparation
1100+
1101+
if (delta[X] < 0) {
1102+
increment[X] = -1;
1103+
delta[X] = -delta[X];
1104+
} else
1105+
increment[X] = 1;
1106+
1107+
if (delta[Y] < 0) {
1108+
increment[Y] = -1;
1109+
delta[Y] = -delta[Y];
1110+
} else
1111+
increment[Y] = 1;
1112+
1113+
// Scale by 2, for better accuracy of the error at the first pixel
1114+
delta2[X] = delta[X] << 1;
1115+
delta2[Y] = delta[Y] << 1;
1116+
1117+
// If X is dominant, Y is submissive, and vice versa.
1118+
if (delta[X] > delta[Y]) {
1119+
dom = X;
1120+
sub = Y;
1121+
} else {
1122+
dom = Y;
1123+
sub = X;
1124+
}
1125+
1126+
error = delta2[sub] - delta[dom];
1127+
1128+
/////////////////////////////////////////////////////
1129+
// Bresenham's line drawing algorithm execution
1130+
1131+
for (domSteps = 0; domSteps < delta[dom]; ++domSteps) {
1132+
intPos[dom] += increment[dom];
1133+
if (error >= 0) {
1134+
intPos[sub] += increment[sub];
1135+
error -= delta2[dom];
1136+
}
1137+
error += delta2[sub];
1138+
1139+
// Only check pixel if we're not due to skip any, or if this is the last pixel
1140+
if (++skipped > skip || domSteps + 1 == delta[dom]) {
1141+
// Scene wrapping
1142+
g_SceneMan.WrapPosition(intPos[X], intPos[Y]);
1143+
1144+
// Check the strength of the terrain to see if we can penetrate further
1145+
materialID = GetTerrMatter(intPos[X], intPos[Y]);
1146+
// Get the material object
1147+
foundMaterial = GetMaterialFromID(materialID);
1148+
// Add the encountered material's strength to the tally
1149+
totalStrength += foundMaterial->GetIntegrity();
1150+
// See if we have hit the limits of our ray's strength
1151+
if (totalStrength >= strengthLimit) {
1152+
// Save the position of the end of the ray where blocked
1153+
endPos.SetXY(intPos[X], intPos[Y]);
1154+
stopped = true;
1155+
break;
1156+
}
1157+
// Reset skip counter
1158+
skipped = 0;
1159+
if (m_pDebugLayer && m_DrawRayCastVisualizations) {
1160+
m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13);
1161+
}
1162+
}
1163+
}
1164+
1165+
return stopped;
1166+
}
1167+
10801168
// TODO Every raycast should use some shared line drawing method (or maybe something more efficient if it exists, that needs looking into) instead of having a ton of duplicated code.
10811169
bool SceneMan::CastUnseenRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip, bool reveal) {
10821170
if (!m_pCurrentScene->GetUnseenLayer(team))

Source/Managers/SceneMan.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,18 @@ namespace RTE {
460460
/// @param width The team to restore for.
461461
void RestoreUnseenBox(const int posX, const int posY, const int width, const int height, const int team);
462462

463+
/// Traces along a vector and stops when the accumulated material strengths of the
464+
/// traced-through terrain meets or exceeds a given value.
465+
/// @param start The starting position.
466+
/// @param ray The vector to trace along.
467+
/// @param endPos A Vector that will be set to the position of where the sight ray was
468+
/// terminated. If it reached the end, it will be set to the end of the ray.
469+
/// @param strengthLimit The accumulated material strength limit where the ray stops.
470+
/// @param skip For every pixel checked along the line, how many to skip between them
471+
/// for optimization reasons. 0 = every pixel is checked.
472+
/// @return Whether the ray was stopped prematurely or not.
473+
bool CastTerrainPenetrationRay(const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip);
474+
463475
/// Traces along a vector and reveals or hides pixels on the unseen layer of a team
464476
/// as long as the accumulated material strengths traced through the terrain
465477
/// don't exceed a specific value.

0 commit comments

Comments
 (0)