Added ConstVolumeProxy to work around const setVoxelAt awkwardness.

This commit is contained in:
David Williams 2011-03-13 22:44:35 +00:00
parent 7c3e63b2ed
commit 0b1659bdef
6 changed files with 114 additions and 32 deletions

View File

@ -506,7 +506,7 @@ void createSphereInVolume(Volume<MaterialDensityPair44>& volData, Vector3DFloat
}
}
void load(const Volume<MaterialDensityPair44>& volume, PolyVox::Region reg)
void load(const ConstVolumeProxy<MaterialDensityPair44>& volume, const PolyVox::Region& reg)
{
Perlin perlin(2,2,1,234);
@ -541,12 +541,12 @@ void load(const Volume<MaterialDensityPair44>& 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<MaterialDensityPair44>& vol, PolyVox::Region reg)
void unload(const ConstVolumeProxy<MaterialDensityPair44>& 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);

View File

@ -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

View File

@ -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 <typename VoxelType>
class ConstVolumeProxy
{
//Volume is a friend so it can call the constructor.
friend class Volume<VoxelType>;
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<VoxelType>& pVolume, const Region& regValid)
:m_pVolume(pVolume)
,m_regValid(regValid)
{
}
const Volume<VoxelType>& m_pVolume;
const Region& m_regValid;
};
}
#endif //__PolyVox_ConstVolumeProxy_H__

View File

@ -60,6 +60,8 @@ namespace PolyVox
template <typename VoxelType> class Block;
template <typename VoxelType> class ConstVolumeProxy;
//---------- Volume ----------
template <typename VoxelType> class Volume;
typedef Volume<float> FloatVolume;

View File

@ -112,6 +112,8 @@ namespace PolyVox
{
// Make VolumeSampler a friend
friend class VolumeSampler<VoxelType>;
// Make the ConstVolumeProxy a friend
friend class ConstVolumeProxy<VoxelType>;
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<void(const Volume<VoxelType>&, 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<void(const ConstVolumeProxy<VoxelType>&, 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<void(const Volume<VoxelType>&, Region)> m_UnloadCallback;
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> dataOverflowHandler;
private:
Block<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
void eraseBlock(typename std::map<Vector3DInt32, Block<VoxelType> >::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<Vector3DInt32, Block<VoxelType> > m_pBlocks;
@ -195,7 +197,6 @@ namespace PolyVox
mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedBlockPos;
mutable Block<VoxelType>* m_pLastAccessedBlock;
mutable Vector3DInt32 m_v3dLoadBlockPos;
uint32_t m_uMaxUncompressedBlockCacheSize;
uint32_t m_uMaxBlocksLoaded;

View File

@ -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 <typename VoxelType>
void Volume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, Block<VoxelType> >::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<VoxelType> ConstVolumeProxy(*this, reg);
dataOverflowHandler(ConstVolumeProxy, reg);
}
m_pBlocks.erase(itBlock);
}
template <typename VoxelType>
bool Volume<VoxelType>::load_setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const
bool Volume<VoxelType>::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<Vector3DInt32, Block<VoxelType> >::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<VoxelType> 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<VoxelType> ConstVolumeProxy(*this, reg);
dataRequiredHandler(ConstVolumeProxy, reg);
}
m_v3dLoadBlockPos = Vector3DInt32((std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)());
}
m_v3dLastAccessedBlockPos = v3dBlockPos;