diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 4d4620972..00621eda9 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -320,6 +320,7 @@ target_link_dependencies(libdevilutionx_lighting PUBLIC DevilutionX::SDL fmt::fmt tl + libdevilutionx_vision ) add_devilutionx_object_library(libdevilutionx_logged_fstream @@ -576,6 +577,13 @@ add_devilutionx_object_library(libdevilutionx_utils_console utils/console.cpp ) +add_devilutionx_object_library(libdevilutionx_vision + vision.cpp +) +target_link_dependencies(libdevilutionx_vision PUBLIC + tl +) + if(USE_SDL1) add_devilutionx_library(libdevilutionx_sdl2_to_1_2_backports STATIC utils/sdl2_to_1_2_backports.cpp diff --git a/Source/lighting.cpp b/Source/lighting.cpp index aa794ab26..b1195fb2e 100644 --- a/Source/lighting.cpp +++ b/Source/lighting.cpp @@ -7,18 +7,25 @@ #include #include +#include #include #include #include #include "automap.h" +#include "engine/displacement.hpp" #include "engine/load_file.hpp" +#include "engine/point.hpp" #include "engine/points_in_rectangle_range.hpp" +#include "engine/world_tile.hpp" +#include "levels/tile_properties.hpp" +#include "objects.h" #include "player.h" #include "utils/attributes.h" #include "utils/is_of.hpp" #include "utils/status_macros.hpp" +#include "vision.hpp" namespace devilution { @@ -40,43 +47,6 @@ bool UpdateLighting; namespace { -/* - * 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 - */ -static const DisplacementOf VisionRays[23][15] = { - // 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 } }, - { { 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 }, { 12, 2 }, { 13, 2 }, { 14, 2 }, { 15, 2 } }, - { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 }, { 8, 2 }, { 9, 2 }, { 10, 2 }, { 11, 2 }, { 12, 2 }, { 13, 3 }, { 14, 3 }, { 15, 3 } }, - { { 1, 0 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 }, { 6, 2 }, { 7, 2 }, { 8, 2 }, { 9, 3 }, { 10, 3 }, { 11, 3 }, { 12, 3 }, { 13, 4 }, { 14, 4 }, { 0, 0 } }, - { { 1, 0 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 2 }, { 6, 2 }, { 7, 3 }, { 8, 3 }, { 9, 3 }, { 10, 4 }, { 11, 4 }, { 12, 4 }, { 13, 5 }, { 14, 5 }, { 0, 0 } }, - { { 1, 0 }, { 2, 1 }, { 3, 1 }, { 4, 2 }, { 5, 2 }, { 6, 3 }, { 7, 3 }, { 8, 3 }, { 9, 4 }, { 10, 4 }, { 11, 5 }, { 12, 5 }, { 13, 6 }, { 14, 6 }, { 0, 0 } }, - { { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 2 }, { 5, 3 }, { 6, 3 }, { 7, 4 }, { 8, 4 }, { 9, 5 }, { 10, 5 }, { 11, 6 }, { 12, 6 }, { 13, 7 }, { 0, 0 }, { 0, 0 } }, - { { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 2 }, { 5, 3 }, { 6, 4 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 6 }, { 11, 7 }, { 12, 7 }, { 12, 8 }, { 13, 8 }, { 0, 0 } }, - { { 1, 1 }, { 2, 2 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 }, { 7, 5 }, { 8, 6 }, { 9, 7 }, { 10, 7 }, { 10, 8 }, { 11, 8 }, { 12, 9 }, { 0, 0 }, { 0, 0 } }, - { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 5 }, { 7, 6 }, { 8, 7 }, { 9, 8 }, { 10, 9 }, { 11, 9 }, { 11, 10 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, - { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 8, 8 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, - { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, { 8, 9 }, { 9, 10 }, { 9, 11 }, { 10, 11 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, - { { 1, 1 }, { 2, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 6 }, { 5, 7 }, { 6, 8 }, { 7, 9 }, { 7, 10 }, { 8, 10 }, { 8, 11 }, { 9, 12 }, { 0, 0 }, { 0, 0 } }, - { { 1, 1 }, { 1, 2 }, { 2, 3 }, { 2, 4 }, { 3, 5 }, { 4, 6 }, { 4, 7 }, { 5, 8 }, { 6, 9 }, { 6, 10 }, { 7, 11 }, { 7, 12 }, { 8, 12 }, { 8, 13 }, { 0, 0 } }, - { { 1, 1 }, { 1, 2 }, { 2, 3 }, { 2, 4 }, { 3, 5 }, { 3, 6 }, { 4, 7 }, { 4, 8 }, { 5, 9 }, { 5, 10 }, { 6, 11 }, { 6, 12 }, { 7, 13 }, { 0, 0 }, { 0, 0 } }, - { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 2, 4 }, { 2, 5 }, { 3, 6 }, { 3, 7 }, { 3, 8 }, { 4, 9 }, { 4, 10 }, { 5, 11 }, { 5, 12 }, { 6, 13 }, { 6, 14 }, { 0, 0 } }, - { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 2, 5 }, { 2, 6 }, { 3, 7 }, { 3, 8 }, { 3, 9 }, { 4, 10 }, { 4, 11 }, { 4, 12 }, { 5, 13 }, { 5, 14 }, { 0, 0 } }, - { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 2, 6 }, { 2, 7 }, { 2, 8 }, { 3, 9 }, { 3, 10 }, { 3, 11 }, { 3, 12 }, { 4, 13 }, { 4, 14 }, { 0, 0 } }, - { { 0, 1 }, { 0, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 1, 6 }, { 1, 7 }, { 2, 8 }, { 2, 9 }, { 2, 10 }, { 2, 11 }, { 2, 12 }, { 3, 13 }, { 3, 14 }, { 3, 15 } }, - { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 4 }, { 1, 5 }, { 1, 6 }, { 1, 7 }, { 1, 8 }, { 1, 9 }, { 1, 10 }, { 1, 11 }, { 2, 12 }, { 2, 13 }, { 2, 14 }, { 2, 15 } }, - { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 0, 5 }, { 0, 6 }, { 0, 7 }, { 1, 8 }, { 1, 9 }, { 1, 10 }, { 1, 11 }, { 1, 12 }, { 1, 13 }, { 1, 14 }, { 1, 15 } }, - { { 0, 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 } }, - // clang-format on -}; - /** @brief Number of supported light radiuses (first radius starts with 0) */ constexpr size_t NumLightRadiuses = 16; /** Falloff tables for the light cone */ @@ -230,80 +200,6 @@ void DoUnVision(Point position, uint8_t radius) } } -void DoVision(Point position, uint8_t radius, - tl::function_ref markVisibleFn, - tl::function_ref markTransparentFn, - tl::function_ref passesLightFn, - tl::function_ref inBoundsFn) -{ - markVisibleFn(position); - - // 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 }; - 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 } }; - - // 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 (!inBoundsFn(rayPoint)) - break; - - // 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 }; - - bool passesLight = (passesLightFn(rayPoint + adjacent1) || passesLightFn(rayPoint + adjacent2)); - if (!passesLight) - // Diagonally adjacent tiles do not pass the - // light further, we are done with this ray - break; - } - markVisibleFn(rayPoint); - - bool passesLight = passesLightFn(rayPoint); - if (!passesLight) - // Tile does not pass the light further, we are - // done with this ray - break; - - markTransparentFn(rayPoint); - } - } - } -} - void DoVision(Point position, uint8_t radius, MapExplorationType doAutomap, bool visible) { auto markVisibleFn = [doAutomap, visible](Point rayPoint) { diff --git a/Source/lighting.h b/Source/lighting.h index eb4fb9816..2a0de57ad 100644 --- a/Source/lighting.h +++ b/Source/lighting.h @@ -9,7 +9,6 @@ #include #include -#include #include "automap.h" #include "engine/displacement.hpp" @@ -63,11 +62,6 @@ extern bool UpdateLighting; void DoUnLight(Point position, uint8_t radius); void DoLighting(Point position, uint8_t radius, DisplacementOf offset); void DoUnVision(Point position, uint8_t radius); -void DoVision(Point position, uint8_t radius, - tl::function_ref markVisibleFn, - tl::function_ref markTransparentFn, - tl::function_ref passesLightFn, - tl::function_ref inBoundsFn); void DoVision(Point position, uint8_t radius, MapExplorationType doAutomap, bool visible); tl::expected LoadTrns(); void MakeLightTable(); diff --git a/Source/vision.cpp b/Source/vision.cpp new file mode 100644 index 000000000..4be081b0a --- /dev/null +++ b/Source/vision.cpp @@ -0,0 +1,122 @@ +#include "vision.hpp" + +#include +#include + +#include + +#include "engine/displacement.hpp" +#include "engine/point.hpp" + +namespace devilution { +namespace { +/* + * 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 VisionRays[23][15] = { + // 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 } }, + { { 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 }, { 12, 2 }, { 13, 2 }, { 14, 2 }, { 15, 2 } }, + { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 }, { 8, 2 }, { 9, 2 }, { 10, 2 }, { 11, 2 }, { 12, 2 }, { 13, 3 }, { 14, 3 }, { 15, 3 } }, + { { 1, 0 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 }, { 6, 2 }, { 7, 2 }, { 8, 2 }, { 9, 3 }, { 10, 3 }, { 11, 3 }, { 12, 3 }, { 13, 4 }, { 14, 4 }, { 0, 0 } }, + { { 1, 0 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 2 }, { 6, 2 }, { 7, 3 }, { 8, 3 }, { 9, 3 }, { 10, 4 }, { 11, 4 }, { 12, 4 }, { 13, 5 }, { 14, 5 }, { 0, 0 } }, + { { 1, 0 }, { 2, 1 }, { 3, 1 }, { 4, 2 }, { 5, 2 }, { 6, 3 }, { 7, 3 }, { 8, 3 }, { 9, 4 }, { 10, 4 }, { 11, 5 }, { 12, 5 }, { 13, 6 }, { 14, 6 }, { 0, 0 } }, + { { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 2 }, { 5, 3 }, { 6, 3 }, { 7, 4 }, { 8, 4 }, { 9, 5 }, { 10, 5 }, { 11, 6 }, { 12, 6 }, { 13, 7 }, { 0, 0 }, { 0, 0 } }, + { { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 2 }, { 5, 3 }, { 6, 4 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 6 }, { 11, 7 }, { 12, 7 }, { 12, 8 }, { 13, 8 }, { 0, 0 } }, + { { 1, 1 }, { 2, 2 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 }, { 7, 5 }, { 8, 6 }, { 9, 7 }, { 10, 7 }, { 10, 8 }, { 11, 8 }, { 12, 9 }, { 0, 0 }, { 0, 0 } }, + { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 5 }, { 7, 6 }, { 8, 7 }, { 9, 8 }, { 10, 9 }, { 11, 9 }, { 11, 10 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 8, 8 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, { 8, 9 }, { 9, 10 }, { 9, 11 }, { 10, 11 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 1, 1 }, { 2, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 5, 6 }, { 5, 7 }, { 6, 8 }, { 7, 9 }, { 7, 10 }, { 8, 10 }, { 8, 11 }, { 9, 12 }, { 0, 0 }, { 0, 0 } }, + { { 1, 1 }, { 1, 2 }, { 2, 3 }, { 2, 4 }, { 3, 5 }, { 4, 6 }, { 4, 7 }, { 5, 8 }, { 6, 9 }, { 6, 10 }, { 7, 11 }, { 7, 12 }, { 8, 12 }, { 8, 13 }, { 0, 0 } }, + { { 1, 1 }, { 1, 2 }, { 2, 3 }, { 2, 4 }, { 3, 5 }, { 3, 6 }, { 4, 7 }, { 4, 8 }, { 5, 9 }, { 5, 10 }, { 6, 11 }, { 6, 12 }, { 7, 13 }, { 0, 0 }, { 0, 0 } }, + { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 2, 4 }, { 2, 5 }, { 3, 6 }, { 3, 7 }, { 3, 8 }, { 4, 9 }, { 4, 10 }, { 5, 11 }, { 5, 12 }, { 6, 13 }, { 6, 14 }, { 0, 0 } }, + { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 2, 5 }, { 2, 6 }, { 3, 7 }, { 3, 8 }, { 3, 9 }, { 4, 10 }, { 4, 11 }, { 4, 12 }, { 5, 13 }, { 5, 14 }, { 0, 0 } }, + { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 2, 6 }, { 2, 7 }, { 2, 8 }, { 3, 9 }, { 3, 10 }, { 3, 11 }, { 3, 12 }, { 4, 13 }, { 4, 14 }, { 0, 0 } }, + { { 0, 1 }, { 0, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 1, 6 }, { 1, 7 }, { 2, 8 }, { 2, 9 }, { 2, 10 }, { 2, 11 }, { 2, 12 }, { 3, 13 }, { 3, 14 }, { 3, 15 } }, + { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 4 }, { 1, 5 }, { 1, 6 }, { 1, 7 }, { 1, 8 }, { 1, 9 }, { 1, 10 }, { 1, 11 }, { 2, 12 }, { 2, 13 }, { 2, 14 }, { 2, 15 } }, + { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 0, 5 }, { 0, 6 }, { 0, 7 }, { 1, 8 }, { 1, 9 }, { 1, 10 }, { 1, 11 }, { 1, 12 }, { 1, 13 }, { 1, 14 }, { 1, 15 } }, + { { 0, 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 } }, + // clang-format on +}; +} // namespace + +void DoVision(Point position, uint8_t radius, + tl::function_ref markVisibleFn, + tl::function_ref markTransparentFn, + tl::function_ref passesLightFn, + tl::function_ref inBoundsFn) +{ + markVisibleFn(position); + + // Adjustment to a ray length to ensure all rays lie on an + // accurate circle + constexpr 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 }; + static_assert(std::size(RayLenAdj) == std::size(VisionRays)); + + // Four quadrants on a circle + constexpr Displacement Quadrants[] = { { 1, 1 }, { -1, 1 }, { 1, -1 }, { -1, -1 } }; + + // 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++) { + const 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 + const Point rayPoint = position + relRayPoint * quadrant; + if (!inBoundsFn(rayPoint)) break; + + // 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) { + const Displacement adjacent1 = { -quadrant.deltaX, 0 }; + const Displacement adjacent2 = { 0, -quadrant.deltaY }; + + // If diagonally adjacent tiles do not pass the + // light further, we are done with this ray. + const bool passesLight = (passesLightFn(rayPoint + adjacent1) || passesLightFn(rayPoint + adjacent2)); + if (!passesLight) break; + } + markVisibleFn(rayPoint); + + // If the tile does not pass the light further, we are + // done with this ray. + const bool passesLight = passesLightFn(rayPoint); + if (!passesLight) break; + + markTransparentFn(rayPoint); + } + } + } +} + +} // namespace devilution diff --git a/Source/vision.hpp b/Source/vision.hpp new file mode 100644 index 000000000..7ba7502e2 --- /dev/null +++ b/Source/vision.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include + +#include "engine/point.hpp" + +namespace devilution { + +void DoVision(Point position, uint8_t radius, + tl::function_ref markVisibleFn, + tl::function_ref markTransparentFn, + tl::function_ref passesLightFn, + tl::function_ref inBoundsFn); + +} // namespace devilution diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f65e89481..dc2ddafa8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -106,7 +106,7 @@ target_link_dependencies(format_int_test PRIVATE libdevilutionx_format_int langu target_link_dependencies(ini_test PRIVATE libdevilutionx_ini app_fatal_for_testing) target_link_dependencies(parse_int_test PRIVATE libdevilutionx_parse_int) target_link_dependencies(path_test PRIVATE libdevilutionx_pathfinding libdevilutionx_direction app_fatal_for_testing) -target_link_dependencies(vision_test PRIVATE DevilutionX::SDL tl libdevilutionx_so app_fatal_for_testing) +target_link_dependencies(vision_test PRIVATE libdevilutionx_vision) target_link_dependencies(path_benchmark PRIVATE libdevilutionx_pathfinding app_fatal_for_testing) target_link_dependencies(random_test PRIVATE libdevilutionx_random) target_link_dependencies(static_vector_test PRIVATE libdevilutionx_random app_fatal_for_testing) diff --git a/test/vision_test.cpp b/test/vision_test.cpp index 3bd46621b..8a6372e05 100644 --- a/test/vision_test.cpp +++ b/test/vision_test.cpp @@ -1,6 +1,6 @@ #include -#include "lighting.h" +#include "vision.hpp" namespace devilution {