#include "lights.hpp" #include 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 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); } }