Skip to content

Commit

Permalink
Extend shadowcasting test to 3D
Browse files Browse the repository at this point in the history
  • Loading branch information
kevingranade committed May 25, 2019
1 parent 3233182 commit 2d606ad
Showing 1 changed file with 179 additions and 119 deletions.
298 changes: 179 additions & 119 deletions tests/shadowcasting_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <array>
#include <functional>
#include <memory>
#include <sstream>
#include <type_traits>
#include <vector>

Expand Down Expand Up @@ -406,197 +407,256 @@ 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<std::vector<float>> data;
point offset;
std::vector<std::vector<std::vector<float>>> data;
tripoint offset;
float default_value;

// origin_offset is specified as the coordinates of the "camera" within the overlay.
grid_overlay( const point origin_offset, const float default_value ) {
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<int>( sizeof( transparency_cache ) /
sizeof( transparency_cache[0] ) ); ++y ) {
for( int x = 0; x < static_cast<int>( 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<float ( * )[MAPSIZE *SEEX][MAPSIZE *SEEY], OVERMAP_LAYERS> seen_squares;
std::array<const float ( * )[MAPSIZE *SEEX][MAPSIZE *SEEY], OVERMAP_LAYERS> transparency_cache;
std::array<const bool ( * )[MAPSIZE *SEEX][MAPSIZE *SEEY], OVERMAP_LAYERS> 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<float, float, sight_calc, sight_check, update_light, accumulate_transparency>(
seen_squares, transparency_cache, ORIGIN.x, ORIGIN.y );
if( fov_3d ) {
cast_zlight<float, sight_calc, sight_check, accumulate_transparency>( seen_squares,
transparency_cache, floor_cache, { ORIGIN.x, ORIGIN.y, ORIGIN.z - OVERMAP_DEPTH }, 0, 1.0 );
} else {
castLightAll<float, float, sight_calc, sight_check, update_light, accumulate_transparency>(
*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.
Expand Down

0 comments on commit 2d606ad

Please sign in to comment.