Lighting is now in its own class using the new Pathing class. This should allow me to make it more consistent and possibly make Pathing more efficient.
parent
e05335b153
commit
3f7a9cc124
@ -0,0 +1,76 @@ |
||||
#include "lights.hpp" |
||||
#include <vector> |
||||
|
||||
const int WALL_LIGHT_LEVEL = 3; |
||||
|
||||
using std::vector; |
||||
|
||||
namespace lighting { |
||||
void LightRender::render_light(LightSource source, Point at) { |
||||
const int UNPATH = $limit; |
||||
Point min, max; |
||||
light_box(source, at, min, max); |
||||
clear_light_target(at); |
||||
vector<Point> has_light; |
||||
|
||||
for(size_t y = min.y; y <= max.y; ++y) { |
||||
auto &light_row = $lightmap[y]; |
||||
auto &path_row = $light.$paths[y]; |
||||
|
||||
for(size_t x = min.x; x <= max.x; ++x) { |
||||
if(path_row[x] != UNPATH) { |
||||
light_row[x] = light_level(source.strength, x, y); |
||||
has_light.push_back({x,y}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
const int wall_light = source.strength + WALL_LIGHT_LEVEL; |
||||
for(auto point : has_light) { |
||||
for(int j = -1;point.y+j >= 0 && j <= 1 && point.y+j < $height; j++) { |
||||
auto &path_row = $light.$paths[point.y+j]; |
||||
auto &light_row = $lightmap[point.y+j]; |
||||
|
||||
for(int i = -1; point.x+i >= 0 && i <= 1 && point.x+i < $width; i++) { |
||||
if(path_row[point.x+i] == UNPATH) { |
||||
light_row[point.x+i] = light_level(wall_light, point.x, point.y); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
int LightRender::light_level(int level, size_t x, size_t y) { |
||||
size_t at = level + $light.$paths[y][x]; |
||||
int cur_level = $lightmap[y][x]; |
||||
int new_level = at < lighting::LEVELS.size() ? lighting::LEVELS[at] : lighting::MIN; |
||||
return cur_level < new_level ? new_level : cur_level; |
||||
} |
||||
|
||||
|
||||
void LightRender::reset_light() { |
||||
for(auto &row : $lightmap) { |
||||
row.assign(row.size(), lighting::MIN); |
||||
} |
||||
} |
||||
|
||||
void LightRender::clear_light_target(const Point &at) { |
||||
$light.clear_target(at); |
||||
} |
||||
|
||||
void LightRender::set_light_target(const Point &at, int value) { |
||||
$light.set_target(at, value); |
||||
} |
||||
|
||||
void LightRender::path_light(Matrix &walls) { |
||||
$light.compute_paths(walls); |
||||
} |
||||
|
||||
void LightRender::light_box(LightSource source, Point from, Point &min_out, Point &max_out) { |
||||
using std::min, std::max; |
||||
min_out.x = max(int(from.x), source.distance) - source.distance; |
||||
max_out.x = min(from.x + source.distance, $width - 1); |
||||
min_out.y = max(int(from.y), source.distance) - source.distance; |
||||
max_out.y = min(from.y + source.distance, $height - 1); |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
#include <catch2/catch_test_macros.hpp> |
||||
#include <fmt/core.h> |
||||
#include <nlohmann/json.hpp> |
||||
#include <fstream> |
||||
#include "map.hpp" |
||||
#include "lights.hpp" |
||||
#include "point.hpp" |
||||
|
||||
using namespace lighting; |
||||
|
||||
TEST_CASE("lighting a map works", "[lighting]") { |
||||
Map map(20,20); |
||||
map.generate(); |
||||
|
||||
Point light1 = map.place_entity(0); |
||||
Point light2 = map.place_entity(1); |
||||
LightSource source1{7,1}; |
||||
LightSource source2{3,2}; |
||||
|
||||
LightRender lr(map.width(), map.height(), map.limit()); |
||||
|
||||
lr.reset_light(); |
||||
|
||||
lr.set_light_target(light1); |
||||
lr.set_light_target(light2); |
||||
|
||||
lr.path_light(map.walls()); |
||||
|
||||
lr.render_light(source1, light1); |
||||
lr.render_light(source2, light2); |
||||
|
||||
lr.clear_light_target(light1); |
||||
lr.clear_light_target(light2); |
||||
|
||||
const auto &lighting = lr.lighting(); |
||||
|
||||
// confirm light is set at least at and around the two points
|
||||
REQUIRE(lighting[light1.y][light1.x] == lighting::LEVELS[source1.strength]); |
||||
REQUIRE(lighting[light2.y][light2.x] == lighting::LEVELS[source2.strength]); |
||||
} |
Loading…
Reference in new issue