Browse Source

more lighting stuff

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

+ 8
- 6
libswan/include/swan/LightingThread.h View File

@@ -32,7 +32,7 @@ struct LightChunk {

class LightingCallback {
public:
virtual void onLightChunkUpdated(const LightChunk &chunk, Vec2i pos) = 0;
virtual void onLightChunkUpdated(const LightChunk &chunk, ChunkPos pos) = 0;
};

class LightingThread {
@@ -44,8 +44,8 @@ public:
void onSolidBlockRemoved(TilePos pos);
void onLightAdded(TilePos pos, uint8_t level);
void onLightRemoved(TilePos pos, uint8_t level);
void onChunkAdded(Vec2i pos, NewLightChunk &&chunk);
void onChunkRemoved(Vec2i pos);
void onChunkAdded(ChunkPos pos, NewLightChunk &&chunk);
void onChunkRemoved(ChunkPos pos);

private:
struct Event {
@@ -61,10 +61,12 @@ private:
};

bool tileIsSolid(TilePos pos);
LightChunk *getChunk(Vec2i cpos);
LightChunk *getChunk(ChunkPos cpos);

int recalcTile(LightChunk &chunk, Vec2i cpos, Vec2i rpos, TilePos base);
void processUpdatedChunk(LightChunk &chunk, Vec2i cpos);
int recalcTile(
LightChunk &chunk, ChunkPos cpos, Vec2i rpos, TilePos base,
std::vector<std::pair<TilePos, uint8_t>> &lights);
void processUpdatedChunk(LightChunk &chunk, ChunkPos cpos);
void processEvent(const Event &event, std::vector<NewLightChunk> &newChunks);
void run();


+ 1
- 0
libswan/include/swan/Vector2.h View File

@@ -15,6 +15,7 @@ struct Vector2 {
MSGPACK_DEFINE(x, y)

constexpr Vector2(T x = 0, T y = 0): x(x), y(y) {}
constexpr Vector2(std::pair<T, T> p): x(p.first), y(p.second) {}

constexpr Vector2<T> &set(T x, T y) {
this->x = x;

+ 53
- 32
libswan/src/LightingThread.cc View File

@@ -4,7 +4,7 @@

namespace Swan {

static Vec2i lightChunkPos(TilePos pos) {
static ChunkPos lightChunkPos(TilePos pos) {
// Same logic as in WorldPlane.cc
return Vec2i(
((size_t)pos.x + (LLONG_MAX / 2) + 1) / CHUNK_WIDTH -
@@ -32,7 +32,7 @@ LightingThread::~LightingThread() {
}

bool LightingThread::tileIsSolid(TilePos pos) {
Vec2i cpos = lightChunkPos(pos);
ChunkPos cpos = lightChunkPos(pos);
LightChunk *chunk = getChunk(cpos);
if (chunk == nullptr) {
return true;
@@ -42,7 +42,7 @@ bool LightingThread::tileIsSolid(TilePos pos) {
return chunk->blocks[rpos.y * CHUNK_WIDTH + rpos.x];
}

LightChunk *LightingThread::getChunk(Vec2i cpos) {
LightChunk *LightingThread::getChunk(ChunkPos cpos) {
if (cached_chunk_ && cached_chunk_pos_ == cpos) {
return cached_chunk_;
}
@@ -60,28 +60,34 @@ LightChunk *LightingThread::getChunk(Vec2i cpos) {
void LightingThread::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) {
for (int x = -1; x <= 1; ++x) {
updated_chunks_.insert(cpos + Vec2i(x, y));
}
}
};

if (evt.tag == Event::Tag::CHUNK_ADDED) {
chunks_.emplace(std::piecewise_construct,
std::forward_as_tuple(evt.pos),
std::forward_as_tuple(std::move(newChunks[evt.num])));
LightChunk &ch = chunks_[evt.pos]; // Create and default initialize
ch.was_updated = true;
updated_chunks_.insert(evt.pos);
markChunksModified(evt.pos);
return;
} else if (evt.tag == Event::Tag::CHUNK_REMOVED) {
chunks_.erase(evt.pos);
markChunksModified(evt.pos);
return;
}

Vec2i cpos = lightChunkPos(evt.pos);
ChunkPos cpos = lightChunkPos(evt.pos);
LightChunk *ch = getChunk(cpos);
if (!ch) return;
ch->was_updated = true;
markChunksModified(cpos);
updated_chunks_.insert(cpos);
Vec2i rpos = lightRelPos(evt.pos);

// TODO: Mark neighbouring chunks as updated

switch (evt.tag) {
case Event::Tag::BLOCK_ADDED:
ch->blocks.set(rpos.y * CHUNK_WIDTH + rpos.x, true);
@@ -108,33 +114,21 @@ void LightingThread::processEvent(const Event &evt, std::vector<NewLightChunk> &
}
}

int LightingThread::recalcTile(LightChunk &chunk, Vec2i cpos, Vec2i rpos, TilePos base) {
std::vector<std::pair<Vec2i, uint8_t>> lights;
int LightingThread::recalcTile(
LightChunk &chunk, ChunkPos cpos, Vec2i rpos, TilePos base,
std::vector<std::pair<TilePos, uint8_t>> &lights) {
TilePos pos = rpos + base;

// TODO: Gather light sources from other chunks oo
for (auto &[lightrel, level]: chunk.light_sources) {
TilePos lightpos = base + Vec2i(lightrel.first, lightrel.second);
Vec2i diff = lightpos - pos;
if (diff.x * diff.x + diff.y * diff.y > level * level) {
continue;
}

lights.push_back({ lightpos, level });
}

chunk.light_levels[rpos.y * CHUNK_WIDTH + rpos.x] = 0;

constexpr int accuracy = 4;
auto raycast = [&](Vec2 from, Vec2 to) {
auto diff = to - from;
float dist = ((Vec2)diff).length();
Vec2 step = (Vec2)diff / (dist * accuracy);
Vec2 currpos = from;
Vec2i currtile = Vec2i(floor(currpos.x), floor(currpos.y));
TilePos currtile = TilePos(floor(currpos.x), floor(currpos.y));
auto proceed = [&]() {
Vec2i t;
while ((t = Vec2i(floor(currpos.x), floor(currpos.y))) == currtile) {
TilePos t;
while ((t = TilePos(floor(currpos.x), floor(currpos.y))) == currtile) {
currpos += step;
}
currtile = t;
@@ -162,6 +156,10 @@ int LightingThread::recalcTile(LightChunk &chunk, Vec2i cpos, Vec2i rpos, TilePo
continue;
}

if ((lightpos - pos).squareLength() > level * level) {
continue;
}

float dist = ((Vec2)(lightpos - pos)).length();
int light = level - (int)dist;

@@ -188,14 +186,37 @@ int LightingThread::recalcTile(LightChunk &chunk, Vec2i cpos, Vec2i rpos, TilePo
return acc;
}

void LightingThread::processUpdatedChunk(LightChunk &chunk, Vec2i cpos) {
void LightingThread::processUpdatedChunk(LightChunk &chunk, ChunkPos cpos) {
auto start = std::chrono::steady_clock::now();
TilePos base = cpos * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT);
std::vector<std::pair<TilePos, uint8_t>> lights;

for (auto &[pos, level]: chunk.light_sources) {
lights.emplace_back(Vec2i(pos) + base, level);
}

auto addLightFromChunk = [&](LightChunk *chunk, int dx, int dy) {
if (chunk == nullptr) {
return;
}

TilePos b = base + Vec2i(dx * CHUNK_WIDTH, dy * CHUNK_HEIGHT);
for (auto &[pos, level]: chunk->light_sources) {
lights.emplace_back(TilePos(pos) + b, level);
}
};

for (int y = -1; y <= 1; ++y) {
for (int x = -1; x <= 1; ++x) {
if (y == 0 && x == 0) continue;
addLightFromChunk(getChunk(cpos + Vec2i(x, y)), x, y);
}
}

TilePos base = cpos * Vec2i(CHUNK_WIDTH * CHUNK_HEIGHT);
for (int y = 0; y < CHUNK_HEIGHT; ++y) {
for (int x = 0; x < CHUNK_WIDTH; ++x) {
chunk.light_levels[y * CHUNK_WIDTH + x] =
recalcTile(chunk, cpos, Vec2i(x, y), base);
recalcTile(chunk, cpos, Vec2i(x, y), base, lights);
}
}

@@ -228,7 +249,7 @@ void LightingThread::run() {
for (auto &pos: updated_chunks_) {
auto ch = chunks_.find(pos);
if (ch != chunks_.end()) {
processUpdatedChunk(ch->second, Vec2i(pos.first, pos.second));
processUpdatedChunk(ch->second, ChunkPos(pos.first, pos.second));
}
}


+ 5
- 0
src/lighting-test.cc View File

@@ -45,6 +45,11 @@ int main() {

std::unique_lock<std::mutex> lock(cb.mut_);
cb.cond_.wait(lock, [&] { return cb.done_; });
cb.done_ = false;

lt.onSolidBlockAdded({ 10, 10 });
cb.cond_.wait(lock, [&] { return cb.done_; });
cb.done_ = false;

png::image<png::rgb_pixel> image(Swan::CHUNK_WIDTH, Swan::CHUNK_HEIGHT);
for (int y = 0; y < Swan::CHUNK_HEIGHT; ++y) {

Loading…
Cancel
Save