1 module prova.math.matrix; 2 3 import prova.math; 4 import std.algorithm.mutation; 5 import std.math; 6 7 /// Struct representing a 4x4 matrix 8 struct Matrix 9 { 10 /// array[row][column] 11 float[4][4] array = [ 12 [0, 0, 0, 0], 13 [0, 0, 0, 0], 14 [0, 0, 0, 0], 15 [0, 0, 0, 0] 16 ]; 17 18 /// 19 static @property Matrix identity() 20 { 21 Matrix identity; 22 23 foreach(i; 0 .. 4) 24 identity[i][i] = 1; 25 26 return identity; 27 } 28 29 /// 30 static Matrix ortho(float left, float right, float top, float bottom, float near, float far) 31 { 32 Matrix ortho; 33 ortho[0][0] = 2 / (right - left); 34 ortho[1][1] = 2 / (top - bottom); 35 ortho[2][2] = 2 / (near - far); 36 37 ortho[0][3] = (left + right) / (left - right); 38 ortho[1][3] = (bottom + top) / (bottom - top); 39 ortho[2][3] = (near + far) / (near - far); 40 ortho[3][3] = 1; 41 42 return ortho; 43 } 44 45 /// 46 static Matrix perspective(float width, float height, float near, float far, float fov) 47 { 48 fov = fov / 180 * PI; 49 50 const float tanHalfFov = tan(fov / 2); 51 const float range = far - near; 52 const float aspectRatio = width / height; 53 54 Matrix perspective; 55 perspective[0][0] = 1 / (tanHalfFov * aspectRatio); 56 perspective[1][1] = 1 / tanHalfFov; 57 perspective[2][2] = - (far + near) / range; 58 perspective[2][3] = - (2 * near * far) / range; 59 perspective[3][2] = -1; 60 return perspective; 61 } 62 63 /// 64 Matrix rotate(Quaternion rotation) const 65 { 66 Matrix rotationMatrix; 67 float x = rotation.x; 68 float y = rotation.y; 69 float z = rotation.z; 70 float w = rotation.w; 71 72 rotationMatrix.array = [ 73 [1 - 2 * y * y - 2 * z * z, 2 * x * y - 2 * w * z, 2 * x * z + 2 * w * y, 0 ], 74 [ 2 * x * y + 2 * w * z, 1 - 2 * x * x - 2 * z * z, 2 * y * z - 2 * w * x, 0 ], 75 [ 2 * x * z - 2 * w * y, 2 * y * z + 2 * w * x, 1 - 2 * x * x - 2 * y * y, 0 ], 76 [ 0f, 0f, 0f, 1f] 77 ]; 78 79 return rotationMatrix * this; 80 } 81 82 /// 83 Matrix rotateX(float degrees) const 84 { 85 const float angle = degrees / 180 * PI; 86 const float angleSin = sin(-angle); 87 const float angleCos = cos(-angle); 88 89 Matrix rotation = identity; 90 rotation[1][1] = angleCos; 91 rotation[1][2] = -angleSin; 92 rotation[2][1] = angleSin; 93 rotation[2][2] = angleCos; 94 95 return rotation * this; 96 } 97 98 /// 99 Matrix rotateY(float degrees) const 100 { 101 const float angle = degrees / 180 * PI; 102 const float angleSin = sin(-angle); 103 const float angleCos = cos(-angle); 104 105 Matrix rotation = identity; 106 rotation[0][0] = angleCos; 107 rotation[0][2] = angleSin; 108 rotation[2][0] = -angleSin; 109 rotation[2][2] = angleCos; 110 111 return rotation * this; 112 } 113 114 /// 115 Matrix rotateZ(float degrees) const 116 { 117 const float angle = degrees / 180 * PI; 118 const float angleSin = sin(-angle); 119 const float angleCos = cos(-angle); 120 121 Matrix rotation = identity; 122 rotation[0][0] = angleCos; 123 rotation[0][1] = -angleSin; 124 rotation[1][0] = angleSin; 125 rotation[1][1] = angleCos; 126 127 return rotation * this; 128 } 129 130 /// 131 Matrix scale(Vector2 vector) const 132 { 133 return scale(vector.x, vector.y, 1); 134 } 135 136 /// 137 Matrix scale(Vector3 vector) const 138 { 139 return scale(vector.x, vector.y, vector.z); 140 } 141 142 /// 143 Matrix scale(float x, float y, float z) const 144 { 145 Matrix result; 146 147 result[0][] = array[0][] * x; 148 result[1][] = array[1][] * y; 149 result[2][] = array[2][] * z; 150 result[3][] = array[3][]; 151 152 return result; 153 } 154 155 /// 156 Matrix translate(Vector2 vector) const 157 { 158 return translate(vector.x, vector.y, 0); 159 } 160 161 /// 162 Matrix translate(Vector3 vector) const 163 { 164 return translate(vector.x, vector.y, vector.z); 165 } 166 167 /// 168 Matrix translate(float x, float y) const 169 { 170 return translate(x, y, 0); 171 } 172 173 /// 174 Matrix translate(float x, float y, float z) const 175 { 176 Matrix translation = identity; 177 translation[0][3] = x; 178 translation[1][3] = y; 179 translation[2][3] = z; 180 181 return translation * this; 182 } 183 184 /// 185 Matrix transpose() const 186 { 187 Matrix transposition; 188 189 foreach(x; 0 .. 4) 190 foreach(y; 0 .. 4) 191 transposition[x][y] = array[y][x]; 192 193 return transposition; 194 } 195 196 /// 197 Matrix invert() const 198 { 199 // calculating inverse using row operations 200 Matrix identity = Matrix.identity; 201 float[8][4] appendedMatrix; 202 203 // setup 204 foreach(row; 0 .. 4) 205 appendedMatrix[row] = array[row] ~ identity[row]; 206 207 // down 208 foreach(i; 0 .. 4) { 209 float denominator = appendedMatrix[i][i]; 210 211 if(denominator == 0) 212 foreach(col; 0 .. 4) 213 foreach(row; i .. 4) { 214 denominator = appendedMatrix[row][col]; 215 216 if(denominator == 0) 217 continue; 218 219 swap(appendedMatrix[i], appendedMatrix[row]); 220 } 221 222 appendedMatrix[i][] *= 1 / denominator; 223 224 foreach(j; i + 1 .. 4) 225 appendedMatrix[j][] += appendedMatrix[i][] * -appendedMatrix[j][i]; 226 } 227 228 // up 229 foreach_reverse(i; 1 .. 4) 230 foreach_reverse(j; 0 .. i) 231 appendedMatrix[j][] += appendedMatrix[i][] * -appendedMatrix[j][i]; 232 233 // storing results 234 Matrix result; 235 236 foreach(i; 0 .. 4) 237 result.array[i] = appendedMatrix[i][4 .. 8]; 238 239 return result; 240 } 241 242 /// 243 ref float[4] opIndex(int i) 244 { 245 return array[i]; 246 } 247 248 /// 249 Matrix opAdd(Matrix matrix) const 250 { 251 foreach(y; 0 .. 4) 252 foreach(x; 0 .. 4) 253 matrix[y][x] += array[x][y]; 254 255 return matrix; 256 } 257 258 /// 259 Matrix opSub(Matrix matrix) const 260 { 261 foreach(y; 0 .. 4) 262 foreach(x; 0 .. 4) 263 matrix[y][x] -= array[y][x]; 264 265 return matrix; 266 } 267 268 /// 269 Matrix opMul(Matrix matrix) const 270 { 271 Matrix result; 272 273 foreach(y; 0 .. 4) 274 foreach(x; 0 .. 4) 275 foreach(i; 0 .. 4) 276 result[y][x] += array[y][i] * matrix[i][x]; 277 278 return result; 279 } 280 281 /// 282 Vector4 opMul(Vector4 vector) const 283 { 284 float[4] result; 285 286 foreach(i; 0 .. 4) { 287 result[i] = array[i][0] * vector.x + 288 array[i][1] * vector.y + 289 array[i][2] * vector.z + 290 array[i][3] * vector.w; 291 } 292 293 return Vector4(result[0], result[1], result[2], result[3]); 294 } 295 296 /// 297 Vector3 opMul(Vector3 vector) const 298 { 299 float[3] result; // x, y, z, 1 300 301 foreach(i; 0 .. 3) { 302 result[i] = array[i][0] * vector.x + 303 array[i][1] * vector.y + 304 array[i][2] * vector.z + 305 array[i][3]/* 1 */; 306 } 307 308 return Vector3(result[0], result[1], result[2]); 309 } 310 311 /// 312 Vector2 opMul(Vector2 vector) const 313 { 314 float[2] result; // x, y, 0, 1 315 316 foreach(i; 0 .. 2) { 317 result[i] = array[i][0] * vector.x + 318 array[i][1] * vector.y + 319 array[i][3]/* 1 */; 320 } 321 322 return Vector2(result[0], result[1]); 323 } 324 325 /// 326 Matrix opMul(float a) const 327 { 328 Matrix matrix; 329 330 foreach(y; 0 .. 4) 331 foreach(x; 0 .. 4) 332 matrix[y][x] = array[y][x] * a; 333 334 return matrix; 335 } 336 337 /// 338 Matrix opDiv(float a) const 339 { 340 Matrix matrix; 341 342 foreach(y; 0 .. 4) 343 foreach(x; 0 .. 4) 344 matrix[y][x] = array[y][x] / a; 345 346 return matrix; 347 } 348 }