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
88 changes: 63 additions & 25 deletions Source/lighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@
namespace {

/*
* X- Y-coordinate offsets of lighting visions.
* The last entry-pair is only for alignment.
* XY points of vision rays are cast to trace the visibility of the
* surrounding environment. The table represents N rays of M points in
* one quadrant (0°-90°) of a circle, so rays for other quadrants will
* be created by mirroring. Zero points at the end will be trimmed and
* ignored. A similar table can be recreated using Bresenham's line
* drawing algorithm, which is suitable for integer arithmetic:
* https://en.wikipedia.org/wiki/Bresenham's_line_algorithm
*/
const DisplacementOf<int8_t> VisionCrawlTable[23][15] = {
static const DisplacementOf<int8_t> VisionRays[23][15] = {

Check warning on line 52 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:52:37 [readability-static-definition-in-anonymous-namespace]

'VisionRays' is a static definition in anonymous namespace; static is redundant here
// clang-format off
{ { 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 0 }, { 5, 0 }, { 6, 0 }, { 7, 0 }, { 8, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 }, { 12, 0 }, { 13, 0 }, { 14, 0 }, { 15, 0 } },
{ { 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 0 }, { 5, 0 }, { 6, 0 }, { 7, 0 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 }, { 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 } },
Expand Down Expand Up @@ -80,9 +85,6 @@
/** interpolations of a 32x32 (16x16 mirrored) light circle moving between tiles in steps of 1/8 of a tile */
uint8_t LightConeInterpolations[8][8][16][16];

/** RadiusAdj maps from VisionCrawlTable index to lighting vision radius adjustment. */
const uint8_t RadiusAdj[23] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0 };

void RotateRadius(DisplacementOf<int8_t> &offset, DisplacementOf<int8_t> &dist, DisplacementOf<int8_t> &light, DisplacementOf<int8_t> &block)
{
dist = { static_cast<int8_t>(7 - dist.deltaY), dist.deltaX };
Expand Down Expand Up @@ -151,7 +153,7 @@
}
}

void DoLighting(Point position, uint8_t radius, DisplacementOf<int8_t> offset)

Check warning on line 156 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:156:6 [readability-function-cognitive-complexity]

function 'DoLighting' has cognitive complexity of 33 (threshold 25)
{
assert(radius >= 0 && radius <= NumLightRadiuses);
assert(InDungeonBounds(position));
Expand Down Expand Up @@ -228,35 +230,71 @@
}
}

void DoVision(Point position, uint8_t radius, MapExplorationType doAutomap, bool visible)

Check warning on line 233 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:233:6 [readability-function-cognitive-complexity]

function 'DoVision' has cognitive complexity of 28 (threshold 25)
{
DoVisionFlags(position, doAutomap, visible);

static const Displacement factors[] = { { 1, 1 }, { -1, 1 }, { 1, -1 }, { -1, -1 } };
for (auto factor : factors) {
for (int j = 0; j < 23; j++) {
int lineLen = radius - RadiusAdj[j];
for (int k = 0; k < lineLen; k++) {
Point crawl = position + VisionCrawlTable[j][k] * factor;
if (!InDungeonBounds(crawl))
// Adjustment to a ray length to ensure all rays lie on an
// accurate circle
static const uint8_t rayLenAdj[23] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0 };

Check warning on line 239 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:239:23 [readability-identifier-naming]

invalid case style for static constant 'rayLenAdj'
static_assert(std::size(rayLenAdj) == std::size(VisionRays));

// Four quadrants on a circle
static const Displacement quadrants[] = { { 1, 1 }, { -1, 1 }, { 1, -1 }, { -1, -1 } };

Check warning on line 243 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:243:28 [readability-identifier-naming]

invalid case style for static constant 'quadrants'

// Loop over quadrants and mirror rays for each one
for (const auto &quadrant : quadrants) {
// Cast a ray for a quadrant
for (unsigned int j = 0; j < std::size(VisionRays); j++) {
int rayLen = radius - rayLenAdj[j];
for (int k = 0; k < rayLen; k++) {
const auto &relRayPoint = VisionRays[j][k];
// Calculate the next point on a ray in the quadrant
Point rayPoint = position + relRayPoint * quadrant;
if (!InDungeonBounds(rayPoint))
break;
bool blockerFlag = TileHasAny(crawl, TileProperties::BlockLight);
bool tileOK = !blockerFlag;

if (VisionCrawlTable[j][k].deltaX > 0 && VisionCrawlTable[j][k].deltaY > 0) {
tileOK = tileOK || TileAllowsLight(crawl + Displacement { -factor.deltaX, 0 });
tileOK = tileOK || TileAllowsLight(crawl + Displacement { 0, -factor.deltaY });
bool visible = true;

//
// We've cast an approximated ray on an integer 2D
// grid, so we need to check if a ray can pass through
// the diagonally adjacent tiles. For example, consider
// this case:
//
// #?
// ↗ #
// x
//
// The ray is cast from the observer 'x', and reaches
// the '?', but diagonally adjacent tiles '#' do not
// pass the light, so the '?' should not be visible
// for the 2D observer.
//
// The trick is to perform two additional visibility
// checks for the diagonally adjacent tiles, but only
// for the rays that are not parallel to the X or Y
// coordinate lines. Parallel rays, which have a 0 in
// one of their coordinate components, do not require
// any additional adjacent visibility checks, and the
// tile, hit by the ray, is always considered visible.
//
if (relRayPoint.deltaX > 0 && relRayPoint.deltaY > 0) {
Displacement adjacent1 = { -quadrant.deltaX, 0 };
Displacement adjacent2 = { 0, -quadrant.deltaY };

visible = (TileAllowsLight(rayPoint + adjacent1) || TileAllowsLight(rayPoint + adjacent2));
}
if (visible)
DoVisionFlags(rayPoint, doAutomap, visible);

if (!tileOK)
break;

DoVisionFlags(crawl, doAutomap, visible);

if (blockerFlag)
bool passesLight = TileAllowsLight(rayPoint);
if (!passesLight)

Check warning on line 292 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:292:22 [readability-braces-around-statements]

statement should be inside braces
// Tile does not pass the light further, we are
// done with this ray
break;

int8_t trans = dTransVal[crawl.x][crawl.y];
int8_t trans = dTransVal[rayPoint.x][rayPoint.y];
if (trans != 0)
TransList[trans] = true;
}
Expand All @@ -271,7 +309,7 @@
return LoadFileInMemWithStatus("gendata\\pause.trn", PauseTable);
}

void MakeLightTable()

Check warning on line 312 in Source/lighting.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/lighting.cpp:312:6 [readability-function-cognitive-complexity]

function 'MakeLightTable' has cognitive complexity of 46 (threshold 25)
{
// Generate 16 gradually darker translation tables for doing lighting
uint8_t shade = 0;
Expand Down
Binary file modified test/fixtures/timedemo/WarriorLevel1to2/demo_0.dmo
Binary file not shown.
Binary file not shown.
Binary file modified test/fixtures/timedemo/WarriorLevel1to2/spawn_0.sv
Binary file not shown.
Loading