Moved Block into SimpleVolume class.

This commit is contained in:
David Williams 2011-04-29 22:43:44 +01:00
parent bc9f1e8ac5
commit 032accd915
3 changed files with 262 additions and 10 deletions

View File

@ -24,7 +24,6 @@ freely, subject to the following restrictions:
#ifndef __PolyVox_SimpleVolume_H__ #ifndef __PolyVox_SimpleVolume_H__
#define __PolyVox_SimpleVolume_H__ #define __PolyVox_SimpleVolume_H__
#include "PolyVoxImpl/Block.h"
#include "Region.h" #include "Region.h"
#include "PolyVoxForwardDeclarations.h" #include "PolyVoxForwardDeclarations.h"
@ -40,6 +39,47 @@ namespace PolyVox
class SimpleVolume class SimpleVolume
{ {
public: public:
class Block
{
template <typename LengthType>
struct RunlengthEntry
{
LengthType length;
VoxelType value;
//We can parametise the length on anything up to uint32_t.
//This lets us experiment with the optimal size in the future.
static uint32_t maxRunlength(void) {return (std::numeric_limits<LengthType>::max)();}
};
//Make Sampler a friend
friend class LargeVolume<VoxelType>::Sampler;
public:
Block(uint16_t uSideLength = 0);
uint16_t getSideLength(void) const;
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
VoxelType getVoxelAt(const Vector3DUint16& v3dPos) const;
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
void fill(VoxelType tValue);
void initialise(uint16_t uSideLength);
uint32_t calculateSizeInBytes(void);
public:
void compress(void);
void uncompress(void);
std::vector< RunlengthEntry<uint16_t> > m_vecCompressedData;
VoxelType* m_tUncompressedData;
uint16_t m_uSideLength;
uint8_t m_uSideLengthPower;
bool m_bIsCompressed;
bool m_bIsUncompressedDataModified;
};
class Sampler class Sampler
{ {
public: public:
@ -110,9 +150,6 @@ namespace PolyVox
VoxelType* mCurrentVoxel; VoxelType* mCurrentVoxel;
}; };
// Make the ConstVolumeProxy a friend
friend class ConstVolumeProxy<VoxelType>;
struct LoadedBlock struct LoadedBlock
{ {
public: public:
@ -122,7 +159,7 @@ namespace PolyVox
{ {
} }
Block<VoxelType> block; Block block;
uint32_t timestamp; uint32_t timestamp;
}; };
@ -194,7 +231,7 @@ private:
/// is absolutely unsafe /// is absolutely unsafe
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> m_funcDataOverflowHandler; polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> m_funcDataOverflowHandler;
Block<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
void eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const; void eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const;
/// this function can be called by m_funcDataRequiredHandler without causing any weird effects /// this function can be called by m_funcDataRequiredHandler without causing any weird effects
bool setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const; bool setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const;
@ -209,7 +246,7 @@ private:
mutable std::vector< LoadedBlock* > m_vecUncompressedBlockCache; mutable std::vector< LoadedBlock* > m_vecUncompressedBlockCache;
mutable uint32_t m_uTimestamper; mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Vector3DInt32 m_v3dLastAccessedBlockPos;
mutable Block<VoxelType>* m_pLastAccessedBlock; mutable Block* m_pLastAccessedBlock;
uint32_t m_uMaxNumberOfUncompressedBlocks; uint32_t m_uMaxNumberOfUncompressedBlocks;
//We don't store an actual Block for the border, just the uncompressed data. This is partly because the border //We don't store an actual Block for the border, just the uncompressed data. This is partly because the border
@ -235,6 +272,7 @@ private:
}; };
} }
#include "SimpleVolumeBlock.inl"
#include "SimpleVolume.inl" #include "SimpleVolume.inl"
#include "SimpleVolumeSampler.inl" #include "SimpleVolumeSampler.inl"

View File

@ -187,7 +187,7 @@ namespace PolyVox
const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset);
} }
@ -276,7 +276,7 @@ namespace PolyVox
const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue);
@ -420,7 +420,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
Block<VoxelType>* SimpleVolume<VoxelType>::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const typename SimpleVolume<VoxelType>::Block* SimpleVolume<VoxelType>::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const
{ {
Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ); Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ);

View File

@ -0,0 +1,214 @@
/*******************************************************************************
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.
*******************************************************************************/
#include "PolyVoxImpl/Utility.h"
#include "Vector.h"
#include <cassert>
#include <cstring> //For memcpy
#include <limits>
#include <stdexcept> //for std::invalid_argument
namespace PolyVox
{
template <typename VoxelType>
SimpleVolume<VoxelType>::Block::Block(uint16_t uSideLength)
:m_uSideLength(0)
,m_uSideLengthPower(0)
,m_tUncompressedData(0)
,m_bIsCompressed(true)
,m_bIsUncompressedDataModified(true)
{
if(uSideLength != 0)
{
initialise(uSideLength);
}
}
template <typename VoxelType>
uint16_t SimpleVolume<VoxelType>::Block::getSideLength(void) const
{
return m_uSideLength;
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Block::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{
assert(uXPos < m_uSideLength);
assert(uYPos < m_uSideLength);
assert(uZPos < m_uSideLength);
assert(m_tUncompressedData);
return m_tUncompressedData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
];
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Block::getVoxelAt(const Vector3DUint16& v3dPos) const
{
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{
assert(uXPos < m_uSideLength);
assert(uYPos < m_uSideLength);
assert(uZPos < m_uSideLength);
assert(m_tUncompressedData);
m_tUncompressedData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
] = tValue;
m_bIsUncompressedDataModified = true;
}
template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
{
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
}
template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::fill(VoxelType tValue)
{
if(!m_bIsCompressed)
{
//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.
const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue);
m_bIsUncompressedDataModified = true;
}
else
{
RunlengthEntry<uint16_t> rle;
rle.length = m_uSideLength*m_uSideLength*m_uSideLength;
rle.value = tValue;
m_vecCompressedData.clear();
m_vecCompressedData.push_back(rle);
}
}
template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::initialise(uint16_t uSideLength)
{
//Debug mode validation
assert(isPowerOf2(uSideLength));
//Release mode validation
if(!isPowerOf2(uSideLength))
{
throw std::invalid_argument("Block side length must be a power of two.");
}
//Compute the side length
m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(uSideLength);
SimpleVolume<VoxelType>::Block::fill(VoxelType());
}
template <typename VoxelType>
uint32_t SimpleVolume<VoxelType>::Block::calculateSizeInBytes(void)
{
uint32_t uSizeInBytes = sizeof(Block<VoxelType>);
uSizeInBytes += m_vecCompressedData.capacity() * sizeof(RunlengthEntry<uint16_t>);
return uSizeInBytes;
}
template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::compress(void)
{
assert(m_bIsCompressed == false);
assert(m_tUncompressedData != 0);
//If the uncompressed data hasn't actually been
//modified then we don't need to redo the compression.
if(m_bIsUncompressedDataModified)
{
uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
m_vecCompressedData.clear();
RunlengthEntry<uint16_t> entry;
entry.length = 1;
entry.value = m_tUncompressedData[0];
for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct)
{
VoxelType value = m_tUncompressedData[ct];
if((value == entry.value) && (entry.length < entry.maxRunlength()))
{
entry.length++;
}
else
{
m_vecCompressedData.push_back(entry);
entry.value = value;
entry.length = 1;
}
}
m_vecCompressedData.push_back(entry);
//Shrink the vectors to their contents (maybe slow?):
//http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector
//C++0x may have a shrink_to_fit() function?
std::vector< RunlengthEntry<uint16_t> >(m_vecCompressedData).swap(m_vecCompressedData);
}
//Flag the uncompressed data as no longer being used.
delete[] m_tUncompressedData;
m_tUncompressedData = 0;
m_bIsCompressed = true;
}
template <typename VoxelType>
void SimpleVolume<VoxelType>::Block::uncompress(void)
{
assert(m_bIsCompressed == true);
assert(m_tUncompressedData == 0);
m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
VoxelType* pUncompressedData = m_tUncompressedData;
for(uint32_t ct = 0; ct < m_vecCompressedData.size(); ++ct)
{
std::fill(pUncompressedData, pUncompressedData + m_vecCompressedData[ct].length, m_vecCompressedData[ct].value);
pUncompressedData += m_vecCompressedData[ct].length;
}
m_bIsCompressed = false;
m_bIsUncompressedDataModified = false;
}
}