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)
6  * Documentation:
7  * Coverage:
8 **/
9 module liberty.math.functions;
10 
11 public import std.math;
12 import std.traits : isIntegral, isSigned, isFloatingPoint;
13 
14 import liberty.math.vector;
15 
16 version (D_InlineAsm_X86) {
17   version = AsmX86;
18 } else version (D_InlineAsm_X86_64) {
19   version = AsmX86;
20 }
21 
22 /**
23  * Convert from radians to degrees.
24 **/
25 T degrees(T)(T x)   if (!isIntegral!T) {
26   return x * (180 / PI);
27 }
28 
29 /**
30  * Convert from degrees to radians.
31 **/
32 T radians(T)(T x)   if (!isIntegral!T) {
33   return x * (PI / 180);
34 }
35 
36 /**
37  * Linear interpolation.
38 **/
39 S lerp(S, T)(S a, S b, T t)   if (is(typeof(t * b + (1 - t) * a) : S)) {
40   return t * b + (1 - t) * a;
41 }
42 
43 /**
44  * Clamp x in [min, max].
45 **/
46 T clamp(T)(T x, T min, T max)   {
47   if (x < min) {
48     return min;
49   } else if (x > max) {
50     return max;
51   }
52   return x;
53 }
54 
55 /**
56  * Integer truncation.
57 **/
58 long ltrunc(real x)  {
59   return cast(long)(trunc(x));
60 }
61 
62 /**
63  * Integer flooring.
64 **/
65 long lfloor(real x)  {
66   return cast(long)(floor(x));
67 }
68 
69 /**
70  * Returns fractional part of x.
71 **/
72 T fract(T)(real x)  {
73   return x - lfloor(x);
74 }
75 
76 /**
77  * Safe asin. Input clamped to [-1, 1].
78 **/
79 T safeAsin(T)(T x)   {
80 	return asin(clamp!T(x, -1, 1));
81 }
82 
83 /**
84  * Safe acos. Input clamped to [-1, 1].
85 **/
86 T safeAcos(T)(T x)   {
87 	return acos(clamp!T(x, -1, 1));
88 }
89 
90 /**
91  * If x < edge => 0.0 is returned, otherwise 1.0 is returned.
92 **/
93 T step(T)(T edge, T x)   {
94 	return (x < edge) ? 0 : 1;
95 }
96 
97 /**
98  *
99 **/
100 T smoothStep(T)(T a, T b, T t)   {
101 	if (t <= a) {
102 		return 0;
103 	} else if (t >= b) {
104 		return 1;
105 	}
106 	T x = (t - a) / (b - a);
107 	return x * x * (3 - 2 * x);
108 }
109 
110 /**
111  * Returns true of i is a power of 2.
112 **/
113 bool isPowerOf2(T)(T i)   if (isIntegral!T)
114 in {
115 	assert(i >= 0);
116 } do {
117 	return (i != 0) && ((i & (i - 1)) == 0);
118 }
119 
120 /**
121  * Integer log2.
122 **/
123 int ilog2(T)(T i)  if (isIntegral!T)
124 in {
125 	assert(i > 0);
126 	assert(isPowerOf2(i));
127 } do {
128 	int result;
129 	while (i > 1) {
130 		i = i / 2;
131 		result++;
132 	}
133 	return result;
134 }
135 
136 /**
137  * Computes next power of 2.
138 **/
139 int nextPowerOf2(int i)  
140 out(result) {
141 	assert(isPowerOf2(result));
142 } do {
143 	int v = i - 1;
144 	v |= v >> 1;
145 	v |= v >> 2;
146 	v |= v >> 4;
147 	v |= v >> 8;
148 	v |= v >> 16;
149 	v++;
150 	return v;
151 }
152 
153 /**
154  * Computes next power of 2.
155 **/
156 long nextPowerOf2(long i)  
157 out(result) {
158 	assert(isPowerOf2(result));
159 } do {
160 	long v = i - 1;
161 	v |= v >> 1;
162 	v |= v >> 2;
163 	v |= v >> 4;
164 	v |= v >> 8;
165 	v |= v >> 16;
166 	v |= v >> 32;
167 	v++;
168 	return v;
169 }
170 
171 /**
172  * Computes sin(x)/x accurately.
173 **/
174 T sinOverX(T)(T x)   {
175 	if (1 + x * x == 1) {
176 		return 1;
177 	}
178 	return sin(x) / x;
179 }
180 
181 /**
182  * Signed integer modulo a/b where the remainder is guaranteed to be in [0..b], even if a is negative.
183  * Only supports positive dividers.
184 **/
185 T moduloWrap(T)(T a, T b)   if (isSigned!T)
186 in {
187 	assert(b > 0);
188 } do {
189 	T x;
190 	if (a >= 0) {
191 		a = a % b;
192 	} else {
193 		const rem = a % b;
194 		x = (rem == 0) ? 0 : (-rem + b);
195 	}
196 	assert(x >= 0 && x < b);
197 	return x;
198 }
199 
200 /**
201  *
202 **/
203   unittest {
204 	assert(nextPowerOf2(3) == 4);
205 	assert(nextPowerOf2(21) == 32);
206 	assert(nextPowerOf2(1000) == 1024);
207 }
208 
209 /**
210  * SSE approximation of reciprocal square root.
211 **/
212 T inverseSqrt(T)(T x)   if (isFloatingPoint!T) {
213 	version(AsmX86) {
214 		static if (is(T == float)) {
215 			float result;
216 			asm   {
217 				movss XMM0, x;
218 				rsqrtss XMM0, XMM0;
219 				movss result, XMM0;
220 			}
221 			return result;
222 		} else {
223 			return 1 / sqrt(x);
224 		}
225 	} else {
226 		return 1 / sqrt(x);
227 	}
228 }
229 
230 /**
231  *
232 **/
233   unittest {
234 	assert(abs(inverseSqrt!float(1) - 1) < 1e-3 );
235 	assert(abs(inverseSqrt!double(1) - 1) < 1e-3 );
236 }
237 
238 /**
239  *
240 **/
241 float barryCentric(Vector3F p1, Vector3F p2, Vector3F p3, Vector2F pos) {
242 	const float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
243 	const float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
244 	const float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
245 	const float l3 = 1.0f - l1 - l2;
246 	return l1 * p1.y + l2 * p2.y + l3 * p3.y;
247 }