diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index ccae9941..e6ae33d7 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -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* compressor = new RLECompressor(); - LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1)), compressor, 0); + RLEBlockCompressor* compressor = new RLEBlockCompressor(); + FilePager* pager = new FilePager("./"); + LargeVolume 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; diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index f172a214..27236afd 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -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* pBlockData) + virtual void pageIn(const PolyVox::Region& region, CompressedBlock* 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 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* compressor = new RLEBlockCompressor(); + compressor->compress(&block, pBlockData); + delete compressor; } - virtual void pageOut(const PolyVox::Region& region, Block* /*pBlockData*/) + virtual void pageOut(const PolyVox::Region& region, CompressedBlock* /*pBlockData*/) { std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl; } @@ -150,12 +157,11 @@ int main(int argc, char *argv[]) OpenGLWidget openGLWidget(0); openGLWidget.show(); - RLECompressor* compressor = new RLECompressor(); + RLEBlockCompressor* compressor = new RLEBlockCompressor(); PerlinNoisePager* pager = new PerlinNoisePager(); LargeVolume volData(PolyVox::Region::MaxRegion, compressor, pager, 256); - //volData.setMaxNumberOfBlocksInMemory(4096); - //volData.setMaxNumberOfUncompressedBlocks(64); - volData.setTargetMemoryLimitInBytes(128 * 1024 * 1024); + volData.setMaxNumberOfBlocksInMemory(4096); + volData.setMaxNumberOfUncompressedBlocks(64); //volData.setMaxNumberOfUncompressedBlocks(4096); //createSphereInVolume(volData, 30); diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index a8ce8a0c..bb28c01e 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -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 @@ -111,8 +119,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 diff --git a/library/PolyVoxCore/include/PolyVoxCore/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Block.h new file mode 100644 index 00000000..e2bb16cb --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Block.h @@ -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 +#include + +namespace PolyVox +{ + template + class Block + { + friend class LargeVolume; + + 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 diff --git a/library/PolyVoxCore/include/PolyVoxCore/BlockCompressor.h b/library/PolyVoxCore/include/PolyVoxCore/BlockCompressor.h new file mode 100644 index 00000000..5af6dbfb --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/BlockCompressor.h @@ -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 + class BlockCompressor + { + public: + BlockCompressor() {}; + virtual ~BlockCompressor() {}; + + virtual void compress(UncompressedBlock* pSrcBlock, CompressedBlock* pDstBlock) = 0; + virtual void decompress(CompressedBlock* pSrcBlock, UncompressedBlock* pDstBlock) = 0; + }; +} + +#endif //__PolyVox_BlockCompressor_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/CompressedBlock.h b/library/PolyVoxCore/include/PolyVoxCore/CompressedBlock.h new file mode 100644 index 00000000..5a8ba89a --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/CompressedBlock.h @@ -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 + class CompressedBlock : public Block + { + friend class LargeVolume; + + 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 diff --git a/library/PolyVoxCore/include/PolyVoxCore/CompressedBlock.inl b/library/PolyVoxCore/include/PolyVoxCore/CompressedBlock.inl new file mode 100644 index 00000000..e98df8e3 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/CompressedBlock.inl @@ -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 + CompressedBlock::CompressedBlock() + :m_pData(0) + ,m_uDataSizeInBytes(0) + { + } + + template + CompressedBlock::~CompressedBlock() + { + delete[] m_pData; + m_pData = 0; + } + + template + const uint8_t* CompressedBlock::getData(void) const + { + return m_pData; + } + + template + uint32_t CompressedBlock::getDataSizeInBytes(void) const + { + return m_uDataSizeInBytes; + } + + template + void CompressedBlock::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 + uint32_t CompressedBlock::calculateSizeInBytes(void) + { + // Returns the size of this class plus the size of the compressed data. + uint32_t uSizeInBytes = sizeof(CompressedBlock) + m_uDataSizeInBytes; + return uSizeInBytes; + } +} diff --git a/library/PolyVoxCore/include/PolyVoxCore/Compressor.h b/library/PolyVoxCore/include/PolyVoxCore/Compressor.h index 8c00be5e..e85610de 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Compressor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Compressor.h @@ -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; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 1f3115ab..3e087b5f 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -29,6 +29,8 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Pager.h" #include "PolyVoxCore/Region.h" +#include +#include #include #include #include @@ -47,21 +49,39 @@ namespace PolyVox :Pager() ,m_strFolderName(strFolderName) { + srand(time(0)); + int iRandomValue = rand(); + + std::stringstream ss; + ss << std::hex << iRandomValue; + m_strRandomPrefix = ss.str(); } /// Destructor - virtual ~FilePager() {}; + virtual ~FilePager() + { + for(std::vector::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* pBlockData) + m_vecCreatedFiles.clear(); + } + + virtual void pageIn(const Region& region, CompressedBlock* 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* pBlockData) + virtual void pageOut(const Region& region, CompressedBlock* 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 m_vecCreatedFiles; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl deleted file mode 100644 index bebcfb35..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ /dev/null @@ -1,277 +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 //For memcpy -#include -#include //for std::invalid_argument - -namespace PolyVox -{ - template - Block::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 - const uint8_t* Block::getCompressedData(void) const - { - POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); - return m_pCompressedData; - } - - template - uint32_t Block::getCompressedDataLength(void) const - { - POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); - return m_uCompressedDataLength; - } - - template - uint16_t Block::getSideLength(void) const - { - return m_uSideLength; - } - - template - VoxelType Block::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 - VoxelType Block::getVoxel(const Vector3DUint16& v3dPos) const - { - return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); - } - - template - bool Block::hasUncompressedData(void) const - { - return m_tUncompressedData != 0; - } - - template - void Block::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 - void Block::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 - void Block::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) - { - setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); - } - - template - void Block::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(m_tUncompressedData); - uint32_t uSrcLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType); - - uint8_t tempBuffer[10000]; - void* pDstData = reinterpret_cast( 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( 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 - void Block::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(m_pCompressedData); - void* pDstData = reinterpret_cast(m_tUncompressedData); - uint32_t uSrcLength = m_uCompressedDataLength; - uint32_t uDstLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType); - - //MinizCompressor compressor; - //RLECompressor 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(uncompressedResult.ptr); - - m_bIsUncompressedDataModified = false; - } - - template - uint32_t Block::calculateSizeInBytes(void) - { - // Returns the size of this class plus the size of the compressed data. It - // doesn't include the uncompressed data cache as that is owned by the volume. - uint32_t uSizeInBytes = sizeof(Block) + m_uCompressedDataLength; - return uSizeInBytes; - } -} diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index cd773156..a26bc29b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -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* pBlockCompressor, Pager* pPager , uint16_t uBlockSideLength = 32 ); @@ -263,10 +263,10 @@ namespace PolyVox /// Gets a voxel at the position given by a 3D vector POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; - void setTargetMemoryLimitInBytes(uint32_t uTargetMemoryLimitInBytes); - /// 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); /// Sets the voxel at the position given by x,y,z 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,10 @@ namespace PolyVox } return false; } - }; + }; + + typedef std::map*, BlockPositionCompare> CompressedBlockMap; + typedef std::map*, BlockPositionCompare> UncompressedBlockMap; uint32_t calculateBlockMemoryUsage(void) const; @@ -329,23 +332,21 @@ namespace PolyVox VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; - Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; - void eraseBlock(typename std::map, BlockPositionCompare>::iterator itBlock) const; + CompressedBlock* getCompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; + UncompressedBlock* 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, 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* > m_vecBlocksWithUncompressedData; mutable uint32_t m_uTimestamper; mutable Vector3DInt32 m_v3dLastAccessedBlockPos; - mutable Block* m_pLastAccessedBlock; + mutable UncompressedBlock* m_pLastAccessedBlock; uint32_t m_uMaxNumberOfUncompressedBlocks; - - uint32_t m_uCompressedBlockMemoryLimitInBytes; + uint32_t m_uMaxNumberOfBlocksInMemory; // The size of the volume Region m_regValidRegionInBlocks; @@ -355,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* m_pBlockCompressor; Pager* m_pPager; + // Compressed data for an empty block (sometimes needed for initialisation). + //CompressedBlock* 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; diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 662d10db..c9fe8fa6 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -23,7 +23,7 @@ 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 @@ -45,7 +45,7 @@ namespace PolyVox { m_uBlockSideLength = uBlockSideLength; - m_pCompressor = new MinizCompressor(); + m_pBlockCompressor = new MinizBlockCompressor(); m_bIsOurCompressor = true; m_pPager = 0; @@ -56,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. @@ -66,16 +66,15 @@ namespace PolyVox LargeVolume::LargeVolume ( const Region& regValid, - Compressor* pCompressor, + BlockCompressor* pBlockCompressor, Pager* pPager, uint16_t uBlockSideLength ) :BaseVolume(regValid) { - m_uBlockSideLength = uBlockSideLength; - m_pCompressor = pCompressor; + m_pBlockCompressor = pBlockCompressor; m_bIsOurCompressor = false; m_pPager = pPager; @@ -107,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; } //////////////////////////////////////////////////////////////////////////////// @@ -223,9 +224,9 @@ namespace PolyVox const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); - Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + const UncompressedBlock* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - return pUncompressedBlock->getVoxel(xOffset,yOffset,zOffset); + return pUncompressedBlock->getVoxel(xOffset, yOffset, zOffset); } else { @@ -243,28 +244,6 @@ namespace PolyVox return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } - template - void LargeVolume::setTargetMemoryLimitInBytes(uint32_t uTargetMemoryLimitInBytes) - { - // The size of a single uncompressed block of data. - uint32_t uUncompressedBlockSizeInBytes = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); - - // The idea number of uncompressed blocks is chosen by gut feeling as much as anything. Part of the - // rationale is that it should let us iterate along any edge without data being pushed out of the cache. - uint32_t uIdealNoOfUncompressedBlocks = m_regValidRegionInBlocks.getWidthInVoxels() + m_regValidRegionInBlocks.getHeightInVoxels() * m_regValidRegionInBlocks.getDepthInVoxels(); - - // Let's (arbitrarily?) say that we should never use more than half the available memory for the uncompressed block cache. - uint32_t uMaxMemoryForUncompressedBlocks = uTargetMemoryLimitInBytes / 2; - - uint32_t uMaxFittableNoOfUncompressedBlocks = uMaxMemoryForUncompressedBlocks / uUncompressedBlockSizeInBytes; - - setMaxNumberOfUncompressedBlocks((std::min)(uIdealNoOfUncompressedBlocks, uMaxFittableNoOfUncompressedBlocks)); - - uint32_t uUncompressedBlockCacheSizeInBytes = m_uMaxNumberOfUncompressedBlocks * uUncompressedBlockSizeInBytes; - - m_uCompressedBlockMemoryLimitInBytes = uTargetMemoryLimitInBytes - uUncompressedBlockCacheSizeInBytes; - } - //////////////////////////////////////////////////////////////////////////////// /// Increasing the size of the block cache will increase memory but may improve performance. /// You may want to set this to a large value (e.g. 1024) when you are first loading your @@ -277,6 +256,25 @@ 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 less paging to occur + /// \param uMaxNumberOfBlocksInMemory The number of blocks + //////////////////////////////////////////////////////////////////////////////// + template + void LargeVolume::setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory) + { + if(m_pBlocks.size() > uMaxNumberOfBlocksInMemory) + { + flushAll(); + } + + m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory; } //////////////////////////////////////////////////////////////////////////////// @@ -312,9 +310,8 @@ namespace PolyVox const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); - Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - - pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); + UncompressedBlock* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + pUncompressedBlock->setVoxelAt(xOffset, yOffset, zOffset, tValue); } //////////////////////////////////////////////////////////////////////////////// @@ -350,9 +347,9 @@ namespace PolyVox const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); - Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + UncompressedBlock* 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; @@ -406,7 +403,7 @@ namespace PolyVox for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) { Vector3DInt32 pos(x,y,z); - typename std::map, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos); + typename CompressedBlockMap::iterator itBlock = m_pBlocks.find(pos); if(itBlock != m_pBlocks.end()) { @@ -437,7 +434,7 @@ namespace PolyVox template void LargeVolume::flushAll() { - typename std::map, 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) @@ -471,7 +468,7 @@ namespace PolyVox for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) { Vector3DInt32 pos(x,y,z); - typename std::map, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos); + typename CompressedBlockMap::iterator itBlock = m_pBlocks.find(pos); if(itBlock == m_pBlocks.end()) { // not loaded, not unloading @@ -494,11 +491,6 @@ namespace PolyVox template void LargeVolume::clearBlockCache(void) { - for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++) - { - m_vecBlocksWithUncompressedData[ct]->destroyUncompressedData(); - } - m_vecBlocksWithUncompressedData.clear(); } //////////////////////////////////////////////////////////////////////////////// @@ -518,7 +510,7 @@ 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."); } @@ -554,42 +546,108 @@ namespace PolyVox } template - void LargeVolume::eraseBlock(typename std::map, BlockPositionCompare>::iterator itBlock) const + void LargeVolume::eraseBlock(typename CompressedBlockMap::iterator itCompressedBlock) const { - if(itBlock->second.hasUncompressedData()) - { - itBlock->second.destroyUncompressedData(); - } + CompressedBlock* 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 - Block* LargeVolume::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const + void LargeVolume::eraseBlock(typename UncompressedBlockMap::iterator itUncompressedBlock) const + { + UncompressedBlock* 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* 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 + CompressedBlock* LargeVolume::getCompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const + { + Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ); + + CompressedBlock* 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; + + // 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 + UncompressedBlock* LargeVolume::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const { Vector3DInt32 v3dBlockPos(uBlockX, uBlockY, uBlockZ); @@ -599,74 +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, 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. - Block newBlock(m_uBlockSideLength, m_pCompressor); - itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; - - // Now use the pager to fill the block with it's initial 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, &(itBlock->second)); - - // Paging in this new block may mean we are now using too much memory. If necessary, flush some old blocks. - flushOldestExcessiveBlocks(); - } - - //Get the block and mark that we accessed it - Block& block = itBlock->second; - block.timestamp = ++m_uTimestamper; - m_v3dLastAccessedBlockPos = v3dBlockPos; - m_pLastAccessedBlock = █ - - 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::max)(); + UncompressedBlock* 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] = █ + return pUncompressedBlock; } else { - m_vecBlocksWithUncompressedData.push_back(&block); - } - - block.createUncompressedData(); + // At this point we just create a new block. + UncompressedBlock* pUncompressedBlock = new UncompressedBlock(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* 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; + } } //////////////////////////////////////////////////////////////////////////////// @@ -689,16 +726,16 @@ namespace PolyVox uint32_t uSizeInBytes = sizeof(LargeVolume); //Memory used by the blocks - typename std::map, 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); - uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); + //uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(Block); + //uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); return uSizeInBytes; } @@ -708,11 +745,11 @@ namespace PolyVox { uint32_t uMemoryUsage = 0; - typename std::map, BlockPositionCompare>::iterator i; + 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(); + uMemoryUsage += i->second->calculateSizeInBytes(); } return uMemoryUsage; @@ -721,27 +758,21 @@ namespace PolyVox template void LargeVolume::flushOldestExcessiveBlocks(void) const { - const uint32_t uMemoryUsedForCompressedBlocks = calculateBlockMemoryUsage(); - uint32_t uMemoryToReclaim = uMemoryUsedForCompressedBlocks - m_uCompressedBlockMemoryLimitInBytes; - - //while(uMemoryToReclaim > 0) - while(calculateBlockMemoryUsage() > m_uCompressedBlockMemoryLimitInBytes) //FIXME - This calculation of size is slow and should be outside the loop. + while(m_pBlocks.size() > m_uMaxNumberOfBlocksInMemory) { - // find the least recently used block - typename std::map, BlockPositionCompare>::iterator i; - typename std::map, BlockPositionCompare>::iterator itUnloadBlock = m_pBlocks.begin(); + // 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.timestamp < itUnloadBlock->second.timestamp) + if(i->second->m_uBlockLastAccessed < itUnloadBlock->second->m_uBlockLastAccessed) { itUnloadBlock = i; } } - POLYVOX_ASSERT(itUnloadBlock->second.hasUncompressedData() == false, "This function should never flush blocks with uncompressed data."); - - uMemoryToReclaim -= itUnloadBlock->second.calculateSizeInBytes(); - + // Erase the least recently used block eraseBlock(itUnloadBlock); } } @@ -749,6 +780,23 @@ namespace PolyVox template void LargeVolume::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 @@ -808,9 +856,8 @@ namespace PolyVox const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); - Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - - return pUncompressedBlock->getVoxel(xOffset,yOffset,zOffset); + UncompressedBlock* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + return pUncompressedBlock->getVoxel(xOffset, yOffset, zOffset); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl index 0d71a68f..c5e4e12c 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl @@ -119,9 +119,9 @@ namespace PolyVox uYPosInBlock * this->mVolume->m_uBlockSideLength + uZPosInBlock * this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength; - Block* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock); + UncompressedBlock* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock); - mCurrentVoxel = pUncompressedCurrentBlock->m_tUncompressedData + uVoxelIndexInBlock; + mCurrentVoxel = pUncompressedCurrentBlock->m_tData + uVoxelIndexInBlock; } else { diff --git a/library/PolyVoxCore/include/PolyVoxCore/MinizBlockCompressor.h b/library/PolyVoxCore/include/PolyVoxCore/MinizBlockCompressor.h new file mode 100644 index 00000000..e4b57cf6 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/MinizBlockCompressor.h @@ -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 + class MinizBlockCompressor : public BlockCompressor + { + public: + MinizBlockCompressor(); + ~MinizBlockCompressor(); + + void compress(UncompressedBlock* pSrcBlock, CompressedBlock* pDstBlock); + void decompress(CompressedBlock* pSrcBlock, UncompressedBlock* pDstBlock); + + MinizCompressor* m_pCompressor; + }; +} + +#include "PolyVoxCore/MinizBlockCompressor.inl" + +#endif //__PolyVox_MinizBlockCompressor_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/MinizBlockCompressor.inl b/library/PolyVoxCore/include/PolyVoxCore/MinizBlockCompressor.inl new file mode 100644 index 00000000..67501ea9 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/MinizBlockCompressor.inl @@ -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 + MinizBlockCompressor::MinizBlockCompressor() + { + m_pCompressor = new MinizCompressor; + } + + template + MinizBlockCompressor::~MinizBlockCompressor() + { + delete m_pCompressor; + } + + template + void MinizBlockCompressor::compress(UncompressedBlock* pSrcBlock, CompressedBlock* pDstBlock) + { + void* pSrcData = reinterpret_cast(pSrcBlock->getData()); + uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes(); + + uint8_t tempBuffer[10000]; + uint8_t* pDstData = reinterpret_cast( 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( 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 + void MinizBlockCompressor::decompress(CompressedBlock* pSrcBlock, UncompressedBlock* pDstBlock) + { + const void* pSrcData = reinterpret_cast(pSrcBlock->getData()); + void* pDstData = reinterpret_cast(pDstBlock->getData()); + uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes(); + uint32_t uDstLength = pDstBlock->getDataSizeInBytes(); + + + //RLECompressor compressor; + uint32_t uUncompressedLength = m_pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength); + + POLYVOX_ASSERT(uUncompressedLength == pDstBlock->getDataSizeInBytes(), "Destination length has changed."); + } +} \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h b/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h index fb2b2473..7ea8f967 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h @@ -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; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Pager.h b/library/PolyVoxCore/include/PolyVoxCore/Pager.h index 4cb95adc..eb37e4f7 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Pager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Pager.h @@ -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* pBlockData) = 0; - virtual void pageOut(const Region& region, Block* pBlockData) = 0; + virtual void pageIn(const Region& region, CompressedBlock* pBlockData) = 0; + virtual void pageOut(const Region& region, CompressedBlock* pBlockData) = 0; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h index 05092ab1..2eef3077 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h +++ b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h @@ -60,6 +60,11 @@ namespace PolyVox typedef Array<3,int32_t> Array3DInt32; typedef Array<3,uint32_t> Array3DUint32; + //////////////////////////////////////////////////////////////////////////////// + // BlockCompressor + //////////////////////////////////////////////////////////////////////////////// + template class BlockCompressor; + //////////////////////////////////////////////////////////////////////////////// // Compressor //////////////////////////////////////////////////////////////////////////////// diff --git a/library/PolyVoxCore/include/PolyVoxCore/RLEBlockCompressor.h b/library/PolyVoxCore/include/PolyVoxCore/RLEBlockCompressor.h new file mode 100644 index 00000000..fd77522f --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/RLEBlockCompressor.h @@ -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 + class Run + { + public: + typedef uint16_t LengthType; + VoxelType value; + LengthType length; + }; + + /** + * Provides an interface for performing paging of data. + */ + template + class RLEBlockCompressor : public BlockCompressor + { + + + public: + RLEBlockCompressor(); + ~RLEBlockCompressor(); + + void compress(UncompressedBlock* pSrcBlock, CompressedBlock* pDstBlock); + void decompress(CompressedBlock* pSrcBlock, UncompressedBlock* pDstBlock); + }; +} + +#include "PolyVoxCore/RLEBlockCompressor.inl" + +#endif //__PolyVox_RLEBlockCompressor_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/RLEBlockCompressor.inl b/library/PolyVoxCore/include/PolyVoxCore/RLEBlockCompressor.inl new file mode 100644 index 00000000..369fb912 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/RLEBlockCompressor.inl @@ -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 + +namespace PolyVox +{ + template + RLEBlockCompressor::RLEBlockCompressor() + { + } + + template + RLEBlockCompressor::~RLEBlockCompressor() + { + } + + template + void RLEBlockCompressor::compress(UncompressedBlock* pSrcBlock, CompressedBlock* pDstBlock) + { + void* pSrcData = reinterpret_cast(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(pSrcData); + //Run* pDstDataAsRun = reinterpret_cast(pDstData); + std::vector< Run > 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 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::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 newRun; + newRun.value = *pSrcDataAsType; + newRun.length = 1; + vecDstDataAsRuns.push_back(newRun); + } + + pSrcDataAsType++; + } + + //Now copy the data into the compressed block. + + pDstBlock->setData(reinterpret_cast(&(vecDstDataAsRuns[0])), vecDstDataAsRuns.size() * sizeof(Run)); + } + + template + void RLEBlockCompressor::decompress(CompressedBlock* pSrcBlock, UncompressedBlock* pDstBlock) + { + const void* pSrcData = reinterpret_cast(pSrcBlock->getData()); + uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes(); + + void* pDstData = pDstBlock->getData(); + uint32_t uDstLength = pDstBlock->getDataSizeInBytes(); + + 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(VoxelType); + + // Get data pointers in the appropriate type + const Run* pSrcDataAsRun = reinterpret_cast*>(pSrcData); + VoxelType* pDstDataAsType = reinterpret_cast(pDstData); + + // Pointers to just past the end of the data + const Run* 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."); + } +} \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h b/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h deleted file mode 100644 index 10b52b90..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h +++ /dev/null @@ -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 - 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__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl b/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl deleted file mode 100644 index 0b43a301..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include - -namespace PolyVox -{ - template - RLECompressor::RLECompressor() - { - } - - template - RLECompressor::~RLECompressor() - { - } - - template - uint32_t RLECompressor::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 - uint32_t RLECompressor::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(pSrcData); - Run* pDstDataAsRun = reinterpret_cast(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::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 - uint32_t RLECompressor::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(pSrcData); - ValueType* pDstDataAsType = reinterpret_cast(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; - } -} diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.h similarity index 59% rename from library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h rename to library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.h index 06963f7c..54a1aacb 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.h @@ -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 -#include +#include "PolyVoxCore/Block.h" namespace PolyVox { template - class Block - { - public: - Block(uint16_t uSideLength, Compressor* pCompressor); + class UncompressedBlock : public Block + { + friend class LargeVolume; + + public: + UncompressedBlock(uint16_t uSideLength); + ~UncompressedBlock(); + + VoxelType* getData(void) const; + uint32_t getDataSizeInBytes(void) const; - const uint8_t* getCompressedData(void) 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 diff --git a/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl new file mode 100644 index 00000000..4d506d74 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl @@ -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 + UncompressedBlock::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 + UncompressedBlock::~UncompressedBlock() + { + delete[] m_tData; + m_tData = 0; + } + + template + VoxelType* UncompressedBlock::getData(void) const + { + return m_tData; + } + + template + uint32_t UncompressedBlock::getDataSizeInBytes(void) const + { + return m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType); + } + + template + VoxelType UncompressedBlock::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 + VoxelType UncompressedBlock::getVoxel(const Vector3DUint16& v3dPos) const + { + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + } + + template + void UncompressedBlock::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 + void UncompressedBlock::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) + { + setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); + } + + template + uint32_t UncompressedBlock::calculateSizeInBytes(void) + { + // Returns the size of this class plus the size of the uncompressed data. + uint32_t uSizeInBytes = sizeof(UncompressedBlock) + (m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); + return uSizeInBytes; + } +} diff --git a/library/PolyVoxCore/source/MinizCompressor.cpp b/library/PolyVoxCore/source/MinizCompressor.cpp index a341ff81..aa35c644 100644 --- a/library/PolyVoxCore/source/MinizCompressor.cpp +++ b/library/PolyVoxCore/source/MinizCompressor.cpp @@ -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(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 diff --git a/library/bindings/Block.i b/library/bindings/Block.i new file mode 100644 index 00000000..d5aa8da7 --- /dev/null +++ b/library/bindings/Block.i @@ -0,0 +1,9 @@ +%module Block +%{ +#include "Block.h" +%} + +%include "Block.h" + +VOLUMETYPES(Block) + \ No newline at end of file diff --git a/library/bindings/BlockCompressor.i b/library/bindings/BlockCompressor.i new file mode 100644 index 00000000..ddb6eb41 --- /dev/null +++ b/library/bindings/BlockCompressor.i @@ -0,0 +1,8 @@ +%module BlockCompressor +%{ +#include "BlockCompressor.h" +%} + +%include "BlockCompressor.h" + +VOLUMETYPES(BlockCompressor) \ No newline at end of file diff --git a/library/bindings/CompressedBlock.i b/library/bindings/CompressedBlock.i new file mode 100644 index 00000000..c27ef617 --- /dev/null +++ b/library/bindings/CompressedBlock.i @@ -0,0 +1,8 @@ +%module CompressedBlock +%{ +#include "CompressedBlock.h" +%} + +%include "CompressedBlock.h" + +VOLUMETYPES(CompressedBlock) diff --git a/library/bindings/MinizBlockCompressor.i b/library/bindings/MinizBlockCompressor.i new file mode 100644 index 00000000..7f2f0c9a --- /dev/null +++ b/library/bindings/MinizBlockCompressor.i @@ -0,0 +1,6 @@ +%module MinizBlockCompressor +%{ +#include "MinizBlockCompressor.h" +%} + +%include "MinizBlockCompressor.h" diff --git a/library/bindings/MinizCompressor.i b/library/bindings/MinizCompressor.i deleted file mode 100644 index f846265f..00000000 --- a/library/bindings/MinizCompressor.i +++ /dev/null @@ -1,6 +0,0 @@ -%module MinizCompressor -%{ -#include "MinizCompressor.h" -%} - -%include "MinizCompressor.h" diff --git a/library/bindings/PolyVoxCore.i b/library/bindings/PolyVoxCore.i index 0a814a59..92a83ead 100644 --- a/library/bindings/PolyVoxCore.i +++ b/library/bindings/PolyVoxCore.i @@ -76,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" diff --git a/library/bindings/RLEBlockCompressor.i b/library/bindings/RLEBlockCompressor.i new file mode 100644 index 00000000..b1ea1810 --- /dev/null +++ b/library/bindings/RLEBlockCompressor.i @@ -0,0 +1,6 @@ +%module RLEBlockCompressor +%{ +#include "RLEBlockCompressor.h" +%} + +%include "RLEBlockCompressor.h" diff --git a/library/bindings/RLECompressor.i b/library/bindings/RLECompressor.i deleted file mode 100644 index 01023c27..00000000 --- a/library/bindings/RLECompressor.i +++ /dev/null @@ -1,6 +0,0 @@ -%module RLECompressor -%{ -#include "RLECompressor.h" -%} - -%include "RLECompressor.h" diff --git a/library/bindings/UncompressedBlock.i b/library/bindings/UncompressedBlock.i new file mode 100644 index 00000000..26598f31 --- /dev/null +++ b/library/bindings/UncompressedBlock.i @@ -0,0 +1,8 @@ +%module UncompressedBlock +%{ +#include "UncompressedBlock.h" +%} + +%include "UncompressedBlock.h" + +VOLUMETYPES(UncompressedBlock) diff --git a/tests/testvolume.cpp b/tests/testvolume.cpp index 2063e8e3..f879f1bf 100644 --- a/tests/testvolume.cpp +++ b/tests/testvolume.cpp @@ -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 @@ -273,17 +272,16 @@ TestVolume::TestVolume() Region region(-57, -31, 12, 64, 96, 131); // Deliberatly awkward size //m_pCompressor = new RLECompressor; - m_pCompressor = new MinizCompressor; + m_pBlockCompressor = new MinizBlockCompressor; m_pFilePager = new FilePager("./"); //Create the volumes m_pRawVolume = new RawVolume(region); m_pSimpleVolume = new SimpleVolume(region); - m_pLargeVolume = new LargeVolume(region, m_pCompressor, m_pFilePager, 32); + m_pLargeVolume = new LargeVolume(region, m_pBlockCompressor, m_pFilePager, 32); - //m_pLargeVolume->setMaxNumberOfBlocksInMemory(32); - //m_pLargeVolume->setMaxNumberOfUncompressedBlocks(16); - m_pLargeVolume->setTargetMemoryLimitInBytes(4 * 1024 * 1024); + m_pLargeVolume->setMaxNumberOfBlocksInMemory(32); + m_pLargeVolume->setMaxNumberOfUncompressedBlocks(16); //Fill the volume with some data for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++) @@ -308,7 +306,7 @@ TestVolume::~TestVolume() delete m_pLargeVolume; delete m_pFilePager; - delete m_pCompressor; + delete m_pBlockCompressor; } /* diff --git a/tests/testvolume.h b/tests/testvolume.h index 8a3e46d7..9db5f7a0 100644 --- a/tests/testvolume.h +++ b/tests/testvolume.h @@ -65,7 +65,7 @@ private slots: void testLargeVolumeSamplersWithExternalBackwards(); private: - PolyVox::Compressor* m_pCompressor; + PolyVox::BlockCompressor* m_pBlockCompressor; PolyVox::FilePager* m_pFilePager; PolyVox::RawVolume* m_pRawVolume;