1 /** 2 Vector struct, which performs basic 3D vector math operations. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.core.vector3; 14 15 import godot.core.defs; 16 import godot.core.basis; 17 import godot.core..string; 18 19 import std.math; 20 21 private bool isValidSwizzle(dstring s) 22 { 23 import std.algorithm : canFind; 24 if(s.length != 2 && s.length != 3) return false; 25 foreach(dchar c; s) 26 { 27 if(!"xyzn".canFind(c)) return false; 28 } 29 return true; 30 } 31 32 /** 33 Vector3 is one of the core classes of the engine, and includes several built-in helper functions to perform basic vector math operations. 34 */ 35 struct Vector3 36 { 37 @nogc nothrow: 38 39 enum Axis 40 { 41 x, 42 y, 43 z 44 } 45 46 union 47 { 48 struct 49 { 50 real_t x = 0; /// 51 real_t y = 0; /// 52 real_t z = 0; /// 53 } 54 55 real_t[3] coord; 56 } 57 58 import std.algorithm : count; 59 /++ 60 Swizzle the vector with x, y, z, or n. Pass floats as args for any n's; if 61 there are more n's than args, the last arg is used for the rest. If no args 62 are passed at all, 0.0 is used for each n. 63 64 The swizzle must be 2 or 3 characters, as Godot only has Vector2/3. 65 +/ 66 auto opDispatch(string swizzle, size_t nArgCount)(float[nArgCount] nArgs...) const 67 if(swizzle.isValidSwizzle && nArgCount <= swizzle.count('n')) 68 { 69 import godot.core.vector3; 70 import std.algorithm : min, count; 71 static if(swizzle.length == 2) Vector2 ret = void; 72 else Vector3 ret = void; 73 /// how many n's already appeared before ci, which equals the index into nArgs for the n at ci 74 enum ni(size_t ci) = min(nArgCount-1, swizzle[0..ci].count('n')); 75 static foreach(ci, c; swizzle) 76 { 77 static if(c == 'n') 78 { 79 static if(nArgCount == 0) ret.coord[ci] = 0f; 80 else static if(ni!ci >= nArgCount) ret.coord[ci] = nArgs[nArgCount-1]; 81 else ret.coord[ci] = nArgs[ni!ci]; 82 } 83 else ret.coord[ci] = mixin([c]); 84 } 85 return ret; 86 } 87 88 this(real_t x, real_t y, real_t z) 89 { 90 this.x = x; 91 this.y = y; 92 this.z = z; 93 } 94 95 this(real_t[3] coord) 96 { 97 this.coord = coord; 98 } 99 100 this(in Vector3 b) 101 { 102 this.x = b.x; 103 this.y = b.y; 104 this.z = b.z; 105 } 106 107 void opAssign(in Vector3 b) 108 { 109 this.x = b.x; 110 this.y = b.y; 111 this.z = b.z; 112 } 113 114 const(real_t) opIndex(int p_axis) const 115 { 116 return coord[p_axis]; 117 } 118 119 ref real_t opIndex(int p_axis) return 120 { 121 return coord[p_axis]; 122 } 123 124 Vector3 opBinary(string op)(in Vector3 other) const 125 if(op=="+" || op=="-" || op=="*" || op=="/") 126 { 127 Vector3 ret; 128 ret.x = mixin("x "~op~"other.x"); 129 ret.y = mixin("y "~op~"other.y"); 130 ret.z = mixin("z "~op~"other.z"); 131 return ret; 132 } 133 void opOpAssign(string op)(in Vector3 other) 134 if(op=="+" || op=="-" || op=="*" || op=="/") 135 { 136 x = mixin("x "~op~"other.x"); 137 y = mixin("y "~op~"other.y"); 138 z = mixin("z "~op~"other.z"); 139 } 140 141 Vector3 opUnary(string op : "-")() 142 { 143 return Vector3(-x, -y, -z); 144 } 145 146 Vector3 opBinary(string op)(in real_t scalar) const 147 if(op=="*" || op=="/") 148 { 149 Vector3 ret; 150 ret.x = mixin("x "~op~" scalar"); 151 ret.y = mixin("y "~op~" scalar"); 152 ret.z = mixin("z "~op~" scalar"); 153 return ret; 154 } 155 Vector3 opBinaryRight(string op)(in real_t scalar) const 156 if(op=="*") 157 { 158 Vector3 ret; 159 ret.x = mixin("x "~op~" scalar"); 160 ret.y = mixin("y "~op~" scalar"); 161 ret.z = mixin("z "~op~" scalar"); 162 return ret; 163 } 164 void opOpAssign(string op)(in real_t scalar) 165 if(op=="*" || op=="/") 166 { 167 x = mixin("x "~op~" scalar"); 168 y = mixin("y "~op~" scalar"); 169 z = mixin("z "~op~" scalar"); 170 } 171 172 int opCmp(in Vector3 other) const 173 { 174 import std.algorithm.comparison; 175 return cmp(this.coord[], other.coord[]); 176 } 177 178 Vector3 abs() const 179 { 180 return Vector3(fabs(x), fabs(y), fabs(z)); 181 } 182 183 Vector3 ceil() const 184 { 185 return Vector3(.ceil(x), .ceil(y), .ceil(z)); 186 } 187 188 Vector3 cross(in Vector3 b) const 189 { 190 return Vector3( 191 (y * b.z) - (z * b.y), 192 (z * b.x) - (x * b.z), 193 (x * b.y) - (y * b.x) 194 ); 195 } 196 197 Vector3 linearInterpolate(in Vector3 p_b, real_t p_t) const 198 { 199 return Vector3( 200 x+(p_t * (p_b.x-x)), 201 y+(p_t * (p_b.y-y)), 202 z+(p_t * (p_b.z-z)) 203 ); 204 } 205 alias lerp = linearInterpolate; 206 207 Vector3 cubicInterpolate(in Vector3 b, in Vector3 pre_a, in Vector3 post_b, in real_t t) const 208 { 209 Vector3 p0=pre_a; 210 Vector3 p1=this; 211 Vector3 p2=b; 212 Vector3 p3=post_b; 213 214 real_t t2 = t * t; 215 real_t t3 = t2 * t; 216 217 Vector3 ret; 218 ret = ( ( p1 * 2.0) + 219 ( -p0 + p2 ) * t + 220 ( p0 * 2.0 - p1 * 5.0 + p2 * 4 - p3 ) * t2 + 221 ( -p0 + p1 * 3.0 - p2 * 3.0 + p3 ) * t3 ) * 0.5; 222 return ret; 223 } 224 225 real_t length() const 226 { 227 real_t x2=x*x; 228 real_t y2=y*y; 229 real_t z2=z*z; 230 231 return sqrt(x2+y2+z2); 232 } 233 234 real_t lengthSquared() const 235 { 236 real_t x2=x*x; 237 real_t y2=y*y; 238 real_t z2=z*z; 239 240 return x2+y2+z2; 241 } 242 243 real_t distanceSquaredTo(in Vector3 b) const 244 { 245 return (b-this).length(); 246 } 247 248 real_t distanceTo(in Vector3 b) const 249 { 250 return (b-this).lengthSquared(); 251 } 252 253 real_t dot(in Vector3 b) const 254 { 255 return x*b.x + y*b.y + z*b.z; 256 } 257 258 Vector3 floor() const 259 { 260 return Vector3(.floor(x), .floor(y), .floor(z)); 261 } 262 263 Vector3 inverse() const 264 { 265 return Vector3( 1.0/x, 1.0/y, 1.0/z ); 266 } 267 268 int maxAxis() const 269 { 270 return (x < y) ? (y < z ? 2 : 1) : (x < z ? 2 : 0); 271 } 272 273 int minAxis() const 274 { 275 return (x < y) ? (x < z ? 0 : 2) : (y < z ? 1 : 2); 276 } 277 278 void normalize() 279 { 280 real_t l=length(); 281 if (l==0) { 282 x=y=z=0; 283 } else { 284 x/=l; 285 y/=l; 286 z/=l; 287 } 288 } 289 290 Vector3 normalized() const 291 { 292 Vector3 v = this; 293 v.normalize(); 294 return v; 295 } 296 297 Vector3 reflect(in Vector3 by) const 298 { 299 return by - this * this.dot(by) * 2.0; 300 } 301 302 Vector3 rotated(in Vector3 axis, in real_t phi) const 303 { 304 Vector3 v = this; 305 v.rotate(axis, phi); 306 return v; 307 } 308 309 void rotate(in Vector3 axis, in real_t phi) 310 { 311 this=Basis(axis,phi).xform(this); 312 } 313 314 Vector3 slide(in Vector3 by) const 315 { 316 return by - this * this.dot(by); 317 } 318 319 void snap(real_t step) 320 { 321 foreach(ref v; coord) v = (step != 0)?(.floor(v/step +0.5)*step):v; 322 } 323 324 Vector3 snapped(in real_t step) const 325 { 326 Vector3 v = this; 327 v.snap(step); 328 return v; 329 } 330 } 331 332 333 334