#include "Lighting.hpp" #include "LightSolver.hpp" #include "Lightmap.hpp" #include "../content/Content.hpp" #include "../voxels/Chunks.hpp" #include "../voxels/Chunk.hpp" #include "../voxels/voxel.hpp" #include "../voxels/Block.hpp" #include "../constants.hpp" #include "../util/timeutil.hpp" #include Lighting::Lighting(const Content* content, Chunks* chunks) : content(content), chunks(chunks) { auto indices = content->getIndices(); solverR = std::make_unique(indices, chunks, 0); solverG = std::make_unique(indices, chunks, 1); solverB = std::make_unique(indices, chunks, 2); solverS = std::make_unique(indices, chunks, 3); } Lighting::~Lighting() = default; void Lighting::clear(){ for (size_t index = 0; index < chunks->volume; index++){ auto chunk = chunks->chunks[index]; if (chunk == nullptr) continue; Lightmap& lightmap = chunk->lightmap; for (int i = 0; i < CHUNK_VOL; i++){ lightmap.map[i] = 0; } } } void Lighting::prebuildSkyLight(Chunk* chunk, const ContentIndices* indices){ const auto* blockDefs = indices->blocks.getDefs(); int highestPoint = 0; for (int z = 0; z < CHUNK_D; z++){ for (int x = 0; x < CHUNK_W; x++){ for (int y = CHUNK_H-1; y >= 0; y--){ int index = (y * CHUNK_D + z) * CHUNK_W + x; voxel& vox = chunk->voxels[index]; const Block* block = blockDefs[vox.id]; if (!block->skyLightPassing) { if (highestPoint < y) highestPoint = y; break; } chunk->lightmap.setS(x,y,z, 15); } } } if (highestPoint < CHUNK_H-1) highestPoint++; chunk->lightmap.highestPoint = highestPoint; } void Lighting::buildSkyLight(int cx, int cz){ const auto blockDefs = content->getIndices()->blocks.getDefs(); Chunk* chunk = chunks->getChunk(cx, cz); for (int z = 0; z < CHUNK_D; z++){ for (int x = 0; x < CHUNK_W; x++){ int gx = x + cx * CHUNK_W; int gz = z + cz * CHUNK_D; for (int y = chunk->lightmap.highestPoint; y >= 0; y--){ while (y > 0 && !blockDefs[chunk->voxels[vox_index(x, y, z)].id]->lightPassing) { y--; } if (chunk->lightmap.getS(x, y, z) != 15) { solverS->add(gx,y+1,gz); for (; y >= 0; y--){ solverS->add(gx+1,y,gz); solverS->add(gx-1,y,gz); solverS->add(gx,y,gz+1); solverS->add(gx,y,gz-1); } } } } } solverS->solve(); } void Lighting::onChunkLoaded(int cx, int cz, bool expand){ LightSolver* solverR = this->solverR.get(); LightSolver* solverG = this->solverG.get(); LightSolver* solverB = this->solverB.get(); LightSolver* solverS = this->solverS.get(); auto blockDefs = content->getIndices()->blocks.getDefs(); auto chunk = chunks->getChunk(cx, cz); for (uint y = 0; y < CHUNK_H; y++){ for (uint z = 0; z < CHUNK_D; z++){ for (uint x = 0; x < CHUNK_W; x++){ const voxel& vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x]; const Block* block = blockDefs[vox.id]; int gx = x + cx * CHUNK_W; int gz = z + cz * CHUNK_D; if (block->rt.emissive){ solverR->add(gx,y,gz,block->emission[0]); solverG->add(gx,y,gz,block->emission[1]); solverB->add(gx,y,gz,block->emission[2]); } } } } if (expand) { for (int x = 0; x < CHUNK_W; x += CHUNK_W-1) { for (int y = 0; y < CHUNK_H; y++) { for (int z = 0; z < CHUNK_D; z++) { int gx = x + cx * CHUNK_W; int gz = z + cz * CHUNK_D; int rgbs = chunk->lightmap.get(x, y, z); if (rgbs){ solverR->add(gx,y,gz, Lightmap::extract(rgbs, 0)); solverG->add(gx,y,gz, Lightmap::extract(rgbs, 1)); solverB->add(gx,y,gz, Lightmap::extract(rgbs, 2)); solverS->add(gx,y,gz, Lightmap::extract(rgbs, 3)); } } } } for (int z = 0; z < CHUNK_D; z += CHUNK_D-1) { for (int y = 0; y < CHUNK_H; y++) { for (int x = 0; x < CHUNK_W; x++) { int gx = x + cx * CHUNK_W; int gz = z + cz * CHUNK_D; int rgbs = chunk->lightmap.get(x, y, z); if (rgbs){ solverR->add(gx,y,gz, Lightmap::extract(rgbs, 0)); solverG->add(gx,y,gz, Lightmap::extract(rgbs, 1)); solverB->add(gx,y,gz, Lightmap::extract(rgbs, 2)); solverS->add(gx,y,gz, Lightmap::extract(rgbs, 3)); } } } } } solverR->solve(); solverG->solve(); solverB->solve(); solverS->solve(); } void Lighting::onBlockSet(int x, int y, int z, blockid_t id){ const auto& block = content->getIndices()->blocks.require(id); solverR->remove(x,y,z); solverG->remove(x,y,z); solverB->remove(x,y,z); if (id == 0){ solverR->solve(); solverG->solve(); solverB->solve(); if (chunks->getLight(x,y+1,z, 3) == 0xF){ for (int i = y; i >= 0; i--){ voxel* vox = chunks->get(x,i,z); if ((vox == nullptr || vox->id != 0) && block.skyLightPassing) break; solverS->add(x,i,z, 0xF); } } solverR->add(x,y+1,z); solverG->add(x,y+1,z); solverB->add(x,y+1,z); solverS->add(x,y+1,z); solverR->add(x,y-1,z); solverG->add(x,y-1,z); solverB->add(x,y-1,z); solverS->add(x,y-1,z); solverR->add(x+1,y,z); solverG->add(x+1,y,z); solverB->add(x+1,y,z); solverS->add(x+1,y,z); solverR->add(x-1,y,z); solverG->add(x-1,y,z); solverB->add(x-1,y,z); solverS->add(x-1,y,z); solverR->add(x,y,z+1); solverG->add(x,y,z+1); solverB->add(x,y,z+1); solverS->add(x,y,z+1); solverR->add(x,y,z-1); solverG->add(x,y,z-1); solverB->add(x,y,z-1); solverS->add(x,y,z-1); solverR->solve(); solverG->solve(); solverB->solve(); solverS->solve(); } else { if (!block.skyLightPassing){ solverS->remove(x,y,z); for (int i = y-1; i >= 0; i--){ solverS->remove(x,i,z); if (i == 0 || chunks->get(x,i-1,z)->id != 0){ break; } } solverS->solve(); } solverR->solve(); solverG->solve(); solverB->solve(); if (block.emission[0] || block.emission[1] || block.emission[2]){ solverR->add(x,y,z,block.emission[0]); solverG->add(x,y,z,block.emission[1]); solverB->add(x,y,z,block.emission[2]); solverR->solve(); solverG->solve(); solverB->solve(); } } }