Преглед на файлове

more lighting stuff

fix/style
Martin Dørum преди 3 години
родител
ревизия
f9aaf6e5c7
променени са 4 файла, в които са добавени 67 реда и са изтрити 38 реда
  1. 8
    6
      libswan/include/swan/LightingThread.h
  2. 1
    0
      libswan/include/swan/Vector2.h
  3. 53
    32
      libswan/src/LightingThread.cc
  4. 5
    0
      src/lighting-test.cc

+ 8
- 6
libswan/include/swan/LightingThread.h Целия файл



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


class LightingThread { class LightingThread {
void onSolidBlockRemoved(TilePos pos); void onSolidBlockRemoved(TilePos pos);
void onLightAdded(TilePos pos, uint8_t level); void onLightAdded(TilePos pos, uint8_t level);
void onLightRemoved(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: private:
struct Event { struct Event {
}; };


bool tileIsSolid(TilePos pos); 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 processEvent(const Event &event, std::vector<NewLightChunk> &newChunks);
void run(); void run();



+ 1
- 0
libswan/include/swan/Vector2.h Целия файл

MSGPACK_DEFINE(x, y) MSGPACK_DEFINE(x, y)


constexpr Vector2(T x = 0, T y = 0): x(x), y(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) { constexpr Vector2<T> &set(T x, T y) {
this->x = x; this->x = x;

+ 53
- 32
libswan/src/LightingThread.cc Целия файл



namespace Swan { namespace Swan {


static Vec2i lightChunkPos(TilePos pos) {
static ChunkPos lightChunkPos(TilePos pos) {
// Same logic as in WorldPlane.cc // Same logic as in WorldPlane.cc
return Vec2i( return Vec2i(
((size_t)pos.x + (LLONG_MAX / 2) + 1) / CHUNK_WIDTH - ((size_t)pos.x + (LLONG_MAX / 2) + 1) / CHUNK_WIDTH -
} }


bool LightingThread::tileIsSolid(TilePos pos) { bool LightingThread::tileIsSolid(TilePos pos) {
Vec2i cpos = lightChunkPos(pos);
ChunkPos cpos = lightChunkPos(pos);
LightChunk *chunk = getChunk(cpos); LightChunk *chunk = getChunk(cpos);
if (chunk == nullptr) { if (chunk == nullptr) {
return true; return true;
return chunk->blocks[rpos.y * CHUNK_WIDTH + rpos.x]; 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) { if (cached_chunk_ && cached_chunk_pos_ == cpos) {
return cached_chunk_; return cached_chunk_;
} }
void LightingThread::processEvent(const Event &evt, std::vector<NewLightChunk> &newChunks) { void LightingThread::processEvent(const Event &evt, std::vector<NewLightChunk> &newChunks) {
info << "event " << (int)evt.tag; 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) { if (evt.tag == Event::Tag::CHUNK_ADDED) {
chunks_.emplace(std::piecewise_construct, chunks_.emplace(std::piecewise_construct,
std::forward_as_tuple(evt.pos), std::forward_as_tuple(evt.pos),
std::forward_as_tuple(std::move(newChunks[evt.num]))); 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; return;
} else if (evt.tag == Event::Tag::CHUNK_REMOVED) { } else if (evt.tag == Event::Tag::CHUNK_REMOVED) {
chunks_.erase(evt.pos); chunks_.erase(evt.pos);
markChunksModified(evt.pos);
return; return;
} }


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


// TODO: Mark neighbouring chunks as updated

switch (evt.tag) { switch (evt.tag) {
case Event::Tag::BLOCK_ADDED: case Event::Tag::BLOCK_ADDED:
ch->blocks.set(rpos.y * CHUNK_WIDTH + rpos.x, true); ch->blocks.set(rpos.y * CHUNK_WIDTH + rpos.x, true);
} }
} }


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; 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; constexpr int accuracy = 4;
auto raycast = [&](Vec2 from, Vec2 to) { auto raycast = [&](Vec2 from, Vec2 to) {
auto diff = to - from; auto diff = to - from;
float dist = ((Vec2)diff).length(); float dist = ((Vec2)diff).length();
Vec2 step = (Vec2)diff / (dist * accuracy); Vec2 step = (Vec2)diff / (dist * accuracy);
Vec2 currpos = from; Vec2 currpos = from;
Vec2i currtile = Vec2i(floor(currpos.x), floor(currpos.y));
TilePos currtile = TilePos(floor(currpos.x), floor(currpos.y));
auto proceed = [&]() { 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; currpos += step;
} }
currtile = t; currtile = t;
continue; continue;
} }


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

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


return acc; return acc;
} }


void LightingThread::processUpdatedChunk(LightChunk &chunk, Vec2i cpos) {
void LightingThread::processUpdatedChunk(LightChunk &chunk, ChunkPos cpos) {
auto start = std::chrono::steady_clock::now(); 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 y = 0; y < CHUNK_HEIGHT; ++y) {
for (int x = 0; x < CHUNK_WIDTH; ++x) { for (int x = 0; x < CHUNK_WIDTH; ++x) {
chunk.light_levels[y * 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);
} }
} }


for (auto &pos: updated_chunks_) { for (auto &pos: updated_chunks_) {
auto ch = chunks_.find(pos); auto ch = chunks_.find(pos);
if (ch != chunks_.end()) { 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 Целия файл



std::unique_lock<std::mutex> lock(cb.mut_); std::unique_lock<std::mutex> lock(cb.mut_);
cb.cond_.wait(lock, [&] { return cb.done_; }); 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); png::image<png::rgb_pixel> image(Swan::CHUNK_WIDTH, Swan::CHUNK_HEIGHT);
for (int y = 0; y < Swan::CHUNK_HEIGHT; ++y) { for (int y = 0; y < Swan::CHUNK_HEIGHT; ++y) {

Loading…
Отказ
Запис