diff --git a/glm/core/func_common.inl b/glm/core/func_common.inl index 06a45018..0d587d66 100644 --- a/glm/core/func_common.inl +++ b/glm/core/func_common.inl @@ -42,6 +42,7 @@ namespace detail detail::type::is_float || detail::type::is_int, "'abs' only accept floating-point and integer inputs"); return x >= genFIType(0) ? x : -x; + // TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff; } }; diff --git a/glm/core/func_integer.inl b/glm/core/func_integer.inl index fb91defc..31f9684f 100644 --- a/glm/core/func_integer.inl +++ b/glm/core/func_integer.inl @@ -26,6 +26,11 @@ /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// +#if(GLM_COMPILER & GLM_COMPILER_VC) +#include +#pragma intrinsic(_BitScanReverse) +#endif + namespace glm { // uaddCarry @@ -550,6 +555,32 @@ namespace glm } // findMSB +#if(GLM_COMPILER & GLM_COMPILER_VC) + + template + GLM_FUNC_QUALIFIER int findMSB + ( + genIUType const & Value + ) + { + unsigned long Result(0); + _BitScanReverse(&Result, Value); + return int(Result); + } + +#elif((GLM_COMPILER & GLM_COMPILER_GCC) && __has_builtin(__builtin_clz)) + + template + GLM_FUNC_QUALIFIER int findMSB + ( + genIUType const & Value + ) + { + return __builtin_clz(x); + } + +#else + template GLM_FUNC_QUALIFIER int findMSB ( @@ -564,6 +595,7 @@ namespace glm for(genIUType tmp = Value; tmp; tmp >>= 1, ++bit){} return bit; } +#endif//(GLM_COMPILER) template GLM_FUNC_QUALIFIER detail::tvec2 findMSB diff --git a/glm/ext.hpp b/glm/ext.hpp index 70209d6d..5c9b0fe5 100644 --- a/glm/ext.hpp +++ b/glm/ext.hpp @@ -124,7 +124,6 @@ #include "./gtx/transform.hpp" #include "./gtx/transform2.hpp" #include "./gtx/ulp.hpp" -#include "./gtx/unsigned_int.hpp" #include "./gtx/vec1.hpp" #include "./gtx/vector_access.hpp" #include "./gtx/vector_angle.hpp" diff --git a/glm/gtx/integer.hpp b/glm/gtx/integer.hpp index 0fe8cb0b..9369bd43 100644 --- a/glm/gtx/integer.hpp +++ b/glm/gtx/integer.hpp @@ -58,6 +58,14 @@ namespace glm //! From GLM_GTX_integer extension. int sqrt(int x); + //! Returns the log2 of x. Can be reliably using to compute mipmap count from the texture size. + //! From GLM_GTX_integer extension. + unsigned int log2(unsigned int x); + + //! Returns the floor log2 of x. + //! From GLM_GTX_integer extension. + unsigned int floor_log2(unsigned int x); + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. //! From GLM_GTX_integer extension. int mod(int x, int y); @@ -67,6 +75,26 @@ namespace glm template genType factorial(genType const & x); + //! 32bit signed integer. + //! From GLM_GTX_integer extension. + typedef signed int sint; + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + uint pow(uint x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + uint sqrt(uint x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + uint mod(uint x, uint y); + + //! Returns the number of leading zeros. + //! From GLM_GTX_integer extension. + uint nlz(uint x); + /// @} }//namespace glm diff --git a/glm/gtx/integer.inl b/glm/gtx/integer.inl index b70868cb..8c883728 100644 --- a/glm/gtx/integer.inl +++ b/glm/gtx/integer.inl @@ -37,6 +37,52 @@ GLM_FUNC_QUALIFIER int sqrt(int x) return CurrentAnswer; } +// Henry Gordon Dietz: http://aggregate.org/MAGIC/ +namespace detail +{ + GLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x) + { + /* 32-bit recursive reduction using SWAR... + but first step is mapping 2-bit values + into sum of 2 1-bit values in sneaky way + */ + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return(x & 0x0000003f); + } +}//namespace detail + +#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC)) + +GLM_FUNC_QUALIFIER unsigned int log2(unsigned int x) +{ + return x <= 1 ? 0 : unsigned(32) - nlz(x - 1u); +} + +#else + +GLM_FUNC_QUALIFIER unsigned int log2(unsigned int x) +{ + return unsigned(32) - nlz(x - 1u); +} + +#endif + +// Henry Gordon Dietz: http://aggregate.org/MAGIC/ +unsigned int floor_log2(unsigned int x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + + return(detail::ones32(x) - 1); +} + // mod GLM_FUNC_QUALIFIER int mod(int x, int y) { @@ -84,4 +130,74 @@ GLM_FUNC_QUALIFIER detail::tvec4 factorial( factorial(x.w)); } +GLM_FUNC_QUALIFIER uint pow(uint x, uint y) +{ + uint result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; +} + +GLM_FUNC_QUALIFIER uint sqrt(uint x) +{ + if(x <= 1) return x; + + uint NextTrial = x >> 1; + uint CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; +} + +GLM_FUNC_QUALIFIER uint mod(uint x, uint y) +{ + return x - y * (x / y); +} + +#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC)) + +GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) +{ + return 31u - findMSB(x); +} + +#else + +// Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt +GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) +{ + int y, m, n; + + y = -int(x >> 16); // If left half of x is 0, + m = (y >> 16) & 16; // set n = 16. If left half + n = 16 - m; // is nonzero, set n = 0 and + x = x >> m; // shift x right 16. + // Now x is of the form 0000xxxx. + y = x - 0x100; // If positions 8-15 are 0, + m = (y >> 16) & 8; // add 8 to n and shift x left 8. + n = n + m; + x = x << m; + + y = x - 0x1000; // If positions 12-15 are 0, + m = (y >> 16) & 4; // add 4 to n and shift x left 4. + n = n + m; + x = x << m; + + y = x - 0x4000; // If positions 14-15 are 0, + m = (y >> 16) & 2; // add 2 to n and shift x left 2. + n = n + m; + x = x << m; + + y = x >> 14; // Set y = 0, 1, 2, or 3. + m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp. + return unsigned(n + 2 - m); +} + +#endif//(GLM_COMPILER) + }//namespace glm diff --git a/glm/gtx/unsigned_int.hpp b/glm/gtx/unsigned_int.hpp index 239e6b6b..d494905f 100644 --- a/glm/gtx/unsigned_int.hpp +++ b/glm/gtx/unsigned_int.hpp @@ -19,58 +19,8 @@ /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN /// THE SOFTWARE. -/// -/// @ref gtx_unsigned_int -/// @file glm/gtx/unsigned_int.hpp -/// @date 2005-12-24 / 2011-06-07 -/// @author Christophe Riccio -/// -/// @see core (dependence) -/// @see gtx_integer (dependence) -/// -/// @defgroup gtx_unsigned_int GLM_GTX_unsigned_int: Unsigned int -/// @ingroup gtx -/// -/// @brief Add support for unsigned integer for core functions -/// -/// need to be included to use these functionalities. /////////////////////////////////////////////////////////////////////////////////// -#ifndef GLM_GTX_unsigned_int -#define GLM_GTX_unsigned_int GLM_VERSION - -// Dependency: -#include "../glm.hpp" -#include "../gtx/integer.hpp" - -#if(defined(GLM_MESSAGES) && !defined(glm_ext)) -# pragma message("GLM: GLM_GTX_unsigned_int extension included") +#if(defined(GLM_MESSAGES)) +# pragma message("GLM: GLM_GTX_unsigned_int extension is deprecated, include GLM_GTX_integer instead") #endif - -namespace glm -{ - /// @addtogroup gtx_unsigned_int - /// @{ - - //! 32bit signed integer. - //! From GLM_GTX_unsigned_int extension. - typedef signed int sint; - - //! Returns x raised to the y power. - //! From GLM_GTX_unsigned_int extension. - uint pow(uint x, uint y); - - //! Returns the positive square root of x. - //! From GLM_GTX_unsigned_int extension. - uint sqrt(uint x); - - //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. - //! From GLM_GTX_unsigned_int extension. - uint mod(uint x, uint y); - - /// @} -}//namespace glm - -#include "unsigned_int.inl" - -#endif//GLM_GTX_unsigned_int diff --git a/glm/gtx/unsigned_int.inl b/glm/gtx/unsigned_int.inl index 133a3022..953e4ba1 100644 --- a/glm/gtx/unsigned_int.inl +++ b/glm/gtx/unsigned_int.inl @@ -9,33 +9,5 @@ namespace glm{ -GLM_FUNC_QUALIFIER uint pow(uint x, uint y) -{ - uint result = x; - for(uint i = 1; i < y; ++i) - result *= x; - return result; -} - -GLM_FUNC_QUALIFIER uint sqrt(uint x) -{ - if(x <= 1) return x; - - uint NextTrial = x >> 1; - uint CurrentAnswer; - - do - { - CurrentAnswer = NextTrial; - NextTrial = (NextTrial + x / NextTrial) >> 1; - } while(NextTrial < CurrentAnswer); - - return CurrentAnswer; -} - -GLM_FUNC_QUALIFIER uint mod(uint x, uint y) -{ - return x - y * (x / y); -} }//namespace glm diff --git a/test/gtx/CMakeLists.txt b/test/gtx/CMakeLists.txt index b7a44b8d..504aeff8 100644 --- a/test/gtx/CMakeLists.txt +++ b/test/gtx/CMakeLists.txt @@ -1,4 +1,5 @@ glmCreateTestGTC(gtx_bit) +glmCreateTestGTC(gtx_integer) glmCreateTestGTC(gtx_noise) glmCreateTestGTC(gtx_quaternion) glmCreateTestGTC(gtx_random) diff --git a/test/gtx/gtx_integer.cpp b/test/gtx/gtx_integer.cpp new file mode 100644 index 00000000..a3429387 --- /dev/null +++ b/test/gtx/gtx_integer.cpp @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Created : 2011-10-11 +// Updated : 2011-10-11 +// Licence : This source is under MIT licence +// File : test/gtx/gtx_integer.cpp +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +int test_floor_log2() +{ + int Error = 0; + + for(std::size_t i = 1; i < 1000000; ++i) + { + glm::uint A = glm::floor_log2(glm::uint(i)); + glm::uint B = glm::uint(glm::log2(double(i))); // Will fail with float, lack of accuracy + + Error += A == B ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_log2() +{ + int Error = 0; + + for(std::size_t i = 1; i < 1000000; ++i) + { + glm::uint A = glm::log2(glm::uint(i)); + double B = glm::log2(double(i)); + + Error += glm::equalEpsilon(double(A), B, 1.0) ? 0 : 1; + //assert(!Error); + } + + return Error; +} + +int test_nlz() +{ + int Error = 0; + + for(std::size_t i = 1; i < 33; ++i) + printf("%d, %d\n", glm::nlz(i), 31u - glm::findMSB(i)); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_nlz(); + Error += test_floor_log2(); + Error += test_log2(); + + return Error; +}