1 module prova.math.matrix; 2 3 import prova.math, 4 std.algorithm.mutation, 5 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 foreach(col; 0 .. 4) { 148 result[0][col] = array[0][col] * x; 149 result[1][col] = array[1][col] * y; 150 result[2][col] = array[2][col] * z; 151 result[3][col] = array[3][col]; 152 } 153 154 return result; 155 } 156 157 /// 158 Matrix translate(Vector2 vector) const 159 { 160 return translate(vector.x, vector.y, 0); 161 } 162 163 /// 164 Matrix translate(Vector3 vector) const 165 { 166 return translate(vector.x, vector.y, vector.z); 167 } 168 169 /// 170 Matrix translate(float x, float y) const 171 { 172 return translate(x, y, 0); 173 } 174 175 /// 176 Matrix translate(float x, float y, float z) const 177 { 178 Matrix translation = identity; 179 translation[0][3] = x; 180 translation[1][3] = y; 181 translation[2][3] = z; 182 183 return translation * this; 184 } 185 186 /// 187 Matrix transpose() const 188 { 189 Matrix transposition; 190 191 foreach(x; 0 .. 4) 192 foreach(y; 0 .. 4) 193 transposition[x][y] = array[y][x]; 194 195 return transposition; 196 } 197 198 /// 199 Matrix invert() const 200 { 201 // calculating inverse using row operations 202 Matrix identity = Matrix.identity; 203 float[8][4] appendedMatrix; 204 205 // setup 206 foreach(row; 0 .. 4) 207 appendedMatrix[row] = array[row] ~ identity[row]; 208 209 // down 210 foreach(i; 0 .. 4) { 211 float denominator = appendedMatrix[i][i]; 212 213 if(denominator == 0) 214 foreach(col; 0 .. 4) 215 foreach(row; i .. 4) { 216 denominator = appendedMatrix[row][col]; 217 218 if(denominator == 0) 219 continue; 220 221 swap(appendedMatrix[i], appendedMatrix[row]); 222 } 223 224 appendedMatrix[i][] *= 1 / denominator; 225 226 foreach(j; i + 1 .. 4) 227 appendedMatrix[j][] += appendedMatrix[i][] * -appendedMatrix[j][i]; 228 } 229 230 // up 231 foreach_reverse(i; 1 .. 4) 232 foreach_reverse(j; 0 .. i) 233 appendedMatrix[j][] += appendedMatrix[i][] * -appendedMatrix[j][i]; 234 235 // storing results 236 Matrix result; 237 238 foreach(i; 0 .. 4) 239 result.array[i] = appendedMatrix[i][4 .. 8]; 240 241 return result; 242 } 243 244 ref float[4] opIndex(int i) 245 { 246 return array[i]; 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 Matrix opSub(Matrix matrix) const 259 { 260 foreach(y; 0 .. 4) 261 foreach(x; 0 .. 4) 262 matrix[y][x] -= array[y][x]; 263 264 return matrix; 265 } 266 267 Matrix opMul(Matrix matrix) const 268 { 269 Matrix result; 270 271 foreach(y; 0 .. 4) 272 foreach(x; 0 .. 4) 273 foreach(i; 0 .. 4) 274 result[y][x] += array[y][i] * matrix[i][x]; 275 276 return result; 277 } 278 279 Vector4 opMul(Vector4 vector) const 280 { 281 float[4] result; 282 283 foreach(i; 0 .. 4) { 284 result[i] = array[0][i] * vector.x + 285 array[1][i] * vector.y + 286 array[2][i] * vector.z + 287 array[3][i] * vector.w; 288 } 289 290 return Vector4(result[0], result[1], result[2], result[3]); 291 } 292 293 Vector3 opMul(Vector3 vector) const 294 { 295 float[3] result; 296 297 foreach(i; 0 .. 3) { 298 result[i] = array[0][i] * vector.x + 299 array[1][i] * vector.y + 300 array[2][i] * vector.z + 301 array[3][i]; 302 } 303 304 return Vector3(result[0], result[1], result[2]); 305 } 306 307 Vector2 opMul(Vector2 vector) const 308 { 309 float[2] result; 310 311 foreach(i; 0 .. 2) { 312 result[i] = array[0][i] * vector.x + 313 array[1][i] * vector.y + 314 array[3][i]; 315 } 316 317 return Vector2(result[0], result[1]); 318 } 319 320 Matrix opMul(float a) const 321 { 322 Matrix matrix; 323 324 foreach(y; 0 .. 4) 325 foreach(x; 0 .. 4) 326 matrix[y][x] = array[y][x] * a; 327 328 return matrix; 329 } 330 331 Matrix opDiv(float a) const 332 { 333 Matrix matrix; 334 335 foreach(y; 0 .. 4) 336 foreach(x; 0 .. 4) 337 matrix[y][x] = array[y][x] / a; 338 339 return matrix; 340 } 341 }