From e40f9d6e5b93e840e3d67e79f5ba49da1fbb75f0 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sat, 26 Apr 2014 10:50:23 -0700 Subject: Implemented Chunk Sparsing with segments --- src/ChunkBuffer.h | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 src/ChunkBuffer.h (limited to 'src/ChunkBuffer.h') diff --git a/src/ChunkBuffer.h b/src/ChunkBuffer.h new file mode 100644 index 000000000..44e447c82 --- /dev/null +++ b/src/ChunkBuffer.h @@ -0,0 +1,310 @@ + +#pragma once + +#define CHUNK_SECTION_HEIGHT 16 +#define CHUNK_SECTION_NUM (256 / CHUNK_SECTION_HEIGHT) + +#if __cplusplus < 201103L +// auto_ptr style interface for memory management +#else +// unique_ptr style interface for memory management +#endif + +class cChunkBuffer +{ +public: + + cChunkBuffer() + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + : IsOwner(true) + #endif + { + memset(m_Sections, 0, sizeof(m_Sections)); + } + ~cChunkBuffer() + { + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + if(!IsOwner) return; + #endif + for (int i = 0; i < CHUNK_SECTION_NUM; i++) + { + if(m_Sections[i]) delete m_Sections[i]; + } + } + + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + cChunkBuffer(cChunkBuffer& other) : + IsOwner(true); + { + for (int i = 0; i < CHUNK_SECTION_NUM; i++) + { + m_Sections[i] = other.m_Sections[i]; + } + other.IsOwner = false; + } + void operator=(cChunkBuffer& other) + { + if(IsOwner) + { + for (int i = 0; i < CHUNK_SECTION_NUM; i++) + { + if(m_Sections[i]) delete m_Sections[i]; + } + } + IsOwner = true; + for (int i = 0; i < CHUNK_SECTION_NUM; i++) + { + m_Sections[i] = other.m_Sections[i]; + } + other.IsOwner = false; + } + #else + // unique_ptr style interface for memory management + cChunkBuffer(cChunkBuffer&& other) + { + for (int i = 0; i < CHUNK_SECTION_NUM; i++) + { + m_Sections[i] = other.m_Sections[i]; + } + } + + void operator=(cChunkBuffer&& other) + { + for (int i = 0; i < CHUNK_SECTION_NUM; i++) + { + if(m_Sections[i]) delete m_Sections[i]; + m_Sections[i] = other.m_Sections[i]; + } + } + #endif + + BLOCKTYPE GetBlock(int a_X, int a_Y, int a_Z) const + { + ASSERT((a_X >= 0) && (a_X < cChunkDef::Width)); + ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height)); + ASSERT((a_Z >= 0) && (a_Z < cChunkDef::Width)); + int Section = a_Y / CHUNK_SECTION_HEIGHT; + if(m_Sections[Section]) + { + int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * CHUNK_SECTION_HEIGHT), a_Z); + return m_Sections[Section]->m_BlockTypes[Index]; + } + else + { + return 0; + } + } + + void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block) + { + if ( + (a_RelX >= cChunkDef::Width) || (a_RelX < 0) || + (a_RelY >= cChunkDef::Height) || (a_RelY < 0) || + (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0) + ) + { + ASSERT(!"cChunkBuffer::SetMeta(): index out of range!"); + return; + } + + int Section = a_RelY / CHUNK_SECTION_HEIGHT; + if(!m_Sections[Section]) + { + m_Sections[Section] = Allocate(); + if(!m_Sections[Section]) + { + ASSERT("Failed to allocate a new section in Chunkbuffer"); + return; + } + } + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ); + m_Sections[Section]->m_BlockTypes[Index] = a_Block; + } + + NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const + { + if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) + { + int Section = a_RelY / CHUNK_SECTION_HEIGHT; + if(m_Sections[Section]) + { + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ); + return (m_Sections[Section]->m_BlockMeta[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + } + else + { + return 0; + } + } + ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!"); + return 0; + } + + void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble) + { + if ( + (a_RelX >= cChunkDef::Width) || (a_RelX < 0) || + (a_RelY >= cChunkDef::Height) || (a_RelY < 0) || + (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0) + ) + { + ASSERT(!"cChunkBuffer::SetMeta(): index out of range!"); + return; + } + + int Section = a_RelY / CHUNK_SECTION_HEIGHT; + if(!m_Sections[Section]) + { + m_Sections[Section] = Allocate(); + if(!m_Sections[Section]) + { + ASSERT("Failed to allocate a new section in Chunkbuffer"); + return; + } + } + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ); + m_Sections[Section]->m_BlockMeta[Index / 2] = static_cast( + (m_Sections[Section]->m_BlockMeta[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set + ); + } + + NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const + { + if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) + { + int Section = a_RelY / CHUNK_SECTION_HEIGHT; + if(m_Sections[Section]) + { + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ); + return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + } + else + { + return 0; + } + } + ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!"); + return 0; + } + + NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const + { + if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) + { + int Section = a_RelY / CHUNK_SECTION_HEIGHT; + if(m_Sections[Section]) + { + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ); + return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + } + else + { + return 0xFF; + } + } + ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!"); + return 0; + } + + cChunkBuffer Copy() const; + void CopyBlocks (BLOCKTYPE * a_dest, size_t a_Idx = 0, size_t length = cChunkDef::NumBlocks) const; + void CopyMeta (NIBBLETYPE * a_dest) const; + void CopyLight (NIBBLETYPE * a_dest) const; + void CopySkyLight (NIBBLETYPE * a_dest) const; + + void SetBlocks (const BLOCKTYPE * a_src); + void SetMeta (const NIBBLETYPE * a_src); + void SetLight (const NIBBLETYPE * a_src); + void SetSkyLight (const NIBBLETYPE * a_src); + +private: + + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + bool IsOwner; + #endif + + struct sChunkSection { + BLOCKTYPE m_BlockTypes [CHUNK_SECTION_HEIGHT * 16 * 16] ; + NIBBLETYPE m_BlockMeta [CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; + NIBBLETYPE m_BlockLight [CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; + NIBBLETYPE m_BlockSkyLight[CHUNK_SECTION_HEIGHT * 16 * 16 / 2]; + }; + + sChunkSection *m_Sections[CHUNK_SECTION_NUM]; + + sChunkSection * Allocate() const; +}; + + + + +/** A simple implementation of the cChunkDataCallback interface that collects all block data into a buffer +*/ +class cChunkBufferCollector : + public cChunkDataCallback +{ +public: + + cChunkBuffer m_BlockData; + +protected: + + virtual void ChunkBuffer(const cChunkBuffer & a_BlockData) override + { + m_BlockData = a_BlockData.Copy(); + } +}; + + +/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer +*/ +class cChunkDataCollector : +public cChunkDataCallback +{ +public: + + // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both. + unsigned char m_BlockData[cChunkDef::BlockDataSize]; + +protected: + + virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override + { + a_ChunkBuffer.CopyBlocks(m_BlockData); + a_ChunkBuffer.CopyMeta(m_BlockData + cChunkDef::NumBlocks); + a_ChunkBuffer.CopyLight(m_BlockData + 3 * cChunkDef::NumBlocks / 2); + a_ChunkBuffer.CopySkyLight(m_BlockData + 2 * cChunkDef::NumBlocks); + } +}; + +/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers +*/ +class cChunkDataSeparateCollector : +public cChunkDataCallback +{ +public: + + cChunkDef::BlockTypes m_BlockTypes; + cChunkDef::BlockNibbles m_BlockMetas; + cChunkDef::BlockNibbles m_BlockLight; + cChunkDef::BlockNibbles m_BlockSkyLight; + +protected: + + virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override + { + a_ChunkBuffer.CopyBlocks(m_BlockTypes); + a_ChunkBuffer.CopyMeta(m_BlockMetas); + a_ChunkBuffer.CopyLight(m_BlockLight); + a_ChunkBuffer.CopySkyLight(m_BlockSkyLight); + } +} ; + + + + -- cgit v1.2.3