summaryrefslogtreecommitdiffstats
path: root/src/LightingThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/LightingThread.cpp')
-rw-r--r--src/LightingThread.cpp535
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;
}