1 /////////////////////////////////////////////////////////////////////////////////// 2 /// OpenGL Mathematics (glm.g-truc.net) 3 /// 4 /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) 5 /// Permission is hereby granted, free of charge, to any person obtaining a copy 6 /// of this software and associated documentation files (the "Software"), to deal 7 /// in the Software without restriction, including without limitation the rights 8 /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 /// copies of the Software, and to permit persons to whom the Software is 10 /// furnished to do so, subject to the following conditions: 11 /// 12 /// The above copyright notice and this permission notice shall be included in 13 /// all copies or substantial portions of the Software. 14 /// 15 /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 /// THE SOFTWARE. 22 /// 23 /// @ref core 24 /// @file glm/core/func_integer.inl 25 /// @date 2010-03-17 / 2011-06-15 26 /// @author Christophe Riccio 27 /////////////////////////////////////////////////////////////////////////////////// 28 29 #include "type_vec2.hpp" 30 #include "type_vec3.hpp" 31 #include "type_vec4.hpp" 32 #include "type_int.hpp" 33 #include "_vectorize.hpp" 34 #if(GLM_ARCH != GLM_ARCH_PURE) 35 #if(GLM_COMPILER & GLM_COMPILER_VC) 36 # include <intrin.h> 37 # pragma intrinsic(_BitScanReverse) 38 #endif//(GLM_COMPILER & GLM_COMPILER_VC) 39 #endif//(GLM_ARCH != GLM_ARCH_PURE) 40 #include <limits> 41 42 namespace glm 43 { 44 // uaddCarry 45 template <> 46 GLM_FUNC_QUALIFIER uint uaddCarry 47 ( 48 uint const & x, 49 uint const & y, 50 uint & Carry 51 ) 52 { 53 uint64 Value64 = static_cast<uint64>(x) + static_cast<uint64>(y); 54 uint32 Result = static_cast<uint32>(Value64 % (static_cast<uint64>(1) << static_cast<uint64>(32))); 55 Carry = (Value64 % (static_cast<uint64>(1) << static_cast<uint64>(32))) > 1 ? static_cast<uint32>(1) : static_cast<uint32>(0); 56 return Result; 57 } 58 59 template <> 60 GLM_FUNC_QUALIFIER uvec2 uaddCarry 61 ( 62 uvec2 const & x, 63 uvec2 const & y, 64 uvec2 & Carry 65 ) 66 { 67 return uvec2( 68 uaddCarry(x[0], y[0], Carry[0]), 69 uaddCarry(x[1], y[1], Carry[1])); 70 } 71 72 template <> 73 GLM_FUNC_QUALIFIER uvec3 uaddCarry 74 ( 75 uvec3 const & x, 76 uvec3 const & y, 77 uvec3 & Carry 78 ) 79 { 80 return uvec3( 81 uaddCarry(x[0], y[0], Carry[0]), 82 uaddCarry(x[1], y[1], Carry[1]), 83 uaddCarry(x[2], y[2], Carry[2])); 84 } 85 86 template <> 87 GLM_FUNC_QUALIFIER uvec4 uaddCarry 88 ( 89 uvec4 const & x, 90 uvec4 const & y, 91 uvec4 & Carry 92 ) 93 { 94 return uvec4( 95 uaddCarry(x[0], y[0], Carry[0]), 96 uaddCarry(x[1], y[1], Carry[1]), 97 uaddCarry(x[2], y[2], Carry[2]), 98 uaddCarry(x[3], y[3], Carry[3])); 99 } 100 101 // usubBorrow 102 template <> 103 GLM_FUNC_QUALIFIER uint usubBorrow 104 ( 105 uint const & x, 106 uint const & y, 107 uint & Borrow 108 ) 109 { 110 GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch"); 111 112 Borrow = x >= y ? static_cast<uint32>(0) : static_cast<uint32>(1); 113 if(y >= x) 114 return y - x; 115 else 116 return static_cast<uint32>((static_cast<int64>(1) << static_cast<int64>(32)) + (static_cast<int64>(y) - static_cast<int64>(x))); 117 } 118 119 template <> 120 GLM_FUNC_QUALIFIER uvec2 usubBorrow 121 ( 122 uvec2 const & x, 123 uvec2 const & y, 124 uvec2 & Borrow 125 ) 126 { 127 return uvec2( 128 usubBorrow(x[0], y[0], Borrow[0]), 129 usubBorrow(x[1], y[1], Borrow[1])); 130 } 131 132 template <> 133 GLM_FUNC_QUALIFIER uvec3 usubBorrow 134 ( 135 uvec3 const & x, 136 uvec3 const & y, 137 uvec3 & Borrow 138 ) 139 { 140 return uvec3( 141 usubBorrow(x[0], y[0], Borrow[0]), 142 usubBorrow(x[1], y[1], Borrow[1]), 143 usubBorrow(x[2], y[2], Borrow[2])); 144 } 145 146 template <> 147 GLM_FUNC_QUALIFIER uvec4 usubBorrow 148 ( 149 uvec4 const & x, 150 uvec4 const & y, 151 uvec4 & Borrow 152 ) 153 { 154 return uvec4( 155 usubBorrow(x[0], y[0], Borrow[0]), 156 usubBorrow(x[1], y[1], Borrow[1]), 157 usubBorrow(x[2], y[2], Borrow[2]), 158 usubBorrow(x[3], y[3], Borrow[3])); 159 } 160 161 // umulExtended 162 template <> 163 GLM_FUNC_QUALIFIER void umulExtended 164 ( 165 uint const & x, 166 uint const & y, 167 uint & msb, 168 uint & lsb 169 ) 170 { 171 GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch"); 172 173 uint64 Value64 = static_cast<uint64>(x) * static_cast<uint64>(y); 174 uint32* PointerMSB = (reinterpret_cast<uint32*>(&Value64) + 1); 175 msb = *PointerMSB; 176 uint32* PointerLSB = (reinterpret_cast<uint32*>(&Value64) + 0); 177 lsb = *PointerLSB; 178 } 179 180 template <> 181 GLM_FUNC_QUALIFIER void umulExtended 182 ( 183 uvec2 const & x, 184 uvec2 const & y, 185 uvec2 & msb, 186 uvec2 & lsb 187 ) 188 { 189 umulExtended(x[0], y[0], msb[0], lsb[0]); 190 umulExtended(x[1], y[1], msb[1], lsb[1]); 191 } 192 193 template <> 194 GLM_FUNC_QUALIFIER void umulExtended 195 ( 196 uvec3 const & x, 197 uvec3 const & y, 198 uvec3 & msb, 199 uvec3 & lsb 200 ) 201 { 202 umulExtended(x[0], y[0], msb[0], lsb[0]); 203 umulExtended(x[1], y[1], msb[1], lsb[1]); 204 umulExtended(x[2], y[2], msb[2], lsb[2]); 205 } 206 207 template <> 208 GLM_FUNC_QUALIFIER void umulExtended 209 ( 210 uvec4 const & x, 211 uvec4 const & y, 212 uvec4 & msb, 213 uvec4 & lsb 214 ) 215 { 216 umulExtended(x[0], y[0], msb[0], lsb[0]); 217 umulExtended(x[1], y[1], msb[1], lsb[1]); 218 umulExtended(x[2], y[2], msb[2], lsb[2]); 219 umulExtended(x[3], y[3], msb[3], lsb[3]); 220 } 221 222 // imulExtended 223 template <> 224 GLM_FUNC_QUALIFIER void imulExtended 225 ( 226 int const & x, 227 int const & y, 228 int & msb, 229 int & lsb 230 ) 231 { 232 GLM_STATIC_ASSERT(sizeof(int) == sizeof(int32), "int and int32 size mismatch"); 233 234 int64 Value64 = static_cast<int64>(x) * static_cast<int64>(y); 235 int32* PointerMSB = (reinterpret_cast<int32*>(&Value64) + 1); 236 msb = *PointerMSB; 237 int32* PointerLSB = (reinterpret_cast<int32*>(&Value64)); 238 lsb = *PointerLSB; 239 } 240 241 template <> 242 GLM_FUNC_QUALIFIER void imulExtended 243 ( 244 ivec2 const & x, 245 ivec2 const & y, 246 ivec2 & msb, 247 ivec2 & lsb 248 ) 249 { 250 imulExtended(x[0], y[0], msb[0], lsb[0]), 251 imulExtended(x[1], y[1], msb[1], lsb[1]); 252 } 253 254 template <> 255 GLM_FUNC_QUALIFIER void imulExtended 256 ( 257 ivec3 const & x, 258 ivec3 const & y, 259 ivec3 & msb, 260 ivec3 & lsb 261 ) 262 { 263 imulExtended(x[0], y[0], msb[0], lsb[0]), 264 imulExtended(x[1], y[1], msb[1], lsb[1]); 265 imulExtended(x[2], y[2], msb[2], lsb[2]); 266 } 267 268 template <> 269 GLM_FUNC_QUALIFIER void imulExtended 270 ( 271 ivec4 const & x, 272 ivec4 const & y, 273 ivec4 & msb, 274 ivec4 & lsb 275 ) 276 { 277 imulExtended(x[0], y[0], msb[0], lsb[0]), 278 imulExtended(x[1], y[1], msb[1], lsb[1]); 279 imulExtended(x[2], y[2], msb[2], lsb[2]); 280 imulExtended(x[3], y[3], msb[3], lsb[3]); 281 } 282 283 // bitfieldExtract 284 template <typename genIUType> 285 GLM_FUNC_QUALIFIER genIUType bitfieldExtract 286 ( 287 genIUType const & Value, 288 int const & Offset, 289 int const & Bits 290 ) 291 { 292 int GenSize = int(sizeof(genIUType)) << int(3); 293 294 assert(Offset + Bits <= GenSize); 295 296 genIUType ShiftLeft = Bits ? Value << (GenSize - (Bits + Offset)) : genIUType(0); 297 genIUType ShiftBack = ShiftLeft >> genIUType(GenSize - Bits); 298 299 return ShiftBack; 300 } 301 302 template <typename T, precision P> 303 GLM_FUNC_QUALIFIER detail::tvec2<T, P> bitfieldExtract 304 ( 305 detail::tvec2<T, P> const & Value, 306 int const & Offset, 307 int const & Bits 308 ) 309 { 310 return detail::tvec2<T, P>( 311 bitfieldExtract(Value[0], Offset, Bits), 312 bitfieldExtract(Value[1], Offset, Bits)); 313 } 314 315 template <typename T, precision P> 316 GLM_FUNC_QUALIFIER detail::tvec3<T, P> bitfieldExtract 317 ( 318 detail::tvec3<T, P> const & Value, 319 int const & Offset, 320 int const & Bits 321 ) 322 { 323 return detail::tvec3<T, P>( 324 bitfieldExtract(Value[0], Offset, Bits), 325 bitfieldExtract(Value[1], Offset, Bits), 326 bitfieldExtract(Value[2], Offset, Bits)); 327 } 328 329 template <typename T, precision P> 330 GLM_FUNC_QUALIFIER detail::tvec4<T, P> bitfieldExtract 331 ( 332 detail::tvec4<T, P> const & Value, 333 int const & Offset, 334 int const & Bits 335 ) 336 { 337 return detail::tvec4<T, P>( 338 bitfieldExtract(Value[0], Offset, Bits), 339 bitfieldExtract(Value[1], Offset, Bits), 340 bitfieldExtract(Value[2], Offset, Bits), 341 bitfieldExtract(Value[3], Offset, Bits)); 342 } 343 344 // bitfieldInsert 345 template <typename genIUType> 346 GLM_FUNC_QUALIFIER genIUType bitfieldInsert 347 ( 348 genIUType const & Base, 349 genIUType const & Insert, 350 int const & Offset, 351 int const & Bits 352 ) 353 { 354 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'bitfieldInsert' only accept integer values"); 355 assert(Offset + Bits <= sizeof(genIUType)); 356 357 if(Bits == 0) 358 return Base; 359 360 genIUType Mask = 0; 361 for(int Bit = Offset; Bit < Offset + Bits; ++Bit) 362 Mask |= (1 << Bit); 363 364 return (Base & ~Mask) | (Insert & Mask); 365 } 366 367 template <typename T, precision P> 368 GLM_FUNC_QUALIFIER detail::tvec2<T, P> bitfieldInsert 369 ( 370 detail::tvec2<T, P> const & Base, 371 detail::tvec2<T, P> const & Insert, 372 int const & Offset, 373 int const & Bits 374 ) 375 { 376 return detail::tvec2<T, P>( 377 bitfieldInsert(Base[0], Insert[0], Offset, Bits), 378 bitfieldInsert(Base[1], Insert[1], Offset, Bits)); 379 } 380 381 template <typename T, precision P> 382 GLM_FUNC_QUALIFIER detail::tvec3<T, P> bitfieldInsert 383 ( 384 detail::tvec3<T, P> const & Base, 385 detail::tvec3<T, P> const & Insert, 386 int const & Offset, 387 int const & Bits 388 ) 389 { 390 return detail::tvec3<T, P>( 391 bitfieldInsert(Base[0], Insert[0], Offset, Bits), 392 bitfieldInsert(Base[1], Insert[1], Offset, Bits), 393 bitfieldInsert(Base[2], Insert[2], Offset, Bits)); 394 } 395 396 template <typename T, precision P> 397 GLM_FUNC_QUALIFIER detail::tvec4<T, P> bitfieldInsert 398 ( 399 detail::tvec4<T, P> const & Base, 400 detail::tvec4<T, P> const & Insert, 401 int const & Offset, 402 int const & Bits 403 ) 404 { 405 return detail::tvec4<T, P>( 406 bitfieldInsert(Base[0], Insert[0], Offset, Bits), 407 bitfieldInsert(Base[1], Insert[1], Offset, Bits), 408 bitfieldInsert(Base[2], Insert[2], Offset, Bits), 409 bitfieldInsert(Base[3], Insert[3], Offset, Bits)); 410 } 411 412 // bitfieldReverse 413 template <typename genIUType> 414 GLM_FUNC_QUALIFIER genIUType bitfieldReverse(genIUType const & Value) 415 { 416 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'bitfieldReverse' only accept integer values"); 417 418 genIUType Out = 0; 419 std::size_t BitSize = sizeof(genIUType) * 8; 420 for(std::size_t i = 0; i < BitSize; ++i) 421 if(Value & (genIUType(1) << i)) 422 Out |= genIUType(1) << (BitSize - 1 - i); 423 return Out; 424 } 425 426 VECTORIZE_VEC(bitfieldReverse) 427 428 // bitCount 429 template <typename genIUType> 430 GLM_FUNC_QUALIFIER int bitCount(genIUType const & Value) 431 { 432 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'bitCount' only accept integer values"); 433 434 int Count = 0; 435 for(std::size_t i = 0; i < sizeof(genIUType) * std::size_t(8); ++i) 436 { 437 if(Value & (1 << i)) 438 ++Count; 439 } 440 return Count; 441 } 442 443 template <typename T, precision P> 444 GLM_FUNC_QUALIFIER detail::tvec2<int, P> bitCount 445 ( 446 detail::tvec2<T, P> const & value 447 ) 448 { 449 return detail::tvec2<int, P>( 450 bitCount(value[0]), 451 bitCount(value[1])); 452 } 453 454 template <typename T, precision P> 455 GLM_FUNC_QUALIFIER detail::tvec3<int, P> bitCount 456 ( 457 detail::tvec3<T, P> const & value 458 ) 459 { 460 return detail::tvec3<int, P>( 461 bitCount(value[0]), 462 bitCount(value[1]), 463 bitCount(value[2])); 464 } 465 466 template <typename T, precision P> 467 GLM_FUNC_QUALIFIER detail::tvec4<int, P> bitCount 468 ( 469 detail::tvec4<T, P> const & value 470 ) 471 { 472 return detail::tvec4<int, P>( 473 bitCount(value[0]), 474 bitCount(value[1]), 475 bitCount(value[2]), 476 bitCount(value[3])); 477 } 478 479 // findLSB 480 template <typename genIUType> 481 GLM_FUNC_QUALIFIER int findLSB 482 ( 483 genIUType const & Value 484 ) 485 { 486 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findLSB' only accept integer values"); 487 if(Value == 0) 488 return -1; 489 490 genIUType Bit; 491 for(Bit = genIUType(0); !(Value & (1 << Bit)); ++Bit){} 492 return Bit; 493 } 494 495 template <typename T, precision P> 496 GLM_FUNC_QUALIFIER detail::tvec2<int, P> findLSB 497 ( 498 detail::tvec2<T, P> const & value 499 ) 500 { 501 return detail::tvec2<int, P>( 502 findLSB(value[0]), 503 findLSB(value[1])); 504 } 505 506 template <typename T, precision P> 507 GLM_FUNC_QUALIFIER detail::tvec3<int, P> findLSB 508 ( 509 detail::tvec3<T, P> const & value 510 ) 511 { 512 return detail::tvec3<int, P>( 513 findLSB(value[0]), 514 findLSB(value[1]), 515 findLSB(value[2])); 516 } 517 518 template <typename T, precision P> 519 GLM_FUNC_QUALIFIER detail::tvec4<int, P> findLSB 520 ( 521 detail::tvec4<T, P> const & value 522 ) 523 { 524 return detail::tvec4<int, P>( 525 findLSB(value[0]), 526 findLSB(value[1]), 527 findLSB(value[2]), 528 findLSB(value[3])); 529 } 530 531 // findMSB 532 #if((GLM_ARCH != GLM_ARCH_PURE) && (GLM_COMPILER & GLM_COMPILER_VC)) 533 534 template <typename genIUType> 535 GLM_FUNC_QUALIFIER int findMSB 536 ( 537 genIUType const & Value 538 ) 539 { 540 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values"); 541 if(Value == 0) 542 return -1; 543 544 unsigned long Result(0); 545 _BitScanReverse(&Result, Value); 546 return int(Result); 547 } 548 /* 549 // __builtin_clz seems to be buggy as it crasks for some values, from 0x00200000 to 80000000 550 #elif((GLM_ARCH != GLM_ARCH_PURE) && (GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC40)) 551 552 template <typename genIUType> 553 GLM_FUNC_QUALIFIER int findMSB 554 ( 555 genIUType const & Value 556 ) 557 { 558 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values"); 559 if(Value == 0) 560 return -1; 561 562 // clz returns the number or trailing 0-bits; see 563 // http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Other-Builtins.html 564 // 565 // NoteBecause __builtin_clz only works for unsigned ints, this 566 // implementation will not work for 64-bit integers. 567 // 568 return 31 - __builtin_clzl(Value); 569 } 570 */ 571 #else 572 573 /* SSE implementation idea 574 575 __m128i const Zero = _mm_set_epi32( 0, 0, 0, 0); 576 __m128i const One = _mm_set_epi32( 1, 1, 1, 1); 577 __m128i Bit = _mm_set_epi32(-1, -1, -1, -1); 578 __m128i Tmp = _mm_set_epi32(Value, Value, Value, Value); 579 __m128i Mmi = Zero; 580 for(int i = 0; i < 32; ++i) 581 { 582 __m128i Shilt = _mm_and_si128(_mm_cmpgt_epi32(Tmp, One), One); 583 Tmp = _mm_srai_epi32(Tmp, One); 584 Bit = _mm_add_epi32(Bit, _mm_and_si128(Shilt, i)); 585 Mmi = _mm_and_si128(Mmi, One); 586 } 587 return Bit; 588 589 */ 590 591 template <typename genIUType> 592 GLM_FUNC_QUALIFIER int findMSB 593 ( 594 genIUType const & Value 595 ) 596 { 597 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values"); 598 599 if(Value == genIUType(0) || Value == genIUType(-1)) 600 return -1; 601 else if(Value > 0) 602 { 603 genIUType Bit = genIUType(-1); 604 for(genIUType tmp = Value; tmp > 0; tmp >>= 1, ++Bit){} 605 return Bit; 606 } 607 else //if(Value < 0) 608 { 609 int const BitCount(sizeof(genIUType) * 8); 610 int MostSignificantBit(-1); 611 for(int BitIndex(0); BitIndex < BitCount; ++BitIndex) 612 MostSignificantBit = (Value & (1 << BitIndex)) ? MostSignificantBit : BitIndex; 613 assert(MostSignificantBit >= 0); 614 return MostSignificantBit; 615 } 616 } 617 #endif//(GLM_COMPILER) 618 619 template <typename T, precision P> 620 GLM_FUNC_QUALIFIER detail::tvec2<int, P> findMSB 621 ( 622 detail::tvec2<T, P> const & value 623 ) 624 { 625 return detail::tvec2<int, P>( 626 findMSB(value[0]), 627 findMSB(value[1])); 628 } 629 630 template <typename T, precision P> 631 GLM_FUNC_QUALIFIER detail::tvec3<int, P> findMSB 632 ( 633 detail::tvec3<T, P> const & value 634 ) 635 { 636 return detail::tvec3<int, P>( 637 findMSB(value[0]), 638 findMSB(value[1]), 639 findMSB(value[2])); 640 } 641 642 template <typename T, precision P> 643 GLM_FUNC_QUALIFIER detail::tvec4<int, P> findMSB 644 ( 645 detail::tvec4<T, P> const & value 646 ) 647 { 648 return detail::tvec4<int, P>( 649 findMSB(value[0]), 650 findMSB(value[1]), 651 findMSB(value[2]), 652 findMSB(value[3])); 653 } 654 }//namespace glm 655