Merged in RLE branch.

This commit is contained in:
David Williams
2011-04-05 20:55:20 +00:00
54 changed files with 29210 additions and 730 deletions

View File

@ -84,7 +84,7 @@ namespace PolyVox
return false;
}
PolyVox::Vector3DInt16 position;
PolyVox::Vector3DInt32 position;
Node* parent;
float gVal;
float hVal;

View File

@ -25,20 +25,29 @@ freely, subject to the following restrictions:
#define __PolyVox_Block_H__
#include "PolyVoxForwardDeclarations.h"
#include <limits>
#include <vector>
namespace PolyVox
{
template <typename VoxelType>
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 VolumeSampler a friend
friend class VolumeSampler<VoxelType>;
public:
Block(uint16_t uSideLength);
Block(const Block& rhs);
~Block();
Block& operator=(const Block& rhs);
Block(uint16_t uSideLength = 0);
uint16_t getSideLength(void) const;
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
@ -48,13 +57,19 @@ namespace PolyVox
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
void fill(VoxelType tValue);
bool isHomogeneous(void);
uint32_t sizeInChars(void);
void initialise(uint16_t uSideLength);
uint32_t calculateSizeInBytes(void);
private:
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;
VoxelType* m_tData;
bool m_bIsCompressed;
bool m_bIsUncompressedDataModified;
};
}

View File

@ -27,63 +27,23 @@ freely, subject to the following restrictions:
#include <cassert>
#include <cstring> //For memcpy
#include <limits>
#include <stdexcept> //for std::invalid_argument
namespace PolyVox
{
template <typename VoxelType>
Block<VoxelType>::Block(uint16_t uSideLength)
:m_tData(0)
:m_uSideLength(0)
,m_uSideLengthPower(0)
,m_tUncompressedData(0)
,m_bIsCompressed(true)
,m_bIsUncompressedDataModified(true)
{
//Debug mode validation
assert(isPowerOf2(uSideLength));
//Release mode validation
if(!isPowerOf2(uSideLength))
if(uSideLength != 0)
{
throw std::invalid_argument("Block side length must be a power of two.");
initialise(uSideLength);
}
//Compute the side length
m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(uSideLength);
//If this fails an exception will be thrown. Memory is not
//allocated and there is nothing else in this class to clean up
m_tData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
}
template <typename VoxelType>
Block<VoxelType>::Block(const Block<VoxelType>& rhs)
{
*this = rhs;
}
template <typename VoxelType>
Block<VoxelType>::~Block()
{
delete[] m_tData;
m_tData = 0;
}
template <typename VoxelType>
Block<VoxelType>& Block<VoxelType>::operator=(const Block<VoxelType>& rhs)
{
if (this == &rhs)
{
return *this;
}
//If this fails an exception will be thrown. Memory is not
//allocated and there is nothing else in this class to clean up
m_tData = new VoxelType[rhs.m_uSideLength * rhs.m_uSideLength * rhs.m_uSideLength];
//Copy the data
m_uSideLength = rhs.m_uSideLength;
m_uSideLengthPower = rhs.m_uSideLengthPower;
memcpy(m_tData, rhs.m_tData, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType));
return *this;
}
template <typename VoxelType>
@ -99,7 +59,9 @@ namespace PolyVox
assert(uYPos < m_uSideLength);
assert(uZPos < m_uSideLength);
return m_tData
assert(m_tUncompressedData);
return m_tUncompressedData
[
uXPos +
uYPos * m_uSideLength +
@ -120,12 +82,16 @@ namespace PolyVox
assert(uYPos < m_uSideLength);
assert(uZPos < m_uSideLength);
m_tData
assert(m_tUncompressedData);
m_tUncompressedData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
] = tValue;
m_bIsUncompressedDataModified = true;
}
template <typename VoxelType>
@ -137,41 +103,113 @@ namespace PolyVox
template <typename VoxelType>
void Block<VoxelType>::fill(VoxelType tValue)
{
//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.
//memset(m_tData, (int)tValue, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType));
const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
std::fill(m_tData, m_tData + uNoOfVoxels, tValue);
}
template <typename VoxelType>
bool Block<VoxelType>::isHomogeneous(void)
{
const VoxelType tFirstVoxel = m_tData[0];
const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct)
{
if(m_tData[ct] != tFirstVoxel)
{
return false;
}
}
return true;
}
template <typename VoxelType>
uint32_t Block<VoxelType>::sizeInChars(void)
{
uint32_t uSizeInChars = sizeof(Block<VoxelType>);
if(m_tData != 0)
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;
uSizeInChars += uNoOfVoxels * sizeof(VoxelType);
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 Block<VoxelType>::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.");
}
return uSizeInChars;
//Compute the side length
m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(uSideLength);
Block<VoxelType>::fill(VoxelType());
}
template <typename VoxelType>
uint32_t Block<VoxelType>::calculateSizeInBytes(void)
{
uint32_t uSizeInBytes = sizeof(Block<VoxelType>);
uSizeInBytes += m_vecCompressedData.capacity() * sizeof(RunlengthEntry<uint16_t>);
return uSizeInBytes;
}
template <typename VoxelType>
void Block<VoxelType>::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 Block<VoxelType>::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;
}
}

View File

@ -51,6 +51,11 @@ freely, subject to the following restrictions:
#include <boost/functional/hash.hpp>
#define polyvox_hash boost::hash
#include <boost/bind.hpp>
#define polyvox_bind boost::bind
#define polyvox_placeholder_1 _1
#define polyvox_placeholder_2 _2
//As long as we're requiring boost, we'll use it to compensate
//for the missing cstdint header too.
@ -68,6 +73,9 @@ freely, subject to the following restrictions:
#include <memory>
#define polyvox_shared_ptr std::shared_ptr
#define polyvox_function std::function
#define polyvox_bind std::bind
#define polyvox_placeholder_1 std::placeholders::_1
#define polyvox_placeholder_2 std::placeholders::_2
#define polyvox_hash std::hash
#endif