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 }