diff options
Diffstat (limited to '')
-rw-r--r-- | src/LightingThread.cpp | 535 |
1 files changed, 183 insertions, 352 deletions
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp index 4e2826778..6f51e173c 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -20,62 +20,20 @@ class cReader : { virtual void ChunkData(const cChunkData & a_ChunkBuffer) override { - BLOCKTYPE * OutputRows = m_BlockTypes; - int InputIdx = 0; - int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3; - int MaxHeight = std::min(+cChunkDef::Height, m_MaxHeight + 16); // Need 16 blocks above the highest - for (int y = 0; y < MaxHeight; y++) - { - for (int z = 0; z < cChunkDef::Width; z++) - { - a_ChunkBuffer.CopyBlockTypes(OutputRows + OutputIdx * 16, static_cast<size_t>(InputIdx * 16), 16); - InputIdx++; - OutputIdx += 3; - } // for z - // Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows - // We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip - OutputIdx += cChunkDef::Width * 6; - } // for y - } // BlockTypes() - + a_ChunkBuffer.CopyBlockTypes(m_BlockTypes.data()); + } virtual void HeightMap(const cChunkDef::HeightMap * a_Heightmap) override { - // Copy the entire heightmap, distribute it into the 3x3 chunk blob: - typedef struct {HEIGHTTYPE m_Row[16]; } ROW; - const ROW * InputRows = reinterpret_cast<const ROW *>(a_Heightmap); - ROW * OutputRows = reinterpret_cast<ROW *>(m_HeightMap); - int InputIdx = 0; - int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3; - for (int z = 0; z < cChunkDef::Width; z++) - { - OutputRows[OutputIdx] = InputRows[InputIdx++]; - OutputIdx += 3; - } // for z - - // Find the highest block in the entire chunk, use it as a base for m_MaxHeight: - HEIGHTTYPE MaxHeight = m_MaxHeight; - for (size_t i = 0; i < ARRAYCOUNT(*a_Heightmap); i++) - { - if ((*a_Heightmap)[i] > MaxHeight) - { - MaxHeight = (*a_Heightmap)[i]; - } - } - m_MaxHeight = MaxHeight; + std::copy(std::begin(*a_Heightmap), std::end(*a_Heightmap), std::begin(m_HeightMap)); } public: - int m_ReadingChunkX; // 0, 1 or 2; x-offset of the chunk we're reading from the BlockTypes start - int m_ReadingChunkZ; // 0, 1 or 2; z-offset of the chunk we're reading from the BlockTypes start - HEIGHTTYPE m_MaxHeight; // Maximum value in this chunk's heightmap - BLOCKTYPE * m_BlockTypes; // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs) - HEIGHTTYPE * m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs) - - cReader(BLOCKTYPE * a_BlockTypes, HEIGHTTYPE * a_HeightMap) : - m_ReadingChunkX(0), - m_ReadingChunkZ(0), - m_MaxHeight(0), + + cLightingThread::BlockDataArray & m_BlockTypes; // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs) + cLightingThread::HeightDataArray & m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs) + + cReader(cLightingThread::BlockDataArray & a_BlockTypes, cLightingThread::HeightDataArray & a_HeightMap) : m_BlockTypes(a_BlockTypes), m_HeightMap(a_HeightMap) { @@ -91,9 +49,7 @@ public: cLightingThread::cLightingThread(void) : super("cLightingThread"), - m_World(nullptr), - m_MaxHeight(0), - m_NumSeeds(0) + m_World(nullptr) { } @@ -124,24 +80,8 @@ bool cLightingThread::Start(cWorld * a_World) void cLightingThread::Stop(void) { - { - cCSLock Lock(m_CS); - for (cChunkStays::iterator itr = m_PendingQueue.begin(), end = m_PendingQueue.end(); itr != end; ++itr) - { - (*itr)->Disable(); - delete *itr; - } - m_PendingQueue.clear(); - for (cChunkStays::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr) - { - (*itr)->Disable(); - delete *itr; - } - m_Queue.clear(); - } m_ShouldTerminate = true; - m_evtItemAdded.Set(); - + m_evtItemDataLoaded.Set(); Wait(); } @@ -153,28 +93,25 @@ void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cCh { ASSERT(m_World != nullptr); // Did you call Start() properly? - cChunkStay * ChunkStay = new cLightingChunkStay(*this, a_ChunkX, a_ChunkZ, std::move(a_CallbackAfter)); + // If the chunk is already lit, skip it: + if (m_World->IsChunkValid(a_ChunkX, a_ChunkZ) && m_World->IsChunkLighted(a_ChunkX, a_ChunkZ)) { - // The ChunkStay will enqueue itself using the QueueChunkStay() once it is fully loaded - // In the meantime, put it into the PendingQueue so that it can be removed when stopping the thread - cCSLock Lock(m_CS); - m_PendingQueue.push_back(ChunkStay); + if (a_CallbackAfter != nullptr) + { + a_CallbackAfter->Call(a_ChunkX, a_ChunkZ, true); + } + return; } - ChunkStay->Enable(*m_World->GetChunkMap()); -} - - - -void cLightingThread::WaitForQueueEmpty(void) -{ - cCSLock Lock(m_CS); - while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PendingQueue.empty())) + auto ChunkStay = new cLightingChunkStay(*this, a_ChunkX, a_ChunkZ, std::move(a_CallbackAfter)); { - cCSUnlock Unlock(Lock); - m_evtQueueEmpty.Wait(); + // The ChunkStay will enqueue itself using the QueueChunkStay() once it is fully loaded + // In the meantime, put it into the PendingQueue so that it can be removed when stopping the thread + cCSLock Lock(m_CS); + m_PendingQueue.emplace_back(ChunkStay); } + ChunkStay->Enable(*m_World->GetChunkMap()); } @@ -184,7 +121,7 @@ void cLightingThread::WaitForQueueEmpty(void) size_t cLightingThread::GetQueueLength(void) { cCSLock Lock(m_CS); - return m_Queue.size() + m_PendingQueue.size(); + return m_PendingQueue.size(); } @@ -193,69 +130,52 @@ size_t cLightingThread::GetQueueLength(void) void cLightingThread::Execute(void) { - for (;;) + while (!m_ShouldTerminate) { + m_evtItemDataLoaded.Wait(); + + decltype(m_Queue) QueuedChunks; { cCSLock Lock(m_CS); - if (m_Queue.empty()) - { - cCSUnlock Unlock(Lock); - m_evtItemAdded.Wait(); - } + std::swap(m_Queue, QueuedChunks); } - if (m_ShouldTerminate) + for (const auto & Entry : QueuedChunks) { - return; + Entry->m_BlockTypes = cpp14::make_unique<BlockDataArray>(); + Entry->m_HeightMap = cpp14::make_unique<HeightDataArray>(); } - // Process one items from the queue: - cLightingChunkStay * Item; - { - cCSLock Lock(m_CS); - if (m_Queue.empty()) - { - continue; - } - Item = static_cast<cLightingChunkStay *>(m_Queue.front()); - m_Queue.pop_front(); - if (m_Queue.empty()) + m_World->QueueTask( + [&QueuedChunks](cWorld & a_World) { - m_evtQueueEmpty.Set(); + for (const auto & Entry : QueuedChunks) + { + cReader Reader(*Entry->m_BlockTypes, *Entry->m_HeightMap); + VERIFY(a_World.GetChunkData(Entry->m_ChunkX, Entry->m_ChunkZ, Reader)); + } } - } // CSLock(m_CS) + ).wait(); - LightChunk(*Item); - Item->Disable(); - delete Item; - } + for (const auto & Entry : QueuedChunks) + { + LightChunk(*Entry); + } + } // while (!m_ShouldTerminate) } - void cLightingThread::LightChunk(cLightingChunkStay & a_Item) { - // If the chunk is already lit, skip it (report as success): - if (m_World->IsChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ)) - { - if (a_Item.m_CallbackAfter != nullptr) - { - a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true); - } - return; - } - - cChunkDef::BlockNibbles BlockLight, SkyLight; - - ReadChunks(a_Item.m_ChunkX, a_Item.m_ChunkZ); + std::unique_ptr<BlockDataArray> + BlockLight{ cpp14::make_unique<decltype(BlockLight)::element_type>() }, + SkyLight{ cpp14::make_unique<decltype(BlockLight)::element_type>() } + ; - PrepareBlockLight(); - CalcLight(m_BlockLight); - - PrepareSkyLight(); + CalcLight(a_Item, PrepareBlockLight(a_Item, *BlockLight), *BlockLight); /* // DEBUG: Save chunk data with highlighted seeds for visual inspection: @@ -269,10 +189,10 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item) for (int y = cChunkDef::Height / 2; y >= 0; y--) { unsigned char Seeds [cChunkDef::Width * 3]; - memcpy(Seeds, m_BlockTypes + y * BlocksPerYLayer + z * cChunkDef::Width * 3, cChunkDef::Width * 3); + memcpy(Seeds, m_BlockTypes + y * cLightingChunkStay::BlocksPerYLayer + z * cChunkDef::Width * 3, cChunkDef::Width * 3); for (int x = 0; x < cChunkDef::Width * 3; x++) { - if (m_IsSeed1[y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x]) + if (m_IsSeed1[y * cLightingChunkStay::BlocksPerYLayer + z * cChunkDef::Width * 3 + x]) { Seeds[x] = E_BLOCK_DIAMOND_BLOCK; } @@ -284,7 +204,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item) } //*/ - CalcLight(m_SkyLight); + CalcLight(a_Item, PrepareSkyLight(a_Item, *SkyLight), *SkyLight); /* // DEBUG: Save XY slices of the chunk data and lighting for visual inspection: @@ -299,13 +219,13 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item) { for (int y = cChunkDef::Height / 2; y >= 0; y--) { - f1.Write(m_BlockTypes + y * BlocksPerYLayer + z * cChunkDef::Width * 3, cChunkDef::Width * 3); + f1.Write(m_BlockTypes + y * cLightingChunkStay::BlocksPerYLayer + z * cChunkDef::Width * 3, cChunkDef::Width * 3); unsigned char SkyLight [cChunkDef::Width * 3]; unsigned char BlockLight[cChunkDef::Width * 3]; for (int x = 0; x < cChunkDef::Width * 3; x++) { - SkyLight[x] = m_SkyLight [y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x] << 4; - BlockLight[x] = m_BlockLight[y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x] << 4; + SkyLight[x] = m_SkyLight [y * cLightingChunkStay::BlocksPerYLayer + z * cChunkDef::Width * 3 + x] << 4; + BlockLight[x] = m_BlockLight[y * cLightingChunkStay::BlocksPerYLayer + z * cChunkDef::Width * 3 + x] << 4; } f2.Write(SkyLight, cChunkDef::Width * 3); f3.Write(BlockLight, cChunkDef::Width * 3); @@ -317,165 +237,91 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item) } //*/ - CompressLight(m_BlockLight, BlockLight); - CompressLight(m_SkyLight, SkyLight); - - m_World->ChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ, BlockLight, SkyLight); - - if (a_Item.m_CallbackAfter != nullptr) - { - a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true); - } -} - - - + std::shared_ptr<BlockNibbles> + CompressedBlockLight{ std::make_shared<decltype(CompressedBlockLight)::element_type>() }, + CompressedSkyLight{ std::make_shared<decltype(CompressedSkyLight)::element_type>() } + ; + CompressLight(*BlockLight, *CompressedBlockLight); + CompressLight(*SkyLight, *CompressedSkyLight); - -void cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ) -{ - cReader Reader(m_BlockTypes, m_HeightMap); - - for (int z = 0; z < 3; z++) - { - Reader.m_ReadingChunkZ = z; - for (int x = 0; x < 3; x++) + m_World->QueueTask( + [&a_Item, CompressedBlockLight, CompressedSkyLight](cWorld & a_World) { - Reader.m_ReadingChunkX = x; - VERIFY(m_World->GetChunkData(a_ChunkX + x - 1, a_ChunkZ + z - 1, Reader)); - } // for z - } // for x - - memset(m_BlockLight, 0, sizeof(m_BlockLight)); - memset(m_SkyLight, 0, sizeof(m_SkyLight)); - m_MaxHeight = Reader.m_MaxHeight; + a_World.ChunkLighted( + a_Item.m_ChunkX, + a_Item.m_ChunkZ, + reinterpret_cast<const cChunkDef::BlockNibbles &>(*CompressedBlockLight->data()), + reinterpret_cast<const cChunkDef::BlockNibbles &>(*CompressedSkyLight->data()) + ); + + if (a_Item.m_CallbackAfter != nullptr) + { + a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true); + } + + a_Item.Disable(); + } + ); } -void cLightingThread::PrepareSkyLight(void) +std::vector<size_t> cLightingThread::PrepareSkyLight(const cLightingChunkStay & a_Item, BlockDataArray & a_SkyLight) { - // Clear seeds: - memset(m_IsSeed1, 0, sizeof(m_IsSeed1)); - m_NumSeeds = 0; + std::vector<size_t> IndicesToProcess; + IndicesToProcess.reserve(a_Item.m_HeightMap->size() * 40); - // Walk every column that has all XZ neighbors - for (int z = 1; z < cChunkDef::Width * 3 - 1; z++) + for (size_t Index = 0; Index != a_Item.m_HeightMap->size(); ++Index) { - int BaseZ = z * cChunkDef::Width * 3; - for (int x = 1; x < cChunkDef::Width * 3 - 1; x++) + for (int Y = cChunkDef::Height - 1; Y >= (*a_Item.m_HeightMap)[Index]; --Y) { - int idx = BaseZ + x; - int Current = m_HeightMap[idx] + 1; - int Neighbor1 = m_HeightMap[idx + 1] + 1; // X + 1 - int Neighbor2 = m_HeightMap[idx - 1] + 1; // X - 1 - int Neighbor3 = m_HeightMap[idx + cChunkDef::Width * 3] + 1; // Z + 1 - int Neighbor4 = m_HeightMap[idx - cChunkDef::Width * 3] + 1; // Z - 1 - int MaxNeighbor = std::max(std::max(Neighbor1, Neighbor2), std::max(Neighbor3, Neighbor4)); // Maximum of the four neighbors - - // Fill the column from the top down to Current with all-light: - for (int y = cChunkDef::Height - 1, Index = idx + y * BlocksPerYLayer; y >= Current; y--, Index -= BlocksPerYLayer) - { - m_SkyLight[Index] = 15; - } + auto HeightAdjustedIndex = Index + Y * cChunkDef::Width * cChunkDef::Width; + a_SkyLight[HeightAdjustedIndex] = 15; - // Add Current as a seed: - if (Current < cChunkDef::Height) - { - int CurrentIdx = idx + Current * BlocksPerYLayer; - m_IsSeed1[CurrentIdx] = true; - m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(CurrentIdx); - } - - // Add seed from Current up to the highest neighbor: - for (int y = Current + 1, Index = idx + y * BlocksPerYLayer; y < MaxNeighbor; y++, Index += BlocksPerYLayer) - { - m_IsSeed1[Index] = true; - m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(Index); - } + IndicesToProcess.emplace_back(HeightAdjustedIndex); } } + + return IndicesToProcess; } -void cLightingThread::PrepareBlockLight(void) +std::vector<size_t> cLightingThread::PrepareBlockLight(const cLightingChunkStay & a_Item, BlockDataArray & a_BlockLight) { - // Clear seeds: - memset(m_IsSeed1, 0, sizeof(m_IsSeed1)); - memset(m_IsSeed2, 0, sizeof(m_IsSeed2)); - m_NumSeeds = 0; + std::vector<size_t> IndicesToProcess; + IndicesToProcess.reserve(cChunkDef::Width * cChunkDef::Width); - // Walk every column that has all XZ neighbors, make a seed for each light-emitting block: - for (int z = 1; z < cChunkDef::Width * 3 - 1; z++) + for (size_t Index = 0; Index != a_Item.m_BlockTypes->size(); ++Index) { - int BaseZ = z * cChunkDef::Width * 3; - for (int x = 1; x < cChunkDef::Width * 3 - 1; x++) - { - int idx = BaseZ + x; - for (int y = m_HeightMap[idx], Index = idx + y * BlocksPerYLayer; y >= 0; y--, Index -= BlocksPerYLayer) - { - if (cBlockInfo::GetLightValue(m_BlockTypes[Index]) == 0) - { - continue; - } - - // Add current block as a seed: - m_IsSeed1[Index] = true; - m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(Index); + auto Light = cBlockInfo::GetLightValue((*a_Item.m_BlockTypes)[Index]); + a_BlockLight[Index] = Light; - // Light it up: - m_BlockLight[Index] = cBlockInfo::GetLightValue(m_BlockTypes[Index]); - } + if (Light > 1) + { + IndicesToProcess.emplace_back(Index); } } + + return IndicesToProcess; } -void cLightingThread::PrepareBlockLight2(void) +void cLightingThread::CalcLight(const cLightingChunkStay & a_Item, std::vector<size_t> a_IndicesToProcess, BlockDataArray & a_Light) { - // Clear seeds: - memset(m_IsSeed1, 0, sizeof(m_IsSeed1)); - memset(m_IsSeed2, 0, sizeof(m_IsSeed2)); - m_NumSeeds = 0; - - // Add each emissive block into the seeds: - for (int y = 0; y < m_MaxHeight; y++) + while (!a_IndicesToProcess.empty()) { - int BaseY = y * BlocksPerYLayer; // Partial offset into m_BlockTypes for the Y coord - for (int z = 1; z < cChunkDef::Width * 3 - 1; z++) - { - int HBaseZ = z * cChunkDef::Width * 3; // Partial offset into m_Heightmap for the Z coord - int BaseZ = BaseY + HBaseZ; // Partial offset into m_BlockTypes for the Y and Z coords - for (int x = 1; x < cChunkDef::Width * 3 - 1; x++) - { - int idx = BaseZ + x; - if (y > m_HeightMap[HBaseZ + x]) - { - // We're above the heightmap, ignore the block - continue; - } - if (cBlockInfo::GetLightValue(m_BlockTypes[idx]) == 0) - { - // Not a light-emissive block - continue; - } + auto Back = a_IndicesToProcess.back(); + a_IndicesToProcess.pop_back(); - // Add current block as a seed: - m_IsSeed1[idx] = true; - m_SeedIdx1[m_NumSeeds++] = static_cast<UInt32>(idx); - - // Light it up: - m_BlockLight[idx] = cBlockInfo::GetLightValue(m_BlockTypes[idx]); - } - } + DiscoverLightAdjacents(a_IndicesToProcess, a_Item, a_Light, Back); } } @@ -483,97 +329,55 @@ void cLightingThread::PrepareBlockLight2(void) -void cLightingThread::CalcLight(NIBBLETYPE * a_Light) +void cLightingThread::DiscoverLightAdjacents(std::vector<size_t> & a_IndicesToProcess, const cLightingChunkStay & a_Item, BlockDataArray & a_Light, size_t a_OriginatorIndex) { - size_t NumSeeds2 = 0; - while (m_NumSeeds > 0) - { - // Buffer 1 -> buffer 2 - memset(m_IsSeed2, 0, sizeof(m_IsSeed2)); - NumSeeds2 = 0; - CalcLightStep(a_Light, m_NumSeeds, m_IsSeed1, m_SeedIdx1, NumSeeds2, m_IsSeed2, m_SeedIdx2); - if (NumSeeds2 == 0) - { - return; - } + auto Position = cChunkDef::IndexToCoordinate(a_OriginatorIndex); - // Buffer 2 -> buffer 1 - memset(m_IsSeed1, 0, sizeof(m_IsSeed1)); - m_NumSeeds = 0; - CalcLightStep(a_Light, NumSeeds2, m_IsSeed2, m_SeedIdx2, m_NumSeeds, m_IsSeed1, m_SeedIdx1); + if (Position.x % cChunkDef::Width != 15) + { + // TODO: update neighbouring chunk + UpdateLightAdjacent(a_IndicesToProcess, a_Item, a_Light, a_OriginatorIndex, a_OriginatorIndex + 1); } -} - + if (Position.x % cChunkDef::Width != 0) + { + // TODO: update neighbouring chunk + UpdateLightAdjacent(a_IndicesToProcess, a_Item, a_Light, a_OriginatorIndex, a_OriginatorIndex - 1); + } + if (Position.z % cChunkDef::Width != 15) + { + // TODO: update neighbouring chunk + UpdateLightAdjacent(a_IndicesToProcess, a_Item, a_Light, a_OriginatorIndex, a_OriginatorIndex + cChunkDef::Width); + } + if (Position.z % cChunkDef::Width != 0) + { + // TODO: update neighbouring chunk + UpdateLightAdjacent(a_IndicesToProcess, a_Item, a_Light, a_OriginatorIndex, a_OriginatorIndex - cChunkDef::Width); + } -void cLightingThread::CalcLightStep( - NIBBLETYPE * a_Light, - size_t a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn, - size_t & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut -) -{ - UNUSED(a_IsSeedIn); - size_t NumSeedsOut = 0; - for (size_t i = 0; i < a_NumSeedsIn; i++) + if (Position.y != cChunkDef::Height - 1) { - UInt32 SeedIdx = static_cast<UInt32>(a_SeedIdxIn[i]); - int SeedX = SeedIdx % (cChunkDef::Width * 3); - int SeedZ = (SeedIdx / (cChunkDef::Width * 3)) % (cChunkDef::Width * 3); - int SeedY = SeedIdx / BlocksPerYLayer; + UpdateLightAdjacent(a_IndicesToProcess, a_Item, a_Light, a_OriginatorIndex, a_OriginatorIndex + cChunkDef::Width * cChunkDef::Width); + } - // Propagate seed: - if (SeedX < cChunkDef::Width * 3 - 1) - { - PropagateLight(a_Light, SeedIdx, SeedIdx + 1, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut); - } - if (SeedX > 0) - { - PropagateLight(a_Light, SeedIdx, SeedIdx - 1, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut); - } - if (SeedZ < cChunkDef::Width * 3 - 1) - { - PropagateLight(a_Light, SeedIdx, SeedIdx + cChunkDef::Width * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut); - } - if (SeedZ > 0) - { - PropagateLight(a_Light, SeedIdx, SeedIdx - cChunkDef::Width * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut); - } - if (SeedY < cChunkDef::Height - 1) - { - PropagateLight(a_Light, SeedIdx, SeedIdx + cChunkDef::Width * cChunkDef::Width * 3 * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut); - } - if (SeedY > 0) - { - PropagateLight(a_Light, SeedIdx, SeedIdx - cChunkDef::Width * cChunkDef::Width * 3 * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut); - } - } // for i - a_SeedIdxIn[] - a_NumSeedsOut = NumSeedsOut; + if (Position.y != 0) + { + UpdateLightAdjacent(a_IndicesToProcess, a_Item, a_Light, a_OriginatorIndex, a_OriginatorIndex - cChunkDef::Width * cChunkDef::Width); + } } -void cLightingThread::CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight) +void cLightingThread::UpdateLightAdjacent(std::vector<size_t> & a_IndicesToProcess, const cLightingChunkStay & a_Item, BlockDataArray & a_Light, size_t a_OriginatorIndex, size_t a_DestinationIndex) { - int InIdx = cChunkDef::Width * 49; // Index to the first nibble of the middle chunk in the a_LightArray - int OutIdx = 0; - for (int y = 0; y < cChunkDef::Height; y++) + // Assertions for index validity occur within PropagateLightToAdjacent + if (PropagateLightToAdjacent(a_Item, a_Light, a_OriginatorIndex, a_DestinationIndex)) { - for (int z = 0; z < cChunkDef::Width; z++) - { - for (int x = 0; x < cChunkDef::Width; x += 2) - { - a_ChunkLight[OutIdx++] = static_cast<NIBBLETYPE>(a_LightArray[InIdx + 1] << 4) | a_LightArray[InIdx]; - InIdx += 2; - } - InIdx += cChunkDef::Width * 2; - } - // Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows - // We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip - InIdx += cChunkDef::Width * cChunkDef::Width * 6; + a_IndicesToProcess.emplace_back(a_DestinationIndex); } } @@ -581,15 +385,13 @@ void cLightingThread::CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_Ch -void cLightingThread::QueueChunkStay(cLightingChunkStay & a_ChunkStay) +void cLightingThread::CompressLight(const BlockDataArray & a_LightArray, BlockNibbles & a_ChunkLight) { - // Move the ChunkStay from the Pending queue to the lighting queue. + for (size_t Index = 0; Index != a_ChunkLight.size(); ++Index) { - cCSLock Lock(m_CS); - m_PendingQueue.remove(&a_ChunkStay); - m_Queue.push_back(&a_ChunkStay); + auto AdjustedIndex = Index * 2; + a_ChunkLight[Index] = a_LightArray[AdjustedIndex] | static_cast<NIBBLETYPE>(a_LightArray[AdjustedIndex + 1] << 4); } - m_evtItemAdded.Set(); } @@ -600,20 +402,13 @@ void cLightingThread::QueueChunkStay(cLightingChunkStay & a_ChunkStay) // cLightingThread::cLightingChunkStay: cLightingThread::cLightingChunkStay::cLightingChunkStay(cLightingThread & a_LightingThread, int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter) : - m_LightingThread(a_LightingThread), + m_CallbackAfter(std::move(a_CallbackAfter)), m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), - m_CallbackAfter(std::move(a_CallbackAfter)) + m_MaxHeight(0), // Required by cReader to be initialised to zero + m_LightingThread(a_LightingThread) { - Add(a_ChunkX + 1, a_ChunkZ + 1); - Add(a_ChunkX + 1, a_ChunkZ); - Add(a_ChunkX + 1, a_ChunkZ - 1); - Add(a_ChunkX, a_ChunkZ + 1); - Add(a_ChunkX, a_ChunkZ); - Add(a_ChunkX, a_ChunkZ - 1); - Add(a_ChunkX - 1, a_ChunkZ + 1); - Add(a_ChunkX - 1, a_ChunkZ); - Add(a_ChunkX - 1, a_ChunkZ - 1); + Add(a_ChunkX, a_ChunkZ); } @@ -622,7 +417,43 @@ cLightingThread::cLightingChunkStay::cLightingChunkStay(cLightingThread & a_Ligh bool cLightingThread::cLightingChunkStay::OnAllChunksAvailable(void) { - m_LightingThread.QueueChunkStay(*this); + if (m_LightingThread.m_ShouldTerminate) + { + return false; + } + + ASSERT(m_LightingThread.m_World->IsChunkValid(m_ChunkX, m_ChunkZ)); + + // If the chunk is already lit, skip it: + if (m_LightingThread.m_World->IsChunkLighted(m_ChunkX, m_ChunkZ)) + { + if (m_CallbackAfter != nullptr) + { + m_CallbackAfter->Call(m_ChunkX, m_ChunkZ, true); + } + + + { + cCSLock Lock(m_LightingThread.m_CS); + m_LightingThread.m_PendingQueue.erase( + std::remove(m_LightingThread.m_PendingQueue.begin(), m_LightingThread.m_PendingQueue.end(), this), + m_LightingThread.m_PendingQueue.end() + ); + } + + return true; + } + + { + cCSLock Lock(m_LightingThread.m_CS); + m_LightingThread.m_PendingQueue.erase( + std::remove(m_LightingThread.m_PendingQueue.begin(), m_LightingThread.m_PendingQueue.end(), this), + m_LightingThread.m_PendingQueue.end() + ); + m_LightingThread.m_Queue.emplace_back(this); + } + + m_LightingThread.m_evtItemDataLoaded.Set(); // Keep the ChunkStay alive: return false; @@ -634,7 +465,7 @@ bool cLightingThread::cLightingChunkStay::OnAllChunksAvailable(void) void cLightingThread::cLightingChunkStay::OnDisabled(void) { - // Nothing needed in this callback + delete this; } |