blob: e792461dc9f21ac3eb54e49d73038ad18a1f4597 [file] [log] [blame]
Tony-LunarGb0b195d2015-05-13 15:01:06 -06001///////////////////////////////////////////////////////////////////////////////////
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
42namespace 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