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 }