summaryrefslogtreecommitdiffstats
path: root/source/LightingThread.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source/LightingThread.h352
1 files changed, 176 insertions, 176 deletions
diff --git a/source/LightingThread.h b/source/LightingThread.h
index b1ff0d33f..96f7c009e 100644
--- a/source/LightingThread.h
+++ b/source/LightingThread.h
@@ -1,176 +1,176 @@
-
-// LightingThread.h
-
-// Interfaces to the cLightingThread class representing the thread that processes requests for lighting
-
-/*
-Lighting is done on whole chunks. For each chunk to be lighted, the whole 3x3 chunk area around it is read,
-then it is processed, so that the middle chunk area has valid lighting, and the lighting is copied into the ChunkMap.
-Lighting is calculated in full char arrays instead of nibbles, so that accessing the arrays is fast.
-Lighting is calculated in a flood-fill fashion:
-1. Generate seeds from where the light spreads (full skylight / light-emitting blocks)
-2. For each seed:
- - Spread the light 1 block in each of the 6 cardinal directions, if the blocktype allows
- - If the recipient block has had lower lighting value than that being spread, make it a new seed
-3. Repeat step 2, until there are no more seeds
-The seeds need two fast operations:
- - Check if a block at [x, y, z] is already a seed
- - Get the next seed in the row
-For that reason it is stored in two arrays, one stores a bool saying a seed is in that position,
-the other is an array of seed coords, encoded as a single int.
-Step 2 needs two separate storages for old seeds and new seeds, so there are two actual storages for that purpose,
-their content is swapped after each full step-2-cycle.
-
-The thread has two queues of chunks that are to be lighted.
-The first queue, m_Queue, is the only one that is publicly visible, chunks get queued there by external requests.
-The second one, m_PostponedQueue, is for chunks that have been taken out of m_Queue and didn't have neighbors ready.
-Chunks from m_PostponedQueue are moved back into m_Queue when their neighbors get valid, using the ChunkReady callback.
-*/
-
-
-
-#pragma once
-
-#include "cIsThread.h"
-#include "ChunkDef.h"
-
-
-
-
-
-// fwd: "cWorld.h"
-class cWorld;
-
-// fwd: "cChunkMap.h"
-class cChunkStay;
-
-
-
-
-
-class cLightingThread :
- public cIsThread
-{
- typedef cIsThread super;
-
-public:
-
- cLightingThread(void);
- ~cLightingThread();
-
- bool Start(cWorld * a_World);
-
- void Stop(void);
-
- /// Queues the entire chunk for lighting
- void QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter = NULL);
-
- /// Blocks until the queue is empty or the thread is terminated
- void WaitForQueueEmpty(void);
-
- size_t GetQueueLength(void);
-
- /// Called from cWorld when a chunk gets valid. Chunks in m_PostponedQueue may need moving into m_Queue
- void ChunkReady(int a_ChunkX, int a_ChunkZ);
-
-protected:
-
- struct sItem
- {
- int x, z;
- cChunkStay * m_ChunkStay;
- cChunkCoordCallback * m_Callback;
-
- sItem(void) {} // empty default constructor needed
- sItem(int a_X, int a_Z, cChunkStay * a_ChunkStay, cChunkCoordCallback * a_Callback) :
- x(a_X),
- z(a_Z),
- m_ChunkStay(a_ChunkStay),
- m_Callback(a_Callback)
- {
- }
- } ;
-
- typedef std::list<sItem> sItems;
-
- cWorld * m_World;
- cCriticalSection m_CS;
- sItems m_Queue;
- sItems m_PostponedQueue; // Chunks that have been postponed due to missing neighbors
- cEvent m_evtItemAdded; // Set when queue is appended, or to stop the thread
- cEvent m_evtQueueEmpty; // Set when the queue gets empty
-
- // Buffers for the 3x3 chunk data
- // These buffers alone are 1.7 MiB in size, therefore they cannot be located on the stack safely - some architectures may have only 1 MiB for stack, or even less
- // Placing the buffers into the object means that this object can light chunks only in one thread!
- // The blobs are XZY organized as a whole, instead of 3x3 XZY-organized subarrays ->
- // -> This means data has to be scatterred when reading and gathered when writing!
- static const int BlocksPerYLayer = cChunkDef::Width * cChunkDef::Width * 3 * 3;
- BLOCKTYPE m_BlockTypes[BlocksPerYLayer * cChunkDef::Height];
- NIBBLETYPE m_BlockLight[BlocksPerYLayer * cChunkDef::Height];
- NIBBLETYPE m_SkyLight [BlocksPerYLayer * cChunkDef::Height];
- HEIGHTTYPE m_HeightMap [BlocksPerYLayer];
-
- // Seed management (5.7 MiB)
- // Two buffers, in each calc step one is set as input and the other as output, then in the next step they're swapped
- // Each seed is represented twice in this structure - both as a "list" and as a "position".
- // "list" allows fast traversal from seed to seed
- // "position" allows fast checking if a coord is already a seed
- unsigned char m_IsSeed1 [BlocksPerYLayer * cChunkDef::Height];
- unsigned int m_SeedIdx1[BlocksPerYLayer * cChunkDef::Height];
- unsigned char m_IsSeed2 [BlocksPerYLayer * cChunkDef::Height];
- unsigned int m_SeedIdx2[BlocksPerYLayer * cChunkDef::Height];
- int m_NumSeeds;
-
- virtual void Execute(void) override;
-
- /// Lights the entire chunk. If neighbor chunks don't exist, touches them and re-queues the chunk
- void LightChunk(sItem & a_Item);
-
- /// Prepares m_BlockTypes and m_HeightMap data; returns false if any of the chunks fail. Zeroes out the light arrays
- bool ReadChunks(int a_ChunkX, int a_ChunkZ);
-
- /// Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight
- void PrepareSkyLight(void);
-
- /// Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight
- void PrepareBlockLight(void);
-
- /// Calculates light in the light array specified, using stored seeds
- void CalcLight(NIBBLETYPE * a_Light);
-
- /// Does one step in the light calculation - one seed propagation and seed recalculation
- void 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
- );
-
- /// Compresses from 1-byte-per-block into 2-bytes-per-block:
- void CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight);
-
- inline void PropagateLight(
- NIBBLETYPE * a_Light,
- int a_SrcIdx, int a_DstIdx,
- int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
- )
- {
- if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]])
- {
- // We're not offering more light than the dest block already has
- return;
- }
-
- a_Light[a_DstIdx] = a_Light[a_SrcIdx] - g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]];
- if (!a_IsSeedOut[a_DstIdx])
- {
- a_IsSeedOut[a_DstIdx] = true;
- a_SeedIdxOut[a_NumSeedsOut++] = a_DstIdx;
- }
- }
-
-} ;
-
-
-
-
+
+// LightingThread.h
+
+// Interfaces to the cLightingThread class representing the thread that processes requests for lighting
+
+/*
+Lighting is done on whole chunks. For each chunk to be lighted, the whole 3x3 chunk area around it is read,
+then it is processed, so that the middle chunk area has valid lighting, and the lighting is copied into the ChunkMap.
+Lighting is calculated in full char arrays instead of nibbles, so that accessing the arrays is fast.
+Lighting is calculated in a flood-fill fashion:
+1. Generate seeds from where the light spreads (full skylight / light-emitting blocks)
+2. For each seed:
+ - Spread the light 1 block in each of the 6 cardinal directions, if the blocktype allows
+ - If the recipient block has had lower lighting value than that being spread, make it a new seed
+3. Repeat step 2, until there are no more seeds
+The seeds need two fast operations:
+ - Check if a block at [x, y, z] is already a seed
+ - Get the next seed in the row
+For that reason it is stored in two arrays, one stores a bool saying a seed is in that position,
+the other is an array of seed coords, encoded as a single int.
+Step 2 needs two separate storages for old seeds and new seeds, so there are two actual storages for that purpose,
+their content is swapped after each full step-2-cycle.
+
+The thread has two queues of chunks that are to be lighted.
+The first queue, m_Queue, is the only one that is publicly visible, chunks get queued there by external requests.
+The second one, m_PostponedQueue, is for chunks that have been taken out of m_Queue and didn't have neighbors ready.
+Chunks from m_PostponedQueue are moved back into m_Queue when their neighbors get valid, using the ChunkReady callback.
+*/
+
+
+
+#pragma once
+
+#include "cIsThread.h"
+#include "ChunkDef.h"
+
+
+
+
+
+// fwd: "cWorld.h"
+class cWorld;
+
+// fwd: "cChunkMap.h"
+class cChunkStay;
+
+
+
+
+
+class cLightingThread :
+ public cIsThread
+{
+ typedef cIsThread super;
+
+public:
+
+ cLightingThread(void);
+ ~cLightingThread();
+
+ bool Start(cWorld * a_World);
+
+ void Stop(void);
+
+ /// Queues the entire chunk for lighting
+ void QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter = NULL);
+
+ /// Blocks until the queue is empty or the thread is terminated
+ void WaitForQueueEmpty(void);
+
+ size_t GetQueueLength(void);
+
+ /// Called from cWorld when a chunk gets valid. Chunks in m_PostponedQueue may need moving into m_Queue
+ void ChunkReady(int a_ChunkX, int a_ChunkZ);
+
+protected:
+
+ struct sItem
+ {
+ int x, z;
+ cChunkStay * m_ChunkStay;
+ cChunkCoordCallback * m_Callback;
+
+ sItem(void) {} // empty default constructor needed
+ sItem(int a_X, int a_Z, cChunkStay * a_ChunkStay, cChunkCoordCallback * a_Callback) :
+ x(a_X),
+ z(a_Z),
+ m_ChunkStay(a_ChunkStay),
+ m_Callback(a_Callback)
+ {
+ }
+ } ;
+
+ typedef std::list<sItem> sItems;
+
+ cWorld * m_World;
+ cCriticalSection m_CS;
+ sItems m_Queue;
+ sItems m_PostponedQueue; // Chunks that have been postponed due to missing neighbors
+ cEvent m_evtItemAdded; // Set when queue is appended, or to stop the thread
+ cEvent m_evtQueueEmpty; // Set when the queue gets empty
+
+ // Buffers for the 3x3 chunk data
+ // These buffers alone are 1.7 MiB in size, therefore they cannot be located on the stack safely - some architectures may have only 1 MiB for stack, or even less
+ // Placing the buffers into the object means that this object can light chunks only in one thread!
+ // The blobs are XZY organized as a whole, instead of 3x3 XZY-organized subarrays ->
+ // -> This means data has to be scatterred when reading and gathered when writing!
+ static const int BlocksPerYLayer = cChunkDef::Width * cChunkDef::Width * 3 * 3;
+ BLOCKTYPE m_BlockTypes[BlocksPerYLayer * cChunkDef::Height];
+ NIBBLETYPE m_BlockLight[BlocksPerYLayer * cChunkDef::Height];
+ NIBBLETYPE m_SkyLight [BlocksPerYLayer * cChunkDef::Height];
+ HEIGHTTYPE m_HeightMap [BlocksPerYLayer];
+
+ // Seed management (5.7 MiB)
+ // Two buffers, in each calc step one is set as input and the other as output, then in the next step they're swapped
+ // Each seed is represented twice in this structure - both as a "list" and as a "position".
+ // "list" allows fast traversal from seed to seed
+ // "position" allows fast checking if a coord is already a seed
+ unsigned char m_IsSeed1 [BlocksPerYLayer * cChunkDef::Height];
+ unsigned int m_SeedIdx1[BlocksPerYLayer * cChunkDef::Height];
+ unsigned char m_IsSeed2 [BlocksPerYLayer * cChunkDef::Height];
+ unsigned int m_SeedIdx2[BlocksPerYLayer * cChunkDef::Height];
+ int m_NumSeeds;
+
+ virtual void Execute(void) override;
+
+ /// Lights the entire chunk. If neighbor chunks don't exist, touches them and re-queues the chunk
+ void LightChunk(sItem & a_Item);
+
+ /// Prepares m_BlockTypes and m_HeightMap data; returns false if any of the chunks fail. Zeroes out the light arrays
+ bool ReadChunks(int a_ChunkX, int a_ChunkZ);
+
+ /// Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight
+ void PrepareSkyLight(void);
+
+ /// Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight
+ void PrepareBlockLight(void);
+
+ /// Calculates light in the light array specified, using stored seeds
+ void CalcLight(NIBBLETYPE * a_Light);
+
+ /// Does one step in the light calculation - one seed propagation and seed recalculation
+ void 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
+ );
+
+ /// Compresses from 1-byte-per-block into 2-bytes-per-block:
+ void CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight);
+
+ inline void PropagateLight(
+ NIBBLETYPE * a_Light,
+ int a_SrcIdx, int a_DstIdx,
+ int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
+ )
+ {
+ if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]])
+ {
+ // We're not offering more light than the dest block already has
+ return;
+ }
+
+ a_Light[a_DstIdx] = a_Light[a_SrcIdx] - g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]];
+ if (!a_IsSeedOut[a_DstIdx])
+ {
+ a_IsSeedOut[a_DstIdx] = true;
+ a_SeedIdxOut[a_NumSeedsOut++] = a_DstIdx;
+ }
+ }
+
+} ;
+
+
+
+