/////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell /// copies of the Software, and to permit persons to whom the Software is /// furnished to do so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in /// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /// 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 core /// @file glm/core/func_integer.inl /// @date 2010-03-17 / 2011-06-15 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #include "type_vec2.hpp" #include "type_vec3.hpp" #include "type_vec4.hpp" #include "type_int.hpp" #include "_vectorize.hpp" #if(GLM_ARCH != GLM_ARCH_PURE) #if(GLM_COMPILER & GLM_COMPILER_VC) # include # pragma intrinsic(_BitScanReverse) #endif//(GLM_COMPILER & GLM_COMPILER_VC) #endif//(GLM_ARCH != GLM_ARCH_PURE) #include namespace glm{ namespace detail { GLM_FUNC_QUALIFIER int mask(int Bits) { return ~((~0) << Bits); } }//namespace detail // uaddCarry GLM_FUNC_QUALIFIER uint uaddCarry(uint const & x, uint const & y, uint & Carry) { uint64 Value64 = static_cast(x) + static_cast(y); uint32 Result = static_cast(Value64 % (static_cast(1) << static_cast(32))); Carry = (Value64 % (static_cast(1) << static_cast(32))) > 1 ? static_cast(1) : static_cast(0); return Result; } template class vecType> GLM_FUNC_QUALIFIER vecType uaddCarry(vecType const & x, vecType const & y, vecType & Carry) { vecType Value64(vecType(x) + vecType(y)); vecType Result(Value64 % (static_cast(1) << static_cast(32))); vecType DoCarry(greaterThan(Value64 % (static_cast(1) << static_cast(32)), vecType(1))); Carry = mix(vecType(0), vecType(1), DoCarry); return Result; } // usubBorrow GLM_FUNC_QUALIFIER uint usubBorrow(uint const & x, uint const & y, uint & Borrow) { GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch"); Borrow = x >= y ? static_cast(0) : static_cast(1); if(y >= x) return y - x; else return static_cast((static_cast(1) << static_cast(32)) + (static_cast(y) - static_cast(x))); } template class vecType> GLM_FUNC_QUALIFIER vecType usubBorrow(vecType const & x, vecType const & y, vecType & Borrow) { Borrow = mix(vecType(1), vecType(0), greaterThanEqual(x, y)); vecType const YgeX(y - x); vecType const XgeY(vecType((static_cast(1) << static_cast(32)) + (vecType(y) - vecType(x)))); return mix(XgeY, YgeX, greaterThanEqual(y, x)); } // umulExtended GLM_FUNC_QUALIFIER void umulExtended(uint const & x, uint const & y, uint & msb, uint & lsb) { GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch"); uint64 Value64 = static_cast(x) * static_cast(y); uint32* PointerMSB = (reinterpret_cast(&Value64) + 1); msb = *PointerMSB; uint32* PointerLSB = (reinterpret_cast(&Value64) + 0); lsb = *PointerLSB; } template class vecType> GLM_FUNC_QUALIFIER void umulExtended(vecType const & x, vecType const & y, vecType & msb, vecType & lsb) { GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch"); vecType Value64(vecType(x) * vecType(y)); msb = vecType(Value64 >> static_cast(32)); lsb = vecType(Value64); } // imulExtended GLM_FUNC_QUALIFIER void imulExtended(int x, int y, int & msb, int & lsb) { GLM_STATIC_ASSERT(sizeof(int) == sizeof(int32), "int and int32 size mismatch"); int64 Value64 = static_cast(x) * static_cast(y); int32* PointerMSB = (reinterpret_cast(&Value64) + 1); msb = *PointerMSB; int32* PointerLSB = (reinterpret_cast(&Value64)); lsb = *PointerLSB; } template class vecType> GLM_FUNC_QUALIFIER void imulExtended(vecType const & x, vecType const & y, vecType & msb, vecType & lsb) { GLM_STATIC_ASSERT(sizeof(int) == sizeof(int32), "int and int32 size mismatch"); vecType Value64(vecType(x) * vecType(y)); lsb = vecType(Value64 & static_cast(0xFFFFFFFF)); msb = vecType((Value64 >> static_cast(32)) & static_cast(0xFFFFFFFF)); } // bitfieldExtract template GLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits) { return bitfieldExtract(tvec1(Value), Offset, Bits).x; } template class vecType> GLM_FUNC_QUALIFIER vecType bitfieldExtract(vecType const & Value, int Offset, int Bits) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); int const Mask = detail::mask(Bits); return (Value >> static_cast(Offset)) & static_cast(Mask); } // bitfieldInsert template GLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const & Base, genIUType const & Insert, int Offset, int Bits) { return bitfieldInsert(tvec1(Base), tvec1(Insert), Offset, Bits).x; } template class vecType> GLM_FUNC_QUALIFIER vecType bitfieldInsert(vecType const & Base, vecType const & Insert, int Offset, int Bits) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); T Mask = static_cast(detail::mask(Bits) << Offset); return (Base & ~Mask) | (Insert & Mask); } // bitfieldReverse template GLM_FUNC_QUALIFIER T bitfieldReverse(T v) { return bitfieldReverse(tvec1(v)).x; } template class vecType> GLM_FUNC_QUALIFIER vecType bitfieldReverse(vecType const & v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); vecType Result(0); T const BitSize = static_cast(sizeof(T) * 8); for(T i = 0; i < BitSize; ++i) { vecType const BitSet(v & (static_cast(1) << i)); vecType const BitFirst(BitSet >> i); Result |= BitFirst << (BitSize - 1 - i); } return Result; } // bitCount template GLM_FUNC_QUALIFIER int bitCount(genIUType x) { return bitCount(tvec1(x)).x; } template class vecType> GLM_FUNC_QUALIFIER vecType bitCount(vecType const & v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); vecType Count(0); for(T i = 0, n = static_cast(sizeof(T) * 8); i < n; ++i) Count += vecType((v >> i) & static_cast(1)); return Count; } // findLSB template GLM_FUNC_QUALIFIER int findLSB(genIUType Value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); if(Value == 0) return -1; genIUType Bit; for(Bit = genIUType(0); !(Value & (1 << Bit)); ++Bit){} return Bit; } template class vecType> GLM_FUNC_QUALIFIER vecType findLSB(vecType const & x) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); return detail::functor1::call(findLSB, x); } // findMSB #if (GLM_ARCH != GLM_ARCH_PURE) && (GLM_COMPILER & GLM_COMPILER_VC) template GLM_FUNC_QUALIFIER int findMSB(genIUType Value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); if(Value == 0) return -1; unsigned long Result(0); _BitScanReverse(&Result, Value); return int(Result); } /* // __builtin_clz seems to be buggy as it crasks for some values, from 0x00200000 to 80000000 #elif((GLM_ARCH != GLM_ARCH_PURE) && (GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC40)) template GLM_FUNC_QUALIFIER int findMSB ( genIUType const & Value ) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); if(Value == 0) return -1; // clz returns the number or trailing 0-bits; see // http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Other-Builtins.html // // NoteBecause __builtin_clz only works for unsigned ints, this // implementation will not work for 64-bit integers. // return 31 - __builtin_clzl(Value); } */ #else /* SSE implementation idea __m128i const Zero = _mm_set_epi32( 0, 0, 0, 0); __m128i const One = _mm_set_epi32( 1, 1, 1, 1); __m128i Bit = _mm_set_epi32(-1, -1, -1, -1); __m128i Tmp = _mm_set_epi32(Value, Value, Value, Value); __m128i Mmi = Zero; for(int i = 0; i < 32; ++i) { __m128i Shilt = _mm_and_si128(_mm_cmpgt_epi32(Tmp, One), One); Tmp = _mm_srai_epi32(Tmp, One); Bit = _mm_add_epi32(Bit, _mm_and_si128(Shilt, i)); Mmi = _mm_and_si128(Mmi, One); } return Bit; */ template GLM_FUNC_QUALIFIER int findMSB(genIUType Value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); if(Value == genIUType(0) || Value == genIUType(-1)) return -1; else if(Value > 0) { genIUType Bit = genIUType(-1); for(genIUType tmp = Value; tmp > 0; tmp >>= 1, ++Bit){} return Bit; } else //if(Value < 0) { int const BitCount(sizeof(genIUType) * 8); int MostSignificantBit(-1); for(int BitIndex(0); BitIndex < BitCount; ++BitIndex) MostSignificantBit = (Value & (1 << BitIndex)) ? MostSignificantBit : BitIndex; assert(MostSignificantBit >= 0); return MostSignificantBit; } } #endif//(GLM_COMPILER) template class vecType> GLM_FUNC_QUALIFIER vecType findMSB(vecType const & x) { return detail::functor1::call(findMSB, x); } }//namespace glm