1 /**
2  * Copyright:       Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved
3  * Authors:         $(Gabriel Gheorghe)
4  * License:         $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007)
5  * Source:			$(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/math/functions.d, _functions.d)
6  * Documentation:
7  * Coverage:
8  */
9 module liberty.math.functions;
10 import std.traits : isIntegral, isSigned, isFloatingPoint;
11 public import std.math;
12 //import std.math : trunc, floor, asin, acos, sin, PI;
13 version (D_InlineAsm_X86) {
14     version = AsmX86;
15 } else version (D_InlineAsm_X86_64) {
16     version = AsmX86;
17 }
18 /// Convert from radians to degrees.
19 T degrees(T)(T x) pure nothrow @safe @nogc if (!isIntegral!T) {
20     return x * (180 / PI);
21 }
22 /// Convert from degrees to radians.
23 T radians(T)(T x) pure nothrow @safe @nogc if (!isIntegral!T) {
24     return x * (PI / 180);
25 }
26 /// Linear interpolation.
27 S lerp(S, T)(S a, S b, T t) pure nothrow @safe @nogc if (is(typeof(t * b + (1 - t) * a) : S)) {
28     return t * b + (1 - t) * a;
29 }
30 /// Clamp x in [min, max].
31 T clamp(T)(T x, T min, T max) pure nothrow @safe @nogc {
32     if (x < min) {
33 	    return min;
34     } else if (x > max) {
35 	    return max;
36     }
37     return x;
38 }
39 /// Integer truncation.
40 long ltrunc(real x) nothrow @safe @nogc {
41     return cast(long)(trunc(x));
42 }
43 /// Integer flooring.
44 long lfloor(real x) nothrow @safe @nogc {
45     return cast(long)(floor(x));
46 }
47 /// Returns fractional part of x.
48 T fract(T)(real x) nothrow @safe @nogc {
49     return x - lfloor(x);
50 }
51 /// Safe asin. Input clamped to [-1, 1].
52 T safeAsin(T)(T x) pure nothrow @safe @nogc {
53 	return asin(clamp!T(x, -1, 1));
54 }
55 /// Safe acos. Input clamped to [-1, 1].
56 T safeAcos(T)(T x) pure nothrow @safe @nogc {
57 	return acos(clamp!T(x, -1, 1));
58 }
59 
60 /// If x < edge => 0.0 is returned, otherwise 1.0 is returned.
61 T step(T)(T edge, T x) pure nothrow @safe @nogc {
62 	return (x < edge) ? 0 : 1;
63 }
64 ///
65 T smoothStep(T)(T a, T b, T t) pure nothrow @safe @nogc {
66 	if (t <= a) {
67 		return 0;
68 	} else if (t >= b) {
69 		return 1;
70 	}
71 	T x = (t - a) / (b - a);
72 	return x * x * (3 - 2 * x);
73 }
74 /// Returns true of i is a power of 2.
75 bool isPowerOf2(T)(T i) pure nothrow @safe @nogc if (isIntegral!T)
76 in {
77 	assert(i >= 0);
78 } do {
79 	return (i != 0) && ((i & (i - 1)) == 0);
80 }
81 
82 /// Integer log2.
83 int ilog2(T)(T i) nothrow @safe @nogc if (isIntegral!T)
84 in {
85 	assert(i > 0);
86 	assert(isPowerOf2(i));
87 } do {
88 	int result = 0;
89 	while (i > 1) {
90 		i = i / 2;
91 		result++;
92 	}
93 	return result;
94 }
95 /// Computes next power of 2.
96 int nextPowerOf2(int i) pure nothrow @safe @nogc
97 out(result) {
98 	assert(isPowerOf2(result));
99 } do {
100 	int v = i - 1;
101 	v |= v >> 1;
102 	v |= v >> 2;
103 	v |= v >> 4;
104 	v |= v >> 8;
105 	v |= v >> 16;
106 	v++;
107 	return v;
108 }
109 /// Computes next power of 2.
110 long nextPowerOf2(long i) pure nothrow @safe @nogc
111 out(result) {
112 	assert(isPowerOf2(result));
113 } do {
114 	long v = i - 1;
115 	v |= v >> 1;
116 	v |= v >> 2;
117 	v |= v >> 4;
118 	v |= v >> 8;
119 	v |= v >> 16;
120 	v |= v >> 32;
121 	v++;
122 	return v;
123 }
124 /// Computes sin(x)/x accurately.
125 T sinOverX(T)(T x) pure nothrow @safe @nogc {
126 	if (1 + x * x == 1) {
127 		return 1;
128 	}
129 	return sin(x) / x;
130 }
131 
132 /// Signed integer modulo a/b where the remainder is guaranteed to be in [0..b], even if a is negative.
133 /// Only supports positive dividers.
134 T moduloWrap(T)(T a, T b) pure nothrow @safe @nogc if (isSigned!T)
135 in {
136 	assert(b > 0);
137 } do {
138 	T x;
139 	if (a >= 0) {
140 		a = a % b;
141 	} else {
142 		auto rem = a % b;
143 		x = (rem == 0) ? 0 : (-rem + b);
144 	}
145 	assert(x >= 0 && x < b);
146 	return x;
147 }
148 ///
149 pure nothrow @safe @nogc unittest {
150 	assert(nextPowerOf2(3) == 4);
151 	assert(nextPowerOf2(21) == 32);
152 	assert(nextPowerOf2(1000) == 1024);
153 }
154 /// SSE approximation of reciprocal square root.
155 T inverseSqrt(T)(T x) pure nothrow @safe @nogc if (isFloatingPoint!T) {
156 	version(AsmX86) {
157 		static if (is(T == float)) {
158 			float result;
159 			asm pure nothrow @safe @nogc {
160 				movss XMM0, x;
161 				rsqrtss XMM0, XMM0;
162 				movss result, XMM0;
163 			}
164 			return result;
165 		} else {
166 			return 1 / sqrt(x);
167 		}
168 	} else {
169 		return 1 / sqrt(x);
170 	}
171 }
172 ///
173 pure nothrow @safe @nogc unittest {
174 	assert (abs(inverseSqrt!float(1) - 1) < 1e-3 );
175 	assert (abs(inverseSqrt!double(1) - 1) < 1e-3 );
176 }