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.
This commit is contained in:
parent
e05335b153
commit
3f7a9cc124
18 changed files with 209 additions and 257 deletions
188
map.cpp
188
map.cpp
|
@ -9,8 +9,6 @@
|
|||
using std::vector, std::pair;
|
||||
using namespace fmt;
|
||||
|
||||
const int WALL_LIGHT_LEVEL = 3;
|
||||
|
||||
void dump_map(const std::string &msg, Matrix &map) {
|
||||
println("----------------- {}", msg);
|
||||
for(auto row : map) {
|
||||
|
@ -21,25 +19,6 @@ void dump_map(const std::string &msg, Matrix &map) {
|
|||
}
|
||||
}
|
||||
|
||||
inline void add_neighbors(PointList &neighbors, Matrix &closed, size_t y, size_t x) {
|
||||
size_t h = closed.size();
|
||||
size_t w = closed[0].size();
|
||||
vector<size_t> rows{y - 1, y, y + 1};
|
||||
vector<size_t> cols{x - 1, x, x + 1};
|
||||
|
||||
for(size_t row : rows) {
|
||||
for(size_t col : cols) {
|
||||
if((0 <= row && row < h) &&
|
||||
(0 <= col && col < w) &&
|
||||
closed[row][col] == 0)
|
||||
{
|
||||
closed[row][col] = 1;
|
||||
neighbors.push_back({.x=col, .y=row});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will create an _inverted_ map that you
|
||||
* can run make_rooms and generate on. It will
|
||||
|
@ -49,84 +28,12 @@ Map::Map(size_t width, size_t height) :
|
|||
$limit(1000),
|
||||
$width(width),
|
||||
$height(height),
|
||||
$input_map(height, MatrixRow(width, 1)),
|
||||
$walls(height, MatrixRow(width, INV_WALL)),
|
||||
$paths(height, MatrixRow(width, 1)),
|
||||
$lightmap(height, MatrixRow(width, 0)),
|
||||
$light_paths(height, MatrixRow(width, 1)),
|
||||
$light_input(height, MatrixRow(width, 1))
|
||||
{
|
||||
}
|
||||
|
||||
// Used on in tests to set an existing map
|
||||
Map::Map(Matrix input_map, Matrix walls_map, int limit) :
|
||||
$limit(limit),
|
||||
$input_map(input_map),
|
||||
$walls(walls_map)
|
||||
{
|
||||
$width = $walls[0].size();
|
||||
$height = $walls.size();
|
||||
$paths = Matrix($height, MatrixRow($width, 1));
|
||||
$lightmap = Matrix($height, MatrixRow($width, 0));
|
||||
$light_paths = Matrix($height, MatrixRow($width, 1));
|
||||
$light_input = Matrix($height, MatrixRow($width, 1));
|
||||
}
|
||||
|
||||
inline void matrix_assign(Matrix &out, int new_value) {
|
||||
for(auto &row : out) {
|
||||
row.assign(row.size(), new_value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used https://github.com/HenrYxZ/dijkstra-map as a reference.
|
||||
*/
|
||||
void Map::pathing_for(Matrix &input_map, Matrix &path_for) {
|
||||
INVARIANT();
|
||||
// Initialize the new array with every pixel at limit distance
|
||||
// NOTE: this is normally ones() * limit
|
||||
int limit = $limit == 0 ? $height * $width : $limit;
|
||||
matrix_assign(path_for, limit);
|
||||
|
||||
Matrix closed = $walls;
|
||||
PointList starting_pixels;
|
||||
PointList open_pixels;
|
||||
|
||||
// First pass: Add starting pixels and put them in closed
|
||||
for(size_t counter = 0; counter < $height * $width; counter++) {
|
||||
size_t x = counter % $width; // BUG: is this right?
|
||||
size_t y = counter / $width;
|
||||
if(input_map[y][x] == 0) {
|
||||
path_for[y][x] = 0;
|
||||
closed[y][x] = 1;
|
||||
starting_pixels.push_back({.x=x,.y=y});
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: Add border to open
|
||||
for(auto sp : starting_pixels) {
|
||||
add_neighbors(open_pixels, closed, sp.y, sp.x);
|
||||
}
|
||||
|
||||
// Third pass: Iterate filling in the open list
|
||||
int counter = 1; // leave this here so it's available below
|
||||
for(; counter < limit && !open_pixels.empty(); ++counter) {
|
||||
PointList next_open;
|
||||
for(auto sp : open_pixels) {
|
||||
path_for[sp.y][sp.x] = counter;
|
||||
add_neighbors(next_open, closed, sp.y, sp.x);
|
||||
}
|
||||
open_pixels = next_open;
|
||||
}
|
||||
|
||||
// Last pass: flood last pixels
|
||||
for(auto sp : open_pixels) {
|
||||
path_for[sp.y][sp.x] = counter;
|
||||
}
|
||||
}
|
||||
$paths(height, width, 1000)
|
||||
{}
|
||||
|
||||
void Map::make_paths() {
|
||||
pathing_for($input_map, $paths);
|
||||
$paths.compute_paths($walls);
|
||||
}
|
||||
|
||||
void Map::make_room(size_t origin_x, size_t origin_y, size_t w, size_t h) {
|
||||
|
@ -198,6 +105,8 @@ void Map::place_rooms(Room &cur) {
|
|||
}
|
||||
|
||||
bool Map::neighbors(Point &out, bool greater) {
|
||||
Matrix &paths = $paths.$paths;
|
||||
|
||||
std::array<Point, 4> dirs{{
|
||||
{out.x,out.y-1},
|
||||
{out.x+1,out.y},
|
||||
|
@ -206,12 +115,12 @@ bool Map::neighbors(Point &out, bool greater) {
|
|||
}};
|
||||
|
||||
int zero_i = -1;
|
||||
int cur = $paths[out.y][out.x];
|
||||
int cur = paths[out.y][out.x];
|
||||
|
||||
// BUG: sometimes cur is in a wall so finding neighbors fails
|
||||
for(size_t i = 0; i < dirs.size(); ++i) {
|
||||
Point dir = dirs[i];
|
||||
int target = inmap(dir.x, dir.y) ? $paths[dir.y][dir.x] : $limit;
|
||||
int target = inmap(dir.x, dir.y) ? paths[dir.y][dir.x] : $limit;
|
||||
|
||||
if(target == $limit) continue; // skip unpathable stuff
|
||||
|
||||
|
@ -274,8 +183,9 @@ void Map::add_door(Room &room) {
|
|||
}
|
||||
|
||||
bool Map::walk(Point &src, Point &target) {
|
||||
Matrix &paths = $paths.$paths;
|
||||
// this sets the target for the path
|
||||
dbc::check($input_map[target.y][target.x] == 0, "target point not set to 0");
|
||||
dbc::check($paths.$input[target.y][target.x] == 0, "target point not set to 0");
|
||||
|
||||
$walls[src.y][src.x] = INV_WALL;
|
||||
$walls[target.y][target.x] = INV_WALL;
|
||||
|
@ -295,7 +205,7 @@ bool Map::walk(Point &src, Point &target) {
|
|||
$walls[out.y][out.x] = INV_SPACE;
|
||||
found = neighbors(out, true);
|
||||
|
||||
if($paths[out.y][out.x] == 0) {
|
||||
if(paths[out.y][out.x] == 0) {
|
||||
$walls[out.y][out.x] = INV_SPACE;
|
||||
return true;
|
||||
}
|
||||
|
@ -305,11 +215,11 @@ bool Map::walk(Point &src, Point &target) {
|
|||
}
|
||||
|
||||
void Map::set_target(const Point &at, int value) {
|
||||
$input_map[at.y][at.x] = 0;
|
||||
$paths.set_target(at, value);
|
||||
}
|
||||
|
||||
void Map::clear_target(const Point &at) {
|
||||
$input_map[at.y][at.x] = 1;
|
||||
$paths.clear_target(at);
|
||||
}
|
||||
|
||||
Point Map::place_entity(size_t room_index) {
|
||||
|
@ -360,9 +270,7 @@ bool Map::iswall(size_t x, size_t y) {
|
|||
}
|
||||
|
||||
void Map::dump() {
|
||||
dump_map("PATHS", $paths);
|
||||
dump_map("WALLS", $walls);
|
||||
dump_map("INPUT", $input_map);
|
||||
}
|
||||
|
||||
bool Map::can_move(Point move_to) {
|
||||
|
@ -387,84 +295,12 @@ Point Map::center_camera(const Point &around, size_t view_x, size_t view_y) {
|
|||
return {start_x, start_y};
|
||||
}
|
||||
|
||||
void Map::reset_light() {
|
||||
matrix_assign($lightmap, lighting::MIN);
|
||||
}
|
||||
|
||||
void Map::clear_light_target(const Point &at) {
|
||||
$light_input[at.y][at.x] = 1;
|
||||
}
|
||||
|
||||
void Map::set_light_target(const Point &at, int value) {
|
||||
$light_input[at.y][at.x] = 0;
|
||||
}
|
||||
|
||||
void Map::path_light() {
|
||||
pathing_for($light_input, $light_paths);
|
||||
}
|
||||
|
||||
void Map::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, width() - 1);
|
||||
}
|
||||
|
||||
int Map::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 Map::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Map::INVARIANT() {
|
||||
using dbc::check;
|
||||
|
||||
check($light_paths.size() == height(), "paths wrong height");
|
||||
check($light_paths[0].size() == width(), "paths wrong width");
|
||||
check($paths.size() == height(), "paths wrong height");
|
||||
check($paths[0].size() == width(), "paths wrong width");
|
||||
check($input_map.size() == height(), "input_map wrong height");
|
||||
check($input_map[0].size() == width(), "input_map wrong width");
|
||||
check($walls.size() == height(), "walls wrong height");
|
||||
check($walls[0].size() == width(), "walls wrong width");
|
||||
check($lightmap.size() == height(), "lightmap wrong height");
|
||||
check($lightmap[0].size() == width(), "lightmap wrong width");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue