Merge branch 'develop' into feature/cubiquity-version

Conflicts:
	library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl
	library/PolyVoxCore/source/Region.cpp
This commit is contained in:
David Williams 2013-08-09 17:05:57 +02:00
commit 6a009825b5
53 changed files with 1468 additions and 793 deletions

View File

@ -68,6 +68,9 @@ void createSphereInVolume(SimpleVolume<uint8_t>& volData, float fRadius)
int main(int argc, char *argv[])
{
// Show logs
setTraceStream(&(std::cout));
//Create and show the Qt OpenGL window
QApplication app(argc, argv);
OpenGLWidget openGLWidget(0);

View File

@ -21,11 +21,12 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#include "PolyVoxCore/FilePager.h"
#include "PolyVoxCore/MaterialDensityPair.h"
#include "PolyVoxCore/LargeVolume.h"
#include "PolyVoxCore/LowPassFilter.h"
#include "PolyVoxCore/RawVolume.h"
#include "PolyVoxCore/RLECompressor.h"
#include "PolyVoxCore/RLEBlockCompressor.h"
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/Impl/Utility.h"
@ -49,8 +50,9 @@ using namespace std;
int main(int argc, char *argv[])
{
RLECompressor<MaterialDensityPair44, uint16_t>* compressor = new RLECompressor<MaterialDensityPair44, uint16_t>();
LargeVolume<MaterialDensityPair44> volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1)), compressor, 0);
RLEBlockCompressor<MaterialDensityPair44>* compressor = new RLEBlockCompressor<MaterialDensityPair44>();
FilePager<MaterialDensityPair44>* pager = new FilePager<MaterialDensityPair44>("./");
LargeVolume<MaterialDensityPair44> volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1)), compressor, pager);
//Make our volume contain a sphere in the center.
int32_t minPos = 0;

View File

@ -28,7 +28,7 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
#include "PolyVoxCore/Pager.h"
#include "PolyVoxCore/RLECompressor.h"
#include "PolyVoxCore/RLEBlockCompressor.h"
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/LargeVolume.h"
@ -91,9 +91,11 @@ public:
/// Destructor
virtual ~PerlinNoisePager() {};
virtual void pageIn(const PolyVox::Region& region, Block<MaterialDensityPair44>* pBlockData)
virtual void pageIn(const PolyVox::Region& region, CompressedBlock<MaterialDensityPair44>* pBlockData)
{
pBlockData->createUncompressedData();
// FIXME - this isn't a great example... it's a shame we have to hard clode the block size and also create/destroy
// a compressor each time. These could at least be moved outside somewhere if we can't fix it in a better way...
UncompressedBlock<MaterialDensityPair44> block(256);
Perlin perlin(2,2,1,234);
@ -131,13 +133,18 @@ public:
// Voxel position within a block always start from zero. So if a block represents region (4, 8, 12) to (11, 19, 15)
// then the valid block voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the
// region from the volume space position in order to get the block space position.
pBlockData->setVoxelAt(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel);
block.setVoxelAt(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel);
}
}
}
// Now compress the computed data into the provided block.
RLEBlockCompressor<MaterialDensityPair44>* compressor = new RLEBlockCompressor<MaterialDensityPair44>();
compressor->compress(&block, pBlockData);
delete compressor;
}
virtual void pageOut(const PolyVox::Region& region, Block<MaterialDensityPair44>* pBlockData)
virtual void pageOut(const PolyVox::Region& region, CompressedBlock<MaterialDensityPair44>* /*pBlockData*/)
{
std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl;
}
@ -150,7 +157,7 @@ int main(int argc, char *argv[])
OpenGLWidget openGLWidget(0);
openGLWidget.show();
RLECompressor<MaterialDensityPair44, uint16_t>* compressor = new RLECompressor<MaterialDensityPair44, uint16_t>();
RLEBlockCompressor<MaterialDensityPair44>* compressor = new RLEBlockCompressor<MaterialDensityPair44>();
PerlinNoisePager* pager = new PerlinNoisePager();
LargeVolume<MaterialDensityPair44> volData(PolyVox::Region::MaxRegion, compressor, pager, 256);
volData.setMaxNumberOfBlocksInMemory(4096);

View File

@ -48,6 +48,10 @@ SET(CORE_INC_FILES
include/PolyVoxCore/BaseVolume.h
include/PolyVoxCore/BaseVolume.inl
include/PolyVoxCore/BaseVolumeSampler.inl
include/PolyVoxCore/Block.h
include/PolyVoxCore/BlockCompressor.h
include/PolyVoxCore/CompressedBlock.h
include/PolyVoxCore/CompressedBlock.inl
include/PolyVoxCore/Compressor.h
include/PolyVoxCore/CubicSurfaceExtractor.h
include/PolyVoxCore/CubicSurfaceExtractor.inl
@ -71,6 +75,8 @@ SET(CORE_INC_FILES
include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl
include/PolyVoxCore/Material.h
include/PolyVoxCore/MaterialDensityPair.h
include/PolyVoxCore/MinizBlockCompressor.h
include/PolyVoxCore/MinizBlockCompressor.inl
include/PolyVoxCore/MinizCompressor.h
include/PolyVoxCore/Pager.h
include/PolyVoxCore/PolyVoxForwardDeclarations.h
@ -82,14 +88,16 @@ SET(CORE_INC_FILES
include/PolyVoxCore/Raycast.h
include/PolyVoxCore/Raycast.inl
include/PolyVoxCore/Region.h
include/PolyVoxCore/RLECompressor.h
include/PolyVoxCore/RLECompressor.inl
include/PolyVoxCore/RLEBlockCompressor.h
include/PolyVoxCore/RLEBlockCompressor.inl
include/PolyVoxCore/SimpleVolume.h
include/PolyVoxCore/SimpleVolume.inl
include/PolyVoxCore/SimpleVolumeBlock.inl
include/PolyVoxCore/SimpleVolumeSampler.inl
include/PolyVoxCore/SurfaceMesh.h
include/PolyVoxCore/SurfaceMesh.inl
include/PolyVoxCore/UncompressedBlock.h
include/PolyVoxCore/UncompressedBlock.inl
include/PolyVoxCore/Vector.h
include/PolyVoxCore/Vector.inl
include/PolyVoxCore/VertexTypes.h
@ -104,6 +112,7 @@ SET(IMPL_SRC_FILES
source/Impl/MarchingCubesTables.cpp
source/Impl/RandomUnitVectors.cpp
source/Impl/RandomVectors.cpp
source/Impl/Timer.cpp
source/Impl/Utility.cpp
)
@ -111,8 +120,6 @@ SET(IMPL_INC_FILES
include/PolyVoxCore/Impl/ArraySizesImpl.h
include/PolyVoxCore/Impl/ArraySizesImpl.inl
include/PolyVoxCore/Impl/AStarPathfinderImpl.h
include/PolyVoxCore/Impl/Block.h
include/PolyVoxCore/Impl/Block.inl
include/PolyVoxCore/Impl/CompilerCapabilities.h
include/PolyVoxCore/Impl/Config.h
include/PolyVoxCore/Impl/ErrorHandling.h
@ -121,6 +128,7 @@ SET(IMPL_INC_FILES
include/PolyVoxCore/Impl/RandomVectors.h
include/PolyVoxCore/Impl/SubArray.h
include/PolyVoxCore/Impl/SubArray.inl
include/PolyVoxCore/Impl/Timer.h
include/PolyVoxCore/Impl/TypeDef.h
include/PolyVoxCore/Impl/Utility.h
)

View File

@ -165,7 +165,7 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tBorder*/) const
{
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType();
@ -183,7 +183,7 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tBorder*/) const
{
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType();
@ -200,7 +200,7 @@ namespace PolyVox
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
{
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType();
@ -215,7 +215,7 @@ namespace PolyVox
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
{
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType();

View File

@ -0,0 +1,66 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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_Block_H__
#define __PolyVox_Block_H__
#include "PolyVoxCore/Impl/TypeDef.h"
#include "PolyVoxCore/PolyVoxForwardDeclarations.h"
#include "PolyVoxCore/Vector.h"
#include <limits>
#include <vector>
namespace PolyVox
{
template <typename VoxelType>
class Block
{
friend class LargeVolume<VoxelType>;
public:
Block()
:m_uBlockLastAccessed(0)
,m_bDataModified(true)
{
}
protected:
// This is updated by the LargeVolume and used to discard the least recently used blocks.
uint32_t m_uBlockLastAccessed;
// This is so we can tell whether a uncompressed block has to be recompressed and whether
// a compressed block has to be paged back to disk, or whether they can just be discarded.
bool m_bDataModified;
private:
/// Private copy constructor to prevent accisdental copying
Block(const Block& /*rhs*/) {};
/// Private assignment operator to prevent accisdental copying
Block& operator=(const Block& /*rhs*/) {};
};
}
#endif

View File

@ -0,0 +1,48 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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_BlockCompressor_H__
#define __PolyVox_BlockCompressor_H__
#include "PolyVoxCore/PolyVoxForwardDeclarations.h"
#include "PolyVoxCore/CompressedBlock.h"
#include "PolyVoxCore/UncompressedBlock.h"
namespace PolyVox
{
/**
* Provides an interface for performing compression of blocks.
*/
template <typename VoxelType>
class BlockCompressor
{
public:
BlockCompressor() {};
virtual ~BlockCompressor() {};
virtual void compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock) = 0;
virtual void decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock) = 0;
};
}
#endif //__PolyVox_BlockCompressor_H__

View File

@ -0,0 +1,63 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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_CompressedBlock_H__
#define __PolyVox_CompressedBlock_H__
#include "PolyVoxCore/Block.h"
namespace PolyVox
{
template <typename VoxelType>
class CompressedBlock : public Block<VoxelType>
{
friend class LargeVolume<VoxelType>;
public:
CompressedBlock();
~CompressedBlock();
const uint8_t* getData(void) const;
uint32_t getDataSizeInBytes(void) const;
void setData(const uint8_t* const pData, uint32_t uDataSizeInBytes);
private:
/// Private copy constructor to prevent accisdental copying
CompressedBlock(const CompressedBlock& /*rhs*/) {};
/// Private assignment operator to prevent accisdental copying
CompressedBlock& operator=(const CompressedBlock& /*rhs*/) {};
// Made this private to avoid any confusion with getDataSizeInBytes().
// Users shouldn't really need this for CompressedBlock anyway.
uint32_t calculateSizeInBytes(void);
uint8_t* m_pData;
uint32_t m_uDataSizeInBytes;
};
}
#include "PolyVoxCore/CompressedBlock.inl"
#endif

View File

@ -0,0 +1,79 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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.
*******************************************************************************/
namespace PolyVox
{
template <typename VoxelType>
CompressedBlock<VoxelType>::CompressedBlock()
:m_pData(0)
,m_uDataSizeInBytes(0)
{
}
template <typename VoxelType>
CompressedBlock<VoxelType>::~CompressedBlock()
{
delete[] m_pData;
m_pData = 0;
}
template <typename VoxelType>
const uint8_t* CompressedBlock<VoxelType>::getData(void) const
{
return m_pData;
}
template <typename VoxelType>
uint32_t CompressedBlock<VoxelType>::getDataSizeInBytes(void) const
{
return m_uDataSizeInBytes;
}
template <typename VoxelType>
void CompressedBlock<VoxelType>::setData(const uint8_t* const pData, uint32_t uDataSizeInBytes)
{
POLYVOX_THROW_IF(pData == 0, std::invalid_argument, "Pointer to data cannot be null");
POLYVOX_THROW_IF(m_pData == pData, std::invalid_argument, "Attempting to copy data onto itself");
// Delete any existing data
delete[] m_pData;
// Allocate new data
m_uDataSizeInBytes = uDataSizeInBytes;
m_pData = new uint8_t[uDataSizeInBytes];
// Copy the data across
memcpy(m_pData, pData, uDataSizeInBytes);
// Flag as modified
this->m_bDataModified = true;
}
template <typename VoxelType>
uint32_t CompressedBlock<VoxelType>::calculateSizeInBytes(void)
{
// Returns the size of this class plus the size of the compressed data.
uint32_t uSizeInBytes = sizeof(CompressedBlock<VoxelType>) + m_uDataSizeInBytes;
return uSizeInBytes;
}
}

View File

@ -76,7 +76,7 @@ namespace PolyVox
* \param uDstLength The length of the destination buffer (compression will fail if this isn't big enough).
* \return The size of the resulting compressed data.
*/
virtual uint32_t compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0;
virtual uint32_t compress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0;
/**
* Decompresses the data.
@ -93,7 +93,7 @@ namespace PolyVox
* \param uDstLength The length of the destination buffer (decompression will fail if this isn't big enough).
* \return The size of the resulting uncompressed data.
*/
virtual uint32_t decompress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0;
virtual uint32_t decompress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0;
};
}

View File

@ -21,6 +21,8 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#include "PolyVoxCore/Impl/Timer.h"
namespace PolyVox
{
// We try to avoid duplicate vertices by checking whether a vertex has already been added at a given position.
@ -48,6 +50,7 @@ namespace PolyVox
template<typename VolumeType, typename IsQuadNeeded>
void CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::execute()
{
Timer timer;
m_meshCurrent->clear();
uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2;
@ -195,6 +198,10 @@ namespace PolyVox
lodRecord.beginIndex = 0;
lodRecord.endIndex = m_meshCurrent->getNoOfIndices();
m_meshCurrent->m_vecLodRecords.push_back(lodRecord);
logTrace() << "Cubic surface extraction took " << timer.elapsedTimeInMilliSeconds()
<< "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels()
<< "x" << m_regSizeInVoxels.getDepthInVoxels() << ")";
}
template<typename VolumeType, typename IsQuadNeeded>

View File

@ -21,6 +21,8 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#include "PolyVoxCore/Impl/Timer.h"
namespace PolyVox
{
template<typename VolumeType, typename IsQuadNeeded>
@ -38,6 +40,7 @@ namespace PolyVox
template<typename VolumeType, typename IsQuadNeeded>
void CubicSurfaceExtractorWithNormals<VolumeType, IsQuadNeeded>::execute()
{
Timer timer;
m_meshCurrent->clear();
for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z < m_regSizeInVoxels.getUpperCorner().getZ(); z++)
@ -126,5 +129,9 @@ namespace PolyVox
lodRecord.beginIndex = 0;
lodRecord.endIndex = m_meshCurrent->getNoOfIndices();
m_meshCurrent->m_vecLodRecords.push_back(lodRecord);
logTrace() << "Cubic surface extraction took " << timer.elapsedTimeInMilliSeconds()
<< "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels()
<< "x" << m_regSizeInVoxels.getDepthInVoxels() << ")";
}
}

View File

@ -29,6 +29,8 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/Pager.h"
#include "PolyVoxCore/Region.h"
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <stdexcept>
#include <string>
@ -47,21 +49,39 @@ namespace PolyVox
:Pager<VoxelType>()
,m_strFolderName(strFolderName)
{
srand(static_cast<unsigned int>(time(0)));
int iRandomValue = rand();
std::stringstream ss;
ss << std::hex << iRandomValue;
m_strRandomPrefix = ss.str();
}
/// Destructor
virtual ~FilePager() {};
virtual ~FilePager()
{
for(std::vector<std::string>::iterator iter = m_vecCreatedFiles.begin(); iter < m_vecCreatedFiles.end(); iter++)
{
if(!std::remove(iter->c_str()))
{
logWarning() << "Failed to delete '" << *iter << "' when destroying FilePager";
}
}
virtual void pageIn(const Region& region, Block<VoxelType>* pBlockData)
m_vecCreatedFiles.clear();
}
virtual void pageIn(const Region& region, CompressedBlock<VoxelType>* pBlockData)
{
POLYVOX_ASSERT(pBlockData, "Attempting to page in NULL block");
POLYVOX_ASSERT(pBlockData->hasUncompressedData() == false, "Block should not have uncompressed data");
//POLYVOX_ASSERT(pBlockData->hasUncompressedData() == false, "Block should not have uncompressed data");
std::stringstream ss;
ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
std::stringstream ssFilename;
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-"
<< region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
<< region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ();
std::string filename = m_strFolderName + ss.str();
std::string filename = ssFilename.str();
// FIXME - This should be replaced by C++ style IO, but currently this causes problems with
// the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919
@ -77,7 +97,7 @@ namespace PolyVox
uint8_t* buffer = new uint8_t[fileSizeInBytes];
fread(buffer, sizeof(uint8_t), fileSizeInBytes, pFile);
pBlockData->setCompressedData(buffer, fileSizeInBytes);
pBlockData->setData(buffer, fileSizeInBytes);
delete[] buffer;
if(ferror(pFile))
@ -93,18 +113,19 @@ namespace PolyVox
}
}
virtual void pageOut(const Region& region, Block<VoxelType>* pBlockData)
virtual void pageOut(const Region& region, CompressedBlock<VoxelType>* pBlockData)
{
POLYVOX_ASSERT(pBlockData, "Attempting to page out NULL block");
POLYVOX_ASSERT(pBlockData->hasUncompressedData() == false, "Block should not have uncompressed data");
//POLYVOX_ASSERT(pBlockData->hasUncompressedData() == false, "Block should not have uncompressed data");
logTrace() << "Paging out data for " << region;
std::stringstream ss;
ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
std::stringstream ssFilename;
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-"
<< region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
<< region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ();
std::string filename = m_strFolderName + ss.str();
std::string filename = ssFilename.str();
// FIXME - This should be replaced by C++ style IO, but currently this causes problems with
// the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919
@ -115,7 +136,10 @@ namespace PolyVox
POLYVOX_THROW(std::runtime_error, "Unable to open file to write out block data.");
}
fwrite(pBlockData->getCompressedData(), sizeof(uint8_t), pBlockData->getCompressedDataLength(), pFile);
//The file has been created, so add it to the list to delete on shutdown.
m_vecCreatedFiles.push_back(filename);
fwrite(pBlockData->getData(), sizeof(uint8_t), pBlockData->getDataSizeInBytes(), pFile);
if(ferror(pFile))
{
@ -127,6 +151,9 @@ namespace PolyVox
protected:
std::string m_strFolderName;
std::string m_strRandomPrefix;
std::vector<std::string> m_vecCreatedFiles;
};
}

View File

@ -1,276 +0,0 @@
/*******************************************************************************
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 "PolyVoxCore/Impl/ErrorHandling.h"
#include "PolyVoxCore/Impl/Utility.h"
#include "PolyVoxCore/Compressor.h"
#include "PolyVoxCore/Vector.h"
#include "PolyVoxCore/Impl/ErrorHandling.h"
#include <cstring> //For memcpy
#include <limits>
#include <stdexcept> //for std::invalid_argument
namespace PolyVox
{
template <typename VoxelType>
Block<VoxelType>::Block(uint16_t uSideLength, Compressor* pCompressor)
:m_pCompressor(pCompressor)
,m_pCompressedData(0)
,m_uCompressedDataLength(0)
,m_tUncompressedData(0)
,m_uSideLength(0)
,m_uSideLengthPower(0)
,m_bIsUncompressedDataModified(true)
{
if(uSideLength == 0)
{
POLYVOX_THROW(std::invalid_argument, "Block side length cannot be zero.");
}
if(!isPowerOf2(uSideLength))
{
POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two.");
}
if(pCompressor == 0)
{
POLYVOX_THROW(std::invalid_argument, "Block must be provided with a valid compressor.");
}
//Compute the side length
m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(uSideLength);
//Temporarily create the block data. This is just so we can compress it an discard it.
// FIXME - this is a temporary solution.
const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
m_tUncompressedData = new VoxelType[uNoOfVoxels];
std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, VoxelType());
m_bIsUncompressedDataModified = true;
destroyUncompressedData();
}
template <typename VoxelType>
const uint8_t* const Block<VoxelType>::getCompressedData(void) const
{
POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL");
return m_pCompressedData;
}
template <typename VoxelType>
const uint32_t Block<VoxelType>::getCompressedDataLength(void) const
{
POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL");
return m_uCompressedDataLength;
}
template <typename VoxelType>
uint16_t Block<VoxelType>::getSideLength(void) const
{
return m_uSideLength;
}
template <typename VoxelType>
VoxelType Block<VoxelType>::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{
// This is internal code not directly called by the user. For efficiency we assert rather than throwing.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(hasUncompressedData(), "The block must have uncompressed data to call getVoxel()");
POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels.");
return m_tUncompressedData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
];
}
template <typename VoxelType>
VoxelType Block<VoxelType>::getVoxel(const Vector3DUint16& v3dPos) const
{
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
template <typename VoxelType>
bool Block<VoxelType>::hasUncompressedData(void) const
{
return m_tUncompressedData != 0;
}
template <typename VoxelType>
void Block<VoxelType>::setCompressedData(const uint8_t* const data, uint32_t dataLength)
{
POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL");
POLYVOX_ASSERT(m_pCompressedData != data, "Attempting to copy data onto itself");
delete[] m_pCompressedData;
m_uCompressedDataLength = dataLength;
m_pCompressedData = new uint8_t[dataLength];
memcpy(m_pCompressedData, data, dataLength);
}
template <typename VoxelType>
void Block<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{
// This is internal code not directly called by the user. For efficiency we assert rather than throwing.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(hasUncompressedData(), "The block must have uncompressed data to call setVoxelAt()");
POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels.");
m_tUncompressedData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
] = tValue;
m_bIsUncompressedDataModified = true;
}
template <typename VoxelType>
void Block<VoxelType>::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
{
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
}
template <typename VoxelType>
void Block<VoxelType>::destroyUncompressedData()
{
if(!hasUncompressedData())
{
POLYVOX_THROW(invalid_operation, "No uncompressed data to compress.");
}
POLYVOX_ASSERT(m_tUncompressedData != 0, "No uncompressed data is present.");
//If the uncompressed data hasn't actually been
//modified then we don't need to redo the compression.
if(m_bIsUncompressedDataModified)
{
// Delete the old compressed data as we'll create a new one
delete[] m_pCompressedData;
m_pCompressedData = 0;
void* pSrcData = reinterpret_cast<void*>(m_tUncompressedData);
uint32_t uSrcLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
uint8_t tempBuffer[10000];
void* pDstData = reinterpret_cast<void*>( tempBuffer );
uint32_t uDstLength = 10000;
uint32_t uCompressedLength = 0;
try
{
uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength);
// Create new compressed data and copy across
m_pCompressedData = new uint8_t[uCompressedLength];
memcpy(m_pCompressedData, pDstData, uCompressedLength);
m_uCompressedDataLength = uCompressedLength;
}
catch(std::exception&)
{
// It is possible for the compression to fail. A common cause for this would be if the destination
// buffer is not big enough. So now we try again using a buffer that is definitely big enough.
// Note that ideally we will choose our earlier buffer size so that this almost never happens.
logWarning() << "The compressor failed to compress the block, proabaly due to the buffer being too small.";
logWarning() << "The compression will be tried again with a larger buffer";
uint32_t uMaxCompressedSize = m_pCompressor->getMaxCompressedSize(uSrcLength);
uint8_t* buffer = new uint8_t[ uMaxCompressedSize ];
pDstData = reinterpret_cast<void*>( buffer );
uDstLength = uMaxCompressedSize;
try
{
uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength);
// Create new compressed data and copy across
m_pCompressedData = new uint8_t[uCompressedLength];
memcpy(m_pCompressedData, pDstData, uCompressedLength);
m_uCompressedDataLength = uCompressedLength;
}
catch(std::exception&)
{
// At this point it didn't work even with a bigger buffer.
// Not much more we can do so just rethrow the exception.
delete[] buffer;
POLYVOX_THROW(std::runtime_error, "Failed to compress block data");
}
delete[] buffer;
}
}
//Flag the uncompressed data as no longer being used.
delete[] m_tUncompressedData;
m_tUncompressedData = 0;
}
template <typename VoxelType>
void Block<VoxelType>::createUncompressedData()
{
if(hasUncompressedData())
{
POLYVOX_THROW(invalid_operation, "Uncompressed data already exists.");
}
POLYVOX_ASSERT(m_tUncompressedData == 0, "Uncompressed data already exists.");
m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
void* pSrcData = reinterpret_cast<void*>(m_pCompressedData);
void* pDstData = reinterpret_cast<void*>(m_tUncompressedData);
uint32_t uSrcLength = m_uCompressedDataLength;
uint32_t uDstLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
//MinizCompressor compressor;
//RLECompressor<VoxelType, uint16_t> compressor;
uint32_t uUncompressedLength = m_pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength);
POLYVOX_ASSERT(uUncompressedLength == m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType), "Destination length has changed.");
//m_tUncompressedData = reinterpret_cast<VoxelType*>(uncompressedResult.ptr);
m_bIsUncompressedDataModified = false;
}
template <typename VoxelType>
uint32_t Block<VoxelType>::calculateSizeInBytes(void)
{
//FIXME - This function is incomplete.
uint32_t uSizeInBytes = sizeof(Block<VoxelType>);
return uSizeInBytes;
}
}

View File

@ -31,6 +31,7 @@ freely, subject to the following restrictions:
#include <stdexcept>
#include <sstream>
#include <string.h> // Exception constuctors take strings.
#include <csignal>
#if defined(_MSC_VER)
// In Visual Studio we can use this function to go into the debugger.
@ -38,7 +39,11 @@ freely, subject to the following restrictions:
#else
// On other platforms we just halt by forcing a crash.
// Hopefully this puts us in the debugger if one is running
#define POLYVOX_HALT() *((unsigned int*)0) = 0xDEAD
#if defined(__linux__) || defined(__APPLE__)
#define POLYVOX_HALT() raise(SIGTRAP)
#else
#define POLYVOX_HALT() *((unsigned int*)0) = 0xDEAD
#endif
#endif
// Macros cannot contain #ifdefs, but some of our macros need to disable warnings and such warning supression is

View File

@ -28,8 +28,8 @@ freely, subject to the following restrictions:
namespace PolyVox
{
extern const POLYVOX_API int edgeTable[256];
extern const POLYVOX_API int triTable[256][16];
extern const POLYVOX_API uint16_t edgeTable[256];
extern const POLYVOX_API int8_t triTable[256][16];
}
#endif

View File

@ -0,0 +1,64 @@
/*******************************************************************************
Copyright (c) 2005-20013 David Williams and Matthew 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_Timer_H__
#define __PolyVox_Timer_H__
#include <cstdint>
#ifdef _MSC_VER // Don't worry about the exact version, as long as this is defied.
#include <Windows.h>
#endif //_MSC_VER
namespace PolyVox
{
#if defined(_MSC_VER)
class Timer
{
public:
Timer(bool bAutoStart = true);
void start(void);
float elapsedTimeInSeconds(void);
uint32_t elapsedTimeInMilliSeconds(void);
private:
double m_fPCFreq;
__int64 m_iStartTime;
};
#else //_MSC_VER
class Timer
{
public:
Timer(bool bAutoStart = true);
void start(void);
float elapsedTimeInSeconds(void);
uint32_t elapsedTimeInMilliSeconds(void);
};
#endif //_MSC_VER
}
#endif //__PolyVox_Timer_H__

View File

@ -25,8 +25,8 @@ freely, subject to the following restrictions:
#define __PolyVox_LargeVolume_H__
#include "PolyVoxCore/BaseVolume.h"
#include "Impl/Block.h"
#include "PolyVoxCore/Compressor.h"
#include "PolyVoxCore/Block.h"
#include "PolyVoxCore/BlockCompressor.h"
#include "PolyVoxCore/Pager.h"
#include "PolyVoxCore/Region.h"
#include "PolyVoxCore/Vector.h"
@ -239,7 +239,7 @@ namespace PolyVox
LargeVolume
(
const Region& regValid,
Compressor* pCompressor,
BlockCompressor<VoxelType>* pBlockCompressor,
Pager<VoxelType>* pPager ,
uint16_t uBlockSideLength = 32
);
@ -266,7 +266,7 @@ namespace PolyVox
/// Sets the number of blocks for which uncompressed data is stored
void setMaxNumberOfUncompressedBlocks(uint32_t uMaxNumberOfUncompressedBlocks);
/// Sets the number of blocks which can be in memory before the paging system starts unloading them
void setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory);
void setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory);
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
/// Sets the voxel at the position given by a 3D vector
@ -312,7 +312,16 @@ namespace PolyVox
}
return false;
}
};
};
typedef std::map<Vector3DInt32, CompressedBlock<VoxelType>*, BlockPositionCompare> CompressedBlockMap;
typedef std::map<Vector3DInt32, UncompressedBlock<VoxelType>*, BlockPositionCompare> UncompressedBlockMap;
uint32_t calculateBlockMemoryUsage(void) const;
void flushOldestExcessiveBlocks(void) const;
void flushExcessiveCacheEntries(void) const;
void initialise();
// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057
@ -323,20 +332,19 @@ namespace PolyVox
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const;
Block<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
void eraseBlock(typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator itBlock) const;
CompressedBlock<VoxelType>* getCompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
UncompressedBlock<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
void eraseBlock(typename CompressedBlockMap::iterator itCompressedBlock) const;
void eraseBlock(typename UncompressedBlockMap::iterator itUncompressedBlock) const;
// The block data
mutable std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare> m_pBlocks;
mutable CompressedBlockMap m_pBlocks;
mutable UncompressedBlockMap m_pUncompressedBlockCache;
// The cache of uncompressed blocks. The uncompressed block data and the timestamps are stored here rather
// than in the Block class. This is so that in the future each VolumeIterator might to maintain its own cache
// of blocks. However, this could mean the same block data is uncompressed and modified in more than one
// location in memory... could be messy with threading.
mutable std::vector< Block<VoxelType>* > m_vecBlocksWithUncompressedData;
mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedBlockPos;
mutable Block<VoxelType>* m_pLastAccessedBlock;
mutable UncompressedBlock<VoxelType>* m_pLastAccessedBlock;
uint32_t m_uMaxNumberOfUncompressedBlocks;
uint32_t m_uMaxNumberOfBlocksInMemory;
@ -348,9 +356,12 @@ namespace PolyVox
uint8_t m_uBlockSideLengthPower;
// The compressor used by the Blocks to compress their data if required.
Compressor* m_pCompressor;
BlockCompressor<VoxelType>* m_pBlockCompressor;
Pager<VoxelType>* m_pPager;
// Compressed data for an empty block (sometimes needed for initialisation).
//CompressedBlock<VoxelType>* m_pCompressedEmptyBlock;
// Whether we created the compressor or whether it was provided
// by the user. This controls whether we delete it on destruction.
bool m_bIsOurCompressor;

View File

@ -23,7 +23,9 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/Impl/ErrorHandling.h"
#include "PolyVoxCore/MinizCompressor.h"
#include "PolyVoxCore/MinizBlockCompressor.h" // For creating a default compressor when none is provided.
#include <algorithm>
namespace PolyVox
{
@ -43,7 +45,7 @@ namespace PolyVox
{
m_uBlockSideLength = uBlockSideLength;
m_pCompressor = new MinizCompressor();
m_pBlockCompressor = new MinizBlockCompressor<VoxelType>();
m_bIsOurCompressor = true;
m_pPager = 0;
@ -54,7 +56,7 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////
/// This constructor creates a volume with a fixed size which is specified as a parameter. By default this constructor will not enable paging but you can override this if desired. If you do wish to enable paging then you are required to provide the call back function (see the other LargeVolume constructor).
/// \param regValid Specifies the minimum and maximum valid voxel positions.
/// \param pCompressor An implementation of the Compressor interface which is used to compress blocks in memory.
/// \param pBlockCompressor An implementation of the Compressor interface which is used to compress blocks in memory.
/// \param dataRequiredHandler The callback function which will be called when PolyVox tries to use data which is not currently in momory.
/// \param dataOverflowHandler The callback function which will be called when PolyVox has too much data and needs to remove some from memory.
/// \param bPagingEnabled Controls whether or not paging is enabled for this LargeVolume.
@ -64,16 +66,15 @@ namespace PolyVox
LargeVolume<VoxelType>::LargeVolume
(
const Region& regValid,
Compressor* pCompressor,
BlockCompressor<VoxelType>* pBlockCompressor,
Pager<VoxelType>* pPager,
uint16_t uBlockSideLength
)
:BaseVolume<VoxelType>(regValid)
{
m_uBlockSideLength = uBlockSideLength;
m_pCompressor = pCompressor;
m_pBlockCompressor = pBlockCompressor;
m_bIsOurCompressor = false;
m_pPager = pPager;
@ -105,8 +106,10 @@ namespace PolyVox
// Only delete the compressor if it was created by us (in the constructor), not by the user.
if(m_bIsOurCompressor)
{
delete m_pCompressor;
delete m_pBlockCompressor;
}
//delete m_pCompressedEmptyBlock;
}
////////////////////////////////////////////////////////////////////////////////
@ -221,9 +224,9 @@ namespace PolyVox
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
const UncompressedBlock<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
return pUncompressedBlock->getVoxel(xOffset,yOffset,zOffset);
return pUncompressedBlock->getVoxel(xOffset, yOffset, zOffset);
}
else
{
@ -253,10 +256,14 @@ namespace PolyVox
clearBlockCache();
m_uMaxNumberOfUncompressedBlocks = uMaxNumberOfUncompressedBlocks;
uint32_t uUncompressedBlockSizeInBytes = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
logDebug() << "The maximum number of uncompresed blocks has been set to " << m_uMaxNumberOfUncompressedBlocks
<< ", which is " << m_uMaxNumberOfUncompressedBlocks * uUncompressedBlockSizeInBytes << " bytes";
}
////////////////////////////////////////////////////////////////////////////////
/// Increasing the number of blocks in memory causes fewer calls to dataRequiredHandler()/dataOverflowHandler()
/// Increasing the number of blocks in memory causes less paging to occur
/// \param uMaxNumberOfBlocksInMemory The number of blocks
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
@ -266,6 +273,7 @@ namespace PolyVox
{
flushAll();
}
m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory;
}
@ -302,9 +310,8 @@ namespace PolyVox
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue);
UncompressedBlock<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
pUncompressedBlock->setVoxelAt(xOffset, yOffset, zOffset, tValue);
}
////////////////////////////////////////////////////////////////////////////////
@ -340,9 +347,9 @@ namespace PolyVox
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
UncompressedBlock<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue);
pUncompressedBlock->setVoxelAt(xOffset, yOffset, zOffset, tValue);
//Return true to indicate that we modified a voxel.
return true;
@ -361,7 +368,7 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////
/// Note that if MaxNumberOfBlocksInMemory is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels.
/// Note that if *NOTE - update docs - MaxNumberOfBlocksInMemory no longer exists* MaxNumberOfBlocksInMemory is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels.
/// \param regPrefetch The Region of voxels to prefetch into memory.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
@ -381,11 +388,14 @@ namespace PolyVox
Vector3DInt32 v3dSize = v3dEnd - v3dStart + Vector3DInt32(1,1,1);
uint32_t numblocks = static_cast<uint32_t>(v3dSize.getX() * v3dSize.getY() * v3dSize.getZ());
if(numblocks > m_uMaxNumberOfBlocksInMemory)
// FIXME - reinstate some logic to handle when the prefetched region is too large.
/*if(numblocks > m_uMaxNumberOfBlocksInMemory)
{
// cannot support the amount of blocks... so only load the maximum possible
numblocks = m_uMaxNumberOfBlocksInMemory;
}
}*/
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
{
for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++)
@ -393,7 +403,7 @@ namespace PolyVox
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
{
Vector3DInt32 pos(x,y,z);
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos);
typename CompressedBlockMap::iterator itBlock = m_pBlocks.find(pos);
if(itBlock != m_pBlocks.end())
{
@ -424,7 +434,7 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::flushAll()
{
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator i;
typename CompressedBlockMap::iterator i;
//Replaced the for loop here as the call to
//eraseBlock was invalidating the iterator.
while(m_pBlocks.size() > 0)
@ -458,7 +468,7 @@ namespace PolyVox
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
{
Vector3DInt32 pos(x,y,z);
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos);
typename CompressedBlockMap::iterator itBlock = m_pBlocks.find(pos);
if(itBlock == m_pBlocks.end())
{
// not loaded, not unloading
@ -481,11 +491,6 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::clearBlockCache(void)
{
for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++)
{
m_vecBlocksWithUncompressedData[ct]->destroyUncompressedData();
}
m_vecBlocksWithUncompressedData.clear();
}
////////////////////////////////////////////////////////////////////////////////
@ -505,14 +510,14 @@ namespace PolyVox
POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two.");
}
if(!m_pCompressor)
if(!m_pBlockCompressor)
{
POLYVOX_THROW(std::invalid_argument, "You must provide a valid compressor for the LargeVolume to use.");
}
m_uTimestamper = 0;
m_uMaxNumberOfUncompressedBlocks = 16;
m_uMaxNumberOfBlocksInMemory = 1024;
//m_uMaxNumberOfUncompressedBlocks = 16;
//m_uMaxNumberOfBlocksInMemory = 1024;
m_v3dLastAccessedBlockPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedBlock pointer will be null;
m_pLastAccessedBlock = 0;
@ -526,7 +531,7 @@ namespace PolyVox
m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower);
setMaxNumberOfUncompressedBlocks(m_uMaxNumberOfUncompressedBlocks);
//setMaxNumberOfUncompressedBlocks(m_uMaxNumberOfUncompressedBlocks);
//Clear the previous data
m_pBlocks.clear();
@ -541,42 +546,108 @@ namespace PolyVox
}
template <typename VoxelType>
void LargeVolume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator itBlock) const
void LargeVolume<VoxelType>::eraseBlock(typename CompressedBlockMap::iterator itCompressedBlock) const
{
if(itBlock->second.hasUncompressedData())
{
itBlock->second.destroyUncompressedData();
}
CompressedBlock<VoxelType>* pCompressedBlock = itCompressedBlock->second;
if(m_pPager)
// Before deleting the block we may need to page out its data. We
// only do this if the data has been modified since it was paged in.
if(pCompressedBlock->m_bDataModified)
{
Vector3DInt32 v3dPos = itBlock->first;
Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower);
// The position of the block within the volume.
Vector3DInt32 v3dBlockPos = itCompressedBlock->first;
// From the coordinates of the block we deduce the coordinates of the contained voxels.
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);
// Page the data out
m_pPager->pageOut(Region(v3dLower, v3dUpper), pCompressedBlock);
m_pPager->pageOut(reg, &(itBlock->second));
}
for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++)
{
// find the block in the uncompressed cache
if(m_vecBlocksWithUncompressedData[ct] == &(itBlock->second))
{
// put last object in cache here
m_vecBlocksWithUncompressedData[ct] = m_vecBlocksWithUncompressedData.back();
// decrease cache size by one since last element is now in here twice
m_vecBlocksWithUncompressedData.resize(m_vecBlocksWithUncompressedData.size()-1);
break;
}
// The compressed data is no longer modified with respect to the data on disk
pCompressedBlock->m_bDataModified = false;
}
m_pBlocks.erase(itBlock);
delete itCompressedBlock->second;
// We can now remove the block data from memory.
m_pBlocks.erase(itCompressedBlock);
}
template <typename VoxelType>
Block<VoxelType>* LargeVolume<VoxelType>::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const
void LargeVolume<VoxelType>::eraseBlock(typename UncompressedBlockMap::iterator itUncompressedBlock) const
{
UncompressedBlock<VoxelType>* pUncompressedBlock = itUncompressedBlock->second;
// This should not often happen as blocks are normally deleted based on being least recently used.
// However, I can imagine that flushing a large number of blocks could cause this to occur. Just
// to be safe we handle it by invalidating the last accessed block pointer.
if(pUncompressedBlock == m_pLastAccessedBlock)
{
logWarning() << "The last accessed block is being erased from the uncompressed cache.";
m_pLastAccessedBlock = 0;
}
// Before deleting the block we may need to recompress its data. We
// only do this if the data has been modified since it was decompressed.
if(pUncompressedBlock->m_bDataModified)
{
// Get the compressed block which we will copy the data back in to.
Vector3DInt32 v3dBlockPos = itUncompressedBlock->first;
CompressedBlock<VoxelType>* pCompressedBlock = getCompressedBlock(v3dBlockPos.getX(), v3dBlockPos.getY(), v3dBlockPos.getZ());
m_pBlockCompressor->compress(pUncompressedBlock, pCompressedBlock);
// The compressed data has been updated, so the uncompressed data is no longer modified with respect to it.
pUncompressedBlock->m_bDataModified = false;
}
delete itUncompressedBlock->second;
// We can now remove the block data from memory.
m_pUncompressedBlockCache.erase(itUncompressedBlock);
}
template <typename VoxelType>
CompressedBlock<VoxelType>* LargeVolume<VoxelType>::getCompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const
{
Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ);
CompressedBlock<VoxelType>* pBlock = 0;
typename CompressedBlockMap::iterator itBlock = m_pBlocks.find(v3dBlockPos);
if(itBlock != m_pBlocks.end())
{
pBlock = itBlock->second;
pBlock->m_uBlockLastAccessed = ++m_uTimestamper;
return pBlock;
}
else
{
// The block wasn't found so we create a new one
pBlock = new CompressedBlock<VoxelType>;
// It's important to set the timestamp before we flush later.
pBlock->m_uBlockLastAccessed = ++m_uTimestamper;
// Pass the block to the Pager to give it a chance to initialise it with any data
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);
m_pPager->pageIn(reg, pBlock);
// Add the block to the map
itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, pBlock)).first;
// Paging in this new block may mean we are now using too much memory. If necessary, flush some old blocks.
flushOldestExcessiveBlocks();
return pBlock;
}
}
template <typename VoxelType>
UncompressedBlock<VoxelType>* LargeVolume<VoxelType>::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const
{
Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ);
@ -586,105 +657,53 @@ namespace PolyVox
//This check should also provide a significant speed boost as usually it is true.
if((v3dBlockPos == m_v3dLastAccessedBlockPos) && (m_pLastAccessedBlock != 0))
{
POLYVOX_ASSERT(m_pLastAccessedBlock->hasUncompressedData(), "Last accessed block has no uncompressed data.");
return m_pLastAccessedBlock;
}
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(v3dBlockPos);
// check whether the block is already loaded
if(itBlock == m_pBlocks.end())
{
//The block is not in the map, so we will have to create a new block and add it.
//Before we do so, we might want to dump some existing data to make space. We
//Only do this if paging is enabled.
if(m_pPager)
{
// check wether another block needs to be unloaded before this one can be loaded
if(m_pBlocks.size() == m_uMaxNumberOfBlocksInMemory)
{
// find the least recently used block
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator i;
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator itUnloadBlock = m_pBlocks.begin();
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
if(i->second.timestamp < itUnloadBlock->second.timestamp)
{
itUnloadBlock = i;
}
}
eraseBlock(itUnloadBlock);
}
}
// create the new block
Block<VoxelType> newBlock(m_uBlockSideLength, m_pCompressor);
itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first;
//We have created the new block. If paging is enabled it should be used to
//fill in the required data. Otherwise it is just left in the default state.
if(m_pPager)
{
//if(m_funcDataRequiredHandler)
{
// "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
//FIXME - can we pass the block around so that we don't have to find it again when we recursively call this function?
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);
m_pPager->pageIn(reg, &(itBlock->second));
}
}
}
//Get the block and mark that we accessed it
Block<VoxelType>& block = itBlock->second;
block.timestamp = ++m_uTimestamper;
m_v3dLastAccessedBlockPos = v3dBlockPos;
m_pLastAccessedBlock = &block;
if(block.hasUncompressedData())
{
return m_pLastAccessedBlock;
}
//If we are allowed to compress then check whether we need to
if(m_vecBlocksWithUncompressedData.size() == m_uMaxNumberOfUncompressedBlocks)
typename UncompressedBlockMap::iterator itUncompressedBlock = m_pUncompressedBlockCache.find(v3dBlockPos);
// check whether the block is already loaded
if(itUncompressedBlock != m_pUncompressedBlockCache.end())
{
int32_t leastRecentlyUsedBlockIndex = -1;
uint32_t uLeastRecentTimestamp = (std::numeric_limits<uint32_t>::max)();
UncompressedBlock<VoxelType>* pUncompressedBlock = itUncompressedBlock->second;
//Currently we find the oldest block by iterating over the whole array. Of course we could store the blocks sorted by
//timestamp (set, priority_queue, etc) but then we'll need to move them around as the timestamp changes. Can come back
//to this if it proves to be a bottleneck (compraed to the cost of actually doing the compression/decompression).
for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++)
{
if(m_vecBlocksWithUncompressedData[ct]->timestamp < uLeastRecentTimestamp)
{
uLeastRecentTimestamp = m_vecBlocksWithUncompressedData[ct]->timestamp;
leastRecentlyUsedBlockIndex = ct;
}
}
//Compress the least recently used block.
m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex]->destroyUncompressedData();
pUncompressedBlock->m_uBlockLastAccessed = ++m_uTimestamper;
m_pLastAccessedBlock = pUncompressedBlock;
m_v3dLastAccessedBlockPos = v3dBlockPos;
//We don't actually remove any elements from this vector, we
//simply change the pointer to point at the new uncompressed bloack.
m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex] = &block;
return pUncompressedBlock;
}
else
{
m_vecBlocksWithUncompressedData.push_back(&block);
}
block.createUncompressedData();
// At this point we just create a new block.
UncompressedBlock<VoxelType>* pUncompressedBlock = new UncompressedBlock<VoxelType>(m_uBlockSideLength);
// It's important to set the timestamp before we flush later.
pUncompressedBlock->m_uBlockLastAccessed = ++m_uTimestamper;
m_pLastAccessedBlock = &(block);
POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data");
return m_pLastAccessedBlock;
// We set these before flushing because the flush can cause block to be erased, and there
// is a test to make sure the block which is being erase is not the last accessed block.
m_pLastAccessedBlock = pUncompressedBlock;
m_v3dLastAccessedBlockPos = v3dBlockPos;
// An uncompressed bock is always backed by a compressed one, and this is created by getCompressedBlock() if it doesn't
// already exist. If it does already exist and has data then we bring this across into the ucompressed version.
if(getCompressedBlock(uBlockX, uBlockY, uBlockZ)->getData() != 0)
{
// FIXME - multiple getCompressedBlock() calls (including the one above)
CompressedBlock<VoxelType>* pBlock = getCompressedBlock(uBlockX, uBlockY, uBlockZ);
m_pBlockCompressor->decompress(pBlock, pUncompressedBlock);
}
// Add our new block to the map.
m_pUncompressedBlockCache.insert(std::make_pair(v3dBlockPos, pUncompressedBlock));
// Our block cache may now have grown too large. Flush some entries if necessary.
// FIXME - Watch out for flushing the block we just created!
flushExcessiveCacheEntries();
return pUncompressedBlock;
}
}
////////////////////////////////////////////////////////////////////////////////
@ -707,20 +726,79 @@ namespace PolyVox
uint32_t uSizeInBytes = sizeof(LargeVolume);
//Memory used by the blocks
typename std::map<Vector3DInt32, Block<VoxelType>, BlockPositionCompare>::iterator i;
typename CompressedBlockMap::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
//Inaccurate - account for rest of loaded block.
uSizeInBytes += i->second.calculateSizeInBytes();
uSizeInBytes += i->second->calculateSizeInBytes();
}
//Memory used by the block cache.
uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(Block<VoxelType>);
uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
//uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(Block<VoxelType>);
//uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
return uSizeInBytes;
}
template <typename VoxelType>
uint32_t LargeVolume<VoxelType>::calculateBlockMemoryUsage(void) const
{
uint32_t uMemoryUsage = 0;
typename CompressedBlockMap::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
//Inaccurate - account for rest of loaded block.
uMemoryUsage += i->second->calculateSizeInBytes();
}
return uMemoryUsage;
}
template <typename VoxelType>
void LargeVolume<VoxelType>::flushOldestExcessiveBlocks(void) const
{
while(m_pBlocks.size() > m_uMaxNumberOfBlocksInMemory)
{
// Find the least recently used block. This is somewhat inefficient as it searches through
// the map, so if it proves to be a bottleneck we may want some kind of sorted structure.
typename CompressedBlockMap::iterator i;
typename CompressedBlockMap::iterator itUnloadBlock = m_pBlocks.begin();
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
if(i->second->m_uBlockLastAccessed < itUnloadBlock->second->m_uBlockLastAccessed)
{
itUnloadBlock = i;
}
}
// Erase the least recently used block
eraseBlock(itUnloadBlock);
}
}
template <typename VoxelType>
void LargeVolume<VoxelType>::flushExcessiveCacheEntries(void) const
{
while(m_pUncompressedBlockCache.size() > m_uMaxNumberOfUncompressedBlocks)
{
// Find the least recently used block. The uncompressed block cache should be
// much smaller than the total number of blocks, so hopefully this isn't too slow.
typename UncompressedBlockMap::iterator i;
typename UncompressedBlockMap::iterator itUnloadBlock = m_pUncompressedBlockCache.begin();
for(i = m_pUncompressedBlockCache.begin(); i != m_pUncompressedBlockCache.end(); i++)
{
if(i->second->m_uBlockLastAccessed < itUnloadBlock->second->m_uBlockLastAccessed)
{
itUnloadBlock = i;
}
}
// Erase the least recently used block
eraseBlock(itUnloadBlock);
}
}
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType LargeVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const
@ -778,9 +856,8 @@ namespace PolyVox
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
return pUncompressedBlock->getVoxel(xOffset,yOffset,zOffset);
UncompressedBlock<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
return pUncompressedBlock->getVoxel(xOffset, yOffset, zOffset);
}
}

View File

@ -88,7 +88,7 @@ namespace PolyVox
}
else
{
return getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
@ -119,9 +119,9 @@ namespace PolyVox
uYPosInBlock * this->mVolume->m_uBlockSideLength +
uZPosInBlock * this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
Block<VoxelType>* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock);
UncompressedBlock<VoxelType>* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock);
mCurrentVoxel = pUncompressedCurrentBlock->m_tUncompressedData + uVoxelIndexInBlock;
mCurrentVoxel = pUncompressedCurrentBlock->m_tData + uVoxelIndexInBlock;
}
else
{

View File

@ -21,6 +21,8 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#include "PolyVoxCore/Impl/Timer.h"
namespace PolyVox
{
template<typename VolumeType, typename Controller>
@ -42,6 +44,7 @@ namespace PolyVox
template<typename VolumeType, typename Controller>
void MarchingCubesSurfaceExtractor<VolumeType, Controller>::execute()
{
Timer timer;
m_meshCurrent->clear();
const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1;
@ -126,6 +129,10 @@ namespace PolyVox
lodRecord.beginIndex = 0;
lodRecord.endIndex = m_meshCurrent->getNoOfIndices();
m_meshCurrent->m_vecLodRecords.push_back(lodRecord);
logTrace() << "Marching cubes surface extraction took " << timer.elapsedTimeInMilliSeconds()
<< "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels()
<< "x" << m_regSizeInVoxels.getDepthInVoxels() << ")";
}
template<typename VolumeType, typename Controller>

View File

@ -0,0 +1,52 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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_MinizBlockCompressor_H__
#define __PolyVox_MinizBlockCompressor_H__
#include "PolyVoxCore/BlockCompressor.h"
#include "PolyVoxCore/MinizCompressor.h"
namespace PolyVox
{
/**
* Provides an interface for performing paging of data.
*/
template <typename VoxelType>
class MinizBlockCompressor : public BlockCompressor<VoxelType>
{
public:
MinizBlockCompressor();
~MinizBlockCompressor();
void compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock);
void decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock);
MinizCompressor* m_pCompressor;
};
}
#include "PolyVoxCore/MinizBlockCompressor.inl"
#endif //__PolyVox_MinizBlockCompressor_H__

View File

@ -0,0 +1,105 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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.
*******************************************************************************/
namespace PolyVox
{
template <typename VoxelType>
MinizBlockCompressor<VoxelType>::MinizBlockCompressor()
{
m_pCompressor = new MinizCompressor;
}
template <typename VoxelType>
MinizBlockCompressor<VoxelType>::~MinizBlockCompressor()
{
delete m_pCompressor;
}
template <typename VoxelType>
void MinizBlockCompressor<VoxelType>::compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock)
{
void* pSrcData = reinterpret_cast<void*>(pSrcBlock->getData());
uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes();
uint8_t tempBuffer[10000];
uint8_t* pDstData = reinterpret_cast<uint8_t*>( tempBuffer );
uint32_t uDstLength = 10000;
uint32_t uCompressedLength = 0;
try
{
// Perform the compression
uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength);
// Copy the resulting compressed data into the compressed block
pDstBlock->setData(pDstData, uDstLength);
}
catch(std::exception&)
{
// It is possible for the compression to fail. A common cause for this would be if the destination
// buffer is not big enough. So now we try again using a buffer that is definitely big enough.
// Note that ideally we will choose our earlier buffer size so that this almost never happens.
logWarning() << "The compressor failed to compress the block, probabaly due to the buffer being too small.";
logWarning() << "The compression will be tried again with a larger buffer";
uint32_t uMaxCompressedSize = m_pCompressor->getMaxCompressedSize(uSrcLength);
uint8_t* buffer = new uint8_t[ uMaxCompressedSize ];
pDstData = reinterpret_cast<uint8_t*>( buffer );
uDstLength = uMaxCompressedSize;
try
{
// Perform the compression
uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength);
// Copy the resulting compressed data into the compressed block
pDstBlock->setData(pDstData, uDstLength);
}
catch(std::exception&)
{
// At this point it didn't work even with a bigger buffer.
// Not much more we can do so just rethrow the exception.
delete[] buffer;
POLYVOX_THROW(std::runtime_error, "Failed to compress block data");
}
delete[] buffer;
}
}
template <typename VoxelType>
void MinizBlockCompressor<VoxelType>::decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock)
{
const void* pSrcData = reinterpret_cast<const void*>(pSrcBlock->getData());
void* pDstData = reinterpret_cast<void*>(pDstBlock->getData());
uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes();
uint32_t uDstLength = pDstBlock->getDataSizeInBytes();
//RLECompressor<VoxelType, uint16_t> compressor;
uint32_t uUncompressedLength = m_pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength);
POLYVOX_ASSERT(uUncompressedLength == pDstBlock->getDataSizeInBytes(), "Destination length has changed.");
}
}

View File

@ -25,8 +25,8 @@ namespace PolyVox
// API documentation is in base class and gets inherited by Doxygen.
uint32_t getMaxCompressedSize(uint32_t uUncompressedInputSize);
uint32_t compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
uint32_t decompress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
uint32_t compress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
uint32_t decompress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
private:
unsigned int m_uCompressionFlags;

View File

@ -24,7 +24,7 @@ freely, subject to the following restrictions:
#ifndef __PolyVox_Pager_H__
#define __PolyVox_Pager_H__
#include "PolyVoxCore/Impl/Block.h"
#include "PolyVoxCore/CompressedBlock.h"
#include "PolyVoxCore/Impl/TypeDef.h"
namespace PolyVox
@ -41,8 +41,8 @@ namespace PolyVox
/// Destructor
virtual ~Pager() {};
virtual void pageIn(const Region& region, Block<VoxelType>* pBlockData) = 0;
virtual void pageOut(const Region& region, Block<VoxelType>* pBlockData) = 0;
virtual void pageIn(const Region& region, CompressedBlock<VoxelType>* pBlockData) = 0;
virtual void pageOut(const Region& region, CompressedBlock<VoxelType>* pBlockData) = 0;
};
}

View File

@ -60,6 +60,11 @@ namespace PolyVox
typedef Array<3,int32_t> Array3DInt32;
typedef Array<3,uint32_t> Array3DUint32;
////////////////////////////////////////////////////////////////////////////////
// BlockCompressor
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class BlockCompressor;
////////////////////////////////////////////////////////////////////////////////
// Compressor
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,61 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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_RLEBlockCompressor_H__
#define __PolyVox_RLEBlockCompressor_H__
#include "PolyVoxCore/BlockCompressor.h"
#include "PolyVoxCore/MinizCompressor.h"
namespace PolyVox
{
template <typename VoxelType>
class Run
{
public:
typedef uint16_t LengthType;
VoxelType value;
LengthType length;
};
/**
* Provides an interface for performing paging of data.
*/
template <typename VoxelType>
class RLEBlockCompressor : public BlockCompressor<VoxelType>
{
public:
RLEBlockCompressor();
~RLEBlockCompressor();
void compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock);
void decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock);
};
}
#include "PolyVoxCore/RLEBlockCompressor.inl"
#endif //__PolyVox_RLEBlockCompressor_H__

View File

@ -0,0 +1,167 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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 <vector>
namespace PolyVox
{
template <typename VoxelType>
RLEBlockCompressor<VoxelType>::RLEBlockCompressor()
{
}
template <typename VoxelType>
RLEBlockCompressor<VoxelType>::~RLEBlockCompressor()
{
}
template <typename VoxelType>
void RLEBlockCompressor<VoxelType>::compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock)
{
void* pSrcData = reinterpret_cast<void*>(pSrcBlock->getData());
uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes();
if(uSrcLength % sizeof(VoxelType) != 0)
{
POLYVOX_THROW(std::length_error, "Source length must be a integer multiple of the ValueType size");
}
// Lengths provided are in bytes, so convert them to be in terms of our types.
uSrcLength /= sizeof(VoxelType);
//uDstLength /= sizeof(Run);
// Get data pointers in the appropriate type
const VoxelType* pSrcDataAsType = reinterpret_cast<const VoxelType*>(pSrcData);
//Run* pDstDataAsRun = reinterpret_cast<Run*>(pDstData);
std::vector< Run<VoxelType> > vecDstDataAsRuns;
// Pointers to just past the end of the data
const VoxelType* pSrcDataEnd = pSrcDataAsType + uSrcLength;
//Run* pDstDataEnd = pDstDataAsRun + uDstLength;
//Counter for the output length
//uint32_t uDstLengthInBytes = 0;
// Read the first element of the source and set up the first run based on it.
/*pDstDataAsRun->value = *pSrcDataAsType;
pSrcDataAsType++;
pDstDataAsRun->length = 1;
uDstLengthInBytes += sizeof(Run);*/
Run<VoxelType> firstRun;
firstRun.value = *pSrcDataAsType;
firstRun.length = 1;
vecDstDataAsRuns.push_back(firstRun);
pSrcDataAsType++;
//Now process all remaining elements of the source.
while(pSrcDataAsType < pSrcDataEnd)
{
// If the value is the same as the current run (and we have not
// reached the maximum run length) then extend the current run.
typename std::vector< Run< VoxelType> >::iterator currentRun = (vecDstDataAsRuns.end() - 1);
if((*pSrcDataAsType == currentRun->value) && (currentRun->length < (std::numeric_limits<typename Run<VoxelType>::LengthType>::max)()))
{
currentRun->length++;
}
// Otherwise we need to start a new Run.
else
{
/*pDstDataAsRun++;
// Check if we have enough space in the destination buffer.
if(pDstDataAsRun >= pDstDataEnd)
{
POLYVOX_THROW(std::runtime_error, "Insufficient space in destination buffer.");
}*/
// Create the new run.
/*pDstDataAsRun->value = *pSrcDataAsType;
pDstDataAsRun->length = 1;
uDstLengthInBytes += sizeof(Run);*/
Run<VoxelType> newRun;
newRun.value = *pSrcDataAsType;
newRun.length = 1;
vecDstDataAsRuns.push_back(newRun);
}
pSrcDataAsType++;
}
//Now copy the data into the compressed block.
pDstBlock->setData(reinterpret_cast<uint8_t*>(&(vecDstDataAsRuns[0])), vecDstDataAsRuns.size() * sizeof(Run<VoxelType>));
}
template <typename VoxelType>
void RLEBlockCompressor<VoxelType>::decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock)
{
const void* pSrcData = reinterpret_cast<const void*>(pSrcBlock->getData());
uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes();
void* pDstData = pDstBlock->getData();
uint32_t uDstLength = pDstBlock->getDataSizeInBytes();
if(uSrcLength % sizeof(Run<VoxelType>) != 0)
{
POLYVOX_THROW(std::length_error, "Source length must be a integer multiple of the Run size");
}
// Lengths provided are in bytes, so convert them to be in terms of our types.
uSrcLength /= sizeof(Run<VoxelType>);
uDstLength /= sizeof(VoxelType);
// Get data pointers in the appropriate type
const Run<VoxelType>* pSrcDataAsRun = reinterpret_cast<const Run<VoxelType>*>(pSrcData);
VoxelType* pDstDataAsType = reinterpret_cast<VoxelType*>(pDstData);
// Pointers to just past the end of the data
const Run<VoxelType>* pSrcDataEnd = pSrcDataAsRun + uSrcLength;
VoxelType* pDstDataEnd = pDstDataAsType + uDstLength;
//Counter for the output length
uint32_t uDstLengthInBytes = 0;
while(pSrcDataAsRun < pSrcDataEnd)
{
// Check if we have enough space in the destination buffer.
if(pDstDataAsType + pSrcDataAsRun->length > pDstDataEnd)
{
POLYVOX_THROW(std::runtime_error, "Insufficient space in destination buffer.");
}
else
{
// Write the run into the destination
std::fill(pDstDataAsType, pDstDataAsType + pSrcDataAsRun->length, pSrcDataAsRun->value);
pDstDataAsType += pSrcDataAsRun->length;
uDstLengthInBytes += pSrcDataAsRun->length * sizeof(VoxelType);
}
pSrcDataAsRun++;
}
POLYVOX_ASSERT(uDstLengthInBytes == pDstBlock->getDataSizeInBytes(), "Uncompressed data does not have the correct length.");
}
}

View File

@ -1,40 +0,0 @@
#ifndef __PolyVox_RLECompressor_H__
#define __PolyVox_RLECompressor_H__
#include "PolyVoxCore/Compressor.h"
namespace PolyVox
{
/**
* Performs compression of data using Run Length Encoding (RLE).
*
* This compressor is designed for voxel data which contains long runs of the same value. Minecraft-style terrain and other
* cubic-style terrains are likely to fall under this category, whereas density fields for Marching Cubes terrain will not. Please
* see the following article if you want more details of how RLE compression works: http://en.wikipedia.org/wiki/Run-length_encoding
*
* \sa MinizCompressor
*/
template<typename ValueType, typename LengthType>
class RLECompressor : public Compressor
{
struct Run
{
ValueType value;
LengthType length;
};
public:
/// Constructor
RLECompressor();
/// Destructor
~RLECompressor();
// API documentation is in base class and gets inherited by Doxygen.
uint32_t getMaxCompressedSize(uint32_t uUncompressedInputSize);
uint32_t compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
uint32_t decompress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
};
}
#include "RLECompressor.inl"
#endif //__PolyVox_RLECompressor_H__

View File

@ -1,126 +0,0 @@
#include <algorithm>
#include <cassert>
#include <limits>
namespace PolyVox
{
template<typename ValueType, typename LengthType>
RLECompressor<ValueType, LengthType>::RLECompressor()
{
}
template<typename ValueType, typename LengthType>
RLECompressor<ValueType, LengthType>::~RLECompressor()
{
}
template<typename ValueType, typename LengthType>
uint32_t RLECompressor<ValueType, LengthType>::getMaxCompressedSize(uint32_t uUncompressedInputSize)
{
// In the worst case we will have a seperate Run (of length one) for each element of the input data.
return uUncompressedInputSize * sizeof(Run);
}
template<typename ValueType, typename LengthType>
uint32_t RLECompressor<ValueType, LengthType>::compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
{
if(uSrcLength % sizeof(ValueType) != 0)
{
POLYVOX_THROW(std::length_error, "Source length must be a integer multiple of the ValueType size");
}
// Lengths provided are in bytes, so convert them to be in terms of our types.
uSrcLength /= sizeof(ValueType);
uDstLength /= sizeof(Run);
// Get data pointers in the appropriate type
ValueType* pSrcDataAsType = reinterpret_cast<ValueType*>(pSrcData);
Run* pDstDataAsRun = reinterpret_cast<Run*>(pDstData);
// Pointers to just past the end of the data
ValueType* pSrcDataEnd = pSrcDataAsType + uSrcLength;
Run* pDstDataEnd = pDstDataAsRun + uDstLength;
//Counter for the output length
uint32_t uDstLengthInBytes = 0;
// Read the first element of the source and set up the first run based on it.
pDstDataAsRun->value = *pSrcDataAsType;
pSrcDataAsType++;
pDstDataAsRun->length = 1;
uDstLengthInBytes += sizeof(Run);
//Now process all remaining elements of the source.
while(pSrcDataAsType < pSrcDataEnd)
{
// If the value is the same as the current run (and we have not
// reached the maximum run length) then extend the current run.
if((*pSrcDataAsType == pDstDataAsRun->value) && (pDstDataAsRun->length < (std::numeric_limits<LengthType>::max)()))
{
pDstDataAsRun->length++;
}
// Otherwise we need to start a new Run.
else
{
pDstDataAsRun++;
// Check if we have enough space in the destination buffer.
if(pDstDataAsRun >= pDstDataEnd)
{
POLYVOX_THROW(std::runtime_error, "Insufficient space in destination buffer.");
}
// Create the new run.
pDstDataAsRun->value = *pSrcDataAsType;
pDstDataAsRun->length = 1;
uDstLengthInBytes += sizeof(Run);
}
pSrcDataAsType++;
}
return uDstLengthInBytes;
}
template<typename ValueType, typename LengthType>
uint32_t RLECompressor<ValueType, LengthType>::decompress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
{
if(uSrcLength % sizeof(Run) != 0)
{
POLYVOX_THROW(std::length_error, "Source length must be a integer multiple of the Run size");
}
// Lengths provided are in bytes, so convert them to be in terms of our types.
uSrcLength /= sizeof(Run);
uDstLength /= sizeof(ValueType);
// Get data pointers in the appropriate type
Run* pSrcDataAsRun = reinterpret_cast<Run*>(pSrcData);
ValueType* pDstDataAsType = reinterpret_cast<ValueType*>(pDstData);
// Pointers to just past the end of the data
Run* pSrcDataEnd = pSrcDataAsRun + uSrcLength;
ValueType* pDstDataEnd = pDstDataAsType + uDstLength;
//Counter for the output length
uint32_t uDstLengthInBytes = 0;
while(pSrcDataAsRun < pSrcDataEnd)
{
// Check if we have enough space in the destination buffer.
if(pDstDataAsType + pSrcDataAsRun->length > pDstDataEnd)
{
POLYVOX_THROW(std::runtime_error, "Insufficient space in destination buffer.");
}
// Write the run into the destination
std::fill(pDstDataAsType, pDstDataAsType + pSrcDataAsRun->length, pSrcDataAsRun->value);
pDstDataAsType += pSrcDataAsRun->length;
uDstLengthInBytes += pSrcDataAsRun->length * sizeof(ValueType);
pSrcDataAsRun++;
}
return uDstLengthInBytes;
}
}

View File

@ -51,7 +51,7 @@ namespace PolyVox
}
else
{
return getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}

View File

@ -215,7 +215,7 @@ namespace PolyVox
// Non-member overloaded operators.
/// Stream insertion operator.
std::ostream& operator<<(std::ostream& os, const Region& region);
std::ostream& operator<<(std::ostream& os, const Region& region);
// Functions to be inlined to to be in the header rather than the .cpp.
// 'inline' keyword is used for the definition rather than the declaration.

View File

@ -94,7 +94,7 @@ namespace PolyVox
}
else
{
return getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}

View File

@ -1,5 +1,5 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
Copyright (c) 2005-2013 David Williams and Matthew 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
@ -21,55 +21,48 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#ifndef __PolyVox_Block_H__
#define __PolyVox_Block_H__
#ifndef __PolyVox_UncompressedBlock_H__
#define __PolyVox_UncompressedBlock_H__
#include "PolyVoxCore/Impl/TypeDef.h"
#include "PolyVoxCore/PolyVoxForwardDeclarations.h"
#include "PolyVoxCore/Vector.h"
#include <limits>
#include <vector>
#include "PolyVoxCore/Block.h"
namespace PolyVox
{
template <typename VoxelType>
class Block
{
public:
Block(uint16_t uSideLength, Compressor* pCompressor);
class UncompressedBlock : public Block<VoxelType>
{
friend class LargeVolume<VoxelType>;
public:
UncompressedBlock(uint16_t uSideLength);
~UncompressedBlock();
VoxelType* getData(void) const;
uint32_t getDataSizeInBytes(void) const;
const uint8_t* const getCompressedData(void) const;
const uint32_t getCompressedDataLength(void) const;
uint16_t getSideLength(void) const;
VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
VoxelType getVoxel(const Vector3DUint16& v3dPos) const;
bool hasUncompressedData(void) const;
void setCompressedData(const uint8_t* const data, uint32_t dataLength);
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
void createUncompressedData(void);
void destroyUncompressedData(void);
private:
/// Private copy constructor to prevent accisdental copying
UncompressedBlock(const UncompressedBlock& /*rhs*/) {};
/// Private assignment operator to prevent accisdental copying
UncompressedBlock& operator=(const UncompressedBlock& /*rhs*/) {};
// Made this private for consistancy with CompressedBlock.
// Users shouldn't really need this for UncompressedBlock anyway.
uint32_t calculateSizeInBytes(void);
public:
Compressor* m_pCompressor;
uint8_t* m_pCompressedData;
uint32_t m_uCompressedDataLength;
VoxelType* m_tUncompressedData;
uint16_t m_uSideLength;
uint8_t m_uSideLengthPower;
bool m_bIsUncompressedDataModified;
uint32_t timestamp;
VoxelType* m_tData;
uint16_t m_uSideLength;
uint8_t m_uSideLengthPower;
};
}
#include "PolyVoxCore/Impl/Block.inl"
#include "PolyVoxCore/UncompressedBlock.inl"
#endif

View File

@ -0,0 +1,117 @@
/*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew 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.
*******************************************************************************/
namespace PolyVox
{
template <typename VoxelType>
UncompressedBlock<VoxelType>::UncompressedBlock(uint16_t uSideLength)
:m_tData(0)
,m_uSideLength(0)
,m_uSideLengthPower(0)
{
// Compute the side length
m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(uSideLength);
// Allocate the data
const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
m_tData = new VoxelType[uNoOfVoxels];
}
template <typename VoxelType>
UncompressedBlock<VoxelType>::~UncompressedBlock()
{
delete[] m_tData;
m_tData = 0;
}
template <typename VoxelType>
VoxelType* UncompressedBlock<VoxelType>::getData(void) const
{
return m_tData;
}
template <typename VoxelType>
uint32_t UncompressedBlock<VoxelType>::getDataSizeInBytes(void) const
{
return m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
}
template <typename VoxelType>
VoxelType UncompressedBlock<VoxelType>::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{
// This code is not usually expected to be called by the user, with the exception of when implementing paging
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(m_tData, "No uncompressed data - block must be decompressed before accessing voxels.");
return m_tData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
];
}
template <typename VoxelType>
VoxelType UncompressedBlock<VoxelType>::getVoxel(const Vector3DUint16& v3dPos) const
{
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
template <typename VoxelType>
void UncompressedBlock<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
{
// This code is not usually expected to be called by the user, with the exception of when implementing paging
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
POLYVOX_ASSERT(m_tData, "No uncompressed data - block must be decompressed before accessing voxels.");
m_tData
[
uXPos +
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
] = tValue;
this->m_bDataModified = true;
}
template <typename VoxelType>
void UncompressedBlock<VoxelType>::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
{
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
}
template <typename VoxelType>
uint32_t UncompressedBlock<VoxelType>::calculateSizeInBytes(void)
{
// Returns the size of this class plus the size of the uncompressed data.
uint32_t uSizeInBytes = sizeof(UncompressedBlock<VoxelType>) + (m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType));
return uSizeInBytes;
}
}

View File

@ -30,7 +30,7 @@ freely, subject to the following restrictions:
namespace PolyVox
{
const int edgeTable[256]=
const uint16_t edgeTable[256]=
{
0x000, 0x109, 0x203, 0x30a, 0x80c, 0x905, 0xa0f, 0xb06,
0x406, 0x50f, 0x605, 0x70c, 0xc0a, 0xd03, 0xe09, 0xf00,
@ -66,7 +66,7 @@ namespace PolyVox
0xb06, 0xa0f, 0x905, 0x80c, 0x30a, 0x203, 0x109, 0x000
};
const int triTable[256][16] =
const int8_t triTable[256][16] =
{
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
{ 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },

View File

@ -0,0 +1,93 @@
/*******************************************************************************
Copyright (c) 2005-20013 David Williams and Matthew 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 "PolyVoxCore/Impl/Timer.h"
#include "PolyVoxCore/Impl/ErrorHandling.h"
#include <iostream>
namespace PolyVox
{
#if defined(_MSC_VER)
Timer::Timer(bool bAutoStart)
:m_fPCFreq(0.0)
,m_iStartTime(0)
{
if(bAutoStart)
{
start();
}
}
void Timer::start(void)
{
LARGE_INTEGER li;
if(!QueryPerformanceFrequency(&li))
{
logWarning() << "QueryPerformanceFrequency failed!";
m_fPCFreq = 1.0f;
}
m_fPCFreq = double(li.QuadPart);
QueryPerformanceCounter(&li);
m_iStartTime = li.QuadPart;
}
float Timer::elapsedTimeInSeconds(void)
{
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
double fDifference = static_cast<double>(li.QuadPart-m_iStartTime);
return static_cast<float>(fDifference / m_fPCFreq);
}
uint32_t Timer::elapsedTimeInMilliSeconds(void)
{
return static_cast<uint32_t>(elapsedTimeInSeconds() * 1000.0f);
}
#else //_MSC_VER
Timer::Timer(bool bAutoStart)
{
if(bAutoStart)
{
start();
}
}
void Timer::start(void)
{
}
float Timer::elapsedTimeInSeconds(void)
{
return 0.0f;
}
uint32_t Timer::elapsedTimeInMilliSeconds(void)
{
return 0;
}
#endif //_MSC_VER
}

View File

@ -1,62 +1,62 @@
/*******************************************************************************
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 "PolyVoxCore/Impl/ErrorHandling.h"
#include "PolyVoxCore/Impl/Utility.h"
namespace PolyVox
{
//Note: this function only works for inputs which are a power of two and not zero
//If this is not the case then the output is undefined.
uint8_t logBase2(uint32_t uInput)
{
//Release mode validation
if(uInput == 0)
{
POLYVOX_THROW(std::invalid_argument, "Cannot compute the log of zero.");
}
if(!isPowerOf2(uInput))
{
POLYVOX_THROW(std::invalid_argument, "Input must be a power of two in order to compute the log.");
}
uint32_t uResult = 0;
while( (uInput >> uResult) != 0)
{
++uResult;
}
return static_cast<uint8_t>(uResult-1);
}
bool isPowerOf2(uint32_t uInput)
{
if(uInput == 0)
return false;
else
return ((uInput & (uInput-1)) == 0);
}
/*******************************************************************************
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 "PolyVoxCore/Impl/ErrorHandling.h"
#include "PolyVoxCore/Impl/Utility.h"
namespace PolyVox
{
//Note: this function only works for inputs which are a power of two and not zero
//If this is not the case then the output is undefined.
uint8_t logBase2(uint32_t uInput)
{
//Release mode validation
if(uInput == 0)
{
POLYVOX_THROW(std::invalid_argument, "Cannot compute the log of zero.");
}
if(!isPowerOf2(uInput))
{
POLYVOX_THROW(std::invalid_argument, "Input must be a power of two in order to compute the log.");
}
uint32_t uResult = 0;
while( (uInput >> uResult) != 0)
{
++uResult;
}
return static_cast<uint8_t>(uResult-1);
}
bool isPowerOf2(uint32_t uInput)
{
if(uInput == 0)
return false;
else
return ((uInput & (uInput-1)) == 0);
}
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
uint32_t upperPowerOfTwo(uint32_t v)
{
@ -68,10 +68,10 @@ namespace PolyVox
v |= v >> 16;
v++;
return v;
}
float triangleFilter(float fInput)
{
return (std::max)(1.0f - (std::abs)(fInput), 0.0f);
}
}
}
float triangleFilter(float fInput)
{
return (std::max)(1.0f - (std::abs)(fInput), 0.0f);
}
}

View File

@ -70,7 +70,7 @@ namespace PolyVox
return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
}
uint32_t MinizCompressor::compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
uint32_t MinizCompressor::compress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
{
//Get the deflator
tdefl_compressor* pDeflator = reinterpret_cast<tdefl_compressor*>(m_pDeflator);
@ -103,7 +103,7 @@ namespace PolyVox
return ulDstLength;
}
uint32_t MinizCompressor::decompress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
uint32_t MinizCompressor::decompress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
{
// I don't know exactly why this limitation exists but it's an implementation detail of miniz. It shouldn't matter for our purposes
// as our detination is a Block and those are always a power of two. If you need to use this class for other purposes then you'll

View File

@ -514,5 +514,5 @@ namespace PolyVox
os << "(" << region.getLowerX() << "," << region.getLowerY() << "," << region.getLowerZ() <<
") to (" << region.getUpperX() << "," << region.getUpperY() << "," << region.getUpperZ() << ")";
return os;
}
}
}

9
library/bindings/Block.i Normal file
View File

@ -0,0 +1,9 @@
%module Block
%{
#include "Block.h"
%}
%include "Block.h"
VOLUMETYPES(Block)

View File

@ -0,0 +1,8 @@
%module BlockCompressor
%{
#include "BlockCompressor.h"
%}
%include "BlockCompressor.h"
VOLUMETYPES(BlockCompressor)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2009-2012 Matt Williams
# Copyright (c) 2009-2013 Matt 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
@ -19,7 +19,7 @@
# 3. This notice may not be removed or altered from any source
# distribution.
option(ENABLE_BINDINGS "Build Python bindings" ON)
option(ENABLE_BINDINGS "Build bindings" ON)
if(ENABLE_BINDINGS)
find_package(SWIG)
mark_as_advanced(SWIG_DIR SWIG_VERSION)
@ -31,24 +31,26 @@ if(ENABLE_BINDINGS)
set_package_properties(SWIG PROPERTIES DESCRIPTION "Bindings generator" URL http://www.swig.org)
set_package_properties(PythonLibs PROPERTIES DESCRIPTION "Programming language" URL http://www.python.org)
endif()
if(SWIG_FOUND AND PYTHONLIBS_FOUND)
set(BUILD_BINDINGS ON CACHE BOOL "Will the bindings be built" FORCE )
if(SWIG_FOUND)
set(BUILD_BINDINGS ON CACHE BOOL "Will the bindings be built" FORCE)
include(${SWIG_USE_FILE})
include_directories(${PYTHON_INCLUDE_PATH})
include_directories(${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include/PolyVoxCore)
link_directories(${PolyVoxCore_BINARY_DIR})
set(CMAKE_SWIG_FLAGS "")
set_source_files_properties(PolyVoxCore.i PROPERTIES CPLUSPLUS ON)
#set_source_files_properties(PolyVoxCore.i PROPERTIES SWIG_FLAGS "-builtin")
set(SWIG_MODULE_PolyVoxCorePython_EXTRA_FLAGS "-py3")
swig_add_module(PolyVoxCorePython python PolyVoxCore.i)
swig_link_libraries(PolyVoxCorePython ${PYTHON_LIBRARIES} PolyVoxCore)
set_target_properties(${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTIES OUTPUT_NAME _PolyVoxCore)
#set_target_properties(${SWIG_MODULE_PolyVoxCore_REAL_NAME} PROPERTIES SUFFIX ".pyd")
SET_PROPERTY(TARGET ${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTY FOLDER "Bindings")
if(PYTHONLIBS_FOUND)
include_directories(${PYTHON_INCLUDE_PATH})
include_directories(${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include/PolyVoxCore)
link_directories(${PolyVoxCore_BINARY_DIR})
#set_source_files_properties(PolyVoxCore.i PROPERTIES SWIG_FLAGS "-builtin")
set(SWIG_MODULE_PolyVoxCorePython_EXTRA_FLAGS "-py3")
swig_add_module(PolyVoxCorePython python PolyVoxCore.i)
swig_link_libraries(PolyVoxCorePython ${PYTHON_LIBRARIES} PolyVoxCore)
set_target_properties(${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTIES OUTPUT_NAME _PolyVoxCore)
#set_target_properties(${SWIG_MODULE_PolyVoxCore_REAL_NAME} PROPERTIES SUFFIX ".pyd")
SET_PROPERTY(TARGET ${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTY FOLDER "Bindings")
endif()
set(SWIG_MODULE_PolyVoxCoreCSharp_EXTRA_FLAGS "-dllimport;PolyVoxCoreCSharp") #This _should_ be inside UseSWIG.cmake - http://www.cmake.org/Bug/view.php?id=13814
swig_add_module(PolyVoxCoreCSharp csharp PolyVoxCore.i)

View File

@ -0,0 +1,8 @@
%module CompressedBlock
%{
#include "CompressedBlock.h"
%}
%include "CompressedBlock.h"
VOLUMETYPES(CompressedBlock)

View File

@ -0,0 +1,6 @@
%module MinizBlockCompressor
%{
#include "MinizBlockCompressor.h"
%}
%include "MinizBlockCompressor.h"

View File

@ -1,6 +0,0 @@
%module MinizCompressor
%{
#include "MinizCompressor.h"
%}
%include "MinizCompressor.h"

View File

@ -68,6 +68,7 @@ EXTRACTOR(shortname, LargeVolume)
%ignore *::operator-=;
%ignore *::operator*=;
%ignore *::operator/=;
%ignore *::operator<<; //This is covered by STR()
#endif
%include "stdint.i"
@ -75,11 +76,15 @@ EXTRACTOR(shortname, LargeVolume)
%include "Vector.i"
%include "DefaultMarchingCubesController.i"
%include "Region.i"
%include "Block.i"
%include "CompressedBlock.i"
%include "UncompressedBlock.i"
%include "Compressor.i"
%include "BlockCompressor.i"
%include "Pager.i"
%include "FilePager.i"
%include "MinizCompressor.i"
%include "RLECompressor.i"
%include "MinizBlockCompressor.i"
%include "RLEBlockCompressor.i"
%include "BaseVolume.i"
%include "SimpleVolume.i"
%include "RawVolume.i"

View File

@ -0,0 +1,6 @@
%module RLEBlockCompressor
%{
#include "RLEBlockCompressor.h"
%}
%include "RLEBlockCompressor.h"

View File

@ -1,6 +0,0 @@
%module RLECompressor
%{
#include "RLECompressor.h"
%}
%include "RLECompressor.h"

View File

@ -4,6 +4,10 @@
#include "Region.h"
%}
%extend PolyVox::Region {
STR()
};
%ignore depth;
%ignore height;
%ignore width;

View File

@ -0,0 +1,8 @@
%module UncompressedBlock
%{
#include "UncompressedBlock.h"
%}
%include "UncompressedBlock.h"
VOLUMETYPES(UncompressedBlock)

View File

@ -25,9 +25,8 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/FilePager.h"
#include "PolyVoxCore/LargeVolume.h"
#include "PolyVoxCore/MinizCompressor.h"
#include "PolyVoxCore/MinizBlockCompressor.h"
#include "PolyVoxCore/RawVolume.h"
#include "PolyVoxCore/RLECompressor.h"
#include "PolyVoxCore/SimpleVolume.h"
#include <QtGlobal>
@ -273,13 +272,13 @@ TestVolume::TestVolume()
Region region(-57, -31, 12, 64, 96, 131); // Deliberatly awkward size
//m_pCompressor = new RLECompressor<int32_t, uint16_t>;
m_pCompressor = new MinizCompressor;
m_pBlockCompressor = new MinizBlockCompressor<int32_t>;
m_pFilePager = new FilePager<int32_t>("./");
//Create the volumes
m_pRawVolume = new RawVolume<int32_t>(region);
m_pSimpleVolume = new SimpleVolume<int32_t>(region);
m_pLargeVolume = new LargeVolume<int32_t>(region, m_pCompressor, m_pFilePager, 32);
m_pLargeVolume = new LargeVolume<int32_t>(region, m_pBlockCompressor, m_pFilePager, 32);
m_pLargeVolume->setMaxNumberOfBlocksInMemory(32);
m_pLargeVolume->setMaxNumberOfUncompressedBlocks(16);
@ -307,7 +306,7 @@ TestVolume::~TestVolume()
delete m_pLargeVolume;
delete m_pFilePager;
delete m_pCompressor;
delete m_pBlockCompressor;
}
/*

View File

@ -65,7 +65,7 @@ private slots:
void testLargeVolumeSamplersWithExternalBackwards();
private:
PolyVox::Compressor* m_pCompressor;
PolyVox::BlockCompressor<int32_t>* m_pBlockCompressor;
PolyVox::FilePager<int32_t>* m_pFilePager;
PolyVox::RawVolume<int32_t>* m_pRawVolume;