From c0b36eee8ab814f841bb6460b8de8a64d9a9af00 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Wed, 15 May 2019 06:31:55 +0000 Subject: [PATCH 1/7] Extend shadowcasting test to 3D --- tests/shadowcasting_test.cpp | 298 +++++++++++++++++++++-------------- 1 file changed, 179 insertions(+), 119 deletions(-) diff --git a/tests/shadowcasting_test.cpp b/tests/shadowcasting_test.cpp index 8006252a1f5b3..2bb2e3a0f8ed2 100644 --- a/tests/shadowcasting_test.cpp +++ b/tests/shadowcasting_test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -406,11 +407,11 @@ static void shadowcasting_3d_2d( const int iterations ) #define V LIGHT_TRANSPARENCY_CLEAR #define X LIGHT_TRANSPARENCY_SOLID -const point ORIGIN( 65, 65 ); +const tripoint ORIGIN( 65, 65, 11 ); struct grid_overlay { - std::vector> data; - point offset; + std::vector>> data; + tripoint offset; float default_value; // origin_offset is specified as the coordinates of the "camera" within the overlay. @@ -418,185 +419,244 @@ struct grid_overlay { this->offset = ORIGIN - origin_offset; this->default_value = default_value; } + grid_overlay( const tripoint origin_offset, const float default_value ) { + this->offset = ORIGIN - origin_offset; + this->default_value = default_value; + } - int height() const { + int depth() const { return data.size(); } - int width() const { + int height() const { if( data.empty() ) { return 0; } return data[0].size(); } + int width() const { + if( data.empty() || data[0].empty() ) { + return 0; + } + return data[0][0].size(); + } + tripoint get_max() const { + return offset + tripoint( width(), height(), depth() ); + } - float get_global( const int x, const int y ) const { + float get_global( const int x, const int y, const int z ) const { if( y >= offset.y && y < offset.y + height() && - x >= offset.x && x < offset.x + width() ) { - return data[ y - offset.y ][ x - offset.x ]; + x >= offset.x && x < offset.x + width() && + z >= offset.z && z < offset.z + depth() ) { + return data[ z - offset.z ][ y - offset.y ][ x - offset.x ]; } return default_value; } - - float get_local( const int x, const int y ) const { - return data[ y ][ x ]; - } }; -static void run_spot_check( const grid_overlay &test_case, const grid_overlay &expected_result ) +static void run_spot_check( const grid_overlay &test_case, const grid_overlay &expected, + bool fov_3d ) { - float seen_squares[ MAPSIZE * SEEY ][ MAPSIZE * SEEX ] = {{ 0 }}; - float transparency_cache[ MAPSIZE * SEEY ][ MAPSIZE * SEEX ] = {{ 0 }}; - - for( int y = 0; y < static_cast( sizeof( transparency_cache ) / - sizeof( transparency_cache[0] ) ); ++y ) { - for( int x = 0; x < static_cast( sizeof( transparency_cache[0] ) / - sizeof( transparency_cache[0][0] ) ); ++x ) { - transparency_cache[ y ][ x ] = test_case.get_global( x, y ); + // Reminder to not trigger 2D shadowcasting on 3D use cases. + if( !fov_3d ) { + REQUIRE( test_case.depth() == 1 ); + } + level_cache *caches[OVERMAP_LAYERS]; + std::array seen_squares; + std::array transparency_cache; + std::array floor_cache; + + int z = fov_3d ? 0 : 11; + const int upper_bound = fov_3d ? OVERMAP_LAYERS : 12; + for( ; z < upper_bound; ++z ) { + caches[z] = new level_cache(); + seen_squares[z] = &caches[z]->seen_cache; + transparency_cache[z] = &caches[z]->transparency_cache; + floor_cache[z] = &caches[z]->floor_cache; + for( int y = 0; y < MAPSIZE * SEEY; ++y ) { + for( int x = 0; x < MAPSIZE * SEEX; ++x ) { + caches[z]->transparency_cache[x][y] = test_case.get_global( x, y, z ); + } } } - castLightAll( - seen_squares, transparency_cache, ORIGIN.x, ORIGIN.y ); + if( fov_3d ) { + cast_zlight( seen_squares, + transparency_cache, floor_cache, { ORIGIN.x, ORIGIN.y, ORIGIN.z - OVERMAP_DEPTH }, 0, 1.0 ); + } else { + castLightAll( + *seen_squares[11], *transparency_cache[11], ORIGIN.x, ORIGIN.y ); - // Compares the whole grid, but out-of-bounds compares will de-facto pass. - for( int y = 0; y < expected_result.height(); ++y ) { - for( int x = 0; x < expected_result.width(); ++x ) { - INFO( "x:" << x << " y:" << y << " expected:" << expected_result.data[y][x] << " actual:" << - seen_squares[expected_result.offset.y + y][expected_result.offset.x + x] ); - if( V == expected_result.get_local( x, y ) ) { - CHECK( seen_squares[expected_result.offset.y + y][expected_result.offset.x + x] > 0 ); - } else { - CHECK( seen_squares[expected_result.offset.y + y][expected_result.offset.x + x] == 0 ); + } + bool passed = true; + std::ostringstream trans_grid; + std::ostringstream expected_grid; + std::ostringstream actual_grid; + for( int gz = expected.offset.z; gz < expected.get_max().z; ++gz ) { + for( int gy = expected.offset.y; gy < expected.get_max().y; ++gy ) { + for( int gx = expected.offset.x; gx < expected.get_max().x; ++gx ) { + trans_grid << caches[gz]->transparency_cache[gx][gy]; + expected_grid << ( expected.get_global( gx, gy, gz ) > 0 ? 'V' : 'O' ); + actual_grid << ( ( *seen_squares[gz] )[gx][gy] > 0 ? 'V' : 'O' ); + if( V == expected.get_global( gx, gy, gz ) && ( *seen_squares[gz] )[gx][gy] == 0 ) { + passed = false; + } else if( O == expected.get_global( gx, gy, gz ) && + ( *seen_squares[gz] )[gx][gy] > 0 ) { + passed = false; + } } + trans_grid << '\n'; + expected_grid << '\n'; + actual_grid << '\n'; } + trans_grid << '\n'; + expected_grid << '\n'; + actual_grid << '\n'; + delete caches[gz]; } + CAPTURE( fov_3d ); + INFO( "transparency:\n" << trans_grid.str() ); + INFO( "actual:\n" << actual_grid.str() ); + INFO( "expected:\n" << expected_grid.str() ); + CHECK( passed ); } TEST_CASE( "shadowcasting_slope_inversion_regression_test", "[shadowcasting]" ) { grid_overlay test_case( { 7, 8 }, LIGHT_TRANSPARENCY_CLEAR ); - test_case.data = { - {T, T, T, T, T, T, T, T, T, T}, - {T, O, T, T, T, T, T, T, T, T}, - {T, O, T, T, T, T, T, T, T, T}, - {T, O, O, T, O, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, O, T}, - {T, T, T, T, T, T, O, T, O, T}, - {T, T, T, T, T, T, O, O, O, T}, - {T, T, T, T, T, T, T, T, T, T} + test_case.data = { { + {T, T, T, T, T, T, T, T, T, T}, + {T, O, T, T, T, T, T, T, T, T}, + {T, O, T, T, T, T, T, T, T, T}, + {T, O, O, T, O, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, O, T}, + {T, T, T, T, T, T, O, T, O, T}, + {T, T, T, T, T, T, O, O, O, T}, + {T, T, T, T, T, T, T, T, T, T} + } }; grid_overlay expected_results( { 7, 8 }, LIGHT_TRANSPARENCY_CLEAR ); - expected_results.data = { - {O, O, O, V, V, V, V, V, V, V}, - {O, V, V, O, V, V, V, V, V, V}, - {O, O, V, V, V, V, V, V, V, V}, - {O, O, V, V, V, V, V, V, V, V}, - {O, O, V, V, V, V, V, V, V, V}, - {O, O, O, V, V, V, V, V, V, O}, - {O, O, O, O, V, V, V, V, V, O}, - {O, O, O, O, O, V, V, V, V, O}, - {O, O, O, O, O, O, V, X, V, O}, - {O, O, O, O, O, O, V, V, V, O}, - {O, O, O, O, O, O, O, O, O, O} + expected_results.data = { { + {O, O, O, V, V, V, V, V, V, V}, + {O, V, V, O, V, V, V, V, V, V}, + {O, O, V, V, V, V, V, V, V, V}, + {O, O, V, V, V, V, V, V, V, V}, + {O, O, V, V, V, V, V, V, V, V}, + {O, O, O, V, V, V, V, V, V, O}, + {O, O, O, O, V, V, V, V, V, O}, + {O, O, O, O, O, V, V, V, V, O}, + {O, O, O, O, O, O, V, X, V, O}, + {O, O, O, O, O, O, V, V, V, O}, + {O, O, O, O, O, O, O, O, O, O} + } }; - run_spot_check( test_case, expected_results ); + run_spot_check( test_case, expected_results, true ); + run_spot_check( test_case, expected_results, false ); } TEST_CASE( "shadowcasting_pillar_behavior_cardinally_adjacent", "[shadowcasting]" ) { grid_overlay test_case( { 1, 4 }, LIGHT_TRANSPARENCY_CLEAR ); - test_case.data = { - {T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T}, - {T, T, O, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T} + test_case.data = { { + {T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T}, + {T, T, O, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T} + } }; grid_overlay expected_results( { 1, 4 }, LIGHT_TRANSPARENCY_CLEAR ); - expected_results.data = { - {V, V, V, V, V, V, V, O, O}, - {V, V, V, V, V, V, O, O, O}, - {V, V, V, V, V, O, O, O, O}, - {V, V, V, V, O, O, O, O, O}, - {V, X, V, O, O, O, O, O, O}, - {V, V, V, V, O, O, O, O, O}, - {V, V, V, V, V, O, O, O, O}, - {V, V, V, V, V, V, O, O, O}, - {V, V, V, V, V, V, V, O, O} + expected_results.data = { { + {V, V, V, V, V, V, V, O, O}, + {V, V, V, V, V, V, O, O, O}, + {V, V, V, V, V, O, O, O, O}, + {V, V, V, V, O, O, O, O, O}, + {V, X, V, O, O, O, O, O, O}, + {V, V, V, V, O, O, O, O, O}, + {V, V, V, V, V, O, O, O, O}, + {V, V, V, V, V, V, O, O, O}, + {V, V, V, V, V, V, V, O, O} + } }; - run_spot_check( test_case, expected_results ); + run_spot_check( test_case, expected_results, true ); + run_spot_check( test_case, expected_results, false ); } TEST_CASE( "shadowcasting_pillar_behavior_2_1_diagonal_gap", "[shadowcasting]" ) { grid_overlay test_case( { 1, 1 }, LIGHT_TRANSPARENCY_CLEAR ); - test_case.data = { - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, O, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T} + test_case.data = { { + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, O, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T} + } }; grid_overlay expected_results( { 1, 1 }, LIGHT_TRANSPARENCY_CLEAR ); - expected_results.data = { - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, X, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, O, O, O, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, O, O, O, O, O, O, O, V, V, V, V, V}, - {V, V, V, V, V, V, V, O, O, O, O, O, O, O, O, O, O, O}, - {V, V, V, V, V, V, V, V, O, O, O, O, O, O, O, O, O, O}, - {V, V, V, V, V, V, V, V, V, O, O, O, O, O, O, O, O, O}, - {V, V, V, V, V, V, V, V, V, V, O, O, O, O, O, O, O, O}, + expected_results.data = { { + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, X, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, O, O, O, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, O, O, O, O, O, O, O, V, V, V, V, V}, + {V, V, V, V, V, V, V, O, O, O, O, O, O, O, O, O, O, O}, + {V, V, V, V, V, V, V, V, O, O, O, O, O, O, O, O, O, O}, + {V, V, V, V, V, V, V, V, V, O, O, O, O, O, O, O, O, O}, + {V, V, V, V, V, V, V, V, V, V, O, O, O, O, O, O, O, O}, + } }; - run_spot_check( test_case, expected_results ); + run_spot_check( test_case, expected_results, true ); + run_spot_check( test_case, expected_results, false ); } TEST_CASE( "shadowcasting_vision_along_a_wall", "[shadowcasting]" ) { grid_overlay test_case( { 8, 2 }, LIGHT_TRANSPARENCY_CLEAR ); - test_case.data = { - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, - {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T} + test_case.data = { { + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T} + } }; grid_overlay expected_results( { 8, 2 }, LIGHT_TRANSPARENCY_CLEAR ); - expected_results.data = { - {O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, X, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, - {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V} + expected_results.data = { { + {O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, X, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V}, + {V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V} + } }; - run_spot_check( test_case, expected_results ); + run_spot_check( test_case, expected_results, true ); + run_spot_check( test_case, expected_results, false ); } // Some random edge cases aren't matching. From fae5f4bd26afd639d31394ee9cf874e114f9c062 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Sun, 26 May 2019 18:14:33 +0000 Subject: [PATCH 2/7] Add some 3D tests. --- tests/shadowcasting_test.cpp | 150 +++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/tests/shadowcasting_test.cpp b/tests/shadowcasting_test.cpp index 2bb2e3a0f8ed2..3fa934ada9cef 100644 --- a/tests/shadowcasting_test.cpp +++ b/tests/shadowcasting_test.cpp @@ -411,8 +411,10 @@ const tripoint ORIGIN( 65, 65, 11 ); struct grid_overlay { std::vector>> data; + std::vector>> floor; tripoint offset; float default_value; + bool default_floor = true; // origin_offset is specified as the coordinates of the "camera" within the overlay. grid_overlay( const point &origin_offset, const float default_value ) { @@ -451,6 +453,15 @@ struct grid_overlay { } return default_value; } + bool get_floor( const int x, const int y, const int z ) const { + if( !floor.empty() && + y >= offset.y && y < offset.y + height() && + x >= offset.x && x < offset.x + width() && + z >= offset.z && z < offset.z + depth() ) { + return data[ z - offset.z ][ y - offset.y ][ x - offset.x ]; + } + return default_floor; + } }; static void run_spot_check( const grid_overlay &test_case, const grid_overlay &expected, @@ -475,6 +486,7 @@ static void run_spot_check( const grid_overlay &test_case, const grid_overlay &e for( int y = 0; y < MAPSIZE * SEEY; ++y ) { for( int x = 0; x < MAPSIZE * SEEX; ++x ) { caches[z]->transparency_cache[x][y] = test_case.get_global( x, y, z ); + caches[z]->floor_cache[x][y] = test_case.get_floor( x, y, z ); } } } @@ -659,6 +671,144 @@ TEST_CASE( "shadowcasting_vision_along_a_wall", "[shadowcasting]" ) run_spot_check( test_case, expected_results, false ); } +TEST_CASE( "shadowcasting_edgewise_wall_view", "[shadowcasting]" ) +{ + grid_overlay test_case( { 1, 2 }, LIGHT_TRANSPARENCY_CLEAR ); + test_case.data = { { + {T, T, O, T, T, T, T}, + {T, T, O, T, T, T, T}, + {T, T, O, O, O, T, T}, + {T, T, T, T, T, T, T}, + {T, T, T, T, T, T, T} + } + }; + + grid_overlay expected_results( { 1, 2 }, LIGHT_TRANSPARENCY_CLEAR ); + expected_results.data = { { + {V, V, V, O, O, O, O}, + {V, V, V, O, O, O, O}, + {V, X, V, O, O, O, O}, + {V, V, V, V, O, O, O}, + {V, V, V, V, V, O, O}, + {V, V, V, V, V, V, O} + } + }; + + run_spot_check( test_case, expected_results, true ); + run_spot_check( test_case, expected_results, false ); +} + +TEST_CASE( "shadowcasting_opaque_floors", "[shadowcasting]" ) +{ + grid_overlay test_case( { 2, 2, 1 }, LIGHT_TRANSPARENCY_CLEAR ); + test_case.data = { + { + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T} + }, + { + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T} + }, + { + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T} + } + }; + + grid_overlay expected_results( { 2, 2, 1 }, LIGHT_TRANSPARENCY_CLEAR ); + expected_results.data = { + { + {O, O, O, O, O}, + {O, O, O, O, O}, + {O, O, O, O, O}, + {O, O, O, O, O}, + {O, O, O, O, O} + }, + { + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, X, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V} + }, + { + {O, O, O, O, O}, + {O, O, O, O, O}, + {O, O, O, O, O}, + {O, O, O, O, O}, + {O, O, O, O, O} + } + }; + + run_spot_check( test_case, expected_results, true ); +} + +TEST_CASE( "shadowcasting_transparent_floors", "[shadowcasting]" ) +{ + grid_overlay test_case( { 2, 2, 1 }, LIGHT_TRANSPARENCY_CLEAR ); + test_case.data = { + { + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T} + }, + { + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T} + }, + { + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T}, + {T, T, T, T, T} + } + }; + test_case.default_floor = false; + + grid_overlay expected_results( { 2, 2, 1 }, LIGHT_TRANSPARENCY_CLEAR ); + expected_results.data = { + { + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V} + }, + { + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, X, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V} + }, + { + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V}, + {V, V, V, V, V} + } + }; + + run_spot_check( test_case, expected_results, true ); +} + // Some random edge cases aren't matching. TEST_CASE( "shadowcasting_runoff", "[.]" ) { From 5a1aa0cdfef65839eb6650b253548ddf94316dad Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Wed, 29 May 2019 01:40:26 +0000 Subject: [PATCH 3/7] Extract cast_zlight to a dedicated code module --- src/lightmap.cpp | 277 ---------------------------------------- src/shadowcasting.cpp | 284 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+), 277 deletions(-) create mode 100644 src/shadowcasting.cpp diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 35ccde7e71676..949628374be77 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -733,283 +733,6 @@ static constexpr quadrant quadrant_from_x_y( int x, int y ) ( ( y > 0 ) ? quadrant::NE : quadrant::SE ); } -// Add defaults for when method is invoked for the first time. -template -void cast_zlight_segment( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint &offset, const int offset_distance, - const T numerator = 1.0f, const int row = 1, - float start_major = 0.0f, const float end_major = 1.0f, - float start_minor = 0.0f, const float end_minor = 1.0f, - T cumulative_transparency = LIGHT_TRANSPARENCY_OPEN_AIR ); - -template -void cast_zlight_segment( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint &offset, const int offset_distance, - const T numerator, const int row, - float start_major, const float end_major, - float start_minor, const float end_minor, - T cumulative_transparency ) -{ - if( start_major >= end_major || start_minor >= end_minor ) { - return; - } - - float radius = 60.0f - offset_distance; - - constexpr int min_z = -OVERMAP_DEPTH; - constexpr int max_z = OVERMAP_HEIGHT; - - float new_start_minor = 1.0f; - - T last_intensity = 0.0; - static constexpr tripoint origin( 0, 0, 0 ); - tripoint delta( 0, 0, 0 ); - tripoint current( 0, 0, 0 ); - for( int distance = row; distance <= radius; distance++ ) { - delta.y = distance; - bool started_block = false; - T current_transparency = 0.0f; - - // TODO: Precalculate min/max delta.z based on start/end and distance - for( delta.z = 0; delta.z <= distance; delta.z++ ) { - float trailing_edge_major = ( delta.z - 0.5f ) / ( delta.y + 0.5f ); - float leading_edge_major = ( delta.z + 0.5f ) / ( delta.y - 0.5f ); - current.z = offset.z + delta.x * 00 + delta.y * 00 + delta.z * zz; - if( current.z > max_z || current.z < min_z ) { - continue; - } else if( start_major > leading_edge_major ) { - continue; - } else if( end_major < trailing_edge_major ) { - break; - } - - bool started_span = false; - const int z_index = current.z + OVERMAP_DEPTH; - for( delta.x = 0; delta.x <= distance; delta.x++ ) { - current.x = offset.x + delta.x * xx + delta.y * xy + delta.z * xz; - current.y = offset.y + delta.x * yx + delta.y * yy + delta.z * yz; - float trailing_edge_minor = ( delta.x - 0.5f ) / ( delta.y + 0.5f ); - float leading_edge_minor = ( delta.x + 0.5f ) / ( delta.y - 0.5f ); - - if( !( current.x >= 0 && current.y >= 0 && - current.x < MAPSIZE_X && - current.y < MAPSIZE_Y ) || start_minor > leading_edge_minor ) { - continue; - } else if( end_minor < trailing_edge_minor ) { - break; - } - - T new_transparency = ( *input_arrays[z_index] )[current.x][current.y]; - // If we're looking at a tile with floor or roof from the floor/roof side, - // that tile is actually invisible to us. - bool floor_block = false; - if( current.z < offset.z ) { - if( z_index < ( OVERMAP_LAYERS - 1 ) && - ( *floor_caches[z_index + 1] )[current.x][current.y] ) { - floor_block = true; - new_transparency = LIGHT_TRANSPARENCY_SOLID; - } - } else if( current.z > offset.z ) { - if( ( *floor_caches[z_index] )[current.x][current.y] ) { - floor_block = true; - new_transparency = LIGHT_TRANSPARENCY_SOLID; - } - } - - if( !started_block ) { - started_block = true; - current_transparency = new_transparency; - } - - const int dist = rl_dist( origin, delta ) + offset_distance; - last_intensity = calc( numerator, cumulative_transparency, dist ); - - if( !floor_block ) { - ( *output_caches[z_index] )[current.x][current.y] = - std::max( ( *output_caches[z_index] )[current.x][current.y], last_intensity ); - } - - if( !started_span ) { - // Need to reset minor slope, because we're starting a new line - new_start_minor = leading_edge_minor; - // Need more precision or artifacts happen - leading_edge_minor = start_minor; - started_span = true; - } - - if( new_transparency == current_transparency ) { - // All in order, no need to recurse - new_start_minor = leading_edge_minor; - continue; - } - - // We split the block into 4 sub-blocks (sub-frustums actually, this is the view from the origin looking out): - // +-------+ <- end major - // | D | - // +---+---+ <- ??? - // | B | C | - // +---+---+ <- major mid - // | A | - // +-------+ <- start major - // ^ ^ - // | end minor - // start minor - // A is previously processed row(s). - // B is already-processed tiles from current row. - // C is remainder of current row. - // D is not yet processed row(s). - // One we processed fully in 2D and only need to extend in last D - // Only cast recursively horizontally if previous span was not opaque. - if( check( current_transparency, last_intensity ) ) { - T next_cumulative_transparency = accumulate( cumulative_transparency, current_transparency, - distance ); - // Blocks can be merged if they are actually a single rectangle - // rather than rectangle + line shorter than rectangle's width - const bool merge_blocks = end_minor <= trailing_edge_minor; - // trailing_edge_major can be less than start_major - const float trailing_clipped = std::max( trailing_edge_major, start_major ); - const float major_mid = merge_blocks ? leading_edge_major : trailing_clipped; - cast_zlight_segment( - output_caches, input_arrays, floor_caches, - offset, offset_distance, numerator, distance + 1, - start_major, major_mid, start_minor, end_minor, - next_cumulative_transparency ); - if( !merge_blocks ) { - // One line that is too short to be part of the rectangle above - cast_zlight_segment( - output_caches, input_arrays, floor_caches, - offset, offset_distance, numerator, distance + 1, - major_mid, leading_edge_major, start_minor, trailing_edge_minor, - next_cumulative_transparency ); - } - } - - // One from which we shaved one line ("processed in 1D") - const float old_start_minor = start_minor; - // The new span starts at the leading edge of the previous square if it is opaque, - // and at the trailing edge of the current square if it is transparent. - if( !check( current_transparency, last_intensity ) ) { - start_minor = new_start_minor; - } else { - // Note this is the same slope as one of the recursive calls we just made. - start_minor = std::max( start_minor, trailing_edge_minor ); - start_major = std::max( start_major, trailing_edge_major ); - } - - // leading_edge_major plus some epsilon - float after_leading_edge_major = ( delta.z + 0.50001f ) / ( delta.y - 0.5f ); - cast_zlight_segment( - output_caches, input_arrays, floor_caches, - offset, offset_distance, numerator, distance, - after_leading_edge_major, end_major, old_start_minor, start_minor, - cumulative_transparency ); - - // One we just entered ("processed in 0D" - the first point) - // No need to recurse, we're processing it right now - - current_transparency = new_transparency; - new_start_minor = leading_edge_minor; - } - - if( !check( current_transparency, last_intensity ) ) { - start_major = leading_edge_major; - } - } - - if( !started_block ) { - // If we didn't scan at least 1 z-level, don't iterate further - // Otherwise we may "phase" through tiles without checking them - break; - } - - if( !check( current_transparency, last_intensity ) ) { - // If we reach the end of the span with terrain being opaque, we don't iterate further. - break; - } - // Cumulative average of the values encountered. - cumulative_transparency = accumulate( cumulative_transparency, current_transparency, distance ); - } -} - -template -void cast_zlight( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint &origin, const int offset_distance, const T numerator ) -{ - // Down - cast_zlight_segment < 0, 1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, 1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - // Up - cast_zlight_segment<0, 1, 0, 1, 0, 0, 1, T, calc, check, accumulate>( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment<1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate>( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, 1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, 1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); -} - -// I can't figure out how to make implicit instantiation work when the parameters of -// the template-supplied function pointers are involved, so I'm explicitly instantiating instead. -template void cast_zlight( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint &origin, const int offset_distance, const float numerator ); - -template void cast_zlight( - const std::array &output_caches, - const std::array - &input_arrays, - const std::array &floor_caches, - const tripoint &origin, const int offset_distance, const fragment_cloud numerator ); - template + +#include "enums.h" +#include "fragment_cloud.h" // IWYU pragma: keep +#include "line.h" + +// Add defaults for when method is invoked for the first time. +template +void cast_zlight_segment( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint &offset, const int offset_distance, + const T numerator = 1.0f, const int row = 1, + float start_major = 0.0f, const float end_major = 1.0f, + float start_minor = 0.0f, const float end_minor = 1.0f, + T cumulative_transparency = LIGHT_TRANSPARENCY_OPEN_AIR ); + +template +void cast_zlight_segment( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint &offset, const int offset_distance, + const T numerator, const int row, + float start_major, const float end_major, + float start_minor, const float end_minor, + T cumulative_transparency ) +{ + if( start_major >= end_major || start_minor >= end_minor ) { + return; + } + + float radius = 60.0f - offset_distance; + + constexpr int min_z = -OVERMAP_DEPTH; + constexpr int max_z = OVERMAP_HEIGHT; + + float new_start_minor = 1.0f; + + T last_intensity = 0.0; + static constexpr tripoint origin( 0, 0, 0 ); + tripoint delta( 0, 0, 0 ); + tripoint current( 0, 0, 0 ); + for( int distance = row; distance <= radius; distance++ ) { + delta.y = distance; + bool started_block = false; + T current_transparency = 0.0f; + + // TODO: Precalculate min/max delta.z based on start/end and distance + for( delta.z = 0; delta.z <= distance; delta.z++ ) { + float trailing_edge_major = ( delta.z - 0.5f ) / ( delta.y + 0.5f ); + float leading_edge_major = ( delta.z + 0.5f ) / ( delta.y - 0.5f ); + current.z = offset.z + delta.x * 00 + delta.y * 00 + delta.z * zz; + if( current.z > max_z || current.z < min_z ) { + continue; + } else if( start_major > leading_edge_major ) { + continue; + } else if( end_major < trailing_edge_major ) { + break; + } + + bool started_span = false; + const int z_index = current.z + OVERMAP_DEPTH; + for( delta.x = 0; delta.x <= distance; delta.x++ ) { + current.x = offset.x + delta.x * xx + delta.y * xy + delta.z * xz; + current.y = offset.y + delta.x * yx + delta.y * yy + delta.z * yz; + float trailing_edge_minor = ( delta.x - 0.5f ) / ( delta.y + 0.5f ); + float leading_edge_minor = ( delta.x + 0.5f ) / ( delta.y - 0.5f ); + + if( !( current.x >= 0 && current.y >= 0 && + current.x < MAPSIZE_X && + current.y < MAPSIZE_Y ) || start_minor > leading_edge_minor ) { + continue; + } else if( end_minor < trailing_edge_minor ) { + break; + } + + T new_transparency = ( *input_arrays[z_index] )[current.x][current.y]; + // If we're looking at a tile with floor or roof from the floor/roof side, + // that tile is actually invisible to us. + bool floor_block = false; + if( current.z < offset.z ) { + if( z_index < ( OVERMAP_LAYERS - 1 ) && + ( *floor_caches[z_index + 1] )[current.x][current.y] ) { + floor_block = true; + new_transparency = LIGHT_TRANSPARENCY_SOLID; + } + } else if( current.z > offset.z ) { + if( ( *floor_caches[z_index] )[current.x][current.y] ) { + floor_block = true; + new_transparency = LIGHT_TRANSPARENCY_SOLID; + } + } + + if( !started_block ) { + started_block = true; + current_transparency = new_transparency; + } + + const int dist = rl_dist( origin, delta ) + offset_distance; + last_intensity = calc( numerator, cumulative_transparency, dist ); + + if( !floor_block ) { + ( *output_caches[z_index] )[current.x][current.y] = + std::max( ( *output_caches[z_index] )[current.x][current.y], last_intensity ); + } + + if( !started_span ) { + // Need to reset minor slope, because we're starting a new line + new_start_minor = leading_edge_minor; + // Need more precision or artifacts happen + leading_edge_minor = start_minor; + started_span = true; + } + + if( new_transparency == current_transparency ) { + // All in order, no need to recurse + new_start_minor = leading_edge_minor; + continue; + } + + // We split the block into 4 sub-blocks (sub-frustums actually, this is the view from the origin looking out): + // +-------+ <- end major + // | D | + // +---+---+ <- ??? + // | B | C | + // +---+---+ <- major mid + // | A | + // +-------+ <- start major + // ^ ^ + // | end minor + // start minor + // A is previously processed row(s). + // B is already-processed tiles from current row. + // C is remainder of current row. + // D is not yet processed row(s). + // One we processed fully in 2D and only need to extend in last D + // Only cast recursively horizontally if previous span was not opaque. + if( check( current_transparency, last_intensity ) ) { + T next_cumulative_transparency = accumulate( cumulative_transparency, current_transparency, + distance ); + // Blocks can be merged if they are actually a single rectangle + // rather than rectangle + line shorter than rectangle's width + const bool merge_blocks = end_minor <= trailing_edge_minor; + // trailing_edge_major can be less than start_major + const float trailing_clipped = std::max( trailing_edge_major, start_major ); + const float major_mid = merge_blocks ? leading_edge_major : trailing_clipped; + cast_zlight_segment( + output_caches, input_arrays, floor_caches, + offset, offset_distance, numerator, distance + 1, + start_major, major_mid, start_minor, end_minor, + next_cumulative_transparency ); + if( !merge_blocks ) { + // One line that is too short to be part of the rectangle above + cast_zlight_segment( + output_caches, input_arrays, floor_caches, + offset, offset_distance, numerator, distance + 1, + major_mid, leading_edge_major, start_minor, trailing_edge_minor, + next_cumulative_transparency ); + } + } + + // One from which we shaved one line ("processed in 1D") + const float old_start_minor = start_minor; + // The new span starts at the leading edge of the previous square if it is opaque, + // and at the trailing edge of the current square if it is transparent. + if( !check( current_transparency, last_intensity ) ) { + start_minor = new_start_minor; + } else { + // Note this is the same slope as one of the recursive calls we just made. + start_minor = std::max( start_minor, trailing_edge_minor ); + start_major = std::max( start_major, trailing_edge_major ); + } + + // leading_edge_major plus some epsilon + float after_leading_edge_major = ( delta.z + 0.50001f ) / ( delta.y - 0.5f ); + cast_zlight_segment( + output_caches, input_arrays, floor_caches, + offset, offset_distance, numerator, distance, + after_leading_edge_major, end_major, old_start_minor, start_minor, + cumulative_transparency ); + + // One we just entered ("processed in 0D" - the first point) + // No need to recurse, we're processing it right now + + current_transparency = new_transparency; + new_start_minor = leading_edge_minor; + } + + if( !check( current_transparency, last_intensity ) ) { + start_major = leading_edge_major; + } + } + + if( !started_block ) { + // If we didn't scan at least 1 z-level, don't iterate further + // Otherwise we may "phase" through tiles without checking them + break; + } + + if( !check( current_transparency, last_intensity ) ) { + // If we reach the end of the span with terrain being opaque, we don't iterate further. + break; + } + // Cumulative average of the values encountered. + cumulative_transparency = accumulate( cumulative_transparency, current_transparency, distance ); + } +} + +template +void cast_zlight( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint &origin, const int offset_distance, const T numerator ) +{ + // Down + cast_zlight_segment < 0, 1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, 1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + // Up + cast_zlight_segment<0, 1, 0, 1, 0, 0, 1, T, calc, check, accumulate>( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment<1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate>( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, 1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, 1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); +} + +// I can't figure out how to make implicit instantiation work when the parameters of +// the template-supplied function pointers are involved, so I'm explicitly instantiating instead. +template void cast_zlight( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint &origin, const int offset_distance, const float numerator ); + +template void cast_zlight( + const std::array &output_caches, + const std::array + &input_arrays, + const std::array &floor_caches, + const tripoint &origin, const int offset_distance, const fragment_cloud numerator ); From f3ccc4dc0f8fe48b85b4c94f151001c742cba96b Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Sun, 2 Jun 2019 17:42:02 +0000 Subject: [PATCH 4/7] WIP de-recursify shadowcasting --- src/shadowcasting.cpp | 461 +++++++++++++++++++++++------------------- 1 file changed, 248 insertions(+), 213 deletions(-) diff --git a/src/shadowcasting.cpp b/src/shadowcasting.cpp index 256b3f178dbc0..00d0e0a4389ce 100644 --- a/src/shadowcasting.cpp +++ b/src/shadowcasting.cpp @@ -1,11 +1,21 @@ #include "shadowcasting.h" -#include +#include #include "enums.h" #include "fragment_cloud.h" // IWYU pragma: keep #include "line.h" +template +struct span { + // TODO: Make these fixed-point or byte/byte pairs + float start_major; + float end_major; + float start_minor; + float end_minor; + T cumulative_value; +}; + // Add defaults for when method is invoked for the first time. template &input_arrays, const std::array &floor_caches, const tripoint &offset, const int offset_distance, - const T numerator = 1.0f, const int row = 1, - float start_major = 0.0f, const float end_major = 1.0f, - float start_minor = 0.0f, const float end_minor = 1.0f, - T cumulative_transparency = LIGHT_TRANSPARENCY_OPEN_AIR ); + const T numerator = 1.0f ); template &input_arrays, const std::array &floor_caches, const tripoint &offset, const int offset_distance, - const T numerator, const int row, + const T numerator ) +/* old recursion args float start_major, const float end_major, float start_minor, const float end_minor, T cumulative_transparency ) +*/ { - if( start_major >= end_major || start_minor >= end_minor ) { - return; - } - - float radius = 60.0f - offset_distance; + const float radius = 60.0f - offset_distance; constexpr int min_z = -OVERMAP_DEPTH; constexpr int max_z = OVERMAP_HEIGHT; @@ -50,235 +55,265 @@ void cast_zlight_segment( static constexpr tripoint origin( 0, 0, 0 ); tripoint delta( 0, 0, 0 ); tripoint current( 0, 0, 0 ); - for( int distance = row; distance <= radius; distance++ ) { + // TODO: More optimal data structure. + // We start out with one span covering the entire horizontal and vertical space + // we are interested in. Then as changes in transparency are encountered, we truncate + // that initial span and insert new spans after it in the list. + std::list spans = { { 0.0, 1.0, 0.0, 1.0, LIGHT_TRANSPARENCY_OPEN_AIR } }; + // At each "depth", a.k.a. distance from the origin, we iterate once over the list of spans, + // possibly splitting them. + for( int distance = 1; distance <= radius; distance++ ) { delta.y = distance; bool started_block = false; T current_transparency = 0.0f; - // TODO: Precalculate min/max delta.z based on start/end and distance - for( delta.z = 0; delta.z <= distance; delta.z++ ) { - float trailing_edge_major = ( delta.z - 0.5f ) / ( delta.y + 0.5f ); - float leading_edge_major = ( delta.z + 0.5f ) / ( delta.y - 0.5f ); - current.z = offset.z + delta.x * 00 + delta.y * 00 + delta.z * zz; - if( current.z > max_z || current.z < min_z ) { - continue; - } else if( start_major > leading_edge_major ) { - continue; - } else if( end_major < trailing_edge_major ) { - break; - } - - bool started_span = false; - const int z_index = current.z + OVERMAP_DEPTH; - for( delta.x = 0; delta.x <= distance; delta.x++ ) { - current.x = offset.x + delta.x * xx + delta.y * xy + delta.z * xz; - current.y = offset.y + delta.x * yx + delta.y * yy + delta.z * yz; - float trailing_edge_minor = ( delta.x - 0.5f ) / ( delta.y + 0.5f ); - float leading_edge_minor = ( delta.x + 0.5f ) / ( delta.y - 0.5f ); - - if( !( current.x >= 0 && current.y >= 0 && - current.x < MAPSIZE_X && - current.y < MAPSIZE_Y ) || start_minor > leading_edge_minor ) { + for( auto it = spans.begin(); it != spans.end(); ++it ) { + span &this_span = *it; + // TODO: Precalculate min/max delta.z based on start/end and distance + for( delta.z = 0; delta.z <= distance; delta.z++ ) { + float trailing_edge_major = ( delta.z - 0.5f ) / ( delta.y + 0.5f ); + float leading_edge_major = ( delta.z + 0.5f ) / ( delta.y - 0.5f ); + current.z = offset.z + delta.x * 00 + delta.y * 00 + delta.z * zz; + if( current.z > max_z || current.z < min_z ) { + continue; + } else if( this_span.start_major > leading_edge_major ) { + // Current span has a higher z-value, + // jump to next iteration to catch up. continue; - } else if( end_minor < trailing_edge_minor ) { + } else if( this_span.end_major < trailing_edge_major ) { + // We've escaped the bounds of the current span we're considering, + // So continue to the next span. break; } - T new_transparency = ( *input_arrays[z_index] )[current.x][current.y]; - // If we're looking at a tile with floor or roof from the floor/roof side, - // that tile is actually invisible to us. - bool floor_block = false; - if( current.z < offset.z ) { - if( z_index < ( OVERMAP_LAYERS - 1 ) && - ( *floor_caches[z_index + 1] )[current.x][current.y] ) { - floor_block = true; - new_transparency = LIGHT_TRANSPARENCY_SOLID; + bool started_span = false; + const int z_index = current.z + OVERMAP_DEPTH; + for( delta.x = 0; delta.x <= distance; delta.x++ ) { + current.x = offset.x + delta.x * xx + delta.y * xy + delta.z * xz; + current.y = offset.y + delta.x * yx + delta.y * yy + delta.z * yz; + // Shadowcasting sweeps from the most extreme edge of the octant to the cardinal + // XXXX + // <--- + // XXX + // <-- + // XX + // <- + // X + // @ + // + // Leading edge -> +- + // |+| <- Center of tile + // -+ <- Trailing edge + // <------ Direction of sweep + // Use corners of given tile as above to determine angles of + // leading and trailing edges being considered. + float trailing_edge_minor = ( delta.x - 0.5f ) / ( delta.y + 0.5f ); + float leading_edge_minor = ( delta.x + 0.5f ) / ( delta.y - 0.5f ); + + if( !( current.x >= 0 && current.y >= 0 && current.x < MAPSIZE_X && + current.y < MAPSIZE_Y ) || this_span.start_minor > leading_edge_minor ) { + // Current tile comes before span we're considering, advance to the next tile. + continue; + } else if( this_span.end_minor < trailing_edge_minor ) { + // Current tile is after the span we're considering, continue to next row. + break; } - } else if( current.z > offset.z ) { - if( ( *floor_caches[z_index] )[current.x][current.y] ) { - floor_block = true; - new_transparency = LIGHT_TRANSPARENCY_SOLID; + + T new_transparency = ( *input_arrays[z_index] )[current.x][current.y]; + // If we're looking at a tile with floor or roof from the floor/roof side, + // that tile is actually invisible to us. + bool floor_block = false; + if( current.z < offset.z ) { + if( z_index < ( OVERMAP_LAYERS - 1 ) && + ( *floor_caches[z_index + 1] )[current.x][current.y] ) { + floor_block = true; + new_transparency = LIGHT_TRANSPARENCY_SOLID; + } + } else if( current.z > offset.z ) { + if( ( *floor_caches[z_index] )[current.x][current.y] ) { + floor_block = true; + new_transparency = LIGHT_TRANSPARENCY_SOLID; + } } - } - if( !started_block ) { - started_block = true; - current_transparency = new_transparency; - } + if( !started_block ) { + started_block = true; + current_transparency = new_transparency; + } - const int dist = rl_dist( origin, delta ) + offset_distance; - last_intensity = calc( numerator, cumulative_transparency, dist ); + const int dist = rl_dist( origin, delta ) + offset_distance; + last_intensity = calc( numerator, this_span.cumulative_transparency, dist ); - if( !floor_block ) { - ( *output_caches[z_index] )[current.x][current.y] = - std::max( ( *output_caches[z_index] )[current.x][current.y], last_intensity ); - } + if( !floor_block ) { + ( *output_caches[z_index] )[current.x][current.y] = + std::max( ( *output_caches[z_index] )[current.x][current.y], last_intensity ); + } - if( !started_span ) { - // Need to reset minor slope, because we're starting a new line - new_start_minor = leading_edge_minor; - // Need more precision or artifacts happen - leading_edge_minor = start_minor; - started_span = true; - } + if( !started_span ) { + // Need to reset minor slope, because we're starting a new line + new_start_minor = leading_edge_minor; + // Need more precision or artifacts happen + leading_edge_minor = start_minor; + started_span = true; + } - if( new_transparency == current_transparency ) { - // All in order, no need to recurse - new_start_minor = leading_edge_minor; - continue; - } + if( new_transparency == current_transparency ) { + // All in order, no need to split the span. + new_start_minor = leading_edge_minor; + continue; + } - // We split the block into 4 sub-blocks (sub-frustums actually, this is the view from the origin looking out): - // +-------+ <- end major - // | D | - // +---+---+ <- ??? - // | B | C | - // +---+---+ <- major mid - // | A | - // +-------+ <- start major - // ^ ^ - // | end minor - // start minor - // A is previously processed row(s). - // B is already-processed tiles from current row. - // C is remainder of current row. - // D is not yet processed row(s). - // One we processed fully in 2D and only need to extend in last D - // Only cast recursively horizontally if previous span was not opaque. - if( check( current_transparency, last_intensity ) ) { - T next_cumulative_transparency = accumulate( cumulative_transparency, current_transparency, - distance ); - // Blocks can be merged if they are actually a single rectangle - // rather than rectangle + line shorter than rectangle's width - const bool merge_blocks = end_minor <= trailing_edge_minor; - // trailing_edge_major can be less than start_major - const float trailing_clipped = std::max( trailing_edge_major, start_major ); - const float major_mid = merge_blocks ? leading_edge_major : trailing_clipped; - cast_zlight_segment( - output_caches, input_arrays, floor_caches, - offset, offset_distance, numerator, distance + 1, - start_major, major_mid, start_minor, end_minor, - next_cumulative_transparency ); - if( !merge_blocks ) { - // One line that is too short to be part of the rectangle above - cast_zlight_segment( - output_caches, input_arrays, floor_caches, - offset, offset_distance, numerator, distance + 1, - major_mid, leading_edge_major, start_minor, trailing_edge_minor, - next_cumulative_transparency ); + T next_cumulative_transparency = accumulate( this_span.cumulative_transparency, + current_transparency, distance ); + // We split the span into up to 4 sub-blocks (sub-frustums actually, + // this is the view from the origin looking out): + // +-------+ <- end major + // | D | + // +---+---+ <- ??? + // | B | C | + // +---+---+ <- major mid + // | A | + // +-------+ <- start major + // ^ ^ + // | end minor + // start minor + // A is previously processed row(s). This might be empty. + // B is already-processed tiles from current row. This must exist. + // C is remainder of current row. This must exist. + // D is not yet processed row(s). Might be empty. + // A, B and D have the previous transparency, C has the new transparency, + // which might be opaque. + // One we processed fully in 2D and only need to extend in last D + // Only emit a new span horizontally if previous span was not opaque. + // If end_minor is <= trailing_edge_minor, A, B, C remain one span and + // D becomes a new span if present. + // If this is the first row processed in the current span, there is no A span. + // If this is the last row processed, there is no D span. + // If check returns false, A and B are opaque and have no spans. + if( check( current_transparency, last_intensity ) ) { + // Emit the A span if it's present. + if( trailing_edge_major > this_span.start_major ) { + // This is BCD + spans.emplace( std::next( it ), + trailing_edge_major, this_span.end_major, + this_span.start_minor, this_span.end_minor, + this_span.cumulative_transparency ); + // All we do to A is truncate it. + this_span.end_major = trailing_edge_major; + // Then make the current span the one we just inserted. + it++; + } + // One way or the other, the current span is now BCD. + // First handle B. + const float major_mid_end = std::min( this_span.end_major, end_major ); + spans.emplace( it, major_mid, major_mid_end, + this_span.start_minor, leading_edge_minor, + next_cumulative_transparency ); + // Overwrite new_start_minor since previous tile is transparent. + new_start_minor = trailing_edge_minor; } + // Current span is BCD, but B either doesn't exist or is handled. + // Split off D if it exists. + if( leading_edge_major < this_span.end_major ) { + spans.emplace( std::next( it ), + leading_edge_major, this_span.end_major, + this_span.start_minor, this_span.end_minor, + this_span.cumulative_transparency ); + } + // Truncate this_span to the current block. + this_span.end_major = std::min( this_span.end_major, leading_edge_major ); + this_span.start_major = std::max( this_span.start_major, trailing_edge_major ); + // The new span starts at the leading edge of the previous square if it is opaque, + // and at the trailing edge of the current square if it is transparent. + this_span.start_minor = new_start_minor; + this_span.cumulative_value = next_cumulative_transparency; + + new_start_minor = leading_edge_minor; + current_transparency = new_transparency; } - // One from which we shaved one line ("processed in 1D") - const float old_start_minor = start_minor; - // The new span starts at the leading edge of the previous square if it is opaque, - // and at the trailing edge of the current square if it is transparent. if( !check( current_transparency, last_intensity ) ) { - start_minor = new_start_minor; - } else { - // Note this is the same slope as one of the recursive calls we just made. - start_minor = std::max( start_minor, trailing_edge_minor ); - start_major = std::max( start_major, trailing_edge_major ); + start_major = leading_edge_major; } + } - // leading_edge_major plus some epsilon - float after_leading_edge_major = ( delta.z + 0.50001f ) / ( delta.y - 0.5f ); - cast_zlight_segment( - output_caches, input_arrays, floor_caches, - offset, offset_distance, numerator, distance, - after_leading_edge_major, end_major, old_start_minor, start_minor, - cumulative_transparency ); - - // One we just entered ("processed in 0D" - the first point) - // No need to recurse, we're processing it right now - - current_transparency = new_transparency; - new_start_minor = leading_edge_minor; + if( !started_block ) { + // If we didn't scan at least 1 z-level, don't iterate further + // Otherwise we may "phase" through tiles without checking them + break; } if( !check( current_transparency, last_intensity ) ) { - start_major = leading_edge_major; + // If we reach the end of the span with terrain being opaque, we don't iterate further. + break; } + // Cumulative average of the values encountered. + cumulative_transparency = accumulate( cumulative_transparency, current_transparency, distance ); } - - if( !started_block ) { - // If we didn't scan at least 1 z-level, don't iterate further - // Otherwise we may "phase" through tiles without checking them - break; - } - - if( !check( current_transparency, last_intensity ) ) { - // If we reach the end of the span with terrain being opaque, we don't iterate further. - break; - } - // Cumulative average of the values encountered. - cumulative_transparency = accumulate( cumulative_transparency, current_transparency, distance ); } -} -template -void cast_zlight( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint &origin, const int offset_distance, const T numerator ) -{ - // Down - cast_zlight_segment < 0, 1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, 1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - // Up - cast_zlight_segment<0, 1, 0, 1, 0, 0, 1, T, calc, check, accumulate>( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment<1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate>( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, 1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, 1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); -} - -// I can't figure out how to make implicit instantiation work when the parameters of -// the template-supplied function pointers are involved, so I'm explicitly instantiating instead. -template void cast_zlight( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint &origin, const int offset_distance, const float numerator ); + template + void cast_zlight( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint & origin, const int offset_distance, const T numerator ) { + // Down + cast_zlight_segment < 0, 1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, 1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + // Up + cast_zlight_segment<0, 1, 0, 1, 0, 0, 1, T, calc, check, accumulate>( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment<1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate>( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, 1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, 1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + } -template void cast_zlight( - const std::array &output_caches, - const std::array - &input_arrays, - const std::array &floor_caches, - const tripoint &origin, const int offset_distance, const fragment_cloud numerator ); + // I can't figure out how to make implicit instantiation work when the parameters of + // the template-supplied function pointers are involved, so I'm explicitly instantiating instead. + template void cast_zlight( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint & origin, const int offset_distance, const float numerator ); + + template void cast_zlight( + const std::array &output_caches, + const std::array + &input_arrays, + const std::array &floor_caches, + const tripoint & origin, const int offset_distance, const fragment_cloud numerator ); From 428bf93e0413e3c0d4b6a52d51405a19fd986271 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Thu, 6 Jun 2019 12:52:18 -0700 Subject: [PATCH 5/7] Bugfixes --- src/shadowcasting.cpp | 180 +++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/src/shadowcasting.cpp b/src/shadowcasting.cpp index 00d0e0a4389ce..7104bab866b71 100644 --- a/src/shadowcasting.cpp +++ b/src/shadowcasting.cpp @@ -38,11 +38,6 @@ void cast_zlight_segment( const std::array &floor_caches, const tripoint &offset, const int offset_distance, const T numerator ) -/* old recursion args - float start_major, const float end_major, - float start_minor, const float end_minor, - T cumulative_transparency ) -*/ { const float radius = 60.0f - offset_distance; @@ -59,7 +54,7 @@ void cast_zlight_segment( // We start out with one span covering the entire horizontal and vertical space // we are interested in. Then as changes in transparency are encountered, we truncate // that initial span and insert new spans after it in the list. - std::list spans = { { 0.0, 1.0, 0.0, 1.0, LIGHT_TRANSPARENCY_OPEN_AIR } }; + std::list> spans = { { 0.0, 1.0, 0.0, 1.0, LIGHT_TRANSPARENCY_OPEN_AIR } }; // At each "depth", a.k.a. distance from the origin, we iterate once over the list of spans, // possibly splitting them. for( int distance = 1; distance <= radius; distance++ ) { @@ -68,7 +63,7 @@ void cast_zlight_segment( T current_transparency = 0.0f; for( auto it = spans.begin(); it != spans.end(); ++it ) { - span &this_span = *it; + span &this_span = *it; // TODO: Precalculate min/max delta.z based on start/end and distance for( delta.z = 0; delta.z <= distance; delta.z++ ) { float trailing_edge_major = ( delta.z - 0.5f ) / ( delta.y + 0.5f ); @@ -153,7 +148,7 @@ void cast_zlight_segment( // Need to reset minor slope, because we're starting a new line new_start_minor = leading_edge_minor; // Need more precision or artifacts happen - leading_edge_minor = start_minor; + leading_edge_minor = this_span.start_minor; started_span = true; } @@ -205,35 +200,38 @@ void cast_zlight_segment( } // One way or the other, the current span is now BCD. // First handle B. - const float major_mid_end = std::min( this_span.end_major, end_major ); + const float major_mid = std::max( this_span.start_major, + trailing_edge_major ); + const float major_mid_end = std::min( this_span.end_major, + leading_edge_major ); spans.emplace( it, major_mid, major_mid_end, this_span.start_minor, leading_edge_minor, next_cumulative_transparency ); - // Overwrite new_start_minor since previous tile is transparent. - new_start_minor = trailing_edge_minor; + // Overwrite new_start_minor since previous tile is transparent. + new_start_minor = trailing_edge_minor; + } + // Current span is BCD, but B either doesn't exist or is handled. + // Split off D if it exists. + if( leading_edge_major < this_span.end_major ) { + spans.emplace( std::next( it ), + leading_edge_major, this_span.end_major, + this_span.start_minor, this_span.end_minor, + this_span.cumulative_transparency ); } - // Current span is BCD, but B either doesn't exist or is handled. - // Split off D if it exists. - if( leading_edge_major < this_span.end_major ) { - spans.emplace( std::next( it ), - leading_edge_major, this_span.end_major, - this_span.start_minor, this_span.end_minor, - this_span.cumulative_transparency ); - } // Truncate this_span to the current block. - this_span.end_major = std::min( this_span.end_major, leading_edge_major ); - this_span.start_major = std::max( this_span.start_major, trailing_edge_major ); + this_span.end_major = std::min( this_span.end_major, leading_edge_major ); + this_span.start_major = std::max( this_span.start_major, trailing_edge_major ); // The new span starts at the leading edge of the previous square if it is opaque, // and at the trailing edge of the current square if it is transparent. - this_span.start_minor = new_start_minor; - this_span.cumulative_value = next_cumulative_transparency; + this_span.start_minor = new_start_minor; + this_span.cumulative_value = next_cumulative_transparency; - new_start_minor = leading_edge_minor; + new_start_minor = leading_edge_minor; current_transparency = new_transparency; } if( !check( current_transparency, last_intensity ) ) { - start_major = leading_edge_major; + this_span.start_major = leading_edge_major; } } @@ -248,72 +246,74 @@ void cast_zlight_segment( break; } // Cumulative average of the values encountered. - cumulative_transparency = accumulate( cumulative_transparency, current_transparency, distance ); + this_span.cumulative_transparency = accumulate( this_span.cumulative_transparency, + current_transparency, distance ); } } +} - template - void cast_zlight( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint & origin, const int offset_distance, const T numerator ) { - // Down - cast_zlight_segment < 0, 1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, 1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - // Up - cast_zlight_segment<0, 1, 0, 1, 0, 0, 1, T, calc, check, accumulate>( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment<1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate>( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, 1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, 1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < 1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - - cast_zlight_segment < 0, -1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - cast_zlight_segment < -1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( - output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); - } +template +void cast_zlight( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint & origin, const int offset_distance, const T numerator ) { + // Down + cast_zlight_segment < 0, 1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, 1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, 1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, 1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, -1, 0, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, -1, 0, -1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + // Up + cast_zlight_segment<0, 1, 0, 1, 0, 0, 1, T, calc, check, accumulate>( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment<1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate>( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, 1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, 1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, 1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < 1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + + cast_zlight_segment < 0, -1, 0, -1, 0, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); + cast_zlight_segment < -1, 0, 0, 0, -1, 0, 1, T, calc, check, accumulate > ( + output_caches, input_arrays, floor_caches, origin, offset_distance, numerator ); +} + +// I can't figure out how to make implicit instantiation work when the parameters of +// the template-supplied function pointers are involved, so I'm explicitly instantiating instead. +template void cast_zlight( + const std::array &output_caches, + const std::array &input_arrays, + const std::array &floor_caches, + const tripoint & origin, const int offset_distance, const float numerator ); - // I can't figure out how to make implicit instantiation work when the parameters of - // the template-supplied function pointers are involved, so I'm explicitly instantiating instead. - template void cast_zlight( - const std::array &output_caches, - const std::array &input_arrays, - const std::array &floor_caches, - const tripoint & origin, const int offset_distance, const float numerator ); - - template void cast_zlight( - const std::array &output_caches, - const std::array - &input_arrays, - const std::array &floor_caches, - const tripoint & origin, const int offset_distance, const fragment_cloud numerator ); +template void cast_zlight( + const std::array &output_caches, + const std::array + &input_arrays, + const std::array &floor_caches, + const tripoint & origin, const int offset_distance, const fragment_cloud numerator ); From e8d31695f2a5679167358027ff130875d5d94e89 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Thu, 6 Jun 2019 16:17:07 -0700 Subject: [PATCH 6/7] More bugfixes --- src/shadowcasting.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shadowcasting.cpp b/src/shadowcasting.cpp index 7104bab866b71..af04e97557054 100644 --- a/src/shadowcasting.cpp +++ b/src/shadowcasting.cpp @@ -137,7 +137,7 @@ void cast_zlight_segment( } const int dist = rl_dist( origin, delta ) + offset_distance; - last_intensity = calc( numerator, this_span.cumulative_transparency, dist ); + last_intensity = calc( numerator, this_span.cumulative_value, dist ); if( !floor_block ) { ( *output_caches[z_index] )[current.x][current.y] = @@ -158,7 +158,7 @@ void cast_zlight_segment( continue; } - T next_cumulative_transparency = accumulate( this_span.cumulative_transparency, + T next_cumulative_transparency = accumulate( this_span.cumulative_value, current_transparency, distance ); // We split the span into up to 4 sub-blocks (sub-frustums actually, // this is the view from the origin looking out): @@ -192,7 +192,7 @@ void cast_zlight_segment( spans.emplace( std::next( it ), trailing_edge_major, this_span.end_major, this_span.start_minor, this_span.end_minor, - this_span.cumulative_transparency ); + this_span.cumulative_value ); // All we do to A is truncate it. this_span.end_major = trailing_edge_major; // Then make the current span the one we just inserted. @@ -216,7 +216,7 @@ void cast_zlight_segment( spans.emplace( std::next( it ), leading_edge_major, this_span.end_major, this_span.start_minor, this_span.end_minor, - this_span.cumulative_transparency ); + this_span.cumulative_value ); } // Truncate this_span to the current block. this_span.end_major = std::min( this_span.end_major, leading_edge_major ); @@ -246,8 +246,8 @@ void cast_zlight_segment( break; } // Cumulative average of the values encountered. - this_span.cumulative_transparency = accumulate( this_span.cumulative_transparency, - current_transparency, distance ); + this_span.cumulative_value = accumulate( this_span.cumulative_value, + current_transparency, distance ); } } } From 169ca393fe6a694642a17ddd51866798049601af Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Thu, 6 Jun 2019 17:27:01 -0700 Subject: [PATCH 7/7] Give span a constructor --- src/shadowcasting.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shadowcasting.cpp b/src/shadowcasting.cpp index af04e97557054..4cf3effa334f4 100644 --- a/src/shadowcasting.cpp +++ b/src/shadowcasting.cpp @@ -7,7 +7,12 @@ #include "line.h" template -struct span { +struct span { + span( const float &s_major, const float &e_major, + const float &s_minor, const float &e_minor, + const T &value ) : + start_major( s_major ), end_major( e_major ), start_minor( s_minor ), end_minor( e_minor ), + cumulative_value( value ) {} // TODO: Make these fixed-point or byte/byte pairs float start_major; float end_major;