Merge branch 'develop' into feature/cubiquity-version
This commit is contained in:
		| @@ -31,7 +31,6 @@ endif() | |||||||
| SET(CORE_SRC_FILES | SET(CORE_SRC_FILES | ||||||
| 	source/ArraySizes.cpp | 	source/ArraySizes.cpp | ||||||
| 	source/AStarPathfinder.cpp | 	source/AStarPathfinder.cpp | ||||||
| 	source/MinizCompressor.cpp |  | ||||||
| 	source/Region.cpp | 	source/Region.cpp | ||||||
| 	source/VertexTypes.cpp | 	source/VertexTypes.cpp | ||||||
| ) | ) | ||||||
| @@ -52,7 +51,6 @@ SET(CORE_INC_FILES | |||||||
| 	include/PolyVoxCore/BlockCompressor.h | 	include/PolyVoxCore/BlockCompressor.h | ||||||
| 	include/PolyVoxCore/CompressedBlock.h | 	include/PolyVoxCore/CompressedBlock.h | ||||||
| 	include/PolyVoxCore/CompressedBlock.inl | 	include/PolyVoxCore/CompressedBlock.inl | ||||||
| 	include/PolyVoxCore/Compressor.h |  | ||||||
| 	include/PolyVoxCore/CubicSurfaceExtractor.h | 	include/PolyVoxCore/CubicSurfaceExtractor.h | ||||||
| 	include/PolyVoxCore/CubicSurfaceExtractor.inl | 	include/PolyVoxCore/CubicSurfaceExtractor.inl | ||||||
| 	include/PolyVoxCore/CubicSurfaceExtractorWithNormals.h | 	include/PolyVoxCore/CubicSurfaceExtractorWithNormals.h | ||||||
| @@ -77,7 +75,6 @@ SET(CORE_INC_FILES | |||||||
| 	include/PolyVoxCore/MaterialDensityPair.h | 	include/PolyVoxCore/MaterialDensityPair.h | ||||||
| 	include/PolyVoxCore/MinizBlockCompressor.h | 	include/PolyVoxCore/MinizBlockCompressor.h | ||||||
| 	include/PolyVoxCore/MinizBlockCompressor.inl | 	include/PolyVoxCore/MinizBlockCompressor.inl | ||||||
| 	include/PolyVoxCore/MinizCompressor.h |  | ||||||
| 	include/PolyVoxCore/Pager.h | 	include/PolyVoxCore/Pager.h | ||||||
| 	include/PolyVoxCore/PolyVoxForwardDeclarations.h | 	include/PolyVoxCore/PolyVoxForwardDeclarations.h | ||||||
| 	include/PolyVoxCore/Picking.h | 	include/PolyVoxCore/Picking.h | ||||||
| @@ -110,6 +107,7 @@ SET(CORE_INC_FILES | |||||||
| SET(IMPL_SRC_FILES | SET(IMPL_SRC_FILES | ||||||
| 	source/Impl/ErrorHandling.cpp | 	source/Impl/ErrorHandling.cpp | ||||||
| 	source/Impl/MarchingCubesTables.cpp | 	source/Impl/MarchingCubesTables.cpp | ||||||
|  | 	source/Impl/MinizWrapper.cpp | ||||||
| 	source/Impl/RandomUnitVectors.cpp | 	source/Impl/RandomUnitVectors.cpp | ||||||
| 	source/Impl/RandomVectors.cpp | 	source/Impl/RandomVectors.cpp | ||||||
| 	source/Impl/Timer.cpp | 	source/Impl/Timer.cpp | ||||||
| @@ -124,6 +122,7 @@ SET(IMPL_INC_FILES | |||||||
|     include/PolyVoxCore/Impl/Config.h |     include/PolyVoxCore/Impl/Config.h | ||||||
| 	include/PolyVoxCore/Impl/ErrorHandling.h | 	include/PolyVoxCore/Impl/ErrorHandling.h | ||||||
| 	include/PolyVoxCore/Impl/MarchingCubesTables.h | 	include/PolyVoxCore/Impl/MarchingCubesTables.h | ||||||
|  | 	include/PolyVoxCore/Impl/MinizWrapper.h | ||||||
| 	include/PolyVoxCore/Impl/RandomUnitVectors.h | 	include/PolyVoxCore/Impl/RandomUnitVectors.h | ||||||
| 	include/PolyVoxCore/Impl/RandomVectors.h | 	include/PolyVoxCore/Impl/RandomVectors.h | ||||||
| 	include/PolyVoxCore/Impl/SubArray.h | 	include/PolyVoxCore/Impl/SubArray.h | ||||||
|   | |||||||
| @@ -1,100 +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. 	 |  | ||||||
| *******************************************************************************/ |  | ||||||
|  |  | ||||||
| #ifndef __PolyVox_Compressor_H__ |  | ||||||
| #define __PolyVox_Compressor_H__ |  | ||||||
|  |  | ||||||
| #include "PolyVoxCore/Impl/TypeDef.h" |  | ||||||
|  |  | ||||||
| namespace PolyVox |  | ||||||
| { |  | ||||||
| 	/** |  | ||||||
| 	 * Provides an interface for performing compression of data. |  | ||||||
| 	 * |  | ||||||
| 	 * This class provides an interface which can be implemented by derived classes which perform data compression. |  | ||||||
| 	 * The main purpose of this is to allow the user to change the compression algorithm which is used by a LargeVolume, |  | ||||||
| 	 * based on the kind of voxel data it is storing. Users may also wish to use Compressor subclasses in more general |  | ||||||
| 	 * compression-related scenarios but this is not well tested. |  | ||||||
| 	 * |  | ||||||
| 	 * If you wish to implement your own compression algorithms for use in PolyVox then you should begin by subclassing this class. |  | ||||||
| 	 * |  | ||||||
| 	 * \sa MinizCompressor, RLECompressor |  | ||||||
| 	 */ |  | ||||||
| 	class Compressor |  | ||||||
| 	{ |  | ||||||
| 	public: |  | ||||||
| 		/// Constructor |  | ||||||
| 		Compressor() {}; |  | ||||||
| 		/// Destructor |  | ||||||
| 		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. It is not guarenteed that compression actually shrinks the data, so the  |  | ||||||
| 		 * worst-case value returned by this function may be bigger than the input size. |  | ||||||
| 		 * |  | ||||||
| 		 * \param uUncompressedInputSize The size of the uncompressed input data |  | ||||||
| 		 * \return The largest possible size of the compressed output data. |  | ||||||
| 		 */ |  | ||||||
| 		virtual uint32_t getMaxCompressedSize(uint32_t uUncompressedInputSize) = 0; |  | ||||||
|  |  | ||||||
| 		/** |  | ||||||
| 		 * Compresses the data. |  | ||||||
| 		 *  |  | ||||||
| 		 * Performs compression of the data pointed to by pSrcData and stores the result in pDstData. |  | ||||||
| 		 * The user is responsible for allocating both buffers and for making sure that the destination |  | ||||||
| 		 * buffer is large enough to hold the result. If you don't know how big the compressed data |  | ||||||
| 		 * will be (and you probably won't know this) then you can call getMaxCompressedSize() to get |  | ||||||
| 		 * an upper bound. The *actual* compressed size is then returned by this function and you can |  | ||||||
| 		 * use this to copy your compressed data to a more suitably size buffer. |  | ||||||
| 		 * |  | ||||||
| 		 * \param pSrcData A pointer to the data to be compressed. |  | ||||||
| 		 * \param uSrcLength The length of the data to be compressed. |  | ||||||
| 		 * \param pDstData A pointer to the memory where the result should be stored. |  | ||||||
| 		 * \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(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0; |  | ||||||
|  |  | ||||||
| 		/** |  | ||||||
| 		 * Decompresses the data. |  | ||||||
| 		 *   |  | ||||||
| 		 * Performs decompression of the data pointed to by pSrcData and stores the result in pDstData. |  | ||||||
| 		 * The user is responsible for allocating both buffers and for making sure that the destination |  | ||||||
| 		 * buffer is large enough to hold the result. This means you need to know how large the resulting |  | ||||||
| 		 * data might be, so before you compress the data it may be worth storing this information somewhere. |  | ||||||
| 		 * The *actual* decompressed size is then returned by this function |  | ||||||
| 		 *  |  | ||||||
| 		 * \param pSrcData A pointer to the data to be decompressed. |  | ||||||
| 		 * \param uSrcLength The length of the data to be decompressed. |  | ||||||
| 		 * \param pDstData A pointer to the memory where the result should be stored. |  | ||||||
| 		 * \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(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0; |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif //__PolyVox_Compressor_H__ |  | ||||||
							
								
								
									
										49
									
								
								library/PolyVoxCore/include/PolyVoxCore/Impl/MinizWrapper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								library/PolyVoxCore/include/PolyVoxCore/Impl/MinizWrapper.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  | Copyright (c) 2005-2013 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. 	 | ||||||
|  | *******************************************************************************/ | ||||||
|  |  | ||||||
|  | #ifndef __PolyVox_MinizWrapper_H__ | ||||||
|  | #define __PolyVox_MinizWrapper_H__ | ||||||
|  |  | ||||||
|  | // The miniz library is suplied as a single '.c' file, but this is messy for a project like PolyVox | ||||||
|  | // because it consists mostly of headers. Many of our headers may want to make use of Miniz code which | ||||||
|  | // means we need to be careful about #including 'miniz.c' multiple times and getting linker errors. | ||||||
|  | // We simplify this situation with this 'MinizWrapper.h' and 'MinizWrapper.c' which include 'miniz.c' | ||||||
|  | // with only declarations and definitions respectively. 'MinizWrapper.cpp' only gets compiled once, | ||||||
|  | // and all other parts of PolyVox can simply include 'MinizWrapper.h' to get the declarations. | ||||||
|  |  | ||||||
|  | // Diable things we don't need, and in particular the zlib compatible names which | ||||||
|  | // would cause conflicts if a user application is using both PolyVox and zlib. | ||||||
|  | #define MINIZ_NO_STDIO | ||||||
|  | #define MINIZ_NO_ARCHIVE_APIS | ||||||
|  | #define MINIZ_NO_TIME | ||||||
|  | #define MINIZ_NO_ZLIB_APIS | ||||||
|  | #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES | ||||||
|  | #define MINIZ_NO_MALLOC | ||||||
|  |  | ||||||
|  | // Include only the declarations of the functions in miniz.c. Don't include | ||||||
|  | // the actual definitions, as this 'MinizWrapper.h' may be included from multiple | ||||||
|  | // locations and we want to avoid linker errors regarding multiple definitions. | ||||||
|  | #define MINIZ_HEADER_FILE_ONLY | ||||||
|  | #include "PolyVoxCore/Impl/miniz.c" | ||||||
|  |  | ||||||
|  | #endif //__PolyVox_MinizWrapper_H__ | ||||||
| @@ -28,11 +28,12 @@ freely, subject to the following restrictions: | |||||||
|  |  | ||||||
| #ifdef _MSC_VER // Don't worry about the exact version, as long as this is defied. | #ifdef _MSC_VER // Don't worry about the exact version, as long as this is defied. | ||||||
| #include <Windows.h> | #include <Windows.h> | ||||||
|  | #else | ||||||
|  | #include <chrono> | ||||||
| #endif //_MSC_VER | #endif //_MSC_VER | ||||||
|  |  | ||||||
| namespace PolyVox | namespace PolyVox | ||||||
| { | { | ||||||
| #if defined(_MSC_VER) |  | ||||||
| 	class Timer | 	class Timer | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| @@ -44,21 +45,14 @@ namespace PolyVox | |||||||
| 		uint32_t elapsedTimeInMilliSeconds(void); | 		uint32_t elapsedTimeInMilliSeconds(void); | ||||||
| 		 | 		 | ||||||
| 	private: | 	private: | ||||||
|  | #if defined(_MSC_VER) | ||||||
| 		double m_fPCFreq; | 		double m_fPCFreq; | ||||||
| 		__int64 m_iStartTime; | 		__int64 m_iStartTime; | ||||||
| 	}; |  | ||||||
| #else //_MSC_VER | #else //_MSC_VER | ||||||
| 	class Timer | 		typedef std::chrono::system_clock clock; | ||||||
| 	{ | 		std::chrono::time_point<clock> m_start; | ||||||
| 	public: |  | ||||||
| 		Timer(bool bAutoStart = true); |  | ||||||
|  |  | ||||||
| 		void start(void); |  | ||||||
|  |  | ||||||
| 		float elapsedTimeInSeconds(void); |  | ||||||
| 		uint32_t elapsedTimeInMilliSeconds(void); |  | ||||||
| 	}; |  | ||||||
| #endif //_MSC_VER | #endif //_MSC_VER | ||||||
|  | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //__PolyVox_Timer_H__ | #endif //__PolyVox_Timer_H__ | ||||||
| @@ -31,9 +31,6 @@ namespace PolyVox | |||||||
|         const Type& v0,const Type& v1, |         const Type& v0,const Type& v1, | ||||||
|         const float x) |         const float x) | ||||||
|     { |     { | ||||||
| 		//This function is called frequently and is very short, so assert rather than exceptions. |  | ||||||
|         POLYVOX_ASSERT((x >= 0.0f) && (x <= 1.0f), "Interpolation input out of 0.0 to 1.0 range."); |  | ||||||
|  |  | ||||||
| 		//Interpolate along X | 		//Interpolate along X | ||||||
| 		Type v0_1 = (v1 - v0) * x + v0; | 		Type v0_1 = (v1 - v0) * x + v0; | ||||||
|  |  | ||||||
| @@ -45,10 +42,6 @@ namespace PolyVox | |||||||
|         const Type& v00,const Type& v10,const Type& v01,const Type& v11, |         const Type& v00,const Type& v10,const Type& v01,const Type& v11, | ||||||
|         const float x, const float y) |         const float x, const float y) | ||||||
|     { |     { | ||||||
| 		//This function is called frequently and is very short, so assert rather than exceptions. |  | ||||||
|         POLYVOX_ASSERT((x >= 0.0f) && (y >= 0.0f) &&  |  | ||||||
|             (x <= 1.0f) && (y <= 1.0f), "Interpolation input out of 0.0 to 1.0 range."); |  | ||||||
|  |  | ||||||
| 		// Linearly interpolate along x | 		// Linearly interpolate along x | ||||||
| 		Type v00_10 = lerp(v00, v10, x); | 		Type v00_10 = lerp(v00, v10, x); | ||||||
| 		Type v01_11 = lerp(v01, v11, x); | 		Type v01_11 = lerp(v01, v11, x); | ||||||
| @@ -65,10 +58,6 @@ namespace PolyVox | |||||||
|         const Type& v001,const Type& v101,const Type& v011,const Type& v111, |         const Type& v001,const Type& v101,const Type& v011,const Type& v111, | ||||||
|         const float x, const float y, const float z) |         const float x, const float y, const float z) | ||||||
|     { |     { | ||||||
| 		//This function is called frequently and is very short, so assert rather than exceptions. |  | ||||||
|         POLYVOX_ASSERT((x >= 0.0f) && (y >= 0.0f) && (z >= 0.0f) &&  |  | ||||||
|             (x <= 1.0f) && (y <= 1.0f) && (z <= 1.0f), "Interpolation input out of 0.0 to 1.0 range."); |  | ||||||
|  |  | ||||||
| 		// Bilinearly interpolate along Y | 		// Bilinearly interpolate along Y | ||||||
| 		Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y); | 		Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y); | ||||||
| 		Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y); | 		Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y); | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ freely, subject to the following restrictions: | |||||||
|  |  | ||||||
| #include "PolyVoxCore/BlockCompressor.h" | #include "PolyVoxCore/BlockCompressor.h" | ||||||
|  |  | ||||||
| #include "PolyVoxCore/MinizCompressor.h" | #include "PolyVoxCore/Impl/MinizWrapper.h" | ||||||
|  |  | ||||||
| namespace PolyVox | namespace PolyVox | ||||||
| { | { | ||||||
| @@ -37,13 +37,26 @@ namespace PolyVox | |||||||
| 	class MinizBlockCompressor : public BlockCompressor<VoxelType> | 	class MinizBlockCompressor : public BlockCompressor<VoxelType> | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| 		MinizBlockCompressor(); | 		MinizBlockCompressor(int iCompressionLevel = 6); // Miniz defines MZ_DEFAULT_LEVEL = 6 so we use the same here | ||||||
| 		~MinizBlockCompressor(); | 		~MinizBlockCompressor(); | ||||||
|  |  | ||||||
| 		void compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock); | 		void compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock); | ||||||
| 		void decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock); | 		void decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock); | ||||||
|  |  | ||||||
| 		MinizCompressor* m_pCompressor; | 	private: | ||||||
|  | 		uint32_t getExpectedCompressedSize(uint32_t uUncompressedInputSize); | ||||||
|  | 		uint32_t getMaxCompressedSize(uint32_t uUncompressedInputSize); | ||||||
|  | 		uint32_t compressWithMiniz(const void* pSrcData, size_t uSrcLength, void* pDstData, size_t uDstLength); | ||||||
|  | 		uint32_t decompressWithMiniz(const void* pSrcData, size_t uSrcLength, void* pDstData, size_t uDstLength); | ||||||
|  |  | ||||||
|  | 		unsigned int m_uCompressionFlags; | ||||||
|  |  | ||||||
|  | 		// Data gets compressed into this, then we check how big the result | ||||||
|  | 		// is and copy the required number of bytes to the destination block. | ||||||
|  | 		std::vector<uint8_t> m_vecTempBuffer; | ||||||
|  |  | ||||||
|  | 		// tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). | ||||||
|  | 		tdefl_compressor* m_pDeflator; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,36 +21,66 @@ freely, subject to the following restrictions: | |||||||
|     distribution. 	 |     distribution. 	 | ||||||
| *******************************************************************************/ | *******************************************************************************/ | ||||||
|  |  | ||||||
|  | #include <sstream> | ||||||
|  |  | ||||||
| namespace PolyVox | namespace PolyVox | ||||||
| { | { | ||||||
|  | 	/** | ||||||
|  | 	 * You can specify a compression level when constructing this compressor. This controls the tradeoff between speed and compression | ||||||
|  | 	 * rate. Levels 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow). | ||||||
|  | 	 * \param iCompressionLevel The desired compression level. | ||||||
|  | 	 */ | ||||||
| 	template <typename VoxelType> | 	template <typename VoxelType> | ||||||
| 	MinizBlockCompressor<VoxelType>::MinizBlockCompressor() | 	MinizBlockCompressor<VoxelType>::MinizBlockCompressor(int iCompressionLevel) | ||||||
|  | 		:m_pDeflator(0) | ||||||
| 	{ | 	{ | ||||||
| 		m_pCompressor = new MinizCompressor; | 		// Create and store the deflator. | ||||||
|  | 		m_pDeflator = new tdefl_compressor; | ||||||
|  |  | ||||||
|  | 		// The number of dictionary probes to use at each compression level (0-10). 0=implies fastest/minimal possible probing. | ||||||
|  | 		// The discontinuity is unsettling but may be explained by the 'iCompressionLevel <= 3' check later? | ||||||
|  | 		static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32,  16, 32, 128, 256,  512, 768, 1500 }; | ||||||
|  |  | ||||||
|  | 		// Create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). | ||||||
|  | 		m_uCompressionFlags = TDEFL_WRITE_ZLIB_HEADER | s_tdefl_num_probes[(std::min)(10, iCompressionLevel)] | ((iCompressionLevel <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); | ||||||
|  | 		if (!iCompressionLevel) | ||||||
|  | 		{ | ||||||
|  | 			m_uCompressionFlags |= TDEFL_FORCE_ALL_RAW_BLOCKS; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename VoxelType> | 	template <typename VoxelType> | ||||||
| 	MinizBlockCompressor<VoxelType>::~MinizBlockCompressor() | 	MinizBlockCompressor<VoxelType>::~MinizBlockCompressor() | ||||||
| 	{ | 	{ | ||||||
| 		delete m_pCompressor; | 		// Delete the deflator | ||||||
|  | 		delete m_pDeflator; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename VoxelType> | 	template <typename VoxelType> | ||||||
| 	void MinizBlockCompressor<VoxelType>::compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock) | 	void MinizBlockCompressor<VoxelType>::compress(UncompressedBlock<VoxelType>* pSrcBlock, CompressedBlock<VoxelType>* pDstBlock) | ||||||
| 	{ | 	{ | ||||||
|  | 		// The uncompressed data will be read straight out of the block | ||||||
| 		void* pSrcData = reinterpret_cast<void*>(pSrcBlock->getData()); | 		void* pSrcData = reinterpret_cast<void*>(pSrcBlock->getData()); | ||||||
| 		uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes(); | 		size_t uSrcLength = pSrcBlock->getDataSizeInBytes(); | ||||||
|  |  | ||||||
| 		uint8_t tempBuffer[10000]; | 		// This compressor is expected to be used many times to compress a large number of blocks, but they are all | ||||||
| 		uint8_t* pDstData = reinterpret_cast<uint8_t*>( tempBuffer );				 | 		// expected to have the same size. Therefore the resize() function below should only perform allocation once. | ||||||
| 		uint32_t uDstLength = 10000; | 		uint32_t expectedCompressedSize = getExpectedCompressedSize(uSrcLength); | ||||||
|  | 		if(m_vecTempBuffer.size() != expectedCompressedSize) | ||||||
|  | 		{ | ||||||
|  | 			logInfo() << "Resizing temp buffer to " << expectedCompressedSize << "bytes. " | ||||||
|  | 				<< "This should only happen the first time the MinizBlockCompressor is used"; | ||||||
|  | 			m_vecTempBuffer.resize(expectedCompressedSize); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		uint32_t uCompressedLength = 0; | 		// The compressed data will be written into this temporary buffer. | ||||||
|  | 		uint8_t* pDstData = &(m_vecTempBuffer[0]); | ||||||
|  | 		size_t uDstLength = m_vecTempBuffer.size(); | ||||||
|  |  | ||||||
| 		try | 		try | ||||||
| 		{ | 		{ | ||||||
| 			// Perform the compression | 			// Perform the compression | ||||||
| 			uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); | 			uint32_t uCompressedLength = compressWithMiniz(pSrcData, uSrcLength, pDstData, uDstLength); | ||||||
|  |  | ||||||
| 			// Copy the resulting compressed data into the compressed block | 			// Copy the resulting compressed data into the compressed block | ||||||
| 			pDstBlock->setData(pDstData, uCompressedLength);			 | 			pDstBlock->setData(pDstData, uCompressedLength);			 | ||||||
| @@ -61,17 +91,18 @@ namespace PolyVox | |||||||
| 			// buffer is not big enough. So now we try again using a buffer that is definitely big enough. | 			// 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. | 			// 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 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"; | 			logWarning() << "The compression will be tried again with a larger buffer."; | ||||||
| 			uint32_t uMaxCompressedSize = m_pCompressor->getMaxCompressedSize(uSrcLength); |  | ||||||
| 			uint8_t* buffer = new uint8_t[ uMaxCompressedSize ]; |  | ||||||
|  |  | ||||||
| 			pDstData = reinterpret_cast<uint8_t*>( buffer );				 | 			std::vector<uint8_t> vecExtraBigBuffer; | ||||||
| 			uDstLength = uMaxCompressedSize; | 			vecExtraBigBuffer.resize(getMaxCompressedSize(uSrcLength)); | ||||||
|  |  | ||||||
|  | 			uint8_t* pDstData = &(vecExtraBigBuffer[0]); | ||||||
|  | 			size_t uDstLength = vecExtraBigBuffer.size(); | ||||||
|  |  | ||||||
| 			try | 			try | ||||||
| 			{		 | 			{		 | ||||||
| 				// Perform the compression | 				// Perform the compression | ||||||
| 				uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); | 				uint32_t uCompressedLength = compressWithMiniz(pSrcData, uSrcLength, pDstData, uDstLength); | ||||||
|  |  | ||||||
| 				// Copy the resulting compressed data into the compressed block | 				// Copy the resulting compressed data into the compressed block | ||||||
| 				pDstBlock->setData(pDstData, uCompressedLength); | 				pDstBlock->setData(pDstData, uCompressedLength); | ||||||
| @@ -80,26 +111,100 @@ namespace PolyVox | |||||||
| 			{ | 			{ | ||||||
| 				// At this point it didn't work even with a bigger buffer. | 				// At this point it didn't work even with a bigger buffer. | ||||||
| 				// Not much more we can do so just rethrow the exception. | 				// Not much more we can do so just rethrow the exception. | ||||||
| 				delete[] buffer; |  | ||||||
| 				POLYVOX_THROW(std::runtime_error, "Failed to compress block data"); | 				POLYVOX_THROW(std::runtime_error, "Failed to compress block data"); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			delete[] buffer; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename VoxelType> | 	template <typename VoxelType> | ||||||
| 	void MinizBlockCompressor<VoxelType>::decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock) | 	void MinizBlockCompressor<VoxelType>::decompress(CompressedBlock<VoxelType>* pSrcBlock, UncompressedBlock<VoxelType>* pDstBlock) | ||||||
| 	{ | 	{ | ||||||
|  | 		// Get raw pointers so that the data can be decompressed directly into the destination block. | ||||||
| 		const void* pSrcData = reinterpret_cast<const void*>(pSrcBlock->getData()); | 		const void* pSrcData = reinterpret_cast<const void*>(pSrcBlock->getData()); | ||||||
| 		void* pDstData = reinterpret_cast<void*>(pDstBlock->getData()); | 		void* pDstData = reinterpret_cast<void*>(pDstBlock->getData()); | ||||||
| 		uint32_t uSrcLength = pSrcBlock->getDataSizeInBytes(); | 		size_t uSrcLength = pSrcBlock->getDataSizeInBytes(); | ||||||
| 		uint32_t uDstLength = pDstBlock->getDataSizeInBytes(); | 		size_t uDstLength = pDstBlock->getDataSizeInBytes(); | ||||||
|  |  | ||||||
|  | 		// Perform the decompression | ||||||
|  | 		uint32_t uUncompressedLength = decompressWithMiniz(pSrcData, uSrcLength, pDstData, uDstLength); | ||||||
|  |  | ||||||
| 		//RLECompressor<VoxelType, uint16_t> compressor; | 		// We know we should have received exactly one block's worth of data. If not then something went wrong. | ||||||
| 		uint32_t uUncompressedLength = m_pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength); | 		POLYVOX_THROW_IF(uUncompressedLength != pDstBlock->getDataSizeInBytes(), std::runtime_error, "Decompressed data does not have the expected length"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 		POLYVOX_ASSERT(uUncompressedLength == pDstBlock->getDataSizeInBytes(), "Destination length has changed."); | 	template <typename VoxelType> | ||||||
|  | 	uint32_t MinizBlockCompressor<VoxelType>::getExpectedCompressedSize(uint32_t uUncompressedInputSize) | ||||||
|  | 	{ | ||||||
|  | 		// We expect this block compressor will be used for smoothly changing volume data such as density fields and so | ||||||
|  | 		// the compression rate might not be great. The value beloew is basically a guess based on previous experience. | ||||||
|  | 		uint32_t uExpectedCompressionRate = 4; | ||||||
|  | 		return uUncompressedInputSize / uExpectedCompressionRate; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	template <typename VoxelType> | ||||||
|  | 	uint32_t MinizBlockCompressor<VoxelType>::getMaxCompressedSize(uint32_t uUncompressedInputSize) | ||||||
|  | 	{ | ||||||
|  | 		// The contents of this function are copied from miniz's 'mz_deflateBound()' | ||||||
|  | 		// (which we can't use because it is part of the zlib-style higher level API). | ||||||
|  | 		unsigned long source_len = uUncompressedInputSize; | ||||||
|  |  | ||||||
|  | 		// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) | ||||||
|  | 		return (std::max)(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	template <typename VoxelType> | ||||||
|  | 	uint32_t MinizBlockCompressor<VoxelType>::compressWithMiniz(const void* pSrcData, size_t uSrcLength, void* pDstData, size_t uDstLength) | ||||||
|  | 	{ | ||||||
|  | 		// It seems we have to reinitialise the deflator for each fresh dataset (it's probably intended for streaming, which we're not doing here) | ||||||
|  | 		tdefl_status status = tdefl_init(m_pDeflator, NULL, NULL, m_uCompressionFlags); | ||||||
|  | 		if (status != TDEFL_STATUS_OKAY) | ||||||
|  | 		{ | ||||||
|  | 			std::stringstream ss; | ||||||
|  | 			ss << "tdefl_init() failed with return code '" << status << "'"; | ||||||
|  | 			POLYVOX_THROW(std::runtime_error, ss.str()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Compress as much of the input as possible (or all of it) to the output buffer. | ||||||
|  | 		status = tdefl_compress(m_pDeflator, pSrcData, &uSrcLength, pDstData, &uDstLength, TDEFL_FINISH); | ||||||
|  |  | ||||||
|  | 		//Check whether the compression was successful. | ||||||
|  | 		if (status != TDEFL_STATUS_DONE) | ||||||
|  | 		{ | ||||||
|  | 			std::stringstream ss; | ||||||
|  | 			ss << "tdefl_compress() failed with return code '" << status << "'"; | ||||||
|  | 			POLYVOX_THROW(std::runtime_error, ss.str()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// The compression modifies 'ulDstLength' to hold the new length. | ||||||
|  | 		return uDstLength; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	template <typename VoxelType> | ||||||
|  | 	uint32_t MinizBlockCompressor<VoxelType>::decompressWithMiniz(const void* pSrcData, size_t uSrcLength, void* pDstData, size_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 destination is a Block and those are always a power of two. If you need to use this code for other purposes then you'll | ||||||
|  | 		// probably have to scale up your dst buffer to the nearest appropriate size. Alternatively you can use the mz_uncompress function, | ||||||
|  | 		// but that means enabling parts of the miniz API which are #defined out at the top of this file. | ||||||
|  | 		POLYVOX_THROW_IF(isPowerOf2(uDstLength) == false, std::invalid_argument, "Miniz decompressor requires the destination buffer to have a size which is a power of two."); | ||||||
|  |  | ||||||
|  | 		// Create and initialise the decompressor (I believe this is much small than the compressor). | ||||||
|  | 		tinfl_decompressor inflator; | ||||||
|  | 		tinfl_init(&inflator); | ||||||
|  |  | ||||||
|  | 		// Do the decompression. In some scenarios 'tinfl_decompress' would be called multiple times with the same dest buffer but | ||||||
|  | 		// different locations within it. In our scenario it's only called once so the start and the location are the same (both pDstData). | ||||||
|  | 		tinfl_status status = tinfl_decompress(&inflator, (const mz_uint8 *)pSrcData, &uSrcLength, (mz_uint8 *)pDstData, (mz_uint8 *)pDstData, &uDstLength, TINFL_FLAG_PARSE_ZLIB_HEADER); | ||||||
|  |  | ||||||
|  | 		//Check whether the decompression was successful. | ||||||
|  | 		if (status != TINFL_STATUS_DONE) | ||||||
|  | 		{ | ||||||
|  | 			std::stringstream ss; | ||||||
|  | 			ss << "tinfl_decompress() failed with return code '" << status << "'"; | ||||||
|  | 			POLYVOX_THROW(std::runtime_error, ss.str()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// The decompression modifies 'ulDstLength' to hold the new length. | ||||||
|  | 		return uDstLength; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| #ifndef __PolyVox_MinizCompressor_H__ |  | ||||||
| #define __PolyVox_MinizCompressor_H__ |  | ||||||
|  |  | ||||||
| #include "PolyVoxCore/Compressor.h" |  | ||||||
|  |  | ||||||
| namespace PolyVox |  | ||||||
| { |  | ||||||
| 	/** |  | ||||||
| 	 * Performs compression of data using the miniz library. |  | ||||||
| 	 * |  | ||||||
| 	 * This compressor implements the DEFLATE (http://en.wikipedia.org/wiki/Deflate) compression algorithm via the pubic domain  |  | ||||||
| 	 * 'miniz' library (https://code.google.com/p/miniz/). This is a general purpose compression algorithm, and within PolyVox it |  | ||||||
| 	 * is intended for situations in which the alternative RLECompressor is not appropriate. It is a good default choice if you |  | ||||||
| 	 * are not sure which compressor is best for your needs. |  | ||||||
| 	 *  |  | ||||||
| 	 * \sa RLECompressor |  | ||||||
| 	 */ |  | ||||||
| 	class MinizCompressor : public Compressor |  | ||||||
| 	{ |  | ||||||
| 	public: |  | ||||||
| 		/// Constructor |  | ||||||
| 		MinizCompressor(int iCompressionLevel = 6); // Miniz defines MZ_DEFAULT_LEVEL = 6 so we use the same here |  | ||||||
| 		/// Destructor |  | ||||||
| 		~MinizCompressor(); |  | ||||||
| 		 |  | ||||||
| 		// API documentation is in base class and gets inherited by Doxygen. |  | ||||||
| 		uint32_t getMaxCompressedSize(uint32_t uUncompressedInputSize); |  | ||||||
| 		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; |  | ||||||
|  |  | ||||||
| 		// tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). |  | ||||||
| 		// We're storing it by void* because miniz does not supply a header and we don't want to include the .c file from  |  | ||||||
| 		// here as it will cause linker problems. |  | ||||||
| 		void* m_pDeflator; |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif //__PolyVox_MinizCompressor_H__ |  | ||||||
| @@ -26,8 +26,6 @@ freely, subject to the following restrictions: | |||||||
|  |  | ||||||
| #include "PolyVoxCore/BlockCompressor.h" | #include "PolyVoxCore/BlockCompressor.h" | ||||||
|  |  | ||||||
| #include "PolyVoxCore/MinizCompressor.h" |  | ||||||
|  |  | ||||||
| namespace PolyVox | namespace PolyVox | ||||||
| { | { | ||||||
| 	template <typename VoxelType> | 	template <typename VoxelType> | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								library/PolyVoxCore/source/Impl/MinizWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								library/PolyVoxCore/source/Impl/MinizWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  | Copyright (c) 2005-2013 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. 	 | ||||||
|  | *******************************************************************************/ | ||||||
|  |  | ||||||
|  | // Please see this header file for comment about the purpose of MinizWrapper.h/cpp | ||||||
|  | #include "PolyVoxCore/Impl/MinizWrapper.h" | ||||||
|  |  | ||||||
|  | // Get the full definitions, not just the declarations. | ||||||
|  | #undef MINIZ_HEADER_FILE_ONLY | ||||||
|  | #include "PolyVoxCore/Impl/miniz.c" | ||||||
| @@ -78,16 +78,19 @@ namespace PolyVox | |||||||
|  |  | ||||||
| 	void Timer::start(void) | 	void Timer::start(void) | ||||||
| 	{ | 	{ | ||||||
|  | 		m_start = clock::now(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	float Timer::elapsedTimeInSeconds(void) | 	float Timer::elapsedTimeInSeconds(void) | ||||||
| 	{ | 	{ | ||||||
| 		return 0.0f; | 		std::chrono::duration<float> elapsed_seconds = clock::now() - m_start; | ||||||
|  | 		return elapsed_seconds.count(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	uint32_t Timer::elapsedTimeInMilliSeconds(void) | 	uint32_t Timer::elapsedTimeInMilliSeconds(void) | ||||||
| 	{ | 	{ | ||||||
| 		return 0; | 		std::chrono::duration<float, std::milli> elapsed_milliseconds = clock::now() - m_start; | ||||||
|  | 		return elapsed_milliseconds.count(); | ||||||
| 	} | 	} | ||||||
| #endif //_MSC_VER | #endif //_MSC_VER | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,141 +0,0 @@ | |||||||
| #include "PolyVoxCore/MinizCompressor.h" |  | ||||||
|  |  | ||||||
| #include "PolyVoxCore/Impl/Utility.h" |  | ||||||
|  |  | ||||||
| // Diable things we don't need, and in particular the zlib compatible names which |  | ||||||
| // would cause conflicts if a user application is using both PolyVox and zlib. |  | ||||||
| #define MINIZ_NO_STDIO |  | ||||||
| #define MINIZ_NO_ARCHIVE_APIS |  | ||||||
| #define MINIZ_NO_TIME |  | ||||||
| #define MINIZ_NO_ZLIB_APIS |  | ||||||
| #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES |  | ||||||
| #define MINIZ_NO_MALLOC |  | ||||||
|  |  | ||||||
| #include "PolyVoxCore/Impl/ErrorHandling.h" |  | ||||||
|  |  | ||||||
| // The miniz library is supplied only as a single .c file without a header. The examples just include the .c file |  | ||||||
| // directly which is also what we do here. Actually is is possible to define 'MINIZ_HEADER_FILE_ONLY' to treat |  | ||||||
| // the .c file as a header, but this seems messy in terms of our project and CMake as we keep the headers and source |  | ||||||
| // files in seperate folders. We could create our own header for miniz (based on the stuff between the MINIZ_HEADER_FILE_ONLY |  | ||||||
| // directives) but the other problem is that we are using #pragma GCC system_header to supress warnings which would |  | ||||||
| // then be in the .c part of the code. If we ever update GCC on the CDash machine so that it properly supports '#pragma |  | ||||||
| // GCC diagnosic ignored' (or so that it doesn't warn in the first place) then we can reconsider spliting miniz.c in two. |  | ||||||
| #include "PolyVoxCore/Impl/miniz.c" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <sstream> |  | ||||||
|  |  | ||||||
| using namespace std; |  | ||||||
|  |  | ||||||
| namespace PolyVox |  | ||||||
| { |  | ||||||
| 	/** |  | ||||||
| 	 * You can specify a compression level when constructing this compressor. This controls the tradeoff between speed and compression |  | ||||||
| 	 * rate. Levels 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow). |  | ||||||
| 	 * \param iCompressionLevel The desired compression level. |  | ||||||
| 	 */ |  | ||||||
| 	MinizCompressor::MinizCompressor(int iCompressionLevel) |  | ||||||
| 		:m_pDeflator(0) |  | ||||||
| 	{ |  | ||||||
| 		// Create and store the deflator. |  | ||||||
| 		tdefl_compressor* pDeflator = new tdefl_compressor; |  | ||||||
| 		m_pDeflator = reinterpret_cast<void*>(pDeflator); |  | ||||||
|  |  | ||||||
| 		// The number of dictionary probes to use at each compression level (0-10). 0=implies fastest/minimal possible probing. |  | ||||||
| 		// The discontinuity is unsettling but may be explained by the 'iCompressionLevel <= 3' check later? |  | ||||||
| 		static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32,  16, 32, 128, 256,  512, 768, 1500 }; |  | ||||||
|  |  | ||||||
| 		// Create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). |  | ||||||
| 		m_uCompressionFlags = TDEFL_WRITE_ZLIB_HEADER | s_tdefl_num_probes[MZ_MIN(10, iCompressionLevel)] | ((iCompressionLevel <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); |  | ||||||
| 		if (!iCompressionLevel) |  | ||||||
| 		{ |  | ||||||
| 			m_uCompressionFlags |= TDEFL_FORCE_ALL_RAW_BLOCKS; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	MinizCompressor::~MinizCompressor() |  | ||||||
| 	{ |  | ||||||
| 		// Delete the deflator |  | ||||||
| 		tdefl_compressor* pDeflator = reinterpret_cast<tdefl_compressor*>(m_pDeflator); |  | ||||||
| 		delete pDeflator; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	uint32_t MinizCompressor::getMaxCompressedSize(uint32_t uUncompressedInputSize) |  | ||||||
| 	{ |  | ||||||
| 		// The contents of this function are copied from miniz's 'mz_deflateBound()' |  | ||||||
| 		// (which we can't use because it is part of the zlib-style higher level API). |  | ||||||
| 		unsigned long source_len = uUncompressedInputSize; |  | ||||||
|  |  | ||||||
| 		// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) |  | ||||||
| 		return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	uint32_t MinizCompressor::compress(const void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) |  | ||||||
| 	{ |  | ||||||
| 		//Get the deflator |  | ||||||
| 		tdefl_compressor* pDeflator = reinterpret_cast<tdefl_compressor*>(m_pDeflator); |  | ||||||
|  |  | ||||||
| 		// It seems we have to reinitialise the deflator for each fresh dataset (it's probably intended for streaming, which we're not doing here) |  | ||||||
| 		tdefl_status status = tdefl_init(pDeflator, NULL, NULL, m_uCompressionFlags); |  | ||||||
| 		if (status != TDEFL_STATUS_OKAY) |  | ||||||
| 		{ |  | ||||||
| 			stringstream ss; |  | ||||||
| 			ss << "tdefl_init() failed with return code '" << status << "'"; |  | ||||||
| 			POLYVOX_THROW(std::runtime_error, ss.str()); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Change the type to avoid compiler warnings |  | ||||||
| 		size_t ulSrcLength = uSrcLength; |  | ||||||
| 		size_t ulDstLength = uDstLength; |  | ||||||
|  |  | ||||||
| 		// Compress as much of the input as possible (or all of it) to the output buffer. |  | ||||||
| 		status = tdefl_compress(pDeflator, pSrcData, &ulSrcLength, pDstData, &ulDstLength, TDEFL_FINISH); |  | ||||||
|  |  | ||||||
| 		//Check whther the compression was successful. |  | ||||||
| 		if (status != TDEFL_STATUS_DONE) |  | ||||||
| 		{ |  | ||||||
| 			stringstream ss; |  | ||||||
| 			ss << "tdefl_compress() failed with return code '" << status << "'"; |  | ||||||
| 			POLYVOX_THROW(std::runtime_error, ss.str()); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// The compression modifies 'ulDstLength' to hold the new length. |  | ||||||
| 		return ulDstLength; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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 |  | ||||||
| 		// probably have to scale up your dst buffer to the nearest appropriate size. Alternatively you can use the mz_uncompress function, |  | ||||||
| 		// but that means enabling parts of the miniz API which are #defined out at the top of this file. |  | ||||||
| 		POLYVOX_ASSERT(isPowerOf2(uDstLength), "Miniz decompressor requires the destination buffer to have a size which is a power of two."); |  | ||||||
| 		if(isPowerOf2(uDstLength) == false) |  | ||||||
| 		{ |  | ||||||
| 			POLYVOX_THROW(std::invalid_argument, "Miniz decompressor requires the destination buffer to have a size which is a power of two."); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Change the type to avoid compiler warnings |  | ||||||
| 		size_t ulSrcLength = uSrcLength; |  | ||||||
| 		size_t ulDstLength = uDstLength; |  | ||||||
|  |  | ||||||
| 		// Create and initialise the decompressor (I believe this is much small than the compressor). |  | ||||||
| 		tinfl_decompressor inflator; |  | ||||||
| 		tinfl_init(&inflator); |  | ||||||
|  |  | ||||||
| 		// Do the decompression. In some scenarios 'tinfl_decompress' would be called multiple times with the same dest buffer but |  | ||||||
| 		// different locations within it. In our scenario it's only called once so the start and the location are the same (both pDstData). |  | ||||||
| 		tinfl_status status = tinfl_decompress(&inflator, (const mz_uint8 *)pSrcData, &ulSrcLength, (mz_uint8 *)pDstData, (mz_uint8 *)pDstData, &ulDstLength, TINFL_FLAG_PARSE_ZLIB_HEADER); |  | ||||||
|  |  | ||||||
| 		//Check whther the decompression was successful. |  | ||||||
| 		if (status != TINFL_STATUS_DONE) |  | ||||||
| 		{ |  | ||||||
| 			stringstream ss; |  | ||||||
| 			ss << "tinfl_decompress() failed with return code '" << status << "'"; |  | ||||||
| 			POLYVOX_THROW(std::runtime_error, ss.str()); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// The decompression modifies 'ulDstLength' to hold the new length. |  | ||||||
| 		return ulDstLength; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| %module Compressor |  | ||||||
| %{ |  | ||||||
| #include "Compressor.h" |  | ||||||
| %} |  | ||||||
|  |  | ||||||
| %include "Compressor.h" |  | ||||||
| @@ -79,7 +79,6 @@ EXTRACTOR(shortname, LargeVolume) | |||||||
| %include "Block.i" | %include "Block.i" | ||||||
| %include "CompressedBlock.i" | %include "CompressedBlock.i" | ||||||
| %include "UncompressedBlock.i" | %include "UncompressedBlock.i" | ||||||
| %include "Compressor.i" |  | ||||||
| %include "BlockCompressor.i" | %include "BlockCompressor.i" | ||||||
| %include "Pager.i" | %include "Pager.i" | ||||||
| %include "FilePager.i" | %include "FilePager.i" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user