diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index 93c05f8d..66eb5254 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) createCubeInVolume(volData, Vector3DUint16(midPos+1, minPos, midPos+1), Vector3DUint16(maxPos, midPos-1, maxPos), 0); createCubeInVolume(volData, Vector3DUint16(minPos, midPos+1, midPos+1), Vector3DUint16(midPos-1, maxPos, maxPos), 0); - volData.idle(0); + volData.tidyUpMemory(0); QApplication app(argc, argv); diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index 3b7b7c01..e99cd24e 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "PolyVoxImpl/CPlusPlusZeroXSupport.h" +#include #include #include @@ -56,7 +57,7 @@ namespace PolyVox void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); - void idle(uint32_t uAmount); + void tidyUpMemory(uint32_t uNoOfBlocksToProcess = numeric_limits::max); bool isRegionHomogenous(const Region& region); private: @@ -80,6 +81,8 @@ namespace PolyVox uint8_t m_uBlockSideLengthPower; uint16_t m_uBlockSideLength; + + uint32_t m_uCurrentBlockForTidying; }; //Required for the static member diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index 33aabb98..73c22cb0 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -38,6 +38,7 @@ namespace PolyVox template Volume::Volume(uint16_t uSideLength, uint16_t uBlockSideLength) :m_pBlocks(0) + ,m_uCurrentBlockForTidying(0) { //Debug mode validation assert(isPowerOf2(uSideLength)); @@ -201,37 +202,56 @@ namespace PolyVox #pragma region Other template - void Volume::idle(uint32_t uAmount) + void Volume::tidyUpMemory(uint32_t uNoOfBlocksToProcess) { - for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) - { - if(m_vecBlockIsPotentiallyHomogenous[i]) - { - if(m_pBlocks[i].m_pBlockData->isHomogeneous()) - { - VoxelType homogeneousValue = m_pBlocks[i].m_pBlockData->getVoxelAt(0,0,0); + //Track the number of blocks we have processed. + uint32_t m_uNoOfProcessedBlocks = 0; - m_pBlocks[i].m_pBlockData = getHomogenousBlockData(homogeneousValue); + //We will loop around, and finish if we get back to our start position + uint32_t uFinishBlock = m_uCurrentBlockForTidying; + + //Increment the current block, looping around if necessary + ++m_uCurrentBlockForTidying; + m_uCurrentBlockForTidying %= m_uNoOfBlocksInVolume; + + //While we have not reached the user specified limit and there are more blocks to process... + while((m_uNoOfProcessedBlocks < uNoOfBlocksToProcess) && (m_uCurrentBlockForTidying != uFinishBlock)) + { + //We only do any work if the block is flagged as potentially homogeneous. + if(m_vecBlockIsPotentiallyHomogenous[m_uCurrentBlockForTidying]) + { + //Check if it's really homogeneous (this can be slow). + if(m_pBlocks[m_uCurrentBlockForTidying].m_pBlockData->isHomogeneous()) + { + //If so, replace is with a block from out homogeneous collection. + VoxelType homogeneousValue = m_pBlocks[m_uCurrentBlockForTidying].m_pBlockData->getVoxelAt(0,0,0); + m_pBlocks[m_uCurrentBlockForTidying].m_pBlockData = getHomogenousBlockData(homogeneousValue); } //Either way, we have now determined whether the block was sharable. So it's not *potentially* sharable. - m_vecBlockIsPotentiallyHomogenous[i] = false; + m_vecBlockIsPotentiallyHomogenous[m_uCurrentBlockForTidying] = false; + + //We've processed a block. This is inside the 'if' because the path outside the 'if' is trivially fast. + ++m_uNoOfProcessedBlocks; } + + //Increment the current block, looping around if necessary + ++m_uCurrentBlockForTidying; + m_uCurrentBlockForTidying %= m_uNoOfBlocksInVolume; } - //FIXME - Better way to do this? Maybe using for_each()? - std::list< std::map > >::iterator > itersToDelete; - for(std::map > >::iterator iter = m_pHomogenousBlockData.begin(); iter != m_pHomogenousBlockData.end(); ++iter) + //Identify and remove any homogeneous blocks which are not actually in use. + std::map > >::iterator iter = m_pHomogenousBlockData.begin(); + while(iter != m_pHomogenousBlockData.end()) { if(iter->second.unique()) { - itersToDelete.push_back(iter); + m_pHomogenousBlockData.erase(iter++); //Increments the iterator and returns the previous position to be erased. + } + else + { + ++iter; //Just increments the iterator. } - } - - for(std::list< std::map > >::iterator >::iterator listIter = itersToDelete.begin(); listIter != itersToDelete.end(); ++listIter) - { - m_pHomogenousBlockData.erase(*listIter); } }