1 module godot.vector; 2 3 import godot.vector2: Vector2, Vector2i; 4 import godot.vector3: Vector3, Vector3i; 5 import godot.vector4: Vector4, Vector4i; 6 7 import std.traits; 8 9 /// Vector structure with data accesible with `[N]` or swizzling 10 struct Vector(T, size_t N) if (isNumeric!T && N > 0) { 11 /// Vector data 12 public T[N] data = [ 0 ]; 13 14 /// Alias to allow easy `data` access 15 alias data this; 16 /// Alias to data type (e.g. float, int) 17 alias dataType = T; 18 /** 19 Alias to vector type. Can be used to contruct vectors 20 of same type 21 --- 22 auto rvec7 = Vector!(real, 7)(10); 23 auto rvec7s = rvec7.VecType(20); 24 --- 25 */ 26 alias VecType = Vector!(T, N); 27 /// Alias to vector size 28 enum size_t size = N; 29 30 /** 31 Constructs Vector from components. If no components present 32 vector will be filled with 0 33 Example: 34 --- 35 // Vector can be constructed manually or with aliases 36 auto v1 = Vector!(int, 2)(10, 20); 37 auto v2 = ivec2(10, 20); 38 auto v3 = Vector2i(10, 20); 39 auto v4 = Vector2!int(10, 20); 40 // Also vector can be given only one value, 41 // in that case it'll be filled with that value 42 auto v5 = ivec4(13); 43 auto v6 = vec4(0.3f); 44 // Vector values can be accessed with array slicing, 45 // by using color symbols or swizzling 46 float v6x = v6.x; 47 float v6z = v6.z; 48 float[] v6yzx = v6.yzx; 49 float v6y = v6[1]; 50 // Valid vector accessors are: 51 // Vector2 - [x, y], [w, h], [u, v] 52 // Vector3 - [x, y, z], [w, h, d], [u, v, t], [r, g, b] 53 // Vector4 - [x, y, z, w], [r, g, b, a] 54 // Other sizes must be accessed with index 55 --- 56 */ 57 this(in T val) { 58 foreach (i; 0 .. size) { data[i] = val; } 59 } 60 /// Ditto 61 this(in T[N] vals...) { 62 data = vals; 63 } 64 65 /* -------------------------------------------------------------------------- */ 66 /* UNARY OPERATIONS OVERRIDES */ 67 /* -------------------------------------------------------------------------- */ 68 69 /// opBinary x [+, -, *, /, %] y 70 auto opBinary(string op, R)(in Vector!(R, N) b) const if ( isNumeric!R ) { 71 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 72 VecType ret = VecType(); 73 foreach (i; 0 .. size) { mixin( "data[i] = data[i] " ~ op ~ " b.data[i];" ); } 74 return ret; 75 } 76 77 /// Ditto 78 auto opBinaryRight(string op, R)(in Vector!(R, N) b) const if ( isNumeric!R ) { 79 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 80 VecType ret = VecType(); 81 foreach (i; 0 .. size) { mixin( "ret[i] = b.data[i] " ~ op ~ " data[i];" ); } 82 return ret; 83 } 84 85 /// Ditto 86 auto opBinary(string op, R)(in R b) const if ( isNumeric!R ) { 87 // assert(this !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 88 VecType ret = VecType(); 89 foreach (i; 0 .. size) { mixin( "data[i] = data[i] " ~ op ~ " b;" ); } 90 return ret; 91 } 92 93 /// Ditto 94 auto opBinaryRight(string op, R)(in R b) const if ( isNumeric!R ) { 95 // assert(this !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 96 VecType ret = VecType(); 97 foreach (i; 0 .. size) { mixin( "ret[i] = b " ~ op ~ " data[i];" ); } 98 return ret; 99 } 100 101 /// opEquals x == y 102 bool opEquals(R)(in Vector!(R, size) b) const if ( isNumeric!R ) { 103 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 104 bool eq = true; 105 foreach (i; 0 .. size) { eq = eq && data[i] == b.data[i]; } 106 return eq; 107 } 108 109 /// opCmp x [< > <= >=] y 110 int opCmp(R)(in Vector!(R, N) b) const if ( isNumeric!R ) { 111 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 112 T al = length; 113 T bl = b.length; 114 if (al == bl) return 0; 115 if (al < bl) return -1; 116 return 1; 117 } 118 119 /// opUnary [-, +, --, ++] x 120 auto opUnary(string op)() if(op == "-"){ 121 // assert(this !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 122 VecType ret = VecType(); 123 if (op == "-") 124 foreach (i; 0 .. size) { data[i] = -data[i]; } 125 return ret; 126 } 127 128 /// opOpAssign x [+, -, *, /, %]= y 129 auto opOpAssign(string op, R)( in Vector!(R, N) b ) if ( isNumeric!R ) { 130 // assert(/* this !is null && */ b !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 131 foreach (i; 0 .. size) { mixin( "data[i] = data[i] " ~ op ~ " b.data[i];" ); } 132 return this; 133 } 134 135 /// Ditto 136 auto opOpAssign(string op, R)( in R b ) if ( isNumeric!R ) { 137 // assert(this !is null, "\nOP::ERROR nullptr Vector!" ~ size.to!string ~ "."); 138 foreach (i; 0 .. size) { mixin( "data[i] = data[i] " ~ op ~ " b;" ); } 139 return this; 140 } 141 142 /// Returns hash 143 size_t toHash() const @safe nothrow { 144 return typeid(data).getHash(&data); 145 } 146 147 // incredible magic from sily.meta 148 // idk how it works but it works awesome 149 // and im not going to touch it at all 150 static if (N == 2 || N == 3 || N == 4) { 151 static if (N == 2) enum AccessString = "x y|w h|u v"; 152 else 153 static if (N == 3) enum AccessString = "x y z|w h d|u v t|r g b"; 154 else 155 static if (N == 4) enum AccessString = "x y z w|r g b a"; 156 157 mixin accessByString!(T, N, "data", AccessString); 158 } 159 160 /// Returns copy of vector 161 public VecType copyof() { 162 return VecType(data); 163 } 164 165 /// Returns string representation of vector: `[1.00, 1.00,... , 1.00]` 166 public string toString() const { 167 import std.conv : to; 168 import std.string: format; 169 string s; 170 s ~= "["; 171 foreach (i; 0 .. size) { 172 s ~= isFloatingPoint!T ? format("%.2f", data[i]) : format("%d", data[i]); 173 if (i != size - 1) s ~= ", "; 174 } 175 s ~= "]"; 176 return s; 177 } 178 179 /// Returns pointer to data 180 T* ptr() return { 181 return data.ptr; 182 } 183 184 /* ------------------------------ Godot Vectors ----------------------------- */ 185 186 static if(N == 2) { 187 static if (isFloatingPoint!T) { 188 Vector2 godotVector() { 189 return Vector2(data); 190 } 191 } else { 192 Vector2i godotVector() { 193 return Vector2i(data); 194 } 195 } 196 } 197 198 static if(N == 3) { 199 static if (isFloatingPoint!T) { 200 Vector3 godotVector() { 201 return Vector3(data); 202 } 203 } else { 204 Vector3i godotVector() { 205 return Vector3i(data); 206 } 207 } 208 } 209 210 static if(N == 4) { 211 static if (isFloatingPoint!T) { 212 Vector4 godotVector() { 213 return Vector4(data); 214 } 215 } else { 216 Vector4i godotVector() { 217 return Vector4i(data); 218 } 219 } 220 } 221 222 /* -------------------------------------------------------------------------- */ 223 /* STATIC GETTERS AND SETTERS */ 224 /* -------------------------------------------------------------------------- */ 225 226 /// Constructs predefined vector 227 static alias zero = () => VecType(0); 228 /// Ditto 229 static alias one = () => VecType(1); 230 231 static if(isFloatingPoint!T) { 232 /// Ditto 233 static alias inf = () => VecType(float.infinity); 234 } 235 236 static if(N == 2) { 237 /// Ditto 238 static alias left = () => VecType(-1, 0); 239 /// Ditto 240 static alias right = () => VecType(1, 0); 241 /// Ditto 242 static alias up = () => VecType(0, -1); 243 /// Ditto 244 static alias down = () => VecType(0, 1); 245 } 246 247 static if(N == 3) { 248 static alias forward = () => VecType(0, 0, -1); 249 /// Ditto 250 static alias back = () => VecType(0, 0, 1); 251 /// Ditto 252 static alias left = () => VecType(-1, 0, 0); 253 /// Ditto 254 static alias right = () => VecType(1, 0, 0); 255 /// Ditto 256 static alias up = () => VecType(0, 1, 0); 257 /// Ditto 258 static alias down = () => VecType(0, -1, 0); 259 } 260 }