Browse Source

integrate lighting with swan

fix/style
Martin Dørum 3 years ago
parent
commit
b8fcf907d5

+ 2
- 4
libswan/include/swan/Chunk.h View File

@@ -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;
}


+ 1
- 1
libswan/include/swan/World.h View File

@@ -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_;
};


+ 3
- 1
libswan/include/swan/WorldPlane.h View File

@@ -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);

+ 2
- 2
libswan/include/swan/common.h View File

@@ -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;

+ 8
- 4
libswan/src/Chunk.cc View File

@@ -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);
}

+ 2
- 3
libswan/src/LightServer.cc View File

@@ -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;


+ 9
- 8
libswan/src/World.cc View File

@@ -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));
}


+ 28
- 56
libswan/src/WorldPlane.cc View File

@@ -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);
}

}

Loading…
Cancel
Save