diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5cceff72..b96f18ad 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,6 +2,10 @@ Changes for PolyVox version 0.3 =============================== This release has focused on... (some introduction here). +Error Handling +-------------- +PolyVox now has it's own POLYVOX_ASSERT() macro rather than using the standard assert(). This has some advantages such as allowing a message to be printed and providing file/line information, and it is also possible to enable/disable it independantly of whether you are making a debug or release build + Volume wrap modes ----------------- This release has seen a overhaul of the way PolyVox handles voxel positions which are outside of the volume. It used to be the case that you could specify a border value which would be returned whenever an out-of-volume access was performed, but this was not flexible enough for all use cases. You can now choose between different wrapping modes (border, clamp, etc) and apply them to both the volume itself or to samplers. If you have multiple samplers pointing at the same volume then you can choose to have different wrap modes for each of them. diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index 48bae99e..f964a8d5 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -94,6 +94,7 @@ SET(CORE_INC_FILES ) SET(IMPL_SRC_FILES + source/Impl/ErrorHandling.cpp source/Impl/MarchingCubesTables.cpp source/Impl/RandomUnitVectors.cpp source/Impl/RandomVectors.cpp @@ -106,6 +107,7 @@ SET(IMPL_INC_FILES include/PolyVoxCore/Impl/AStarPathfinderImpl.h include/PolyVoxCore/Impl/Block.h include/PolyVoxCore/Impl/Block.inl + include/PolyVoxCore/Impl/ErrorHandling.h include/PolyVoxCore/Impl/MarchingCubesTables.h include/PolyVoxCore/Impl/RandomUnitVectors.h include/PolyVoxCore/Impl/RandomVectors.h diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h new file mode 100644 index 00000000..d3ef8b49 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h @@ -0,0 +1,124 @@ +/******************************************************************************* +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_ErrorHandling_H__ +#define __PolyVox_ErrorHandling_H__ + +#include //For std::exit +#include //For std::cerr +#include + +#define POLYVOX_ASSERTS_ENABLED +//#define POLYVOX_THROW_ENABLED + +#if defined(_MSC_VER) + #define POLYVOX_HALT() __debugbreak() +#else + #define POLYVOX_HALT() std::exit(EXIT_FAILURE) +#endif + +#define POLYVOX_UNUSED(x) do { (void)sizeof(x); } while(0) + +/* + * Assertions + * ---------- + * The code below implements a custom assert function called POLYVOX_ASSERT which has a number of advantages compared + * to the standard C/C++ assert(). It is inspired by http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ + * which provides code under the MIT license. + */ + +#ifdef POLYVOX_ASSERTS_ENABLED + + #define POLYVOX_ASSERT(condition, message) \ + do \ + { \ + if (!(condition)) \ + { \ + std::cerr << std::endl << std::endl; \ + std::cerr << " PolyVox Assertion Failed!" << std::endl; \ + std::cerr << " =========================" << std::endl; \ + std::cerr << " Condition: " << #condition << std::endl; \ + std::cerr << " Message: " << (message) << std::endl; \ + std::cerr << " Location: " << "Line " << __LINE__ << " of " << __FILE__ << std::endl << std::endl; \ + POLYVOX_HALT(); \ + } \ + } while(0) + +#else + + #define POLYVOX_ASSERT(condition, message) \ + do { POLYVOX_UNUSED(condition); POLYVOX_UNUSED(message); } while(0) + +#endif + +/* + * Static Assertions + * ----------------- + * These map to C+11 static_assert if available or our own implentation otherwise. + */ + +#if defined(HAS_CXX11_STATIC_ASSERT) + //In this case we can just use static_assert + #define POLYVOX_STATIC_ASSERT static_assert +#else + namespace PolyVox + { + // empty default template + template + struct StaticAssert {}; + + // template specialized on true + template <> + struct StaticAssert + { + // If the static assertion is failing then this function won't exist. It will then + // appear in the error message which gives a clue to the user about what is wrong. + static void ERROR_The_static_assertion_has_failed() {} + }; + } + + #define POLYVOX_STATIC_ASSERT(condition, message) StaticAssert<(condition)>::ERROR_The_static_assertion_has_failed(); +#endif + +/* + * Exceptions + * ---------- + * ... + */ +#ifdef POLYVOX_THROW_ENABLED + #define POLYVOX_THROW(type, message) throw type((message)) +#else + namespace PolyVox + { + typedef void (*ThrowHandler)(std::exception& e, const char* file, int line); + + ThrowHandler getThrowHandler(); + void setThrowHandler(ThrowHandler newHandler); + } + + #define POLYVOX_THROW(type, message) \ + type except = (type)((message)); \ + getThrowHandler()((except), __FILE__, __LINE__) +#endif + +#endif //__PolyVox_ErrorHandling_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h index da1fedd5..3724efe4 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h @@ -98,13 +98,6 @@ freely, subject to the following restrictions: #define polyvox_constexpr #endif -#if defined(HAS_CXX11_STATIC_ASSERT) - //In this case we can just use static_assert -#else - #include - #define static_assert(condition, message) BOOST_STATIC_ASSERT(condition) -#endif - #if defined(HAS_CXX11_CSTDINT_H) #include #else diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl index 45d24ada..1b9f2bd0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl @@ -21,6 +21,8 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ +#include + namespace PolyVox { template diff --git a/library/PolyVoxCore/include/PolyVoxCore/Vector.h b/library/PolyVoxCore/include/PolyVoxCore/Vector.h index 12c3c201..db3da0f8 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Vector.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Vector.h @@ -24,11 +24,11 @@ freely, subject to the following restrictions: #ifndef __PolyVox_Vector_H__ #define __PolyVox_Vector_H__ +#include "Impl/ErrorHandling.h" #include "Impl/TypeDef.h" #include "PolyVoxForwardDeclarations.h" -#include #include #include #include diff --git a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl index 22d3009e..57b3e2f0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl @@ -53,7 +53,7 @@ namespace PolyVox template Vector::Vector(StorageType x, StorageType y) { - static_assert(Size == 2, "This constructor should only be used for vectors with two elements."); + POLYVOX_STATIC_ASSERT(Size == 2, "This constructor should only be used for vectors with two elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -68,7 +68,7 @@ namespace PolyVox template Vector::Vector(StorageType x, StorageType y, StorageType z) { - static_assert(Size == 3, "This constructor should only be used for vectors with three elements."); + POLYVOX_STATIC_ASSERT(Size == 3, "This constructor should only be used for vectors with three elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -86,7 +86,7 @@ namespace PolyVox template Vector::Vector(StorageType x, StorageType y, StorageType z, StorageType w) { - static_assert(Size == 4, "This constructor should only be used for vectors with four elements."); + POLYVOX_STATIC_ASSERT(Size == 4, "This constructor should only be used for vectors with four elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -129,14 +129,14 @@ namespace PolyVox template Vector::~Vector(void) { - // We put the static_asserts in the destructor because there is one one of these, + // We put the static asserts in the destructor because there is one one of these, // where as there are multiple constructors. // Force a vector to have a length greater than one. There is no need for a // vector with one element, and supporting this would cause confusion over the // behaviour of the constructor taking a single value, as this fills all elements // to that value rather than just the first one. - static_assert(Size > 1, "Vector must have a length greater than one."); + POLYVOX_STATIC_ASSERT(Size > 1, "Vector must have a length greater than one."); } /** @@ -414,7 +414,7 @@ namespace PolyVox template inline StorageType Vector::getElement(uint32_t index) const { - assert(index < Size); + POLYVOX_ASSERT(index < Size, "Attempted to access invalid vector element."); return m_tElements[index]; } @@ -442,7 +442,7 @@ namespace PolyVox template inline StorageType Vector::getZ(void) const { - static_assert(Size >= 3, "You can only get the 'z' component from a vector with at least three elements."); + POLYVOX_STATIC_ASSERT(Size >= 3, "You can only get the 'z' component from a vector with at least three elements."); return m_tElements[2]; } @@ -453,7 +453,7 @@ namespace PolyVox template inline StorageType Vector::getW(void) const { - static_assert(Size >= 4, "You can only get the 'w' component from a vector with at least four elements."); + POLYVOX_STATIC_ASSERT(Size >= 4, "You can only get the 'w' component from a vector with at least four elements."); return m_tElements[3]; } @@ -465,7 +465,7 @@ namespace PolyVox template inline void Vector::setElement(uint32_t index, StorageType tValue) { - assert(index < Size); + POLYVOX_ASSERT(index < Size, "Attempted to access invalid vector element."); m_tElements[index] = tValue; } @@ -491,7 +491,7 @@ namespace PolyVox template inline void Vector::setElements(StorageType x, StorageType y, StorageType z) { - static_assert(Size >= 3, "You can only use this version of setElements() on a vector with at least three elements."); + POLYVOX_STATIC_ASSERT(Size >= 3, "You can only use this version of setElements() on a vector with at least three elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -508,7 +508,7 @@ namespace PolyVox template inline void Vector::setElements(StorageType x, StorageType y, StorageType z, StorageType w) { - static_assert(Size >= 4, "You can only use this version of setElements() on a vector with at least four elements."); + POLYVOX_STATIC_ASSERT(Size >= 4, "You can only use this version of setElements() on a vector with at least four elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -540,7 +540,7 @@ namespace PolyVox template inline void Vector::setZ(StorageType tZ) { - static_assert(Size >= 3, "You can only set the 'w' component from a vector with at least three elements."); + POLYVOX_STATIC_ASSERT(Size >= 3, "You can only set the 'w' component from a vector with at least three elements."); m_tElements[2] = tZ; } @@ -551,7 +551,7 @@ namespace PolyVox template inline void Vector::setW(StorageType tW) { - static_assert(Size >= 4, "You can only set the 'w' component from a vector with at least four elements."); + POLYVOX_STATIC_ASSERT(Size >= 4, "You can only set the 'w' component from a vector with at least four elements."); m_tElements[3] = tW; } @@ -649,7 +649,7 @@ namespace PolyVox { // Standard float rules apply for divide-by-zero m_tElements[ct] /= fLength; - assert(m_tElements[ct] == m_tElements[ct]); //Will assert if NAN + POLYVOX_ASSERT(m_tElements[ct] == m_tElements[ct], "Obtained NAN during vector normalisation. Perhaps the input vector was too short?"); } } }//namespace PolyVox diff --git a/library/PolyVoxCore/source/Impl/Utility.cpp b/library/PolyVoxCore/source/Impl/Utility.cpp index 6e907ab9..c82c9630 100644 --- a/library/PolyVoxCore/source/Impl/Utility.cpp +++ b/library/PolyVoxCore/source/Impl/Utility.cpp @@ -21,11 +21,9 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ +#include "PolyVoxCore/Impl/ErrorHandling.h" #include "PolyVoxCore/Impl/Utility.h" -#include -#include - namespace PolyVox { //Note: this function only works for inputs which are a power of two and not zero @@ -33,17 +31,17 @@ namespace PolyVox uint8_t logBase2(uint32_t uInput) { //Debug mode validation - assert(uInput != 0); - assert(isPowerOf2(uInput)); + POLYVOX_ASSERT(uInput != 0, "Cannot compute the log of zero."); + POLYVOX_ASSERT(isPowerOf2(uInput), "Input must be a power of two in order to compute the log."); //Release mode validation if(uInput == 0) { - throw std::invalid_argument("Cannot compute the log of zero."); + POLYVOX_THROW(std::invalid_argument, "Cannot compute the log of zero."); } if(!isPowerOf2(uInput)) { - throw std::invalid_argument("Input must be a power of two in order to compute the log."); + POLYVOX_THROW(std::invalid_argument, "Input must be a power of two in order to compute the log."); } uint32_t uResult = 0;