Browse Source

more lighting

fix/style
Martin Dørum 3 years ago
parent
commit
d00aea0dca
3 changed files with 111 additions and 35 deletions
  1. 8
    5
      libswan/include/swan/LightServer.h
  2. 8
    0
      libswan/include/swan/Vector2.h
  3. 95
    30
      libswan/src/LightServer.cc

+ 8
- 5
libswan/include/swan/LightServer.h View File



struct NewLightChunk { struct NewLightChunk {
std::bitset<CHUNK_WIDTH * CHUNK_HEIGHT> blocks; std::bitset<CHUNK_WIDTH * CHUNK_HEIGHT> blocks;
std::map<std::pair<int, int>, int> light_sources;
std::map<std::pair<int, int>, float> light_sources;
}; };


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


bool was_updated = false; bool was_updated = false;
}; };
bool tileIsSolid(TilePos pos); bool tileIsSolid(TilePos pos);
LightChunk *getChunk(ChunkPos cpos); LightChunk *getChunk(ChunkPos cpos);


int recalcTile(
float recalcTile(
LightChunk &chunk, ChunkPos cpos, Vec2i rpos, TilePos base, LightChunk &chunk, ChunkPos cpos, Vec2i rpos, TilePos base,
std::vector<std::pair<TilePos, int>> &lights);
void processUpdatedChunk(LightChunk &chunk, ChunkPos cpos);
std::vector<std::pair<TilePos, float>> &lights);
void processChunkLights(LightChunk &chunk, ChunkPos cpos);
void processChunkBounces(LightChunk &chunk, ChunkPos cpos);
void processChunkSmoothing(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();



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

return scale(s, s); return scale(s, s);
} }


constexpr Vector2<T> norm() {
return *this / length();
}

constexpr T dot(const Vector2<T> &vec) const {
return x * vec.x + y * vec.y;
}

constexpr operator std::pair<T, T>() const { constexpr operator std::pair<T, T>() const {
return std::pair<T, T>(x, y); return std::pair<T, T>(x, y);
} }

+ 95
- 30
libswan/src/LightServer.cc View File

} }
} }


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


constexpr int accuracy = 4; constexpr int accuracy = 4;
}; };


bool hit = false; bool hit = false;
while ((currpos - from).squareLength() <= diff.squareLength()) {
Vec2i target = TilePos(floor(to.x), floor(to.y));
while (currtile != target && (currpos - from).squareLength() <= diff.squareLength()) {
if (tileIsSolid(currtile)) { if (tileIsSolid(currtile)) {
hit = true; hit = true;
break; break;
return hit; return hit;
}; };


int acc = 0;
auto diffusedRaycast = [&](Vec2 from, Vec2 to, Vec2 norm) {
if (raycast(from, to)) {
return 0.0f;
}

float dot = (to - from).norm().dot(norm);
if (dot > 1) dot = 1;
else if (dot < 0) dot = 0;
return dot;
};

float acc = 0;
for (auto &[lightpos, level]: lights) { for (auto &[lightpos, level]: lights) {
if (lightpos == pos) { if (lightpos == pos) {
acc += level; acc += level;
} }


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


if (!tileIsSolid(pos)) { if (!tileIsSolid(pos)) {
bool hit = raycast( bool hit = raycast(
continue; continue;
} }


bool blocked =
raycast(
float frac =
diffusedRaycast(
Vec2(pos.x + 0.5, pos.y - 0.1), Vec2(pos.x + 0.5, pos.y - 0.1),
Vec2(lightpos.x + 0.5, lightpos.y + 0.5)) &&
raycast(
Vec2(lightpos.x + 0.5, lightpos.y + 0.5),
Vec2(0, -1)) +
diffusedRaycast(
Vec2(pos.x + 0.5, pos.y + 1.1), Vec2(pos.x + 0.5, pos.y + 1.1),
Vec2(lightpos.x + 0.5, lightpos.y + 0.5)) &&
raycast(
Vec2(lightpos.x + 0.5, lightpos.y + 0.5),
Vec2(0, 1)) +
diffusedRaycast(
Vec2(pos.x - 0.1, pos.y + 0.5), Vec2(pos.x - 0.1, pos.y + 0.5),
Vec2(lightpos.x + 0.5, lightpos.y + 0.5)) &&
raycast(
Vec2(lightpos.x + 0.5, lightpos.y + 0.5),
Vec2(-1, 0)) +
diffusedRaycast(
Vec2(pos.x + 1.1, pos.y + 0.5), Vec2(pos.x + 1.1, pos.y + 0.5),
Vec2(lightpos.x + 0.5, lightpos.y + 0.5));

if (!blocked) {
acc += light;
}
Vec2(lightpos.x + 0.5, lightpos.y + 0.5),
Vec2(1, 0));


if (acc >= 255) {
return 255;
}
acc += light * frac;
} }


return acc; return acc;
} }


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


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


chunk.bounces.clear();
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] =
recalcTile(chunk, cpos, Vec2i(x, y), base, lights);
float light = recalcTile(chunk, cpos, Vec2i(x, y), base, lights);
chunk.light_levels[y * CHUNK_WIDTH + x] = std::min((int)light, 255);

if (light > 0 && chunk.blocks[y * CHUNK_WIDTH + x]) {
chunk.bounces.emplace_back(base + Vec2i(x, y), light);
}
} }
} }
}

void LightServer::processChunkBounces(LightChunk &chunk, ChunkPos cpos) {
TilePos base = cpos * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT);
std::vector<std::pair<TilePos, float>> lights;

for (auto &light: chunk.bounces) {
lights.emplace_back(light);
}


auto end = std::chrono::steady_clock::now();
auto dur = std::chrono::duration<double, std::milli>(end - start);
info << "Generating light for " << cpos << " took " << dur.count() << "ms";
auto addLightFromChunk = [&](LightChunk *chunk) {
if (chunk == nullptr) {
return;
}

for (auto &light: chunk->bounces) {
lights.emplace_back(light);
}
};

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

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) * 0.1;
float sum = chunk.light_levels[y * CHUNK_WIDTH + x] + light;
chunk.light_levels[y * CHUNK_WIDTH + x] = std::min((int)sum, 255);
}
}
}

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) {
}
}
} }


void LightServer::run() { void LightServer::run() {
buf.clear(); buf.clear();
newChunks.clear(); newChunks.clear();


auto start = std::chrono::steady_clock::now();

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

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, ChunkPos(pos.first, pos.second));
processChunkBounces(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()
<< " chunks took " << dur.count() << "ms";

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()) {

Loading…
Cancel
Save