diff --git a/src/lighting/LightSolver.cpp b/src/lighting/LightSolver.cpp index be608f1d..cda3ccc8 100644 --- a/src/lighting/LightSolver.cpp +++ b/src/lighting/LightSolver.cpp @@ -16,18 +16,23 @@ LightSolver::LightSolver(const ContentIndices& contentIds, Chunks& chunks, int c } void LightSolver::add(int x, int y, int z, int emission) { - if (emission <= 1) + if (emission <= 1) { return; + } Chunk* chunk = chunks.getChunkByVoxel(x, y, z); - if (chunk == nullptr) + if (chunk == nullptr) { return; - ubyte light = chunk->lightmap.get(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel); + } + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; + + ubyte light = lightmap.get(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel); if (emission < light) return; addqueue.push(lightentry {x, y, z, ubyte(emission)}); chunk->flags.modified = true; - chunk->lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, emission); + lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, emission); } void LightSolver::add(int x, int y, int z) { @@ -36,15 +41,18 @@ void LightSolver::add(int x, int y, int z) { void LightSolver::remove(int x, int y, int z) { Chunk* chunk = chunks.getChunkByVoxel(x, y, z); - if (chunk == nullptr) + if (chunk == nullptr) { return; + } + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; - ubyte light = chunk->lightmap.get(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel); - if (light == 0){ + ubyte light = lightmap.get(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel); + if (light == 0) { return; } remqueue.push(lightentry {x, y, z, light}); - chunk->lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, 0); + lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, 0); } void LightSolver::solve(){ @@ -73,18 +81,21 @@ void LightSolver::solve(){ int lz = z - chunk->z * CHUNK_D; chunk->flags.modified = true; - ubyte light = chunk->lightmap.get(lx,y,lz, channel); + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; + + ubyte light = lightmap.get(lx,y,lz, channel); if (light != 0 && light == entry.light-1){ voxel* vox = chunks.get(x, y, z); if (vox && vox->id != 0) { const Block* block = blockDefs[vox->id]; if (uint8_t emission = block->emission[channel]) { addqueue.push(lightentry {x, y, z, emission}); - chunk->lightmap.set(lx, y, lz, channel, emission); + lightmap.set(lx, y, lz, channel, emission); } - else chunk->lightmap.set(lx, y, lz, channel, 0); + else lightmap.set(lx, y, lz, channel, 0); } - else chunk->lightmap.set(lx, y, lz, channel, 0); + else lightmap.set(lx, y, lz, channel, 0); remqueue.push(lightentry {x, y, z, light}); } else if (light >= entry.light){ @@ -105,21 +116,24 @@ void LightSolver::solve(){ int z = entry.z+coords[imul3+2]; Chunk* chunk = chunks.getChunkByVoxel(x,y,z); - if (chunk) { - int lx = x - chunk->x * CHUNK_W; - int lz = z - chunk->z * CHUNK_D; - chunk->flags.modified = true; + if (chunk == nullptr) { + continue; + } + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; + int lx = x - chunk->x * CHUNK_W; + int lz = z - chunk->z * CHUNK_D; + chunk->flags.modified = true; - ubyte light = chunk->lightmap.get(lx, y, lz, channel); - voxel& v = chunk->voxels[vox_index(lx, y, lz)]; - const Block* block = blockDefs[v.id]; - if (block->lightPassing && light+2 <= entry.light){ - chunk->lightmap.set( - x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, - channel, - entry.light-1); - addqueue.push(lightentry {x, y, z, ubyte(entry.light-1)}); - } + ubyte light = lightmap.get(lx, y, lz, channel); + voxel& v = chunk->voxels[vox_index(lx, y, lz)]; + const Block* block = blockDefs[v.id]; + if (block->lightPassing && light+2 <= entry.light){ + lightmap.set( + x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, + channel, + entry.light-1); + addqueue.push(lightentry {x, y, z, ubyte(entry.light-1)}); } } } diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp index eb721db2..9101c72a 100644 --- a/src/lighting/Lighting.cpp +++ b/src/lighting/Lighting.cpp @@ -29,16 +29,21 @@ void Lighting::clear(){ const auto& chunks = this->chunks.getChunks(); for (size_t index = 0; index < chunks.size(); index++){ auto chunk = chunks[index]; - if (chunk == nullptr) + if (chunk == nullptr) { continue; - Lightmap& lightmap = chunk->lightmap; - for (int i = 0; i < CHUNK_VOL; i++){ - lightmap.map[i] = 0; } + auto& lightmap = chunk->lightmap; + if (lightmap == nullptr) { + continue; + } + std::memset(lightmap->map, 0, sizeof(Lightmap::map)); } } -void Lighting::prebuildSkyLight(Chunk& chunk, const ContentIndices& indices){ +void Lighting::prebuildSkyLight(Chunk& chunk, const ContentIndices& indices) { + assert(chunk.lightmap != nullptr); + auto& lightmap = *chunk.lightmap; + const auto* blockDefs = indices.blocks.getDefs(); int highestPoint = 0; @@ -49,17 +54,19 @@ void Lighting::prebuildSkyLight(Chunk& chunk, const ContentIndices& indices){ voxel& vox = chunk.voxels[index]; const Block* block = blockDefs[vox.id]; if (!block->skyLightPassing) { - if (highestPoint < y) + if (highestPoint < y) { highestPoint = y; + } break; } - chunk.lightmap.setS(x,y,z, 15); + lightmap.setS(x, y, z, 15); } } } - if (highestPoint < CHUNK_H-1) + if (highestPoint < CHUNK_H-1) { highestPoint++; - chunk.lightmap.highestPoint = highestPoint; + } + lightmap.highestPoint = highestPoint; } void Lighting::buildSkyLight(int cx, int cz){ @@ -70,15 +77,18 @@ void Lighting::buildSkyLight(int cx, int cz){ logger.error() << "attempted to build sky lights to chunk missing in local matrix"; return; } + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; + 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--){ + for (int y = 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) { + if (lightmap.getS(x, y, z) != 15) { solverS->add(gx,y+1,gz); for (; y >= 0; y--){ solverS->add(gx+1,y,gz); @@ -106,6 +116,9 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) { logger.error() << "attempted to build lights to chunk missing in local matrix"; return; } + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; + for (uint y = 0; y < CHUNK_H; y++){ for (uint z = 0; z < CHUNK_D; z++){ for (uint x = 0; x < CHUNK_W; x++){ @@ -128,7 +141,7 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) { 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); + int rgbs = 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)); @@ -143,7 +156,7 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) { 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); + int rgbs = 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)); diff --git a/src/lighting/Lightmap.hpp b/src/lighting/Lightmap.hpp index d31ace74..b376c0db 100644 --- a/src/lighting/Lightmap.hpp +++ b/src/lighting/Lightmap.hpp @@ -89,4 +89,6 @@ public: std::unique_ptr encode() const; static std::unique_ptr decode(const ubyte* buffer); + + static inline light_t SUN_LIGHT_ONLY = combine(0U, 0U, 0U, 15U); }; diff --git a/src/logic/ChunksController.cpp b/src/logic/ChunksController.cpp index b521b0d8..0c65a8df 100644 --- a/src/logic/ChunksController.cpp +++ b/src/logic/ChunksController.cpp @@ -150,7 +150,7 @@ bool ChunksController::buildLights( } } if (surrounding == MIN_SURROUNDING) { - if (lighting) { + if (lighting && chunk->lightmap) { bool lightsCache = chunk->flags.loadedLights; if (!lightsCache) { lighting->buildSkyLight(chunk->x, chunk->z); @@ -170,7 +170,7 @@ void ChunksController::createChunk(const Player& player, int x, int z) const { } return; } - auto chunk = level.chunks->create(x, z); + auto chunk = level.chunks->create(x, z, lighting != nullptr); player.chunks->putChunk(chunk); auto& chunkFlags = chunk->flags; if (!chunkFlags.loaded) { @@ -179,7 +179,7 @@ void ChunksController::createChunk(const Player& player, int x, int z) const { } chunk->updateHeights(); level.events->trigger(LevelEventType::CHUNK_PRESENT, chunk.get()); - if (!chunkFlags.loadedLights) { + if (!chunkFlags.loadedLights && chunk->lightmap) { Lighting::prebuildSkyLight(*chunk, *level.content.getIndices()); } chunkFlags.loaded = true; diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index eb966f50..7a53c4cb 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -153,8 +153,10 @@ static void integrate_chunk_client(Chunk& chunk) { chunk.flags.loadedLights = false; chunk.flags.lighted = false; - chunk.lightmap.clear(); - Lighting::prebuildSkyLight(chunk, *indices); + if (chunk.lightmap) { + chunk.lightmap->clear(); + Lighting::prebuildSkyLight(chunk, *indices); + } for (int lz = -1; lz <= 1; lz++) { for (int lx = -1; lx <= 1; lx++) { diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index e6da850e..732e67a0 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -8,7 +8,8 @@ #include "util/data_io.hpp" #include "voxel.hpp" -Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos) { +Chunk::Chunk(int xpos, int zpos, std::shared_ptr lightmap) + : x(xpos), z(zpos), lightmap(std::move(lightmap)) { bottom = 0; top = CHUNK_H; } @@ -56,15 +57,6 @@ std::shared_ptr Chunk::getBlockInventory(uint x, uint y, uint z) return found->second; } -std::unique_ptr Chunk::clone() const { - auto other = std::make_unique(x, z); - for (uint i = 0; i < CHUNK_VOL; i++) { - other->voxels[i] = voxels[i]; - } - other->lightmap.set(&lightmap); - return other; -} - /** Current chunk format: - byte-order: little-endian diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index a15907f0..393f05f8 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -27,7 +27,7 @@ public: int x, z; int bottom, top; voxel voxels[CHUNK_VOL] {}; - Lightmap lightmap; + std::shared_ptr lightmap; struct { bool modified : 1; bool ready : 1; @@ -45,14 +45,11 @@ public: /// @brief Blocks metadata heap BlocksMetadata blocksMetadata; - Chunk(int x, int z); + Chunk(int x, int z, std::shared_ptr lightmap=nullptr); /// @brief Refresh `bottom` and `top` values void updateHeights(); - // unused - std::unique_ptr clone() const; - /// @brief Creates new block inventory given size /// @return inventory id or 0 if block does not exists void addBlockInventory( diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index dcdee71e..eded34e8 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -115,9 +115,10 @@ ubyte Chunks::getLight(int32_t x, int32_t y, int32_t z, int channel) const { if (chunk == nullptr) { return 0; } + assert(chunk->lightmap != nullptr); int lx = x - cx * CHUNK_W; int lz = z - cz * CHUNK_D; - return chunk->lightmap.get(lx, y, lz, channel); + return chunk->lightmap->get(lx, y, lz, channel); } light_t Chunks::getLight(int32_t x, int32_t y, int32_t z) const { @@ -135,9 +136,10 @@ light_t Chunks::getLight(int32_t x, int32_t y, int32_t z) const { if (chunk == nullptr) { return 0; } + assert(chunk->lightmap != nullptr); int lx = x - cx * CHUNK_W; int lz = z - cz * CHUNK_D; - return chunk->lightmap.get(lx, y, lz); + return chunk->lightmap->get(lx, y, lz); } Chunk* Chunks::getChunkByVoxel(int32_t x, int32_t y, int32_t z) const { @@ -373,7 +375,8 @@ void Chunks::getVoxels(VoxelsVolume& volume, bool backlight) const { } } else { const voxel* cvoxels = chunk->voxels; - const light_t* clights = chunk->lightmap.getLights(); + const light_t* clights = + chunk->lightmap ? chunk->lightmap->getLights() : nullptr; for (int ly = y; ly < y + h; ly++) { for (int lz = std::max(z, cz * CHUNK_D); lz < std::min(z + d, (cz + 1) * CHUNK_D); @@ -390,7 +393,8 @@ void Chunks::getVoxels(VoxelsVolume& volume, bool backlight) const { CHUNK_D ); voxels[vidx] = cvoxels[cidx]; - light_t light = clights[cidx]; + light_t light = clights ? clights[cidx] + : Lightmap::SUN_LIGHT_ONLY; if (backlight) { const auto block = indices.blocks.get(voxels[vidx].id); diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 438ae6d8..e284fa07 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -91,14 +91,16 @@ static inline auto load_inventories( } static util::ObjectsPool chunks_pool(1'024); +static util::ObjectsPool lightmaps_pool; -std::shared_ptr GlobalChunks::create(int x, int z) { +std::shared_ptr GlobalChunks::create(int x, int z, bool lighting) { const auto& found = chunksMap.find(keyfrom(x, z)); if (found != chunksMap.end()) { return found->second; } - auto chunk = chunks_pool.create(x, z); + auto chunk = + chunks_pool.create(x, z, lighting ? lightmaps_pool.create() : nullptr); chunksMap[keyfrom(x, z)] = chunk; World& world = *level.getWorld(); @@ -125,9 +127,11 @@ std::shared_ptr GlobalChunks::create(int x, int z) { level.inventories->store(entry.second); } } - if (auto lights = regions.getLights(chunk->x, chunk->z)) { - chunk->lightmap.set(lights.get()); - chunk->flags.loadedLights = true; + if (chunk->lightmap) { + if (auto lights = regions.getLights(chunk->x, chunk->z)) { + chunk->lightmap->set(lights.get()); + chunk->flags.loadedLights = true; + } } chunk->blocksMetadata = regions.getBlocksData(chunk->x, chunk->z); return chunk; diff --git a/src/voxels/GlobalChunks.hpp b/src/voxels/GlobalChunks.hpp index 1a554dfd..7120658c 100644 --- a/src/voxels/GlobalChunks.hpp +++ b/src/voxels/GlobalChunks.hpp @@ -40,7 +40,7 @@ public: void setOnUnload(consumer onUnload); std::shared_ptr fetch(int x, int z); - std::shared_ptr create(int x, int z); + std::shared_ptr create(int x, int z, bool lighting); void pinChunk(std::shared_ptr chunk); void unpinChunk(int x, int z); diff --git a/src/voxels/blocks_agent.cpp b/src/voxels/blocks_agent.cpp index 990ff390..ea668f8e 100644 --- a/src/voxels/blocks_agent.cpp +++ b/src/voxels/blocks_agent.cpp @@ -434,7 +434,8 @@ inline void get_voxels_impl( } } else { const voxel* cvoxels = chunk->voxels; - const light_t* clights = chunk->lightmap.getLights(); + const light_t* clights = + chunk->lightmap ? chunk->lightmap->getLights() : nullptr; for (int ly = y; ly < y + h; ly++) { for (int lz = std::max(z, cz * CHUNK_D); lz < std::min(z + d, (cz + 1) * CHUNK_D); @@ -451,7 +452,8 @@ inline void get_voxels_impl( CHUNK_D ); voxels[vidx] = cvoxels[cidx]; - light_t light = clights[cidx]; + light_t light = clights ? clights[cidx] + : Lightmap::SUN_LIGHT_ONLY; if (backlight) { const auto block = blocks.get(voxels[vidx].id); if (block && block->lightPassing) { diff --git a/src/world/files/WorldRegions.cpp b/src/world/files/WorldRegions.cpp index 62817ee6..6cfe55d6 100644 --- a/src/world/files/WorldRegions.cpp +++ b/src/world/files/WorldRegions.cpp @@ -175,11 +175,11 @@ void WorldRegions::put(Chunk* chunk, std::vector entitiesData) { CHUNK_DATA_LEN); // Writing lights cache - if (doWriteLights && chunk->flags.lighted) { + if (doWriteLights && chunk->flags.lighted && chunk->lightmap) { put(chunk->x, chunk->z, REGION_LAYER_LIGHTS, - chunk->lightmap.encode(), + chunk->lightmap->encode(), LIGHTMAP_DATA_LEN); } // Writing block inventories