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 }