diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index a73dccbe..5ad96666 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -506,7 +506,7 @@ void createSphereInVolume(Volume& volData, Vector3DFloat } } -void load(const Volume& volume, PolyVox::Region reg) +void load(const ConstVolumeProxy& volume, const PolyVox::Region& reg) { Perlin perlin(2,2,1,234); @@ -541,12 +541,12 @@ void load(const Volume& volume, PolyVox::Region reg) voxel.setDensity(MaterialDensityPair44::getMinDensity()); } - volume.load_setVoxelAt(x, y, z, voxel); + volume.setVoxelAt(x, y, z, voxel); } } } } -void unload(const Volume& vol, PolyVox::Region reg) +void unload(const ConstVolumeProxy& vol, const PolyVox::Region& reg) { std::cout << "warning unloading region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; } @@ -564,10 +564,10 @@ int main(int argc, char *argv[]) //If these two lines don't compile, please try commenting them out and using the two lines after //(you will need Boost for this). If you have to do this then please let us know in the forums as //we rely on community feedback to keep the Boost version running. - volData.m_LoadCallback = &load; - volData.m_UnloadCallback = &unload; - //volData.m_LoadCallback = polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2); - //volData.m_UnloadCallback = polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2); + volData.dataRequiredHandler = &load; + volData.dataOverflowHandler = &unload; + //volData.dataRequiredHandler = polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2); + //volData.dataOverflowHandler = polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2); volData.setBlockCacheSize(4096); //createSphereInVolume(volData, 30); diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index d3505650..19549348 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -22,6 +22,7 @@ SET(CORE_INC_FILES include/ArraySizes.h include/AStarPathfinder.h include/AStarPathfinder.inl + include/ConstVolumeProxy.h include/CubicSurfaceExtractor.h include/CubicSurfaceExtractor.inl include/CubicSurfaceExtractorWithNormals.h diff --git a/library/PolyVoxCore/include/ConstVolumeProxy.h b/library/PolyVoxCore/include/ConstVolumeProxy.h new file mode 100644 index 00000000..b571d462 --- /dev/null +++ b/library/PolyVoxCore/include/ConstVolumeProxy.h @@ -0,0 +1,73 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#ifndef __PolyVox_ConstVolumeProxy_H__ +#define __PolyVox_ConstVolumeProxy_H__ + +#include "PolyVoxForwardDeclarations.h" + +namespace PolyVox +{ + template + class ConstVolumeProxy + { + //Volume is a friend so it can call the constructor. + friend class Volume; + public: + VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const + { + assert(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos))); + return m_pVolume.getVoxelAt(uXPos, uYPos, uZPos); + } + + VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const + { + assert(m_regValid.containsPoint(v3dPos)); + return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + } + + void setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const + { + assert(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos))); + m_pVolume.setVoxelAtConst(uXPos, uYPos, uZPos, tValue); + } + + void setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) const + { + assert(m_regValid.containsPoint(v3dPos)); + setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); + } + private: + //Private constructor, so client code can't abuse this class. + ConstVolumeProxy(const Volume& pVolume, const Region& regValid) + :m_pVolume(pVolume) + ,m_regValid(regValid) + { + } + + const Volume& m_pVolume; + const Region& m_regValid; + }; +} + +#endif //__PolyVox_ConstVolumeProxy_H__ \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h b/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h index 9dd94c38..ec112630 100644 --- a/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h +++ b/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h @@ -60,6 +60,8 @@ namespace PolyVox template class Block; + template class ConstVolumeProxy; + //---------- Volume ---------- template class Volume; typedef Volume FloatVolume; diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index d4bcb04c..1aeabb14 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -112,6 +112,8 @@ namespace PolyVox { // Make VolumeSampler a friend friend class VolumeSampler; + // Make the ConstVolumeProxy a friend + friend class ConstVolumeProxy; struct UncompressedBlock { @@ -171,17 +173,17 @@ namespace PolyVox /// gets called when a new region is allocated and needs to be filled /// NOTE: accessing ANY voxels outside this region during the process of this function /// is absolutely unsafe - polyvox_function&, Region)> m_LoadCallback; - /// this function can be called by m_LoadCallback without causing any weird effects - bool load_setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const; + polyvox_function&, const Region&)> dataRequiredHandler; /// gets called when a Region needs to be stored by the user, because Volume will erase it right after /// this function returns /// NOTE: accessing ANY voxels outside this region during the process of this function /// is absolutely unsafe - polyvox_function&, Region)> m_UnloadCallback; + polyvox_function&, const Region&)> dataOverflowHandler; private: Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; void eraseBlock(typename std::map >::iterator itBlock) const; + /// this function can be called by dataRequiredHandler without causing any weird effects + bool setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const; //The block data mutable std::map > m_pBlocks; @@ -195,7 +197,6 @@ namespace PolyVox mutable uint32_t m_uTimestamper; mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Block* m_pLastAccessedBlock; - mutable Vector3DInt32 m_v3dLoadBlockPos; uint32_t m_uMaxUncompressedBlockCacheSize; uint32_t m_uMaxBlocksLoaded; diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index d3ebf68f..e274ad3a 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -21,6 +21,7 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ +#include "ConstVolumeProxy.h" #include "PolyVoxImpl/Block.h" #include "Log.h" #include "VolumeSampler.h" @@ -399,28 +400,30 @@ namespace PolyVox template void Volume::eraseBlock(typename std::map >::iterator itBlock) const { - Vector3DInt32 v3dPos = itBlock->first; - Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower); - Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); - Region reg(v3dLower, v3dUpper); - if(m_UnloadCallback) { - m_UnloadCallback(std::ref(*this), reg); + if(dataOverflowHandler) + { + Vector3DInt32 v3dPos = itBlock->first; + Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower); + Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); + + Region reg(v3dLower, v3dUpper); + ConstVolumeProxy ConstVolumeProxy(*this, reg); + + dataOverflowHandler(ConstVolumeProxy, reg); } m_pBlocks.erase(itBlock); } template - bool Volume::load_setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const + bool Volume::setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const { + //We don't have any range checks in this function because it + //is a private function only called by the ConstVolumeProxy. The + //ConstVolumeProxy takes care of ensuring the range is appropriate. + const int32_t blockX = uXPos >> m_uBlockSideLengthPower; const int32_t blockY = uYPos >> m_uBlockSideLengthPower; const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; - assert(blockX == m_v3dLoadBlockPos.getX()); - assert(blockY == m_v3dLoadBlockPos.getY()); - assert(blockZ == m_v3dLoadBlockPos.getZ()); - if(blockX != m_v3dLoadBlockPos.getX() && blockY != m_v3dLoadBlockPos.getY() && blockZ != m_v3dLoadBlockPos.getZ()) { - throw(std::invalid_argument("you are not allowed to write to any voxels outside the designated region")); - } const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower); const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); @@ -462,7 +465,8 @@ namespace PolyVox typename std::map >::iterator itUnloadBlock = m_pBlocks.begin(); for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) { - if(i->second.m_uTimestamp < itUnloadBlock->second.m_uTimestamp) { + if(i->second.m_uTimestamp < itUnloadBlock->second.m_uTimestamp) + { itUnloadBlock = i; } } @@ -470,20 +474,21 @@ namespace PolyVox } Vector3DInt32 v3dLower(v3dBlockPos.getX() << m_uBlockSideLengthPower, v3dBlockPos.getY() << m_uBlockSideLengthPower, v3dBlockPos.getZ() << m_uBlockSideLengthPower); Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); - Region reg(v3dLower, v3dUpper); + // create the new block Block newBlock(m_uBlockSideLength); itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; // fill it with data (well currently fill it with nothingness) // "load" will actually call setVoxel, which will in turn call this function again but the block will be found - // so this if(itBlock == m_pBlocks.end()) never is entered + // so this if(itBlock == m_pBlocks.end()) never is entered - m_v3dLoadBlockPos = v3dBlockPos; - if(m_LoadCallback) { - m_LoadCallback(std::ref(*this), reg); + if(dataRequiredHandler) + { + Region reg(v3dLower, v3dUpper); + ConstVolumeProxy ConstVolumeProxy(*this, reg); + dataRequiredHandler(ConstVolumeProxy, reg); } - m_v3dLoadBlockPos = Vector3DInt32((std::numeric_limits::max)(), (std::numeric_limits::max)(), (std::numeric_limits::max)()); } m_v3dLastAccessedBlockPos = v3dBlockPos;