diff --git a/examples/Basic/OpenGLWidget.cpp b/examples/Basic/OpenGLWidget.cpp index d5a8f283..dacfe30f 100644 --- a/examples/Basic/OpenGLWidget.cpp +++ b/examples/Basic/OpenGLWidget.cpp @@ -41,6 +41,7 @@ void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh::Block(uint16_t uSideLength) :m_uSideLength(0) ,m_uSideLengthPower(0) - ,m_tData(0) + ,m_tCompressedData(0) + ,m_tUncompressedData(0) + ,m_bIsCompressed(true) + ,m_uTimestamp(0) { if(uSideLength != 0) { @@ -52,8 +55,8 @@ namespace PolyVox template Block::~Block() { - delete[] m_tData; - m_tData = 0; + delete[] m_tCompressedData; + m_tCompressedData = 0; } template @@ -66,12 +69,12 @@ namespace PolyVox //If this fails an exception will be thrown. Memory is not //allocated and there is nothing else in this class to clean up - m_tData = new VoxelType[rhs.m_uSideLength * rhs.m_uSideLength * rhs.m_uSideLength]; + m_tCompressedData = new VoxelType[rhs.m_uSideLength * rhs.m_uSideLength * rhs.m_uSideLength]; //Copy the data m_uSideLength = rhs.m_uSideLength; m_uSideLengthPower = rhs.m_uSideLengthPower; - memcpy(m_tData, rhs.m_tData, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); + memcpy(m_tCompressedData, rhs.m_tCompressedData, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); return *this; } @@ -89,7 +92,9 @@ namespace PolyVox assert(uYPos < m_uSideLength); assert(uZPos < m_uSideLength); - return m_tData + assert(m_tUncompressedData); + + return m_tUncompressedData [ uXPos + uYPos * m_uSideLength + @@ -110,7 +115,9 @@ namespace PolyVox assert(uYPos < m_uSideLength); assert(uZPos < m_uSideLength); - m_tData + assert(m_tUncompressedData); + + m_tUncompressedData [ uXPos + uYPos * m_uSideLength + @@ -130,9 +137,11 @@ namespace PolyVox //The memset *may* be faster than the std::fill(), but it doesn't compile nicely //in 64-bit mode as casting the pointer to an int causes a loss of precision. - //memset(m_tData, (int)tValue, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); + assert(m_tUncompressedData); + + //memset(m_tCompressedData, (int)tValue, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; - std::fill(m_tData, m_tData + uNoOfVoxels, tValue); + std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue); } template @@ -152,12 +161,12 @@ namespace PolyVox m_uSideLengthPower = logBase2(uSideLength); //Delete the old data - delete[] m_tData; - m_tData = 0; + delete[] m_tCompressedData; + m_tCompressedData = 0; //If this fails an exception will be thrown. Memory is not //allocated and there is nothing else in this class to clean up - m_tData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; + m_tCompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; } template @@ -165,7 +174,7 @@ namespace PolyVox { uint32_t uSizeInChars = sizeof(Block); - if(m_tData != 0) + if(m_tCompressedData != 0) { const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; uSizeInChars += uNoOfVoxels * sizeof(VoxelType); @@ -173,4 +182,21 @@ namespace PolyVox return uSizeInChars; } + + template + void Block::compress(void) + { + memcpy(m_tCompressedData, m_tUncompressedData, sizeof(VoxelType) * m_uSideLength * m_uSideLength * m_uSideLength); + delete[] m_tUncompressedData; + m_tUncompressedData = 0; + m_bIsCompressed = true; + } + + template + void Block::uncompress(void) + { + m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; + memcpy(m_tUncompressedData, m_tCompressedData, sizeof(VoxelType) * m_uSideLength * m_uSideLength * m_uSideLength); + m_bIsCompressed = false; + } } diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index 32d7f672..36b24e9c 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -29,6 +29,7 @@ freely, subject to the following restrictions: #include #include +#include #include #include @@ -155,8 +156,12 @@ namespace PolyVox void resize(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength = 32); private: + Block* getUncompressedBlock(Block* block) const; + Block m_pBorderBlock; std::vector< Block > m_pBlocks; + //mutable Block* m_pUncompressedBlock; + mutable std::set*> m_pUncompressedBlocks; uint32_t m_uNoOfBlocksInVolume; @@ -174,6 +179,7 @@ namespace PolyVox uint16_t m_uLongestSideLength; uint16_t m_uShortestSideLength; float m_fDiagonalLength; + mutable uint32_t m_uTimestamper; }; //Some handy typedefs diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index d53427fc..1c25c957 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -48,6 +48,7 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// template Volume::Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength) + :m_uTimestamper(0) { //Create a volume of the right size. resize(uWidth, uHeight, uDepth, uBlockSideLength); @@ -69,7 +70,8 @@ namespace PolyVox template VoxelType Volume::getBorderValue(void) const { - return m_pBorderBlock.getVoxelAt(0,0,0); + Block* pUncompressedBorderBlock = getUncompressedBlock(const_cast*>(&m_pBorderBlock)); + return pUncompressedBorderBlock->getVoxelAt(0,0,0); } //////////////////////////////////////////////////////////////////////////////// @@ -176,7 +178,9 @@ namespace PolyVox blockZ * m_uWidthInBlocks * m_uHeightInBlocks ]; - return block.getVoxelAt(xOffset,yOffset,zOffset); + Block* pUncompressedBlock = getUncompressedBlock(const_cast*>(&block)); + + return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); } else { @@ -200,7 +204,8 @@ namespace PolyVox template void Volume::setBorderValue(const VoxelType& tBorder) { - return m_pBorderBlock.fill(tBorder); + Block* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock); + return pUncompressedBorderBlock->fill(tBorder); } //////////////////////////////////////////////////////////////////////////////// @@ -232,7 +237,9 @@ namespace PolyVox Block& block = m_pBlocks[uBlockIndex]; - block.setVoxelAt(xOffset,yOffset,zOffset, tValue); + Block* pUncompressedBlock = getUncompressedBlock(&block); + + pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); //Return true to indicate that we modified a voxel. return true; @@ -328,11 +335,80 @@ namespace PolyVox //Create the border block m_pBorderBlock.resize(uBlockSideLength); - m_pBorderBlock.fill(VoxelType()); + Block* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock); + pUncompressedBorderBlock->fill(VoxelType()); //Other properties we might find useful later m_uLongestSideLength = (std::max)((std::max)(m_uWidth,m_uHeight),m_uDepth); m_uShortestSideLength = (std::min)((std::min)(m_uWidth,m_uHeight),m_uDepth); m_fDiagonalLength = sqrtf(static_cast(m_uWidth * m_uWidth + m_uHeight * m_uHeight + m_uDepth * m_uDepth)); } + + /*template + Block* Volume::getUncompressedBlock(Block* block) const + { + if(block == m_pUncompressedBlock) + { + return m_pUncompressedBlock; + } + + if(m_pUncompressedBlock) + { + m_pUncompressedBlock->compress(); + } + + m_pUncompressedBlock = block; + m_pUncompressedBlock->uncompress(); + + return m_pUncompressedBlock; + }*/ + + /*template + Block* Volume::getUncompressedBlock(Block* block) const + { + std::set*>::iterator iterBlock = m_pUncompressedBlocks.find(block); + if(iterBlock != m_pUncompressedBlocks.end()) + { + return block; + } + + block->uncompress(); + m_pUncompressedBlocks.insert(block); + + return block; + }*/ + + template + Block* Volume::getUncompressedBlock(Block* block) const + { + block->m_uTimestamp = ++m_uTimestamper; + + if(block->m_bIsCompressed == false) + { + return block; + } + + const uint32_t MaxUncompressedBlocks = 4; + if(m_pUncompressedBlocks.size() == MaxUncompressedBlocks) + { + Block* pLeastRecentlyUsedBlock; + uint32_t uLeastRecentTimestamp = 100000000; + for(std::set*>::iterator iter = m_pUncompressedBlocks.begin(); iter != m_pUncompressedBlocks.end(); iter++) + { + if((*iter)->m_uTimestamp < uLeastRecentTimestamp) + { + uLeastRecentTimestamp = (*iter)->m_uTimestamp; + pLeastRecentlyUsedBlock = *iter; + } + } + + pLeastRecentlyUsedBlock->compress(); + m_pUncompressedBlocks.erase(pLeastRecentlyUsedBlock); + } + + block->uncompress(); + m_pUncompressedBlocks.insert(block); + + return block; + } } diff --git a/library/PolyVoxCore/include/VolumeSampler.inl b/library/PolyVoxCore/include/VolumeSampler.inl index a9752074..df97d81c 100644 --- a/library/PolyVoxCore/include/VolumeSampler.inl +++ b/library/PolyVoxCore/include/VolumeSampler.inl @@ -155,11 +155,14 @@ namespace PolyVox uZBlock * mVolume->m_uWidthInBlocks * mVolume->m_uHeightInBlocks; const Block& currentBlock = mVolume->m_pBlocks[uBlockIndexInVolume]; - mCurrentVoxel = currentBlock.m_tData + uVoxelIndexInBlock; + Block* pUncompressedCurrentBlock = mVolume->getUncompressedBlock(const_cast*>(¤tBlock)); + + mCurrentVoxel = pUncompressedCurrentBlock->m_tUncompressedData + uVoxelIndexInBlock; } else { - mCurrentVoxel = mVolume->m_pBorderBlock.m_tData + uVoxelIndexInBlock; + Block* pUncompressedBorderBlock = mVolume->getUncompressedBlock(&(mVolume->m_pBorderBlock)); + mCurrentVoxel = pUncompressedBorderBlock->m_tUncompressedData + uVoxelIndexInBlock; } }