fennec
Loading...
Searching...
No Matches
common.h
Go to the documentation of this file.
1// =====================================================================================================================
2// fennec, a free and open source game engine
3// Copyright © 2025 Medusa Slockbower
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// =====================================================================================================================
18
30
31
32#ifndef FENNEC_MATH_COMMON_H
33#define FENNEC_MATH_COMMON_H
34
35
271
272#include <fennec/math/detail/_math.h>
273
274#include <fennec/lang/limits.h>
275
276#include <fennec/math/vector.h>
277
278#if FENNEC_COMPILER_MSVC
279#define isnanf(x) isnan(x)
280#define isinff(x) isinf(x)
281#endif
282
283namespace fennec
284{
285
286
287// Sign Functions ======================================================================================================
288
289
292
293
294
295// Sign ================================================================================================================
296
305template<typename genType>
306constexpr genType sign(genType x) {
307 return (x < genType(0) ? genType(-1) : genType(1)) * static_cast<genType>(x != 0); // reduces to cmove
308}
309
310
311// Absolute Value ======================================================================================================
312
321template<typename genType>
322constexpr genType abs(genType x) {
323 return x * fennec::sign(x);
324}
325
327
328
329
330// Rounding Functions ==================================================================================================
331
332
335
336
337// Floor ===============================================================================================================
338
347template<typename genType>
348constexpr genType floor(genType x) {
349 return ::floor(x);
350}
351
352
353
354// Ceil ================================================================================================================
355
364template<typename genType>
365constexpr genType ceil(genType x) {
366 return ::ceil(x);
367}
368
369
370
371// Round ===============================================================================================================
372
382template<typename genType> constexpr genType round(genType x) {
383 return ::round(x);
384}
385
386
387
388// Trunc ===============================================================================================================
389
398template<typename genType>
399constexpr genType trunc(genType x) {
400 return ::trunc(x);
401}
402
403
404
405// Round Even ==========================================================================================================
406
417template<typename genType>
418constexpr genType roundEven(genType x) {
419 static const genType e = numeric_limits<genType>::epsilon();
420 int I = static_cast<int>(x);
421 genType i = static_cast<genType>(I);
422 genType f = x - i;
423 if (abs(f - genType(0.5)) > e)
424 return fennec::round(x);
425
426 bool dir = (I % 2);
427 return dir ? i + 1 : i;
428
429 // Older version that generates significantly more branching and asm instructions
430 //const genType e = numeric_limits<genType>::epsilon();
431 //genType f = x - fennec::floor(x);
432 //if (fennec::abs(f - genType(0.5)) > e)
433 // return fennec::round(x);
434 //
435 //genType i = fennec::floor(x);
436 //genType r = i / 2;
437 //bool up = r - fennec::floor(r) > e; // This will cause a branch in most circumstances
438 //return i + static_cast<genType>(up);
439}
440
442
443
444// Floating Point Functions ============================================================================================
445
446
449
450
451// Fract ===============================================================================================================
452
461template<typename genType>
462constexpr genType fract(genType x) {
463 return x - ::floor(x);
464}
465
466
467// Mod =================================================================================================================
468
478template<typename genType>
479constexpr genType mod(genType x, genType y) {
480 return x - y * fennec::floor(x / y);
481}
482
483
484// ModF ================================================================================================================
485
495template<typename genType>
496constexpr genType modf(genType x, genType& i) {
497 i = fennec::floor(x); return fennec::fract(x);
498}
499
500
501// Is NaN ==============================================================================================================
502
516template<typename genType, typename genBType = bool_t> requires(is_bool_v<genBType>)
517constexpr genBType isnan(genType x) {
518 return ::isnanf(x);
519}
520
521
522// Is Inf ==============================================================================================================
523
532template<typename genType, typename genBType = bool_t> requires(is_bool_v<genBType>)
533constexpr genBType isinf(genType x) {
534 return ::isinff(x);
535}
536
537
538
539// Bit Conversion ======================================================================================================
540
543template<typename genType, typename genIType = int_t> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
544constexpr genIType floatBitsToInt(genType x) {
545 return fennec::bit_cast<genIType>(x);
546}
547
548
565template<typename genType, typename genUType = uint_t> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
566constexpr genUType floatBitsToUint(genType x) {
567 return fennec::bit_cast<genUType>(x);
568}
569
570
573template<typename genType = float_t, typename genIType = int_t> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
574constexpr genType intBitsToFloat(genIType x) {
575 return fennec::bit_cast<genType>(x);
576}
577
578
593template<typename genType = float_t, typename genUType = uint_t> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
594constexpr genType uintBitsToFloat(genUType x) {
595 return fennec::bit_cast<genType>(x);
596}
597
598
599
600// fma =================================================================================================================
601
612template<typename genType>
613constexpr genType fma(genType a, genType b, genType c) {
614 return genType(::fma(a, b, c));
615}
616
617
618
619// frexp ===============================================================================================================
620
635template<typename genType, typename genIType = int_t> requires(is_integral_v<genIType>)
636constexpr genType frexp(genType x, genIType& exp) {
637 return ::frexp(x, &exp);
638}
639
640
641
642// ldexp ===============================================================================================================
643
660template<typename genType, typename genIType = int_t> requires(is_integral_v<genIType>)
661constexpr genType ldexp(genType x, genIType exp) {
662 return ::ldexp(x, exp);
663}
664
665
667
668
669// Comparison Functions ================================================================================================
670
671
674
675
676// Min =================================================================================================================
677
687template<typename genType>
688constexpr genType min(genType x, genType y) {
689 return (y < x) ? y : x;
690}
691
692
693// Max =================================================================================================================
694
704template<typename genType>
705constexpr genType max(genType x, genType y) {
706 return (x < y) ? y : x;
707}
708
709
710// Clamp ===============================================================================================================
711
722template<typename genType>
723constexpr genType clamp(genType x, genType minVal, genType maxVal) {
724 return min(max(x, minVal), maxVal);
725}
726
727
729
730
731// Curves ==============================================================================================================
732
733
736
737
738// Step ================================================================================================================
739
749template<typename genType> requires(is_floating_point_v<genType>)
750constexpr genType step(genType edge, genType x) {
751 return static_cast<genType>(not(x < edge));
752}
753
754
755// Smoothstep ==========================================================================================================
756
777template<typename genType> requires(is_floating_point_v<genType>)
778constexpr genType smoothstep(genType edge0, genType edge1, genType x) {
779 genType t = fennec::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); return t * t * (3 - 2 * t);
780}
781
782
783// Mix =================================================================================================================
784
798template<typename genType> requires(is_floating_point_v<genType>)
799constexpr genType mix(genType x, genType y, genType a) {
800 return x * (genType(1.0) - a) + y * a;
801}
802
803
804// Mix (Bool) ==========================================================================================================
805
821template<typename genType, typename genBType = bool_t> requires(is_bool_v<genBType> and is_floating_point_v<genType>)
822constexpr genType mix(genType x, genType y, genBType a) {
823 return a ? y : x;
824}
825
826
827// Internal ============================================================================================================
828
829template<typename genType, size_t...i>
830constexpr vector<genType, i...> sign(const vector<genType, i...>& x) {
831 return vector<genType, i...>(fennec::sign(x[i]) ...);
832}
833
834template<typename genType, size_t...i>
835constexpr vector<genType, i...> abs(const vector<genType, i...>& x) {
836 return vector<genType, i...>(fennec::abs(x[i]) ...);
837}
838
839template<typename genType, size_t...i>
840constexpr vector<genType, i...> floor(const vector<genType, i...>& x) {
841 return vector<genType, i...>(fennec::floor(x[i]) ...);
842}
843
844template<typename genType, size_t...i>
845constexpr vector<genType, i...> ceil(const vector<genType, i...>& x) {
846 return vector<genType, i...>(fennec::ceil(x[i]) ...);
847}
848
849template<typename genType, size_t...i>
850constexpr vector<genType, i...> round(const vector<genType, i...>& x) {
851 return vector<genType, i...>(fennec::round(x[i]) ...);
852}
853
854template<typename genType, size_t...i>
855constexpr vector<genType, i...> trunc(const vector<genType, i...>& x) {
856 return vector<genType, i...>(fennec::trunc(x[i]) ...);
857}
858
859template<typename genType, size_t...i>
860constexpr vector<genType, i...> roundEven(const vector<genType, i...>& x) {
861 return vector<genType, i...>(fennec::roundEven(x[i]) ...);
862}
863
864template<typename genType, size_t...i>
865constexpr vector<genType, i...> fract(const vector<genType, i...>& x) {
866 return vector<genType, i...>(fennec::fract(x[i]) ...);
867}
868
869template<typename genType, size_t...i>
870constexpr vector<genType, i...> mod(const vector<genType, i...>& x, genType y) {
871 return x - y * fennec::floor(x / y);
872}
873
874template<typename genType, size_t...i>
875constexpr vector<genType, i...> mod(const vector<genType, i...>& x, const vector<genType, i...>& y) {
876 return x - y * fennec::floor(x / y);
877}
878
879template<typename genType, size_t...i>
880constexpr vector<genType, i...> modf(const vector<genType, i...>& x, vector<genType, i...>& I) {
881 I = fennec::floor(x); return fennec::fract(x);
882}
883
884template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
885constexpr vector<genBType, i...> isnan(const vector<genType, i...>& x) {
886 return vector<genBType, i...>(fennec::isnan(x[i]) ...);
887}
888
889template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
890constexpr vector<genBType, i...> isinf(const vector<genType, i...>& x) {
891 return vector<genBType, i...>(fennec::isinf(x[i]) ...);
892}
893
894template<typename genType = float_t, typename genIType = int_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
895constexpr vector<genIType, i...> floatBitsToInt(const vector<genType, i...>& x) {
896 return vector<genIType, i...>(fennec::bit_cast<genIType>(x[i])...);
897}
898
899template<typename genType = float_t, typename genUType = uint_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
900constexpr vector<genUType, i...> floatBitsToUint(const vector<genType, i...>& x) {
901 return vector<genUType, i...>(fennec::bit_cast<genUType>(x[i])...);
902}
903
904template<typename genType = float_t, typename genIType = int_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
905constexpr vector<genType, i...> intBitsToFloat(const vector<genIType, i...>& x) {
906 return vector<genType, i...>(fennec::bit_cast<genType>(x[i]) ...);
907}
908
909template<typename genType = float_t, typename genUType = uint_t, size_t...i> requires(is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
910constexpr vector<genType, i...> uintBitsToFloat(const vector<genUType, i...>& x) {
911 return vector<genType, i...>(fennec::bit_cast<genType>(x[i]) ...);
912}
913
914template<typename genType, size_t...i>
915constexpr vector<genType, i...> fma(const vector<genType, i...>& a, const vector<genType, i...>& b, const vector<genType, i...>& c) {
916 return vector<genType, i...>(fennec::fma(a[i], b[i], c[i]) ...);
917}
918
919template<typename genType, typename genIType = int_t, size_t...i> requires(is_integral_v<genIType>)
920constexpr vector<genType, i...> frexp(const vector<genType, i...>& x, vector<genIType, i...>& exp) {
921 return vector<genType, i...>(fennec::frexp(x[i], exp[i])...);
922}
923
924template<typename genType, typename genIType = int_t, size_t...i> requires(is_integral_v<genIType>)
925constexpr vector<genType, i...> ldexp(const vector<genType, i...>& x, const vector<genIType, i...>& exp) {
926 return vector<genType, i...>(fennec::ldexp(x[i], exp[i])...);
927}
928
929template<typename genType, size_t...i>
930constexpr vector<genType, i...> min(genType x, const vector<genType, i...>& y) {
931 return vector<genType, i...>(fennec::min(x, y[i]) ...);
932}
933
934template<typename genType, size_t...i>
935constexpr vector<genType, i...> min(const vector<genType, i...>& x, genType y) {
936 return vector<genType, i...>(fennec::min(x[i], y) ...);
937}
938
939template<typename genType, size_t...i>
940constexpr vector<genType, i...> min(const vector<genType, i...>& x, const vector<genType, i...>& y) {
941 return vector<genType, i...>(fennec::min(x[i], y[i]) ...);
942}
943
944template<typename genType, size_t...i>
945constexpr vector<genType, i...> max(genType x, const vector<genType, i...>& y) {
946 return vector<genType, i...>(fennec::max(x, y[i]) ...);
947}
948
949template<typename genType, size_t...i>
950constexpr vector<genType, i...> max(const vector<genType, i...>& x, genType y) {
951 return vector<genType, i...>(fennec::max(x[i], y) ...);
952}
953
954template<typename genType, size_t...i>
955constexpr vector<genType, i...> max(const vector<genType, i...>& x, const vector<genType, i...>& y) {
956 return vector<genType, i...>(fennec::max(x[i], y[i]) ...);
957}
958
959template<typename genType, size_t...i>
960constexpr vector<genType, i...> clamp(const vector<genType, i...>& x, genType minVal, genType maxVal) {
961 return vector<genType, i...>(fennec::min(fennec::max(x[i], minVal), maxVal)...);
962}
963
964template<typename genType, size_t...i>
965constexpr vector<genType, i...> clamp(const vector<genType, i...>& x, const vector<genType, i...>& minVal, const vector<genType, i...>& maxVal) {
966 return vector<genType, i...>(fennec::min(fennec::max(x[i], minVal[i]), maxVal[i])...);
967}
968
969template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
970constexpr vector<genType, i...> step(genType edge, const vector<genType, i...>& x) {
971 return vector<genType, i...>(fennec::step(edge, x[i]) ...);
972}
973
974template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
975constexpr vector<genType, i...> step(const vector<genType, i...>& edge, const vector<genType, i...>& x) {
976 return vector<genType, i...>(fennec::step(edge[i], x[i]) ...);
977}
978
979template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
980constexpr vector<genType, i...> smoothstep(genType edge0, genType edge1, const vector<genType, i...>& x) {
981 return vector<genType, i...>(fennec::smoothstep(edge0, edge1, x[i]) ...);
982}
983
984template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
985constexpr vector<genType, i...> smoothstep(const vector<genType, i...>& edge0, const vector<genType, i...>& edge1, const vector<genType, i...>& x) {
986 return vector<genType, i...>(fennec::smoothstep(edge0[i], edge1[i], x[i]) ...);
987}
988
989template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
990constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, genType a) {
991 return x * (genType(1.0) - a) + y * a;
992}
993
994template<typename genType, size_t...i> requires(is_floating_point_v<genType>)
995constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, const vector<genType, i...>& a) {
996 return x * (genType(1.0) - a) + y * a;
997}
998
999template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType> and is_floating_point_v<genType>)
1000constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, genBType a) {
1001 return genDType((a ? y[i] : x[i])...);
1002}
1003
1004
1005template<typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType>)
1006constexpr vector<genBType, i...> mix(const vector<genBType, i...>& x, const vector<genBType, i...>& y, const vector<genBType, i...>& a) {
1007 return genBType((a[i] ? y[i] : x[i])...);
1008}
1009
1010template<typename genType, typename genBType = bool_t, size_t...i> requires(is_bool_v<genBType> and is_floating_point_v<genType>)
1011constexpr vector<genType, i...> mix(const vector<genType, i...>& x, const vector<genType, i...>& y, const vector<genBType, i...>& a) {
1012 return genDType((a[i] ? y[i] : x[i])...);
1013}
1014
1015
1017
1018
1019}
1020
1021#endif // FENNEC_MATH_COMMON_H
constexpr genType exp(genType x)
Returns the natural exponentiation of , i.e., .
Definition exponential.h:122
Limits
constexpr genType min(genType x, genType y)
Returns if otherwise it returns .
Definition common.h:688
constexpr genBType isnan(genType x)
Returns true if holds a NaN. Returns false otherwise.
Definition common.h:517
constexpr genType uintBitsToFloat(genUType x)
Returns a floating-point value corresponding to a signed or unsigned integer encoding of a floating-p...
Definition common.h:594
constexpr genUType floatBitsToUint(genType x)
Returns a signed or unsigned integer value representing the encoding of a floating-point value....
Definition common.h:566
constexpr genType mod(genType x, genType y)
Modulus. Returns .
Definition common.h:479
constexpr genType smoothstep(genType edge0, genType edge1, genType x)
Returns if and if , and performs smooth Hermite interpolation between and when .
Definition common.h:778
constexpr genType step(genType edge, genType x)
Returns if , otherwise, it returns .
Definition common.h:750
constexpr genType intBitsToFloat(genIType x)
Definition common.h:574
constexpr genType ldexp(genType x, genIType exp)
Builds a floating-point number from and the corresponding integral exponent of two in .
Definition common.h:661
constexpr genType max(genType x, genType y)
Returns if , otherwise it returns .
Definition common.h:705
constexpr genType trunc(genType x)
Returns a value equal to the nearest integer that is less than or equal to .
Definition common.h:399
constexpr genType roundEven(genType x)
Returns a value equal to the nearest integer. In C++, a fractional part of will always round to the ...
Definition common.h:418
constexpr genType ceil(genType x)
Returns a value equal to the nearest integer that is greater than or equal to .
Definition common.h:365
constexpr genType sign(genType x)
Returns if , if , or if .
Definition common.h:306
constexpr genType floor(genType x)
Returns a value equal to the nearest integer that is less than or equal to .
Definition common.h:348
constexpr genType mix(genType x, genType y, genType a)
Returns the linear blend of and , i.e., .
Definition common.h:799
constexpr genType fma(genType a, genType b, genType c)
Computes and returns .
Definition common.h:613
constexpr genType frexp(genType x, genIType &exp)
Splits into a floating-point significand in the range , and an integral exponent of two,...
Definition common.h:636
constexpr genType abs(genType x)
Returns if , otherwise it returns .
Definition common.h:322
constexpr genType fract(genType x)
Returns .
Definition common.h:462
constexpr genIType floatBitsToInt(genType x)
Definition common.h:544
constexpr genType clamp(genType x, genType minVal, genType maxVal)
Returns .
Definition common.h:723
constexpr genType round(genType x)
Returns a value equal to the nearest integer. In C++, a fractional part of will always round up.
Definition common.h:382
constexpr genBType isinf(genType x)
Returns true if holds a positive or negative infinity. Returns false otherwise.
Definition common.h:533
constexpr genType modf(genType x, genType &i)
Returns the fractional part of and stores the integral part in .
Definition common.h:496
constexpr genType y()
Definition constants.h:672
constexpr genType e()
Definition constants.h:635
static constexpr TypeT epsilon()
Returns the difference between 1.0 and the next representable value.
Definition limits.h:255
bool bool_t
A conditional type.
Definition types.h:214
unsigned int uint_t
An unsigned integer type, size varies by implementation, but typically 32-bit.
Definition types.h:226
signed int int_t
A signed integer type, size varies by implementation, but typically 32-bit.
Definition types.h:225
float float_t
A single-precision floating-point type, typically with a size of 32-bits.
Definition types.h:234
the Vectors