diff --git a/library/include/PolyVoxCore/BlockData.h b/library/include/PolyVoxCore/BlockData.h index 040f7493..90934b41 100644 --- a/library/include/PolyVoxCore/BlockData.h +++ b/library/include/PolyVoxCore/BlockData.h @@ -50,10 +50,11 @@ namespace PolyVox void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); void fill(VoxelType tValue); + bool isHomogeneous(void); private: uint16 m_uSideLength; - uint8 m_uSideLengthPower; + uint8 m_uSideLengthPower; VoxelType* m_tData; }; } diff --git a/library/include/PolyVoxCore/BlockData.inl b/library/include/PolyVoxCore/BlockData.inl index 218580d2..0ea5d60d 100644 --- a/library/include/PolyVoxCore/BlockData.inl +++ b/library/include/PolyVoxCore/BlockData.inl @@ -141,5 +141,23 @@ namespace PolyVox { memset(m_tData, tValue, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); } + + template + bool BlockData::isHomogeneous(void) + { + VoxelType currentVoxel = m_tData; + VoxelType firstVal = *currentVoxel; + + uint32 uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; + for(uint32 ct = 1; ct < uNoOfVoxels; ++ct) + { + ++currentVoxel; + if(*currentVoxel != firstVoxel) + { + return false; + } + } + return true; + } #pragma endregion } diff --git a/library/include/PolyVoxCore/Volume.h b/library/include/PolyVoxCore/Volume.h index 5973f77d..49b4fa90 100644 --- a/library/include/PolyVoxCore/Volume.h +++ b/library/include/PolyVoxCore/Volume.h @@ -38,8 +38,18 @@ namespace PolyVox public: BlockData* m_pBlockData; VoxelType m_pHomogenousValue; - bool m_pIsShared; - bool m_pIsPotentiallySharable; + bool m_bIsShared; + bool m_bIsPotentiallySharable; + }; + + template + class ReferenceCountedBlockData + { + public: + ReferenceCountedBlockData() : m_pBlockData(0), m_uReferenceCount(0) {} + + BlockData* m_pBlockData; + uint32 m_uReferenceCount; }; template @@ -69,14 +79,10 @@ namespace PolyVox VolumeIterator lastVoxel(void); private: - BlockData* getHomogenousBlock(VoxelType tHomogenousValue) const; + BlockData* getHomogenousBlockData(VoxelType tHomogenousValue) const; - //Block** m_pBlocks; - //bool* m_pIsShared; - //bool* m_pIsPotentiallySharable; - //VoxelType* m_pHomogenousValue; Block* m_pBlocks; - mutable std::map*> m_pHomogenousBlocks; + mutable std::map > m_pHomogenousBlockData; uint32 m_uNoOfBlocksInVolume; uint16 m_uSideLengthInBlocks; diff --git a/library/include/PolyVoxCore/Volume.inl b/library/include/PolyVoxCore/Volume.inl index fe07942b..d599f64a 100644 --- a/library/include/PolyVoxCore/Volume.inl +++ b/library/include/PolyVoxCore/Volume.inl @@ -71,23 +71,23 @@ namespace PolyVox //Create the blocks /*m_pBlocks = new Block*[m_uNoOfBlocksInVolume]; - m_pIsShared = new bool[m_uNoOfBlocksInVolume]; - m_pIsPotentiallySharable = new bool[m_uNoOfBlocksInVolume]; + m_bIsShared = new bool[m_uNoOfBlocksInVolume]; + m_bIsPotentiallySharable = new bool[m_uNoOfBlocksInVolume]; m_pHomogenousValue = new VoxelType[m_uNoOfBlocksInVolume]; for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) { m_pBlocks[i] = getHomogenousBlock(0); - m_pIsShared[i] = true; - m_pIsPotentiallySharable[i] = false; + m_bIsShared[i] = true; + m_bIsPotentiallySharable[i] = false; m_pHomogenousValue[i] = 0; }*/ m_pBlocks = new Block[m_uNoOfBlocksInVolume]; for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) { - m_pBlocks[i].m_pBlockData = getHomogenousBlock(0); - m_pBlocks[i].m_pIsShared = true; - m_pBlocks[i].m_pIsPotentiallySharable = false; + m_pBlocks[i].m_pBlockData = getHomogenousBlockData(0); + m_pBlocks[i].m_bIsShared = true; + m_pBlocks[i].m_bIsPotentiallySharable = false; m_pBlocks[i].m_pHomogenousValue = 0; } } @@ -103,15 +103,15 @@ namespace PolyVox { for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) { - if(m_pBlocks[i].m_pIsShared == false) + if(m_pBlocks[i].m_bIsShared == false) { delete m_pBlocks[i].m_pBlockData; m_pBlocks[i].m_pBlockData = 0; } } delete[] m_pBlocks; - /*delete[] m_pIsShared; - delete[] m_pIsPotentiallySharable; + /*delete[] m_bIsShared; + delete[] m_bIsPotentiallySharable; delete[] m_pHomogenousValue;*/ } #pragma endregion @@ -190,14 +190,14 @@ namespace PolyVox blockY * m_uSideLengthInBlocks + blockZ * m_uSideLengthInBlocks * m_uSideLengthInBlocks; - const bool bIsShared = m_pBlocks[uBlockIndex].m_pIsShared; + const bool bIsShared = m_pBlocks[uBlockIndex].m_bIsShared; if(bIsShared) { const VoxelType tHomogenousValue = m_pBlocks[uBlockIndex].m_pHomogenousValue; if(tHomogenousValue != tValue) { m_pBlocks[uBlockIndex].m_pBlockData = new BlockData(m_uBlockSideLength); - m_pBlocks[uBlockIndex].m_pIsShared = false; + m_pBlocks[uBlockIndex].m_bIsShared = false; m_pBlocks[uBlockIndex].m_pBlockData->fill(tHomogenousValue); m_pBlocks[uBlockIndex].m_pBlockData->setVoxelAt(xOffset,yOffset,zOffset, tValue); } @@ -207,7 +207,7 @@ namespace PolyVox m_pBlocks[uBlockIndex].m_pBlockData->setVoxelAt(xOffset,yOffset,zOffset, tValue); //There is a chance that setting this voxel makes the block homogenous and therefore shareable. But checking //this will take some time, so for now just set a flag. - m_pBlocks[uBlockIndex].m_pIsPotentiallySharable = true; + m_pBlocks[uBlockIndex].m_bIsPotentiallySharable = true; } } @@ -230,6 +230,34 @@ namespace PolyVox template void Volume::idle(uint32 uAmount) { + //This function performs two roles. Firstly, it examines all of the blocks which are marked as + //'potentially sharable' to determine whether they really are sharable or not. For those which + //are sharable, it adjusts the pointer and deletes tho old data. Secondly, it determines which + //homogeneous regions are not actually being used (by thier reference count) and frees them. + + for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) + { + Block block = m_pBlocks[i]; + if(block.m_bIsPotentiallySharable) + { + bool isSharable = block.m_pBlockData->isHomogeneous(); + if(isSharable) + { + VoxelType homogeneousValue = block.m_pBlockData->getVoxelAt(0,0,0); + delete block.m_pBlockData; + + block.m_pBlockData = getHomogenousBlockData(homogeneousValue); + block.m_pHomogenousValue = homogeneousValue; + block.m_bIsShared = true; + } + + //Either way, we have now determined whether the block was sharable. So it's not *potentially* sharable. + block.m_bIsPotentiallySharable = false; + } + } + + //Note - this second step should probably happen immediatly, rather than in this function. + //Use of a shared pointer system would allow this. } template @@ -265,17 +293,23 @@ namespace PolyVox #pragma region Private Implementation template - BlockData* Volume::getHomogenousBlock(VoxelType tHomogenousValue) const + BlockData* Volume::getHomogenousBlockData(VoxelType tHomogenousValue) const { - typename std::map*>::iterator iterResult = m_pHomogenousBlocks.find(tHomogenousValue); - if(iterResult == m_pHomogenousBlocks.end()) + typename std::map >::iterator iterResult = m_pHomogenousBlockData.find(tHomogenousValue); + if(iterResult == m_pHomogenousBlockData.end()) { - BlockData* pBlock = new BlockData(m_uBlockSideLength); - pBlock->fill(tHomogenousValue); - m_pHomogenousBlocks.insert(std::make_pair(tHomogenousValue, pBlock)); - return pBlock; + ReferenceCountedBlockData referenceCountedBlockData; + referenceCountedBlockData.m_pBlockData = new BlockData(m_uBlockSideLength); + referenceCountedBlockData.m_uReferenceCount++; + referenceCountedBlockData.m_pBlockData->fill(tHomogenousValue); + m_pHomogenousBlockData.insert(std::make_pair(tHomogenousValue, referenceCountedBlockData)); + return referenceCountedBlockData.m_pBlockData; + } + else + { + iterResult->second.m_uReferenceCount++; + return iterResult->second.m_pBlockData; } - return iterResult->second; } #pragma endregion }