Lighting now uses pathing to determine where it can go, but _distance_ to determin strength. Looks way better.

main
Zed A. Shaw 3 days ago
parent 31620adf7a
commit f46b5f15ef
  1. 37
      lights.cpp
  2. 2
      lights.hpp
  3. 4
      main.cpp
  4. 16
      matrix.cpp
  5. 3
      matrix.hpp
  6. 4
      systems.cpp
  7. 46
      tests/lighting.cpp
  8. 23
      tests/matrix.cpp

@ -5,29 +5,10 @@
using std::vector; using std::vector;
namespace lighting { namespace lighting {
void LightRender::render_circle_light(LightSource source, Point at, PointList &has_light) {
for(matrix::circle it{$lightmap, at, source.radius}; it.next();) {
for(int x = it.left; x < it.right; x++) {
$lightmap[it.y][x] = light_level(source.strength, x, it.y);
has_light.push_back({(size_t)x, (size_t)it.y});
}
}
}
void LightRender::render_compass_light(LightSource source, Point at, PointList &has_light) {
for(matrix::compass it{$lightmap, at.x, at.y}; it.next();) {
if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) {
$lightmap[it.y][it.x] = light_level(source.strength, it.x, it.y);
has_light.push_back({it.x, it.y});
}
}
}
void LightRender::render_square_light(LightSource source, Point at, PointList &has_light) { void LightRender::render_square_light(LightSource source, Point at, PointList &has_light) {
for(matrix::in_box it{$lightmap, at.x, at.y, (size_t)floor(source.radius)}; it.next();) { for(matrix::in_box it{$lightmap, at.x, at.y, (size_t)floor(source.radius)}; it.next();) {
if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) { if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) {
$lightmap[it.y][it.x] = light_level(source.strength, it.x, it.y); $lightmap[it.y][it.x] = light_level(source.strength, it.distance(), it.x, it.y);
has_light.push_back({it.x, it.y}); has_light.push_back({it.x, it.y});
} }
} }
@ -38,26 +19,22 @@ namespace lighting {
clear_light_target(at); clear_light_target(at);
PointList has_light; PointList has_light;
if(source.radius < 1.5f) { render_square_light(source, at, has_light);
render_compass_light(source, at, has_light);
} else if(source.radius < 2.0f) {
render_square_light(source, at, has_light);
} else {
render_circle_light(source, at, has_light);
}
const int wall_light = source.strength + WALL_LIGHT_LEVEL; const int wall_light = source.strength + WALL_LIGHT_LEVEL;
for(auto point : has_light) { for(auto point : has_light) {
for(matrix::compass it{$lightmap, point.x, point.y}; it.next();) { for(matrix::compass it{$lightmap, point.x, point.y}; it.next();) {
if($paths.$paths[it.y][it.x] == WALL_PATH_LIMIT) { if($paths.$paths[it.y][it.x] == WALL_PATH_LIMIT) {
$lightmap[it.y][it.x] = light_level(wall_light, point.x, point.y); // BUG: include the distance in the list of walls to light
// so that they will be closer to the light level at that point
$lightmap[it.y][it.x] = light_level(wall_light, 1.0f, point.x, point.y);
} }
} }
} }
} }
int LightRender::light_level(int level, size_t x, size_t y) { int LightRender::light_level(int level, float distance, size_t x, size_t y) {
size_t at = level + $paths.$paths[y][x]; size_t at = level + ceil(distance);
int cur_level = $lightmap[y][x]; int cur_level = $lightmap[y][x];
int new_level = at < lighting::LEVELS.size() ? lighting::LEVELS[at] : lighting::MIN; int new_level = at < lighting::LEVELS.size() ? lighting::LEVELS[at] : lighting::MIN;
return cur_level < new_level ? new_level : cur_level; return cur_level < new_level ? new_level : cur_level;

@ -49,7 +49,7 @@ namespace lighting {
void clear_light_target(const Point &at); void clear_light_target(const Point &at);
void path_light(Matrix &walls); void path_light(Matrix &walls);
void light_box(LightSource source, Point from, Point &min_out, Point &max_out); void light_box(LightSource source, Point from, Point &min_out, Point &max_out);
int light_level(int level, size_t x, size_t y); int light_level(int level, float distance, size_t x, size_t y);
void render_light(LightSource source, Point at); void render_light(LightSource source, Point at);
void render_square_light(LightSource source, Point at, PointList &has_light); void render_square_light(LightSource source, Point at, PointList &has_light);
void render_compass_light(LightSource source, Point at, PointList &has_light); void render_compass_light(LightSource source, Point at, PointList &has_light);

@ -33,7 +33,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) {
world.set<Combat>(player.entity, {100, 10}); world.set<Combat>(player.entity, {100, 10});
world.set<Tile>(player.entity, {config.PLAYER_TILE}); world.set<Tile>(player.entity, {config.PLAYER_TILE});
world.set<Inventory>(player.entity, {5}); world.set<Inventory>(player.entity, {5});
world.set<LightSource>(player.entity, {6,2.1}); world.set<LightSource>(player.entity, {6,1.0});
auto enemy = world.entity(); auto enemy = world.entity();
world.set<Position>(enemy, {game_map.place_entity(1)}); world.set<Position>(enemy, {game_map.place_entity(1)});
@ -55,7 +55,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) {
auto wall_torch = world.entity(); auto wall_torch = world.entity();
world.set<Position>(wall_torch, {game_map.place_entity(4)}); world.set<Position>(wall_torch, {game_map.place_entity(4)});
world.set<LightSource>(wall_torch, {3,2.4}); world.set<LightSource>(wall_torch, {4,3});
world.set<Tile>(wall_torch, {""}); world.set<Tile>(wall_torch, {""});
} }

@ -53,9 +53,11 @@ namespace matrix {
return at_end(y, height); return at_end(y, height);
} }
in_box::in_box(Matrix &mat, size_t from_x, size_t from_y, size_t size) { in_box::in_box(Matrix &mat, size_t at_x, size_t at_y, size_t size) :
size_t h = mat.size(); from_x(at_x), from_y(at_y)
size_t w = mat[0].size(); {
size_t h = matrix::height(mat);
size_t w = matrix::width(mat);
// keeps it from going below zero // keeps it from going below zero
// need extra -1 to compensate for the first next() // need extra -1 to compensate for the first next()
@ -78,9 +80,17 @@ namespace matrix {
// if x==0 then this moves it to min_x // if x==0 then this moves it to min_x
x = max(x, left); x = max(x, left);
// and done // and done
return at_end(y, bottom); return at_end(y, bottom);
} }
float in_box::distance() {
int dx = from_x - x;
int dy = from_y - y;
return sqrt((dx * dx) + (dy * dy));
}
void in_box::dump() { void in_box::dump() {
println("BOX: x={},y={}; left={},right={}; top={},bottom={}", println("BOX: x={},y={}; left={},right={}; top={},bottom={}",
x, y, left, right, top, bottom); x, y, left, right, top, bottom);

@ -37,6 +37,8 @@ namespace matrix {
}; };
struct in_box { struct in_box {
size_t from_x;
size_t from_y;
size_t x = 0; // these are set in constructor size_t x = 0; // these are set in constructor
size_t y = 0; // again, no fancy ~ trick needed size_t y = 0; // again, no fancy ~ trick needed
size_t left = 0; size_t left = 0;
@ -45,6 +47,7 @@ namespace matrix {
size_t bottom = 0; size_t bottom = 0;
in_box(Matrix &mat, size_t x, size_t y, size_t size); in_box(Matrix &mat, size_t x, size_t y, size_t size);
float distance();
bool next(); bool next();
void dump(); void dump();
}; };

@ -143,8 +143,8 @@ void System::collision(DinkyECS::World &world, Player &player) {
world.send<Events::GUI>(Events::GUI::LOOT, entity, loot); world.send<Events::GUI>(Events::GUI::LOOT, entity, loot);
inventory.gold += loot.amount; inventory.gold += loot.amount;
light.strength = 4; light.strength = 5;
light.radius = 2.3; light.radius = 2;
collider.remove(loot_pos.location); collider.remove(loot_pos.location);
} else { } else {
println("UNKNOWN COLLISION TYPE {}", entity); println("UNKNOWN COLLISION TYPE {}", entity);

@ -10,38 +10,36 @@
using namespace lighting; using namespace lighting;
TEST_CASE("lighting a map works", "[lighting]") { TEST_CASE("lighting a map works", "[lighting]") {
for(int i = 0; i < 5; i++) { Map map(20,23);
Map map(20+i,23+i); WorldBuilder builder(map);
WorldBuilder builder(map); builder.generate();
builder.generate();
Point light1 = map.place_entity(0); Point light1 = map.place_entity(0);
Point light2 = map.place_entity(1); Point light2 = map.place_entity(1);
LightSource source1{7,1}; LightSource source1{0,2};
LightSource source2{3,2}; LightSource source2{1,3};
LightRender lr(map.width(), map.height()); LightRender lr(map.width(), map.height());
lr.reset_light(); lr.reset_light();
lr.set_light_target(light1); lr.set_light_target(light1);
lr.set_light_target(light2); lr.set_light_target(light2);
lr.path_light(map.walls()); lr.path_light(map.walls());
lr.render_light(source1, light1); lr.render_light(source1, light1);
lr.render_light(source2, light2); lr.render_light(source2, light2);
lr.clear_light_target(light1); lr.clear_light_target(light1);
lr.clear_light_target(light2); lr.clear_light_target(light2);
Matrix &lighting = lr.lighting(); Matrix &lighting = lr.lighting();
//matrix::dump("WALLS=====", map.walls()); matrix::dump("WALLS=====", map.walls(), light1.x, light1.y);
//matrix::dump("LIGHT PATHS======", lr.$paths.$paths); matrix::dump("LIGHTING======", lighting, light1.x, light1.y);
// confirm light is set at least at and around the two points // confirm light is set at least at and around the two points
REQUIRE(lighting[light1.y][light1.x] == lighting::LEVELS[source1.strength]); REQUIRE(lighting[light1.y][light1.x] == lighting::LEVELS[source1.strength]);
REQUIRE(lighting[light2.y][light2.x] == lighting::LEVELS[source2.strength]); REQUIRE(lighting[light2.y][light2.x] == lighting::LEVELS[source2.strength]);
}
} }

@ -101,6 +101,27 @@ TEST_CASE("thash matrix iterators", "[matrix]") {
} }
} }
TEST_CASE("thrash box distance iterators", "[matrix:distance]") {
size_t width = Random::uniform<size_t>(10, 21);
size_t height = Random::uniform<size_t>(10, 25);
Matrix result(height, matrix::Row(width));
matrix::assign(result, 0);
size_t size = Random::uniform<int>(4, 10);
Point target{width/2, height/2};
matrix::in_box box{result, target.x, target.y, size};
while(box.next()) {
result[box.y][box.x] = box.distance();
}
matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}",
matrix::width(result), matrix::height(result),
target.x, target.y, box.right - box.left, box.bottom - box.top, size),
result, target.x, target.y);
}
TEST_CASE("thrash box iterators", "[matrix]") { TEST_CASE("thrash box iterators", "[matrix]") {
for(int count = 0; count < 20; count++) { for(int count = 0; count < 20; count++) {
size_t width = Random::uniform<size_t>(1, 25); size_t width = Random::uniform<size_t>(1, 25);
@ -250,7 +271,7 @@ TEST_CASE("prototype circle algorithm", "[matrix:circle]") {
} }
} }
matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y); // matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y);
} }
} }
} }

Loading…
Cancel
Save