@@ -61,10 +61,8 @@ public: | |||
return getLightData()[pos.y * CHUNK_WIDTH + pos.x]; | |||
} | |||
void setLightLevel(RelPos pos, uint8_t level, SDL_Renderer *rnd); | |||
void setLightData(RelPos pos, uint8_t level) { | |||
getLightData()[pos.y * CHUNK_WIDTH + pos.x] = level; | |||
void setLightData(const uint8_t *data) { | |||
memcpy(getLightData(), data, CHUNK_WIDTH * CHUNK_HEIGHT); | |||
need_light_render_ = true; | |||
} | |||
@@ -73,7 +73,7 @@ private: | |||
ChunkRenderer chunk_renderer_; | |||
WorldPlane::ID current_plane_; | |||
std::vector<WorldPlane> planes_; | |||
std::vector<std::unique_ptr<WorldPlane>> planes_; | |||
std::string default_world_gen_; | |||
}; | |||
@@ -7,6 +7,7 @@ | |||
#include <map> | |||
#include <set> | |||
#include <typeindex> | |||
#include <mutex> | |||
#include "common.h" | |||
#include "traits/BodyTrait.h" | |||
@@ -76,11 +77,12 @@ public: | |||
void debugBox(TilePos pos); | |||
// LightingCallback implementation | |||
void onLightChunkUpdated(const LightChunk &chunk, Vec2i pos) final { /* TODO */ }; | |||
void onLightChunkUpdated(const LightChunk &chunk, Vec2i pos) final; | |||
ID id_; | |||
World *world_; | |||
std::unique_ptr<WorldGen> gen_; | |||
std::mutex mut_; | |||
private: | |||
void addLight(TilePos pos, uint8_t level); |
@@ -9,8 +9,8 @@ namespace Swan { | |||
static constexpr int TILE_SIZE = 32; | |||
static constexpr int TICK_RATE = 20; | |||
static constexpr int CHUNK_HEIGHT = 32; | |||
static constexpr int CHUNK_WIDTH = 32; | |||
static constexpr int CHUNK_HEIGHT = 64; | |||
static constexpr int CHUNK_WIDTH = 64; | |||
static constexpr int PLACEHOLDER_RED = 245; | |||
static constexpr int PLACEHOLDER_GREEN = 66; | |||
static constexpr int PLACEHOLDER_BLUE = 242; |
@@ -93,11 +93,15 @@ void Chunk::renderLight(const Context &ctx, SDL_Renderer *rnd) { | |||
RenderDrawColor color(rnd, 0, 0, 0, 0); | |||
for (int y = 0; y < CHUNK_HEIGHT; ++y) { | |||
for (int x = 0; x < CHUNK_WIDTH; ++x) { | |||
int level = getLightLevel({ x, y }); | |||
if (level >= 8) | |||
float level = (float)getLightLevel({ x, y }) / 255; | |||
float l = 1.055 * pow(level, 1/2.4) - 0.055; | |||
if (l >= 0.5) { | |||
color.change(0, 0, 0, 0); | |||
else | |||
color.change(0, 0, 0, 255 - level * 32); | |||
} else if (l > 0) { | |||
color.change(0, 0, 0, 255 - l * (255 * 2)); | |||
} else { | |||
color.change(0, 0, 0, 255); | |||
} | |||
SDL_Rect rect{ x, y, 1, 1 }; | |||
SDL_RenderFillRect(rnd, &rect); | |||
} |
@@ -58,8 +58,6 @@ LightChunk *LightServer::getChunk(ChunkPos cpos) { | |||
} | |||
void LightServer::processEvent(const Event &evt, std::vector<NewLightChunk> &newChunks) { | |||
info << "event " << (int)evt.tag; | |||
// TODO: Only mark chunks within some sphere | |||
auto markChunksModified = [&](ChunkPos cpos) { | |||
for (int y = -1; y <= 1; ++y) { | |||
@@ -85,7 +83,6 @@ void LightServer::processEvent(const Event &evt, std::vector<NewLightChunk> &new | |||
LightChunk *ch = getChunk(cpos); | |||
if (!ch) return; | |||
markChunksModified(cpos); | |||
updated_chunks_.insert(cpos); | |||
Vec2i rpos = lightRelPos(evt.pos); | |||
switch (evt.tag) { | |||
@@ -100,10 +97,12 @@ void LightServer::processEvent(const Event &evt, std::vector<NewLightChunk> &new | |||
break; | |||
case Event::Tag::LIGHT_ADDED: | |||
info << cpos << ": Add " << evt.num << " light to " << rpos; | |||
ch->light_sources[rpos] += evt.num; | |||
break; | |||
case Event::Tag::LIGHT_REMOVED: | |||
info << cpos << ": Remove " << evt.num << " light to " << rpos; | |||
ch->light_sources[rpos] -= evt.num; | |||
break; | |||
@@ -84,7 +84,7 @@ void World::setWorldGen(std::string gen) { | |||
void World::spawnPlayer() { | |||
player_ = &((dynamic_cast<BodyTrait *>( | |||
planes_[current_plane_].spawnPlayer().get()))->get(BodyTrait::Tag{})); | |||
planes_[current_plane_]->spawnPlayer().get()))->get(BodyTrait::Tag{})); | |||
} | |||
void World::setCurrentPlane(WorldPlane &plane) { | |||
@@ -107,8 +107,9 @@ WorldPlane &World::addPlane(const std::string &gen) { | |||
WorldGen::Factory &factory = it->second; | |||
std::unique_ptr<WorldGen> g = factory.create(*this); | |||
planes_.emplace_back(id, this, std::move(g), std::move(colls)); | |||
return planes_[id]; | |||
planes_.push_back(std::make_unique<WorldPlane>( | |||
id, this, std::move(g), std::move(colls))); | |||
return *planes_[id]; | |||
} | |||
Item &World::getItem(const std::string &name) { | |||
@@ -137,28 +138,28 @@ Tile &World::getTile(const std::string &name) { | |||
} | |||
SDL_Color World::backgroundColor() { | |||
return planes_[current_plane_].backgroundColor(); | |||
return planes_[current_plane_]->backgroundColor(); | |||
} | |||
void World::draw(Win &win) { | |||
ZoneScopedN("World draw"); | |||
win.cam_ = player_->pos - (win.getSize() / 2) + (player_->size / 2); | |||
planes_[current_plane_].draw(win); | |||
planes_[current_plane_]->draw(win); | |||
} | |||
void World::update(float dt) { | |||
ZoneScopedN("World update"); | |||
for (auto &plane: planes_) | |||
plane.update(dt); | |||
plane->update(dt); | |||
} | |||
void World::tick(float dt) { | |||
ZoneScopedN("World tick"); | |||
for (auto &plane: planes_) | |||
plane.tick(dt); | |||
plane->tick(dt); | |||
chunk_renderer_.tick( | |||
planes_[current_plane_], | |||
*planes_[current_plane_], | |||
ChunkPos((int)player_->pos.x / CHUNK_WIDTH, (int)player_->pos.y / CHUNK_HEIGHT)); | |||
} | |||
@@ -89,6 +89,23 @@ Chunk &WorldPlane::slowGetChunk(ChunkPos pos) { | |||
active_chunks_.push_back(&chunk); | |||
chunk_init_list_.push_back(&chunk); | |||
// Need to tell the light engine too | |||
NewLightChunk lc; | |||
for (int y = 0; y < CHUNK_HEIGHT; ++y) { | |||
for (int x = 0; x < CHUNK_WIDTH; ++x) { | |||
Tile::ID id = chunk.getTileID({ x, y }); | |||
Tile &tile = world_->getTileByID(id); | |||
if (tile.is_solid_) { | |||
lc.blocks[y * CHUNK_HEIGHT + x] = true; | |||
} | |||
if (tile.light_level_ > 0) { | |||
lc.light_sources[{ x, y }] = tile.light_level_; | |||
} | |||
} | |||
} | |||
lighting_->onChunkAdded(pos, std::move(lc)); | |||
// Otherwise, it might not be active, so let's activate it | |||
} else if (!iter->second.isActive()) { | |||
iter->second.keepActive(); | |||
@@ -118,12 +135,10 @@ void WorldPlane::setTileID(TilePos pos, Tile::ID id) { | |||
if (newTile.light_level_ != oldTile.light_level_) { | |||
if (oldTile.light_level_ > 0) { | |||
lighting_->onLightRemoved(pos, oldTile.light_level_); | |||
removeLight(pos, oldTile.light_level_); | |||
} | |||
if (newTile.light_level_ > 0) { | |||
lighting_->onLightAdded(pos, newTile.light_level_); | |||
addLight(pos, newTile.light_level_); | |||
} | |||
} | |||
@@ -190,6 +205,7 @@ SDL_Color WorldPlane::backgroundColor() { | |||
void WorldPlane::draw(Win &win) { | |||
ZoneScopedN("WorldPlane draw"); | |||
std::lock_guard<std::mutex> lock(mut_); | |||
auto ctx = getContext(); | |||
auto &pbody = *(world_->player_); | |||
@@ -227,6 +243,7 @@ void WorldPlane::draw(Win &win) { | |||
void WorldPlane::update(float dt) { | |||
ZoneScopedN("WorldPlane update"); | |||
std::lock_guard<std::mutex> lock(mut_); | |||
auto ctx = getContext(); | |||
debug_boxes_.clear(); | |||
@@ -236,6 +253,7 @@ void WorldPlane::update(float dt) { | |||
void WorldPlane::tick(float dt) { | |||
ZoneScopedN("WorldPlane tick"); | |||
std::lock_guard<std::mutex> lock(mut_); | |||
auto ctx = getContext(); | |||
// Any chunk which has been in use since last tick should be kept alive | |||
@@ -277,64 +295,18 @@ void WorldPlane::debugBox(TilePos pos) { | |||
debug_boxes_.push_back(pos); | |||
} | |||
void WorldPlane::addLight(TilePos pos, uint8_t level) { | |||
int sqrLevel = level * level; | |||
for (int y = -level; y <= level; ++y) { | |||
for (int x = -level; x <= level; ++x) { | |||
int sqrDist = x * x + y * y; | |||
if (sqrDist > sqrLevel) { | |||
continue; | |||
} | |||
int lightDiff = level - (int)sqrt(sqrDist); | |||
if (lightDiff <= 0) { | |||
continue; | |||
} | |||
TilePos tp = pos + Vec2i(x, y); | |||
ChunkPos cp = chunkPos(tp); | |||
Chunk::RelPos rp = relPos(tp); | |||
Chunk &ch = getChunk(cp); | |||
int light = (int)ch.getLightLevel(rp) + lightDiff; | |||
if (light > 255) { | |||
light = 255; | |||
} | |||
void WorldPlane::onLightChunkUpdated(const LightChunk &chunk, ChunkPos pos) { | |||
std::lock_guard<std::mutex> lock(mut_); | |||
Chunk &realChunk = getChunk(pos); | |||
realChunk.setLightData(chunk.light_levels); | |||
} | |||
ch.setLightData(rp, light); | |||
} | |||
} | |||
void WorldPlane::addLight(TilePos pos, uint8_t level) { | |||
lighting_->onLightAdded(pos, level); | |||
} | |||
void WorldPlane::removeLight(TilePos pos, uint8_t level) { | |||
int sqrLevel = level * level; | |||
for (int y = -level; y <= level; ++y) { | |||
for (int x = -level; x <= level; ++x) { | |||
int sqrDist = x * x + y * y; | |||
if (sqrDist > sqrLevel) { | |||
continue; | |||
} | |||
int lightDiff = level - (int)sqrt(sqrDist); | |||
if (lightDiff <= 0) { | |||
continue; | |||
} | |||
TilePos tp = pos + Vec2i(x, y); | |||
ChunkPos cp = chunkPos(tp); | |||
Chunk::RelPos rp = relPos(tp); | |||
Chunk &ch = getChunk(cp); | |||
int light = (int)ch.getLightLevel(rp) - lightDiff; | |||
if (light < 0) { | |||
light = 0; | |||
} | |||
ch.setLightData(rp, light); | |||
} | |||
} | |||
lighting_->onLightRemoved(pos, level); | |||
} | |||
} |