Browse Source

some light smoothing

fix/style
Martin Dørum 3 years ago
parent
commit
7bc2c743bc
2 changed files with 113 additions and 10 deletions
  1. 1
    0
      libswan/include/swan/LightServer.h
  2. 112
    10
      libswan/src/LightServer.cc

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

@@ -24,6 +24,7 @@ struct LightChunk {

std::bitset<CHUNK_WIDTH * CHUNK_HEIGHT> blocks;
uint8_t light_levels[CHUNK_WIDTH * CHUNK_HEIGHT] = { 0 };
float light_buffer[CHUNK_WIDTH * CHUNK_HEIGHT] = { 0 };
uint8_t blocks_line[CHUNK_WIDTH] = { 0 };
std::map<std::pair<int, int>, float> light_sources;
std::vector<std::pair<TilePos, float>> bounces;

+ 112
- 10
libswan/src/LightServer.cc View File

@@ -24,13 +24,17 @@ static Vec2i lightRelPos(TilePos pos) {
CHUNK_HEIGHT)) % CHUNK_HEIGHT);
}

static float attenuate(float dist) {
float a = 1 / (1 + dist);
static float attenuate(float dist, float squareDist) {
float a = 1 / (1 + 1.0 * dist + 0.5 * squareDist);
return a > 1 ? 1 : a;
}

static float attenuate(float dist) {
return attenuate(dist, dist * dist);
}

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

LightServer::LightServer(LightCallback &cb):
@@ -305,8 +309,7 @@ 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)round(light), 255);
chunk.light_buffer[y * CHUNK_WIDTH + x] = light;

if (light > 0 && chunk.blocks[y * CHUNK_WIDTH + x]) {
chunk.bounces.emplace_back(base + Vec2i(x, y), light * 0.1);
@@ -343,17 +346,109 @@ void LightServer::processChunkBounces(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);
float sum = chunk.light_levels[y * CHUNK_WIDTH + x] + light;
chunk.light_levels[y * CHUNK_WIDTH + x] =
std::min((int)round(sum), 255);
float sum = chunk.light_buffer[y * CHUNK_WIDTH + x] + light;
chunk.light_buffer[y * CHUNK_WIDTH + x] = sum;
}
}
}

void LightServer::processChunkSmoothing(LightChunk &chunk, ChunkPos cpos) {
for (int y = 1; y < CHUNK_HEIGHT - 1; ++y) {
for (int x = 1; x < CHUNK_WIDTH - 1; ++x) {
LightChunk *tc = getChunk(cpos + Vec2i(0, -1));
LightChunk *bc = getChunk(cpos + Vec2i(0, 1));
LightChunk *lc = getChunk(cpos + Vec2i(-1, 0));
LightChunk *rc = getChunk(cpos + Vec2i(1, 0));

auto getLight = [&](LightChunk &chunk, int x, int y) {
return chunk.light_buffer[y * CHUNK_WIDTH + x];
};

auto calc = [&](int x1, int x2, int y1, int y2, auto tf, auto bf, auto lf, auto rf) {
for (int y = y1; y < y2; ++y) {
for (int x = x1; x < x2; ++x) {
float t = tf(x, y);
float b = bf(x, y);
float l = lf(x, y);
float r = rf(x, y);
float light = chunk.light_buffer[y * CHUNK_WIDTH + x];
int count = 1;
if (t > light) { light += t; count += 1; }
if (b > light) { light += b; count += 1; }
if (l > light) { light += l; count += 1; }
if (r > light) { light += r; count += 1; }
light = std::min(light / count, 255.0f);
chunk.light_levels[y * CHUNK_WIDTH + x] = light;
}
}
};

calc(1, CHUNK_WIDTH - 1, 1, CHUNK_HEIGHT - 1,
[&](int x, int y) { return getLight(chunk, x, y - 1); },
[&](int x, int y) { return getLight(chunk, x, y + 1); },
[&](int x, int y) { return getLight(chunk, x - 1, y); },
[&](int x, int y) { return getLight(chunk, x + 1, y); });

if (tc) {
calc(1, CHUNK_WIDTH - 1, 0, 1,
[&](int x, int y) { return tc->light_buffer[(CHUNK_HEIGHT - 1) * CHUNK_WIDTH + x]; },
[&](int x, int y) { return getLight(chunk, x, y + 1); },
[&](int x, int y) { return getLight(chunk, x - 1, y); },
[&](int x, int y) { return getLight(chunk, x + 1, y); });
}

if (bc) {
calc(1, CHUNK_WIDTH - 1, CHUNK_HEIGHT - 1, CHUNK_HEIGHT,
[&](int x, int y) { return getLight(chunk, x, y - 1); },
[&](int x, int y) { return bc->light_buffer[x]; },
[&](int x, int y) { return getLight(chunk, x - 1, y); },
[&](int x, int y) { return getLight(chunk, x + 1, y); });
}

if (lc) {
calc(0, 1, 1, CHUNK_HEIGHT - 1,
[&](int x, int y) { return getLight(chunk, x, y - 1); },
[&](int x, int y) { return getLight(chunk, x, y + 1); },
[&](int x, int y) { return lc->light_buffer[y * CHUNK_WIDTH + CHUNK_WIDTH - 1]; },
[&](int x, int y) { return getLight(chunk, x + 1, y); });
}

if (rc) {
calc(CHUNK_WIDTH - 1, CHUNK_WIDTH, 1, CHUNK_HEIGHT - 1,
[&](int x, int y) { return getLight(chunk, x, y - 1); },
[&](int x, int y) { return getLight(chunk, x, y + 1); },
[&](int x, int y) { return getLight(chunk, x - 1, y); },
[&](int x, int y) { return rc->light_buffer[y * CHUNK_WIDTH]; });
}

if (tc && lc) {
calc(0, 1, 0, 1,
[&](int x, int y) { return tc->light_buffer[(CHUNK_HEIGHT - 1) * CHUNK_WIDTH + x]; },
[&](int x, int y) { return getLight(chunk, x, y + 1); },
[&](int x, int y) { return lc->light_buffer[y * CHUNK_WIDTH + CHUNK_WIDTH - 1]; },
[&](int x, int y) { return getLight(chunk, x + 1, y); });
}

if (tc && rc) {
calc(CHUNK_WIDTH - 1, CHUNK_WIDTH, 0, 1,
[&](int x, int y) { return tc->light_buffer[(CHUNK_HEIGHT - 1) * CHUNK_WIDTH + x]; },
[&](int x, int y) { return getLight(chunk, x, y + 1); },
[&](int x, int y) { return getLight(chunk, x - 1, y); },
[&](int x, int y) { return rc->light_buffer[y * CHUNK_WIDTH]; });
}

if (bc && lc) {
calc(0, 1, CHUNK_HEIGHT - 1, CHUNK_HEIGHT,
[&](int x, int y) { return getLight(chunk, x, y - 1); },
[&](int x, int y) { return bc->light_buffer[x]; },
[&](int x, int y) { return lc->light_buffer[y * CHUNK_WIDTH + CHUNK_WIDTH - 1]; },
[&](int x, int y) { return getLight(chunk, x + 1, y); });
}

if (bc && rc) {
calc(CHUNK_WIDTH - 1, CHUNK_WIDTH, CHUNK_HEIGHT - 1, CHUNK_HEIGHT,
[&](int x, int y) { return getLight(chunk, x, y - 1); },
[&](int x, int y) { return bc->light_buffer[x]; },
[&](int x, int y) { return getLight(chunk, x - 1, y); },
[&](int x, int y) { return rc->light_buffer[y * CHUNK_WIDTH]; });
}
}

@@ -392,6 +487,13 @@ void LightServer::run() {
}
}

for (auto &pos: updated_chunks_) {
auto ch = chunks_.find(pos);
if (ch != chunks_.end()) {
processChunkSmoothing(ch->second, ChunkPos(pos.first, pos.second));
}
}

auto end = std::chrono::steady_clock::now();
auto dur = std::chrono::duration<double, std::milli>(end - start);
info << "Generating light for " << updated_chunks_.size()

Loading…
Cancel
Save