diff options
Diffstat (limited to 'source/LightingThread.cpp')
-rw-r--r-- | source/LightingThread.cpp | 562 |
1 files changed, 0 insertions, 562 deletions
diff --git a/source/LightingThread.cpp b/source/LightingThread.cpp deleted file mode 100644 index d7e60e458..000000000 --- a/source/LightingThread.cpp +++ /dev/null @@ -1,562 +0,0 @@ - -// LightingThread.cpp - -// Implements the cLightingThread class representing the thread that processes requests for lighting - -#include "Globals.h" -#include "LightingThread.h" -#include "ChunkMap.h" -#include "World.h" - - - - - -/// If more than this many chunks are in the queue, a warning is printed to the log -#define WARN_ON_QUEUE_SIZE 800 - - - - - -/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]: -class cReader : - public cChunkDataCallback -{ - virtual void BlockTypes(const BLOCKTYPE * a_Type) override - { - // ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that) - // C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :) - typedef struct {BLOCKTYPE m_Row[16]; } ROW; - ROW * InputRows = (ROW *)a_Type; - ROW * OutputRows = (ROW *)m_BlockTypes; - int InputIdx = 0; - int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3; - for (int y = 0; y < cChunkDef::Height; y++) - { - for (int z = 0; z < cChunkDef::Width; z++) - { - OutputRows[OutputIdx] = InputRows[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() - - - virtual void HeightMap(const cChunkDef::HeightMap * a_Heightmap) override - { - typedef struct {HEIGHTTYPE m_Row[16]; } ROW; - ROW * InputRows = (ROW *)a_Heightmap; - ROW * OutputRows = (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 - } - -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 - 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) -} ; - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cLightingThread: - -cLightingThread::cLightingThread(void) : - super("cLightingThread"), - m_World(NULL) -{ -} - - - - - -cLightingThread::~cLightingThread() -{ - Stop(); -} - - - - - -bool cLightingThread::Start(cWorld * a_World) -{ - ASSERT(m_World == NULL); // Not started yet - m_World = a_World; - - return super::Start(); -} - - - - - -void cLightingThread::Stop(void) -{ - { - cCSLock Lock(m_CS); - for (sItems::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr) - { - delete itr->m_ChunkStay; - } - m_Queue.clear(); - } - m_ShouldTerminate = true; - m_evtItemAdded.Set(); - - Wait(); -} - - - - - -void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter) -{ - ASSERT(m_World != NULL); // Did you call Start() properly? - - cChunkStay * ChunkStay = new cChunkStay(m_World); - ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ + 1); - ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ); - ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ - 1); - ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ + 1); - ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ - 1); - ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ + 1); - ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ); - ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ - 1); - ChunkStay->Enable(); - ChunkStay->Load(); - cCSLock Lock(m_CS); - m_Queue.push_back(sItem(a_ChunkX, a_ChunkZ, ChunkStay, a_CallbackAfter)); - if (m_Queue.size() > WARN_ON_QUEUE_SIZE) - { - LOGINFO("Lighting thread overloaded, %d items in queue", m_Queue.size()); - } - m_evtItemAdded.Set(); -} - - - - - -void cLightingThread::WaitForQueueEmpty(void) -{ - cCSLock Lock(m_CS); - while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PostponedQueue.empty())) - { - cCSUnlock Unlock(Lock); - m_evtQueueEmpty.Wait(); - } -} - - - - - -size_t cLightingThread::GetQueueLength(void) -{ - cCSLock Lock(m_CS); - return m_Queue.size() + m_PostponedQueue.size(); -} - - - - - -void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ) -{ - // Check all the items in the m_PostponedQueue, if the chunk is their neighbor, move the item to m_Queue - - bool NewlyAdded = false; - { - cCSLock Lock(m_CS); - for (sItems::iterator itr = m_PostponedQueue.begin(); itr != m_PostponedQueue.end(); ) - { - if ( - (itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) && - (itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) - ) - { - // It is a neighbor - m_Queue.push_back(*itr); - itr = m_PostponedQueue.erase(itr); - NewlyAdded = true; - } - else - { - ++itr; - } - } // for itr - m_PostponedQueue[] - } // Lock(m_CS) - - if (NewlyAdded) - { - m_evtItemAdded.Set(); // Notify the thread it has some work to do - } -} - - - - - -void cLightingThread::Execute(void) -{ - while (true) - { - { - cCSLock Lock(m_CS); - if (m_Queue.size() == 0) - { - cCSUnlock Unlock(Lock); - m_evtItemAdded.Wait(); - } - } - - if (m_ShouldTerminate) - { - return; - } - - // Process one items from the queue: - sItem Item; - { - cCSLock Lock(m_CS); - if (m_Queue.empty()) - { - continue; - } - Item = m_Queue.front(); - m_Queue.pop_front(); - if (m_Queue.empty()) - { - m_evtQueueEmpty.Set(); - } - } // CSLock(m_CS) - - LightChunk(Item); - } -} - - - - - - -void cLightingThread::LightChunk(cLightingThread::sItem & a_Item) -{ - cChunkDef::BlockNibbles BlockLight, SkyLight; - - if (!ReadChunks(a_Item.x, a_Item.z)) - { - // Neighbors not available. Re-queue in the postponed queue - cCSLock Lock(m_CS); - m_PostponedQueue.push_back(a_Item); - return; - } - - /* - // DEBUG: torch somewhere: - m_BlockTypes[19 + 24 * cChunkDef::Width * 3 + (m_HeightMap[24 + 24 * cChunkDef::Width * 3] / 2) * BlocksPerYLayer] = E_BLOCK_TORCH; - // m_HeightMap[24 + 24 * cChunkDef::Width * 3]++; - */ - - PrepareBlockLight(); - CalcLight(m_BlockLight); - - PrepareSkyLight(); - - /* - // DEBUG: Save chunk data with highlighted seeds for visual inspection: - cFile f4; - if ( - f4.Open(Printf("Chunk_%d_%d_seeds.grab", a_Item.x, a_Item.z), cFile::fmWrite) - ) - { - for (int z = 0; z < cChunkDef::Width * 3; z++) - { - 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); - for (int x = 0; x < cChunkDef::Width * 3; x++) - { - if (m_IsSeed1[y * BlocksPerYLayer + z * cChunkDef::Width * 3 + x]) - { - Seeds[x] = E_BLOCK_DIAMOND_BLOCK; - } - } - f4.Write(Seeds, cChunkDef::Width * 3); - } - } - } - //*/ - - CalcLight(m_SkyLight); - - /* - // DEBUG: Save XY slices of the chunk data and lighting for visual inspection: - cFile f1, f2, f3; - if ( - f1.Open(Printf("Chunk_%d_%d_data.grab", a_Item.x, a_Item.z), cFile::fmWrite) && - f2.Open(Printf("Chunk_%d_%d_sky.grab", a_Item.x, a_Item.z), cFile::fmWrite) && - f3.Open(Printf("Chunk_%d_%d_glow.grab", a_Item.x, a_Item.z), cFile::fmWrite) - ) - { - for (int z = 0; z < cChunkDef::Width * 3; z++) - { - for (int y = cChunkDef::Height / 2; y >= 0; y--) - { - f1.Write(m_BlockTypes + y * 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; - } - f2.Write(SkyLight, cChunkDef::Width * 3); - f3.Write(BlockLight, cChunkDef::Width * 3); - } - } - } - //*/ - - CompressLight(m_BlockLight, BlockLight); - CompressLight(m_SkyLight, SkyLight); - - m_World->ChunkLighted(a_Item.x, a_Item.z, BlockLight, SkyLight); - - if (a_Item.m_Callback != NULL) - { - a_Item.m_Callback->Call(a_Item.x, a_Item.z); - } - delete a_Item.m_ChunkStay; -} - - - - - -bool cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ) -{ - cReader Reader; - Reader.m_BlockTypes = m_BlockTypes; - Reader.m_HeightMap = m_HeightMap; - - for (int z = 0; z < 3; z++) - { - Reader.m_ReadingChunkZ = z; - for (int x = 0; x < 3; x++) - { - Reader.m_ReadingChunkX = x; - if (!m_World->GetChunkData(a_ChunkX + x - 1, a_ChunkZ + z - 1, Reader)) - { - return false; - } - } // for z - } // for x - - memset(m_BlockLight, 0, sizeof(m_BlockLight)); - memset(m_SkyLight, 0, sizeof(m_SkyLight)); - return true; -} - - - - - -void cLightingThread::PrepareSkyLight(void) -{ - // Clear seeds: - memset(m_IsSeed1, 0, sizeof(m_IsSeed1)); - m_NumSeeds = 0; - - // Walk every column that has all XZ neighbors - for (int z = 1; z < cChunkDef::Width * 3 - 1; z++) - { - int BaseZ = z * cChunkDef::Width * 3; - for (int x = 1; x < cChunkDef::Width * 3 - 1; x++) - { - 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; - } - - // Add Current as a seed: - if (Current < cChunkDef::Height) - { - int CurrentIdx = idx + Current * BlocksPerYLayer; - m_IsSeed1[CurrentIdx] = true; - m_SeedIdx1[m_NumSeeds++] = 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++] = Index; - } - } - } -} - - - - - -void cLightingThread::PrepareBlockLight(void) -{ - // Clear seeds: - memset(m_IsSeed1, 0, sizeof(m_IsSeed1)); - memset(m_IsSeed2, 0, sizeof(m_IsSeed2)); - m_NumSeeds = 0; - - // 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++) - { - 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 (g_BlockLightValue[m_BlockTypes[Index]] == 0) - { - continue; - } - - // Add current block as a seed: - m_IsSeed1[Index] = true; - m_SeedIdx1[m_NumSeeds++] = Index; - - // Light it up: - m_BlockLight[Index] = g_BlockLightValue[m_BlockTypes[Index]]; - } - } - } -} - - - - - -void cLightingThread::CalcLight(NIBBLETYPE * a_Light) -{ - int 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; - } - - // 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); - } -} - - - - - -void cLightingThread::CalcLightStep( - NIBBLETYPE * a_Light, - int a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn, - int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut -) -{ - int NumSeedsOut = 0; - for (int i = 0; i < a_NumSeedsIn; i++) - { - int SeedIdx = a_SeedIdxIn[i]; - int SeedX = SeedIdx % (cChunkDef::Width * 3); - int SeedZ = (SeedIdx / (cChunkDef::Width * 3)) % (cChunkDef::Width * 3); - int SeedY = SeedIdx / BlocksPerYLayer; - - // 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; -} - - - - - -void cLightingThread::CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight) -{ - 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++) - { - for (int z = 0; z < cChunkDef::Width; z++) - { - for (int x = 0; x < cChunkDef::Width; x += 2) - { - a_ChunkLight[OutIdx++] = (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; - } -} - - - - |