Merge branch 'develop' into feature/cubiquity-version

Conflicts:
	library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h
	library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl
This commit is contained in:
David Williams
2013-03-04 21:05:51 +01:00
10 changed files with 250 additions and 58 deletions

View File

@ -153,7 +153,7 @@ SET_PROPERTY(TARGET PolyVoxCore PROPERTY FOLDER "Library")
SET_TARGET_PROPERTIES(PolyVoxCore PROPERTIES VERSION ${POLYVOX_VERSION} SOVERSION ${POLYVOX_VERSION_MAJOR})
IF(MSVC)
SET_TARGET_PROPERTIES(PolyVoxCore PROPERTIES COMPILE_FLAGS "/W4 /wd4251 /wd4127") #Disable warning on STL exports
SET_TARGET_PROPERTIES(PolyVoxCore PROPERTIES COMPILE_FLAGS "/W4 /wd4251") #Disable warning on STL exports
ENDIF(MSVC)
#Install

View File

@ -28,20 +28,71 @@ freely, subject to the following restrictions:
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.
/**
* 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.
/**
* 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(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0;
// Decompresses the data.
/**
* 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(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength) = 0;
};
}

View File

@ -121,7 +121,7 @@ namespace PolyVox
void execute();
private:
int32_t addVertex(float fX, float fY, float fZ, typename VolumeType::VoxelType uMaterial, Array<3, IndexAndMaterial>& existingVertices);
int32_t addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterial, Array<3, IndexAndMaterial>& existingVertices);
bool performQuadMerging(std::list<Quad>& quads);
bool mergeQuads(Quad& q1, Quad& q2);

View File

@ -94,20 +94,20 @@ namespace PolyVox
// X
if(m_funcIsQuadNeededCallback(currentVoxel, negXVoxel, material))
{
uint32_t v0 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v1 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v2 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v3 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
uint32_t v2 = addVertex(regX , regY + 1, regZ + 1, material, m_currentSliceVertices);
uint32_t v3 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
m_vecQuads[NegativeX][regX].push_back(Quad(v0, v1, v2, v3));
}
if(m_funcIsQuadNeededCallback(negXVoxel, currentVoxel, material))
{
uint32_t v0 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v1 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v2 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v3 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
uint32_t v2 = addVertex(regX , regY + 1, regZ + 1, material, m_currentSliceVertices);
uint32_t v3 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
m_vecQuads[PositiveX][regX].push_back(Quad(v0, v3, v2, v1));
}
@ -115,20 +115,20 @@ namespace PolyVox
// Y
if(m_funcIsQuadNeededCallback(currentVoxel, negYVoxel, material))
{
uint32_t v0 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v1 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v2 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v3 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
uint32_t v2 = addVertex(regX + 1, regY , regZ + 1, material, m_currentSliceVertices);
uint32_t v3 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
m_vecQuads[NegativeY][regY].push_back(Quad(v0, v1, v2, v3));
}
if(m_funcIsQuadNeededCallback(negYVoxel, currentVoxel, material))
{
uint32_t v0 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v1 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v2 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v3 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) + 0.5f, material, m_currentSliceVertices);
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
uint32_t v2 = addVertex(regX + 1, regY , regZ + 1, material, m_currentSliceVertices);
uint32_t v3 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
m_vecQuads[PositiveY][regY].push_back(Quad(v0, v3, v2, v1));
}
@ -136,20 +136,20 @@ namespace PolyVox
// Z
if(m_funcIsQuadNeededCallback(currentVoxel, negZVoxel, material))
{
uint32_t v0 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v1 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v2 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v3 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ , material, m_previousSliceVertices);
uint32_t v3 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
m_vecQuads[NegativeZ][regZ].push_back(Quad(v0, v1, v2, v3));
}
if(m_funcIsQuadNeededCallback(negZVoxel, currentVoxel, material))
{
uint32_t v0 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v1 = addVertex(static_cast<float>(regX) - 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v2 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) + 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v3 = addVertex(static_cast<float>(regX) + 0.5f, static_cast<float>(regY) - 0.5f, static_cast<float>(regZ) - 0.5f, material, m_previousSliceVertices);
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ , material, m_previousSliceVertices);
uint32_t v3 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
m_vecQuads[PositiveZ][regZ].push_back(Quad(v0, v3, v2, v1));
}
@ -198,19 +198,16 @@ namespace PolyVox
}
template<typename VolumeType, typename IsQuadNeeded>
int32_t CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::addVertex(float fX, float fY, float fZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices)
int32_t CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices)
{
uint32_t uX = static_cast<uint32_t>(fX + 0.75f);
uint32_t uY = static_cast<uint32_t>(fY + 0.75f);
for(uint32_t ct = 0; ct < MaxVerticesPerPosition; ct++)
{
IndexAndMaterial& rEntry = existingVertices[uX][uY][ct];
if(rEntry.iIndex == -1)
{
//No vertices matched and we've now hit an empty space. Fill it by creating a vertex.
rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial<typename VolumeType::VoxelType> (Vector3DFloat(fX, fY, fZ), uMaterialIn));
//No vertices matched and we've now hit an empty space. Fill it by creating a vertex. The 0.5f offset is because vertices set between voxels in order to build cubes around them.
rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial<typename VolumeType::VoxelType> (Vector3DFloat(static_cast<float>(uX) - 0.5f, static_cast<float>(uY) - 0.5f, static_cast<float>(uZ) - 0.5f), uMaterialIn));
rEntry.uMaterial = uMaterialIn;
return rEntry.iIndex;
@ -298,4 +295,4 @@ namespace PolyVox
//Quads cannot be merged.
return false;
}
}
}

View File

@ -36,6 +36,19 @@ freely, subject to the following restrictions:
#define POLYVOX_HALT() std::exit(EXIT_FAILURE)
#endif
// Macros cannot contain #ifdefs, but some of our macros need to disable warnings and such warning supression is
// platform specific. But macros can contain other macros, so we create macros to control the warnings and use
// those instead. This set of warning supression macros can be extended to GCC/Clang when required.
#if defined(_MSC_VER)
#define POLYVOX_MSC_WARNING_PUSH __pragma(warning(push))
#define POLYVOX_DISABLE_MSC_WARNING(x) __pragma(warning(disable:x))
#define POLYVOX_MSC_WARNING_POP __pragma(warning(pop))
#else
#define POLYVOX_MSC_WARNING_PUSH
#define POLYVOX_DISABLE_MSC_WARNING(x)
#define POLYVOX_MSC_WARNING_POP
#endif
#define POLYVOX_UNUSED(x) do { (void)sizeof(x); } while(0)
/*
@ -49,6 +62,11 @@ freely, subject to the following restrictions:
#ifdef POLYVOX_ASSERTS_ENABLED
#define POLYVOX_ASSERT(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if (!(condition)) \
@ -61,12 +79,19 @@ freely, subject to the following restrictions:
std::cerr << " Location: " << "Line " << __LINE__ << " of " << __FILE__ << std::endl << std::endl; \
POLYVOX_HALT(); \
} \
} while(0)
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
#define POLYVOX_ASSERT(condition, message) \
do { POLYVOX_UNUSED(condition); POLYVOX_UNUSED(message); } while(0)
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do { POLYVOX_UNUSED(condition); POLYVOX_UNUSED(message); } while(0) \
POLYVOX_MSC_WARNING_POP
#endif

View File

@ -1,3 +1,14 @@
/*
* CHANGES FOR POLYVOX
* -------------------
* This file gave compiler warnings on certain versions of GCC (at least version 4.3.5 used by out build machine)
* and I did not want to risk tampering with the code to fix them.Therefore the only difference between this file
* and the official 'miniz.c' is the pragma below which disables warnings for this file in GCC.
*/
#ifdef __GNUC__
#pragma GCC system_header
#endif
/* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
See "unlicense" statement at the end of this file.
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2012

View File

@ -5,15 +5,36 @@
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:
MinizCompressor();
/// 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(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength);
uint32_t decompress(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;
};
}

View File

@ -5,6 +5,15 @@
namespace PolyVox
{
/**
* Performs compression of data using Run Length Encoding (RLE).
*
* This compressor is designed for voxel data which contains long runs of the same value. Minecraft-style terrain and other
* cubic-style terrains are likely to fall under this category, whereas density fields for Marching Cubes terrain will not. Please
* see the following article if you want more details of how RLE compression works: http://en.wikipedia.org/wiki/Run-length_encoding
*
* \sa MinizCompressor
*/
template<typename ValueType, typename LengthType>
class RLECompressor : public Compressor
{
@ -14,9 +23,12 @@ namespace PolyVox
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);

View File

@ -1,68 +1,141 @@
#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_APIS
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
//#define MINIZ_NO_MALLOC
#define MINIZ_NO_MALLOC
#include "PolyVoxCore/Impl/ErrorHandling.h"
// For some unknown reason the miniz library is supplied only as a
// single .c file without a header. Apparently the only way to use
// it is then to #include it directly which is what the examples do.
// 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
{
MinizCompressor::MinizCompressor()
/**
* 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)
{
return static_cast<uint32_t>(mz_compressBound(static_cast<mz_ulong>(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(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
{
mz_ulong ulDstLength = uDstLength;
//Get the deflator
tdefl_compressor* pDeflator = reinterpret_cast<tdefl_compressor*>(m_pDeflator);
// Do the compression
int result = mz_compress((unsigned char*)pDstData, &ulDstLength, (const unsigned char*) pSrcData, uSrcLength);
if(result != MZ_OK)
// 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 << "mz_compress() failed with return code '" << result << "'";
ss << "tdefl_init() failed with return code '" << status << "'";
POLYVOX_THROW(std::runtime_error, ss.str());
}
// Return the number of bytes written to the output.
// 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(void* pSrcData, uint32_t uSrcLength, void* pDstData, uint32_t uDstLength)
{
mz_ulong ulDstLength = 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.");
}
int result = mz_uncompress((unsigned char*) pDstData, &ulDstLength, (const unsigned char*) pSrcData, uSrcLength);
if(result != MZ_OK)
// 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 << "mz_uncompress() failed with return code '" << result << "'";
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;
}
}