#include "lights.hpp" #include "constants.hpp" #include using std::vector; namespace lighting { void LightRender::render_square_light(LightSource source, Point at, PointList &has_light) { for(matrix::box it{$lightmap, at.x, at.y, (size_t)floor(source.radius)}; it.next();) { if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) { $lightmap[it.y][it.x] = light_level(source.strength, it.distance(), it.x, it.y); has_light.push_back({it.x, it.y}); } } } /* * NOTE: This really doesn't need to calculate light all the time. It doesn't * change around the light source until the lightsource is changed, so the * light levels could be placed in a Matrix inside LightSource, calculated once * and then simply "applied" to the area where the entity is located. The only * thing that would need to be calculated each time is the walls. */ void LightRender::render_light(LightSource source, Point at) { Point min, max; clear_light_target(at); PointList has_light; render_square_light(source, at, has_light); for(auto point : has_light) { for(matrix::compass it{$lightmap, point.x, point.y}; it.next();) { if($paths.$paths[it.y][it.x] == WALL_PATH_LIMIT) { $lightmap[it.y][it.x] = light_level(source.strength, 1.5f, point.x, point.y); } } } } int LightRender::light_level(int strength, float distance, size_t x, size_t y) { int new_level = distance <= 1.0f ? strength : strength / sqrt(distance); int cur_level = $lightmap[y][x]; 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) { $paths.clear_target(at); } void LightRender::set_light_target(const Point &at, int value) { $paths.set_target(at, value); } void LightRender::path_light(Matrix &walls) { $paths.compute_paths(walls); } }