diff --git a/library/PolyVoxCore/include/PolyVoxCore/Compressor.h b/library/PolyVoxCore/include/PolyVoxCore/Compressor.h index 2d79d99b..f731bd68 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Compressor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Compressor.h @@ -34,7 +34,14 @@ namespace PolyVox Compressor() {}; virtual ~Compressor() {}; + // Computes a worst-case scenario for how big the output can be for a given input size. If + // necessary you can use this as a destination buffer size, though it may be somewhat wasteful. + virtual uint32_t getMaxCompressedSize(uint32_t uUncompressedInputSize) = 0; + + // Compresses the data. virtual uint32_t compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0; + + // Decompresses the data. virtual uint32_t decompress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index 374ae124..ed893e47 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -150,19 +150,52 @@ namespace PolyVox if(m_bIsUncompressedDataModified) { void* pSrcData = reinterpret_cast(m_tUncompressedData); - void* pDstData = reinterpret_cast( new uint8_t[1000000] ); uint32_t uSrcLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType); - uint32_t uDstLength = 1000000; - //MinizCompressor compressor; - //RLECompressor compressor; - uint32_t uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); + void* pDstData = 0; + uint32_t uCompressedLength = 0; + try + { + uint8_t buffer[1000000]; + + pDstData = reinterpret_cast( buffer ); + uint32_t uDstLength = 1000000; + + uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); + } + catch(std::exception& e) + { + // 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. + uint32_t uMaxCompressedSize = pCompressor->getMaxCompressedSize(uSrcLength); + uint8_t* buffer = new uint8_t[ uMaxCompressedSize ]; + + pDstData = reinterpret_cast( buffer ); + uint32_t uDstLength = uMaxCompressedSize; + + try + { + uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); + } + catch(std::exception& e) + { + // 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; + } + + // Delete the old compressed data and assign a new one + delete m_pCompressedData; m_pCompressedData = reinterpret_cast( new uint8_t[uCompressedLength] ); + + //Copy the data across memcpy(m_pCompressedData, pDstData, uCompressedLength); m_uCompressedDataLength = uCompressedLength; - - delete pDstData; } //Flag the uncompressed data as no longer being used. diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index c3f53407..91efdf80 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -619,7 +619,9 @@ namespace PolyVox // create the new block LoadedBlock newBlock(m_uBlockSideLength); - //Blocks start out compressed - should we change this? + // Blocks start out compressed - should we change this? + // Or maybe we should just 'seed' them with compressed data, + // rather than creating an empty block and then compressing? newBlock.block.compress(m_pCompressor); itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; diff --git a/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h b/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h index 3c4ba64d..2770300e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/MinizCompressor.h @@ -11,6 +11,7 @@ namespace PolyVox MinizCompressor(); ~MinizCompressor(); + 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); }; diff --git a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h b/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h index f17cdf51..7e75742b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.h @@ -17,6 +17,7 @@ namespace PolyVox RLECompressor(); ~RLECompressor(); + 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); }; diff --git a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl b/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl index 6a229d9d..0b43a301 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/RLECompressor.inl @@ -14,6 +14,13 @@ namespace PolyVox { } + 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) { diff --git a/library/polyvoxcore/source/MinizCompressor.cpp b/library/polyvoxcore/source/MinizCompressor.cpp index 30b7988c..2d749a54 100644 --- a/library/polyvoxcore/source/MinizCompressor.cpp +++ b/library/polyvoxcore/source/MinizCompressor.cpp @@ -29,6 +29,11 @@ namespace PolyVox { } + uint32_t MinizCompressor::getMaxCompressedSize(uint32_t uUncompressedInputSize) + { + return static_cast(mz_compressBound(static_cast(uUncompressedInputSize))); + } + uint32_t MinizCompressor::compress(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) { mz_ulong ulDstLength = uDstLength;