1 module polyplex.math.simplemath.matrix4x4; 2 import polyplex.math.simplemath; 3 import polyplex.math; 4 import std.conv; 5 6 // TODO: Redo implementation 7 public struct Matrix4x4 { 8 private float[4][4] data; 9 10 private static float[4][4] clear(float val) { 11 float[4][4] dat; 12 foreach ( x; 0 .. 4 ) { 13 foreach ( y; 0 .. 4 ) { 14 dat[x][y] = val; 15 } 16 } 17 return dat; 18 } 19 20 float opIndex(size_t x, size_t y) { 21 return data[y][x]; 22 } 23 24 float opIndex(int x, int y) { 25 return data[y][x]; 26 } 27 28 void opIndexAssign(float value, size_t x, size_t y) { 29 data[y][x] = value; 30 } 31 32 void opIndex(float value, int x, int y) { 33 data[y][x] = value; 34 } 35 36 public static Matrix4x4 Identity() { 37 float[4][4] data = clear(0); 38 foreach ( i; 0 .. 4 ) { 39 data[i][i] = 1f; 40 } 41 return Matrix4x4(data); 42 } 43 44 public Vector3 Column(int index) { 45 return Vector3(this[0,index], this[1,index], this[2,index]); 46 } 47 48 public Vector3 ToScaling() { 49 return Vector3(Column(0).Length, Column(1).Length, Column(2).Length); 50 } 51 52 public static Matrix4x4 Scaling(Vector3 scale_vec) { 53 Matrix4x4 dims = Matrix4x4.Identity; 54 dims[0,0] = scale_vec.X; 55 dims[1,1] = scale_vec.Y; 56 dims[2,2] = scale_vec.Z; 57 return dims; 58 } 59 60 /*public static Matrix4x4 Scaling(Vector3 scale_vec) { 61 float[4][4] dims = Matrix4x4.Identity.data; 62 foreach( x; 0 .. 4-1 ) { 63 foreach( y; 0 .. 4-1 ) { 64 if (x == y) dims[x][y] = scale_vec.data[x]; 65 else dims[x][y] = 0; 66 } 67 } 68 dims[4-1][4-1] = 1; 69 return Matrix4x4(dims); 70 }*/ 71 72 public static Matrix4x4 RotationX(float x_rot) { 73 Matrix4x4 dims = Matrix4x4.Identity; 74 dims[1,1] = Mathf.Cos(x_rot); 75 dims[1,2] = Mathf.Sin(x_rot); 76 dims[2,1] = -Mathf.Sin(x_rot); 77 dims[2,2] = Mathf.Cos(x_rot); 78 return dims; 79 } 80 81 public static Matrix4x4 RotationY(float y_rot) { 82 Matrix4x4 dims = Matrix4x4.Identity; 83 dims[0,0] = Mathf.Cos(y_rot); 84 dims[2,0] = Mathf.Sin(y_rot); 85 dims[0,2] = -Mathf.Sin(y_rot); 86 dims[2,2] = Mathf.Cos(y_rot); 87 return dims; 88 } 89 90 public static Matrix4x4 RotationZ(float z_rot) { 91 Matrix4x4 dims = Matrix4x4.Identity; 92 dims[0,0] = Mathf.Cos(z_rot); 93 dims[1,0] = -Mathf.Sin(z_rot); 94 dims[0,1] = Mathf.Sin(z_rot); 95 dims[1,1] = Mathf.Cos(z_rot); 96 return dims; 97 } 98 99 public static Matrix4x4 FromQuaternion(Quaternion quat) { 100 float sqx = quat.X*quat.X; 101 float sqy = quat.Y*quat.Y; 102 float sqz = quat.Z*quat.Z; 103 float sqw = quat.W*quat.W; 104 float n = 1f/(sqx+sqy+sqz+sqw); 105 106 Matrix4x4 mat = Matrix4x4.Identity; 107 108 if (sqx == 0 && sqy == 0 && sqz == 0 && sqw == 0) 109 return mat; 110 111 mat[0,0] = ( sqx - sqy - sqz + sqw) * n; 112 mat[1,1] = (-sqx + sqy - sqz + sqw) * n; 113 mat[2,2] = (-sqx - sqy + sqz + sqw) * n; 114 115 double tx = quat.X*quat.Y; 116 double ty = quat.Z*quat.W; 117 mat[1,0] = 2.0 * (tx + ty) * n; 118 mat[0,1] = 2.0 * (tx - ty) * n; 119 120 tx = quat.X*quat.Z; 121 ty = quat.Y*quat.W; 122 mat[2,0] = 2.0 * (tx - ty) * n; 123 mat[0,2] = 2.0 * (tx + ty) * n; 124 125 tx = quat.Y*quat.Z; 126 ty = quat.X*quat.W; 127 mat[2,1] = 2.0 * (tx + ty) * n; 128 mat[1,2] = 2.0 * (tx - ty) * n; 129 130 return mat; 131 } 132 public Vector3 ToTranslation() { 133 return Vector3(this[3,0], this[3,1], this[3,2]); 134 } 135 136 public float XComponent() { 137 return this[3, 0]; 138 } 139 140 public float YComponent() { 141 return this[3, 1]; 142 } 143 144 public float ZComponent() { 145 return this[3, 2]; 146 } 147 148 public Vector3 TranslatedVector() { 149 return Vector3(XComponent, YComponent, ZComponent); 150 } 151 152 public static Matrix4x4 Translation(Vector3 trans_vec) { 153 return Matrix4x4([ 154 [1f, 0f, 0f, trans_vec.X], 155 [0f, 1f, 0f, trans_vec.Y], 156 [0f, 0f, 1f, trans_vec.Z], 157 [0f, 0f, 0f, 1f] 158 ]); 159 } 160 161 public static Matrix4x4 Orthographic(float left, float right, float bottom, float top, float znear, float zfar) { 162 return Matrix4x4([ 163 [2/(right-left), 0f, 0f, -(right+left)/(right-left)], 164 [0f, 2/(top-bottom), 0f, -(top+bottom)/(top-bottom)], 165 [0f, 0f, -2/(zfar-znear), -(zfar+znear)/(zfar-znear)], 166 [0f, 0f, 0f, 1f] 167 ]); 168 } 169 170 public static Matrix4x4 OrthographicInverse(float left, float right, float bottom, float top, float znear, float zfar) { 171 return Matrix4x4([ 172 [(right-left)/2f, 0, 0, 0], 173 [0, (top-bottom)/2f, 0, 0], 174 [0, 0, (zfar-znear)/-2f, 0], 175 [(right+left)/2f, (top+bottom)/2f, (zfar+znear)/2f, 1f] 176 ]); 177 } 178 179 public Matrix4x4 Inverse() { 180 Matrix4x4 mat; 181 foreach(x; 0 .. 4) { 182 foreach(y; 0 .. 4) { 183 mat[x,y] = this[y,x]; 184 } 185 } 186 return mat; 187 } 188 189 private static float[6] prepPerspective(float width, float height, float fov, float znear, float zfar) { 190 float aspect = width/height; 191 float top = znear * Mathf.Tan(Mathf.ToRadians(fov)); 192 float bottom = -top; 193 float right = top * aspect; 194 float left = -right; 195 return [left, right, bottom, top, znear, zfar]; 196 } 197 198 public static Matrix4x4 Perspective(float width, float height, float fov, float znear, float zfar) { 199 float[6] persp_data = prepPerspective(width, height, fov, znear, zfar); 200 return perspective(persp_data[0], persp_data[1], persp_data[2], persp_data[3], persp_data[4], persp_data[5]); 201 } 202 203 private static Matrix4x4 perspective(float left, float right, float bottom, float top, float near, float far) { 204 return Matrix4x4([ 205 [(2f*near)/(right-left), 0, (right+left)/(right-left), 0], 206 [0, (2f*near)/(top-bottom), -(2f*far*near)/(far-near), 0], 207 [0, (top+bottom)/(top-bottom), -(far+near)/(far-near), 0], 208 [0, 0, -1f, 0] 209 ]); 210 } 211 212 public Matrix4x4 opBinary(string op: "*")(Matrix4x4 other) { 213 float[4][4] dim = clear(0); 214 foreach ( row; 0 .. 4 ) { 215 foreach ( column; 0 .. 4 ) { 216 foreach ( i; 0 .. 4 ) { 217 dim[row][column] += this.data[row][i] * other.data[i][column]; 218 } 219 } 220 } 221 return Matrix4x4(dim); 222 } 223 224 public Matrix4x4 Transpose() pure const nothrow { 225 Matrix4x4 temp = this; 226 static foreach( x; 0 .. 4 ) { 227 static foreach ( y; 0 .. 4 ) { 228 temp.data[x][y] = this.data[y][x]; 229 } 230 } 231 return temp; 232 } 233 234 public Matrix4x4 Translate (Vector3 trans_vec) { 235 this = Matrix4x4.Translation(trans_vec) * this; 236 return this; 237 } 238 239 public Matrix4x4 Scale(Vector3 scale_vec) { 240 this = Matrix4x4.Scaling(scale_vec) * this; 241 return this; 242 } 243 244 public Matrix4x4 RotateX(float rot) { 245 this = Matrix4x4.RotationX(rot) * this; 246 return this; 247 } 248 249 public Matrix4x4 RotateY(float rot) { 250 return Matrix4x4.RotationY(rot) * this; 251 } 252 253 public Matrix4x4 RotateZ(float rot) { 254 return Matrix4x4.RotationZ(rot) * this; 255 } 256 257 public Matrix4x4 Rotate(Quaternion rot) { 258 return Matrix4x4.FromQuaternion(rot) * this; 259 } 260 261 public string ToString() { 262 string dim = "["; 263 foreach( x; 0 .. 4 ) { 264 dim ~= "\n\t["; 265 foreach ( y; 0 .. 4 ) { 266 dim ~= this.data[x][y].text; 267 if (y != 4-1) dim ~= ", "; 268 } 269 dim ~= "]"; 270 if (x != 4-1) dim ~= ","; 271 } 272 return dim ~ "\n]"; 273 } 274 275 /** 276 Pointer to the underlying array data. 277 */ 278 public float* ptr() { return data[0].ptr; } 279 }