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