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 Matrix rotate(Quaternion rotation) const 64 { 65 Matrix rotationMatrix; 66 float x = rotation.x; 67 float y = rotation.y; 68 float z = rotation.z; 69 float w = rotation.w; 70 71 rotationMatrix.array = [ 72 [1 - 2 * y * y - 2 * z * z, 2 * x * y - 2 * w * z, 2 * x * z + 2 * w * y, 0 ], 73 [ 2 * x * y + 2 * w * z, 1 - 2 * x * x - 2 * z * z, 2 * y * z - 2 * w * x, 0 ], 74 [ 2 * x * z - 2 * w * y, 2 * y * z + 2 * w * x, 1 - 2 * x * x - 2 * y * y, 0 ], 75 [ 0f, 0f, 0f, 1f] 76 ]; 77 78 return rotationMatrix * this; 79 } 80 81 /// 82 Matrix rotateX(float degrees) const 83 { 84 const float angle = degrees / 180 * PI; 85 const float angleSin = sin(-angle); 86 const float angleCos = cos(-angle); 87 88 Matrix rotation = identity; 89 rotation[1][1] = angleCos; 90 rotation[1][2] = -angleSin; 91 rotation[2][1] = angleSin; 92 rotation[2][2] = angleCos; 93 94 return rotation * this; 95 } 96 97 /// 98 Matrix rotateY(float degrees) const 99 { 100 const float angle = degrees / 180 * PI; 101 const float angleSin = sin(-angle); 102 const float angleCos = cos(-angle); 103 104 Matrix rotation = identity; 105 rotation[0][0] = angleCos; 106 rotation[0][2] = angleSin; 107 rotation[2][0] = -angleSin; 108 rotation[2][2] = angleCos; 109 110 return rotation * this; 111 } 112 113 /// 114 Matrix rotateZ(float degrees) const 115 { 116 const float angle = degrees / 180 * PI; 117 const float angleSin = sin(-angle); 118 const float angleCos = cos(-angle); 119 120 Matrix rotation = identity; 121 rotation[0][0] = angleCos; 122 rotation[0][1] = -angleSin; 123 rotation[1][0] = angleSin; 124 rotation[1][1] = angleCos; 125 126 return rotation * this; 127 } 128 129 /// 130 Matrix scale(Vector2 vector) const 131 { 132 return scale(vector.x, vector.y, 1); 133 } 134 135 /// 136 Matrix scale(Vector3 vector) const 137 { 138 return scale(vector.x, vector.y, vector.z); 139 } 140 141 /// 142 Matrix scale(float x, float y, float z) const 143 { 144 Matrix result; 145 146 foreach(col; 0 .. 4) { 147 result[0][col] = array[0][col] * x; 148 result[1][col] = array[1][col] * y; 149 result[2][col] = array[2][col] * z; 150 result[3][col] = array[3][col]; 151 } 152 153 return result; 154 } 155 156 /// 157 Matrix translate(Vector2 vector) const 158 { 159 return translate(vector.x, vector.y, 0); 160 } 161 162 /// 163 Matrix translate(Vector3 vector) const 164 { 165 return translate(vector.x, vector.y, vector.z); 166 } 167 168 /// 169 Matrix translate(float x, float y) const 170 { 171 return translate(x, y, 0); 172 } 173 174 /// 175 Matrix translate(float x, float y, float z) const 176 { 177 Matrix translation = identity; 178 translation[0][3] = x; 179 translation[1][3] = y; 180 translation[2][3] = z; 181 182 return translation * this; 183 } 184 185 /// 186 Matrix transpose() const 187 { 188 Matrix transposition; 189 190 foreach(x; 0 .. 4) 191 foreach(y; 0 .. 4) 192 transposition[x][y] = array[y][x]; 193 194 return transposition; 195 } 196 197 /// 198 Matrix invert() const 199 { 200 // calculating inverse using row operations 201 Matrix identity = Matrix.identity; 202 float[8][4] appendedMatrix; 203 204 // setup 205 foreach(row; 0 .. 4) 206 appendedMatrix[row] = array[row] ~ identity[row]; 207 208 // down 209 foreach(i; 0 .. 4) { 210 float denominator = appendedMatrix[i][i]; 211 212 if(denominator == 0) 213 foreach(col; 0 .. 4) 214 foreach(row; i .. 4) { 215 denominator = appendedMatrix[row][col]; 216 217 if(denominator == 0) 218 continue; 219 220 swap(appendedMatrix[i], appendedMatrix[row]); 221 } 222 223 appendedMatrix[i][] *= 1 / denominator; 224 225 foreach(j; i + 1 .. 4) 226 appendedMatrix[j][] += appendedMatrix[i][] * -appendedMatrix[j][i]; 227 } 228 229 // up 230 foreach_reverse(i; 1 .. 4) 231 foreach_reverse(j; 0 .. i) 232 appendedMatrix[j][] += appendedMatrix[i][] * -appendedMatrix[j][i]; 233 234 // storing results 235 Matrix result; 236 237 foreach(i; 0 .. 4) 238 result.array[i] = appendedMatrix[i][4 .. 8]; 239 240 return result; 241 } 242 243 ref float[4] opIndex(int i) 244 { 245 return array[i]; 246 } 247 248 Matrix opAdd(Matrix matrix) const 249 { 250 foreach(y; 0 .. 4) 251 foreach(x; 0 .. 4) 252 matrix[y][x] += array[x][y]; 253 254 return matrix; 255 } 256 257 Matrix opSub(Matrix matrix) const 258 { 259 foreach(y; 0 .. 4) 260 foreach(x; 0 .. 4) 261 matrix[y][x] -= array[y][x]; 262 263 return matrix; 264 } 265 266 Matrix opMul(Matrix matrix) const 267 { 268 Matrix result; 269 270 foreach(y; 0 .. 4) 271 foreach(x; 0 .. 4) 272 foreach(i; 0 .. 4) 273 result[y][x] += array[y][i] * matrix[i][x]; 274 275 return result; 276 } 277 278 Vector4 opMul(Vector4 vector) const 279 { 280 float[4] result; 281 282 foreach(i; 0 .. 4) { 283 result[i] = array[0][i] * vector.x + 284 array[1][i] * vector.y + 285 array[2][i] * vector.z + 286 array[3][i] * vector.w; 287 } 288 289 return Vector4(result[0], result[1], result[2], result[3]); 290 } 291 292 Vector3 opMul(Vector3 vector) const 293 { 294 float[3] result; 295 296 foreach(i; 0 .. 3) { 297 result[i] = array[0][i] * vector.x + 298 array[1][i] * vector.y + 299 array[2][i] * vector.z + 300 array[3][i]; 301 } 302 303 return Vector3(result[0], result[1], result[2]); 304 } 305 306 Vector2 opMul(Vector2 vector) const 307 { 308 float[2] result; 309 310 foreach(i; 0 .. 2) { 311 result[i] = array[0][i] * vector.x + 312 array[1][i] * vector.y + 313 array[3][i]; 314 } 315 316 return Vector2(result[0], result[1]); 317 } 318 319 Matrix opMul(float a) const 320 { 321 Matrix matrix; 322 323 foreach(y; 0 .. 4) 324 foreach(x; 0 .. 4) 325 matrix[y][x] = array[y][x] * a; 326 327 return matrix; 328 } 329 330 Matrix opDiv(float a) const 331 { 332 Matrix matrix; 333 334 foreach(y; 0 .. 4) 335 foreach(x; 0 .. 4) 336 matrix[y][x] = array[y][x] / a; 337 338 return matrix; 339 } 340 }