Bounds check added to get/setVoxelAt.

This commit is contained in:
David Williams 2010-06-15 20:32:14 +00:00
parent d0ebd53407
commit 29928b774d
4 changed files with 95 additions and 58 deletions

View File

@ -1,3 +1,11 @@
Short term
==========
Sort awkward use of 'offset'
Replace float with uchar for material.
Mesh smoothing (surface nets?)
Mesh filters/modifiers - A 'translate' modifier?
For Version 1.0 For Version 1.0
=============== ===============
Implement Memory Pool Implement Memory Pool

View File

@ -132,11 +132,11 @@ namespace PolyVox
uint16_t getShortestSideLength(void) const; uint16_t getShortestSideLength(void) const;
///Gets the length of the diagonal in voxels ///Gets the length of the diagonal in voxels
float getDiagonalLength(void) const; float getDiagonalLength(void) const;
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault = 0) const;
VoxelType getVoxelAt(const Vector3DUint16& v3dPos) const; VoxelType getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault = 0) const;
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); bool setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); bool setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
void tidyUpMemory(uint32_t uNoOfBlocksToProcess = (std::numeric_limits<uint32_t>::max)()); void tidyUpMemory(uint32_t uNoOfBlocksToProcess = (std::numeric_limits<uint32_t>::max)());

View File

@ -224,82 +224,99 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType Volume<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const VoxelType Volume<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault) const
{ {
assert(uXPos < getWidth()); //We don't use getEnclosingRegion here because we care
assert(uYPos < getHeight()); //about speed and don't need to check the lower bound.
assert(uZPos < getDepth()); if((uXPos < getWidth()) && (uYPos < getHeight()) && (uZPos < getDepth()))
{
const uint16_t blockX = uXPos >> m_uBlockSideLengthPower;
const uint16_t blockY = uYPos >> m_uBlockSideLengthPower;
const uint16_t blockZ = uZPos >> m_uBlockSideLengthPower;
const uint16_t blockX = uXPos >> m_uBlockSideLengthPower; const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower);
const uint16_t blockY = uYPos >> m_uBlockSideLengthPower; const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const uint16_t blockZ = uZPos >> m_uBlockSideLengthPower; const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower); const std::shared_ptr< Block< VoxelType > >& block = m_pBlocks
const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); [
const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); blockX +
blockY * m_uWidthInBlocks +
blockZ * m_uWidthInBlocks * m_uHeightInBlocks
];
const std::shared_ptr< Block< VoxelType > >& block = m_pBlocks return block->getVoxelAt(xOffset,yOffset,zOffset);
[ }
blockX + else
blockY * m_uWidthInBlocks + {
blockZ * m_uWidthInBlocks * m_uHeightInBlocks return tDefault;
]; }
return block->getVoxelAt(xOffset,yOffset,zOffset);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType Volume<VoxelType>::getVoxelAt(const Vector3DUint16& v3dPos) const VoxelType Volume<VoxelType>::getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault) const
{ {
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tDefault);
} }
#pragma endregion #pragma endregion
#pragma region Setters #pragma region Setters
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) bool Volume<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{ {
const uint16_t blockX = uXPos >> m_uBlockSideLengthPower; //We don't use getEnclosingRegion here because we care
const uint16_t blockY = uYPos >> m_uBlockSideLengthPower; //about speed and don't need to check the lower bound.
const uint16_t blockZ = uZPos >> m_uBlockSideLengthPower; if((uXPos < getWidth()) && (uYPos < getHeight()) && (uZPos < getDepth()))
const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower);
const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
uint32_t uBlockIndex =
blockX +
blockY * m_uWidthInBlocks +
blockZ * m_uWidthInBlocks * m_uHeightInBlocks;
std::shared_ptr< Block<VoxelType> >& block = m_pBlocks[uBlockIndex];
//It's quite possible that the user might attempt to set a voxel to it's current value.
//We test for this case firstly because it could help performance, but more importantly
//because it lets us avoid unsharing blocks unnecessarily.
if(block->getVoxelAt(xOffset, yOffset, zOffset) != tValue)
{ {
if(block.unique()) const uint16_t blockX = uXPos >> m_uBlockSideLengthPower;
const uint16_t blockY = uYPos >> m_uBlockSideLengthPower;
const uint16_t blockZ = uZPos >> m_uBlockSideLengthPower;
const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower);
const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
uint32_t uBlockIndex =
blockX +
blockY * m_uWidthInBlocks +
blockZ * m_uWidthInBlocks * m_uHeightInBlocks;
std::shared_ptr< Block<VoxelType> >& block = m_pBlocks[uBlockIndex];
//It's quite possible that the user might attempt to set a voxel to it's current value.
//We test for this case firstly because it could help performance, but more importantly
//because it lets us avoid unsharing blocks unnecessarily.
if(block->getVoxelAt(xOffset, yOffset, zOffset) != tValue)
{ {
block->setVoxelAt(xOffset,yOffset,zOffset, tValue); if(block.unique())
//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. block->setVoxelAt(xOffset,yOffset,zOffset, tValue);
m_vecBlockIsPotentiallyHomogenous[uBlockIndex] = true; //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.
else m_vecBlockIsPotentiallyHomogenous[uBlockIndex] = true;
{ }
std::shared_ptr< Block<VoxelType> > pNewBlock(new Block<VoxelType>(*(block))); else
block = pNewBlock; {
m_vecBlockIsPotentiallyHomogenous[uBlockIndex] = false; std::shared_ptr< Block<VoxelType> > pNewBlock(new Block<VoxelType>(*(block)));
block->setVoxelAt(xOffset,yOffset,zOffset, tValue); block = pNewBlock;
m_vecBlockIsPotentiallyHomogenous[uBlockIndex] = false;
block->setVoxelAt(xOffset,yOffset,zOffset, tValue);
}
} }
//Return true to indicate that we modified a voxel.
return true;
}
else
{
//Return false to indicate that no voxel was modified.
return false;
} }
} }
template <typename VoxelType> template <typename VoxelType>
void Volume<VoxelType>::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) bool Volume<VoxelType>::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
{ {
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
} }
#pragma endregion #pragma endregion

View File

@ -33,6 +33,18 @@ void TestVolume::testSize()
{ {
const uint16_t g_uVolumeSideLength = 128; const uint16_t g_uVolumeSideLength = 128;
Volume<uint8_t> volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength); Volume<uint8_t> volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength);
//Note: Deliberatly go past each edge by one to test if the bounds checking works.
for (uint16_t z = 0; z < g_uVolumeSideLength + 1; z++)
{
for (uint16_t y = 0; y < g_uVolumeSideLength + 1; y++)
{
for (uint16_t x = 0; x < g_uVolumeSideLength + 1; x++)
{
volData.setVoxelAt(x,y,z,255);
}
}
}
volData.tidyUpMemory(0); volData.tidyUpMemory(0);