Browse Source

lighting

fix/style
Martin Dørum 3 years ago
parent
commit
8f2e3578ea
4 changed files with 77 additions and 40 deletions
  1. 1
    1
      core.mod/src/main.cc
  2. 14
    12
      libswan/include/swan/LightServer.h
  3. 3
    7
      libswan/src/Chunk.cc
  4. 59
    20
      libswan/src/LightServer.cc

+ 1
- 1
core.mod/src/main.cc View File

@@ -48,7 +48,7 @@ public:
.name = "torch",
.image = "core/tile/torch",
.is_solid = false,
.light_level = 20,
.light_level = 40,
});

registerItem({

+ 14
- 12
libswan/include/swan/LightServer.h View File

@@ -43,13 +43,14 @@ public:

void onSolidBlockAdded(TilePos pos);
void onSolidBlockRemoved(TilePos pos);
void onLightAdded(TilePos pos, int level);
void onLightRemoved(TilePos pos, int level);
void onLightAdded(TilePos pos, float level);
void onLightRemoved(TilePos pos, float level);
void onChunkAdded(ChunkPos pos, NewLightChunk &&chunk);
void onChunkRemoved(ChunkPos pos);

private:
static constexpr int LIGHT_CUTOFF = 64;
static constexpr int LIGHT_CUTOFF_DIST = 64;
static constexpr float LIGHT_CUTOFF = 1;

struct Event {
enum class Tag {
@@ -59,7 +60,8 @@ private:

TilePos pos;
union {
int num;
float f;
int i;
};
};

@@ -92,39 +94,39 @@ private:

inline void LightServer::onSolidBlockAdded(TilePos pos) {
std::lock_guard<std::mutex> lock(mut_);
buffers_[buffer_].push_back({ Event::Tag::BLOCK_ADDED, pos, { 0 } });
buffers_[buffer_].push_back({ Event::Tag::BLOCK_ADDED, pos, { .i = 0 } });
cond_.notify_one();
}

inline void LightServer::onSolidBlockRemoved(TilePos pos) {
std::lock_guard<std::mutex> lock(mut_);
buffers_[buffer_].push_back({ Event::Tag::BLOCK_REMOVED, pos, { 0 } });
buffers_[buffer_].push_back({ Event::Tag::BLOCK_REMOVED, pos, { .i = 0 } });
cond_.notify_one();
}

inline void LightServer::onLightAdded(TilePos pos, int level) {
inline void LightServer::onLightAdded(TilePos pos, float level) {
std::lock_guard<std::mutex> lock(mut_);
buffers_[buffer_].push_back({ Event::Tag::LIGHT_ADDED, pos, { .num = level } });
buffers_[buffer_].push_back({ Event::Tag::LIGHT_ADDED, pos, { .f = level } });
cond_.notify_one();
}

inline void LightServer::onLightRemoved(TilePos pos, int level) {
inline void LightServer::onLightRemoved(TilePos pos, float level) {
std::lock_guard<std::mutex> lock(mut_);
buffers_[buffer_].push_back({ Event::Tag::LIGHT_REMOVED, pos, { .num = level } });
buffers_[buffer_].push_back({ Event::Tag::LIGHT_REMOVED, pos, { .f = level } });
cond_.notify_one();
}

inline void LightServer::onChunkAdded(Vec2i pos, NewLightChunk &&chunk) {
std::lock_guard<std::mutex> lock(mut_);
buffers_[buffer_].push_back({ Event::Tag::CHUNK_ADDED, pos,
{ .num = (int)new_chunk_buffers_[buffer_].size() } });
{ .i = (int)new_chunk_buffers_[buffer_].size() } });
new_chunk_buffers_[buffer_].push_back(std::move(chunk));
cond_.notify_one();
}

inline void LightServer::onChunkRemoved(Vec2i pos) {
std::lock_guard<std::mutex> lock(mut_);
buffers_[buffer_].push_back({ Event::Tag::CHUNK_ADDED, pos, { 0 } });
buffers_[buffer_].push_back({ Event::Tag::CHUNK_REMOVED, pos, { .i = 0 } });
cond_.notify_one();
}


+ 3
- 7
libswan/src/Chunk.cc View File

@@ -3,6 +3,7 @@
#include <zlib.h>
#include <stdint.h>
#include <assert.h>
#include <algorithm>

#include "log.h"
#include "Clock.h"
@@ -95,13 +96,8 @@ void Chunk::renderLight(const Context &ctx, SDL_Renderer *rnd) {
for (int x = 0; x < CHUNK_WIDTH; ++x) {
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 if (l > 0) {
color.change(0, 0, 0, 255 - l * (255 * 2));
} else {
color.change(0, 0, 0, 255);
}
int b = std::clamp((int)(l * 1.5 * 255), 0, 255);
color.change(0, 0, 0, 255 - b);
SDL_Rect rect{ x, y, 1, 1 };
SDL_RenderFillRect(rnd, &rect);
}

+ 59
- 20
libswan/src/LightServer.cc View File

@@ -1,5 +1,7 @@
#include "LightServer.h"

#include <algorithm>

#include "log.h"

namespace Swan {
@@ -22,6 +24,15 @@ static Vec2i lightRelPos(TilePos pos) {
CHUNK_HEIGHT)) % CHUNK_HEIGHT);
}

static float attenuate(float dist) {
float a = 1 / (1 + dist);
return a > 1 ? 1 : a;
}

static float attenuateSquared(float squareDist) {
return attenuate(sqrt(squareDist));
}

LightServer::LightServer(LightCallback &cb):
cb_(cb), thread_(&LightServer::run, this) {}

@@ -66,12 +77,7 @@ void LightServer::processEvent(const Event &evt, std::vector<NewLightChunk> &new
}
};

auto markChunksModified = [&](ChunkPos cpos, Vec2i rpos, int range) {
bool l = rpos.x - range <= 0;
bool r = rpos.x + range >= CHUNK_WIDTH - 1;
bool t = rpos.y - range <= 0;
bool b = rpos.y + range >= CHUNK_HEIGHT - 1;

auto markChunks = [&](ChunkPos cpos, Vec2i rpos, bool l, bool r, bool t, bool b) {
updated_chunks_.insert(cpos);
if (l) updated_chunks_.insert(cpos + Vec2i(-1, 0));
if (r) updated_chunks_.insert(cpos + Vec2i(1, 0));
@@ -83,10 +89,26 @@ void LightServer::processEvent(const Event &evt, std::vector<NewLightChunk> &new
if (r && b) updated_chunks_.insert(cpos + Vec2i(1, 1));
};

auto markChunksModified = [&](ChunkPos cpos, Vec2i rpos, float light) {
markChunks(cpos, rpos,
light * attenuate(rpos.x) > LIGHT_CUTOFF,
light * attenuate(CHUNK_WIDTH - rpos.x) > LIGHT_CUTOFF,
light * attenuate(rpos.y) > LIGHT_CUTOFF,
light * attenuate(CHUNK_HEIGHT - rpos.y) > LIGHT_CUTOFF);
};

auto markChunksModifiedRange = [&](ChunkPos cpos, Vec2i rpos, int range) {
markChunks(cpos, rpos,
rpos.x <= range,
CHUNK_WIDTH - rpos.x <= range,
rpos.y <= range,
CHUNK_WIDTH - rpos.y <= range);
};

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])));
std::forward_as_tuple(std::move(newChunks[evt.i])));
markAdjacentChunksModified(evt.pos);
return;
} else if (evt.tag == Event::Tag::CHUNK_REMOVED) {
@@ -104,26 +126,26 @@ void LightServer::processEvent(const Event &evt, std::vector<NewLightChunk> &new
case Event::Tag::BLOCK_ADDED:
ch->blocks.set(rpos.y * CHUNK_WIDTH + rpos.x, true);
ch->blocks_line[rpos.x] += 1;
markChunksModified(cpos, rpos, LIGHT_CUTOFF);
markChunksModifiedRange(cpos, rpos, LIGHT_CUTOFF_DIST);
break;

case Event::Tag::BLOCK_REMOVED:
ch->blocks.set(rpos.y * CHUNK_WIDTH + rpos.x, false);
ch->blocks_line[rpos.x] -= 1;
markChunksModified(cpos, rpos, LIGHT_CUTOFF);
markChunksModifiedRange(cpos, rpos, LIGHT_CUTOFF_DIST);
break;

case Event::Tag::LIGHT_ADDED:
info << cpos << ": Add " << evt.num << " light to " << rpos;
ch->light_sources[rpos] += evt.num;
info << cpos << ": Add " << evt.f << " light to " << rpos;
ch->light_sources[rpos] += evt.f;
markChunksModified(cpos, rpos, ch->light_sources[rpos]);
break;

case Event::Tag::LIGHT_REMOVED:
info << cpos << ": Remove " << evt.num << " light to " << rpos;
info << cpos << ": Remove " << evt.f << " light to " << rpos;
markChunksModified(cpos, rpos, ch->light_sources[rpos]);
ch->light_sources[rpos] -= evt.num;
if (ch->light_sources[rpos] == 0) {
ch->light_sources[rpos] -= evt.f;
if (ch->light_sources[rpos] < LIGHT_CUTOFF) {
ch->light_sources.erase(rpos);
}
break;
@@ -180,6 +202,14 @@ float LightServer::recalcTile(
return dot;
};

bool isSolid = tileIsSolid(pos);

bool culled =
tileIsSolid(pos + Vec2i(-1, 0)) &&
tileIsSolid(pos + Vec2i(1, 0)) &&
tileIsSolid(pos + Vec2i(0, -1)) &&
tileIsSolid(pos + Vec2i(0, 1));

float acc = 0;
for (auto &[lightpos, level]: lights) {
if (lightpos == pos) {
@@ -187,14 +217,21 @@ float LightServer::recalcTile(
continue;
}

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

int squareDist = (lightpos - pos).squareLength();
if (squareDist > LIGHT_CUTOFF_DIST * LIGHT_CUTOFF_DIST) {
continue;
}

float dist = ((Vec2)(lightpos - pos)).length();
float light = level - dist;
float light = level * attenuateSquared(squareDist);
if (light < LIGHT_CUTOFF) {
continue;
}

if (!tileIsSolid(pos)) {
if (!isSolid) {
bool hit = raycast(
Vec2(pos.x + 0.5, pos.y + 0.5),
Vec2(lightpos.x + 0.5, lightpos.y + 0.5));
@@ -259,7 +296,8 @@ void LightServer::processChunkLights(LightChunk &chunk, ChunkPos cpos) {
for (int y = 0; y < CHUNK_HEIGHT; ++y) {
for (int x = 0; x < CHUNK_WIDTH; ++x) {
float light = recalcTile(chunk, cpos, Vec2i(x, y), base, lights);
chunk.light_levels[y * CHUNK_WIDTH + x] = std::min((int)light, 255);
chunk.light_levels[y * CHUNK_WIDTH + x] =
std::min((int)round(light), 255);

if (light > 0 && chunk.blocks[y * CHUNK_WIDTH + x]) {
chunk.bounces.emplace_back(base + Vec2i(x, y), light);
@@ -297,7 +335,8 @@ void LightServer::processChunkBounces(LightChunk &chunk, ChunkPos cpos) {
for (int x = 0; x < CHUNK_WIDTH; ++x) {
float light = recalcTile(chunk, cpos, Vec2i(x, y), base, lights) * 0.1;
float sum = chunk.light_levels[y * CHUNK_WIDTH + x] + light;
chunk.light_levels[y * CHUNK_WIDTH + x] = std::min((int)sum, 255);
chunk.light_levels[y * CHUNK_WIDTH + x] =
std::min((int)round(sum), 255);
}
}
}

Loading…
Cancel
Save