1/// @ref core
2/// @file glm/detail/func_matrix.inl
3
4#include "../geometric.hpp"
5#include <limits>
6
7namespace glm{
8namespace detail
9{
10	template <template <typename, precision> class matType, typename T, precision P, bool Aligned>
11	struct compute_matrixCompMult
12	{
13		GLM_FUNC_QUALIFIER static matType<T, P> call(matType<T, P> const& x, matType<T, P> const& y)
14		{
15			matType<T, P> result(uninitialize);
16			for(length_t i = 0; i < result.length(); ++i)
17				result[i] = x[i] * y[i];
18			return result;
19		}
20	};
21
22	template <template <class, precision> class matType, typename T, precision P, bool Aligned>
23	struct compute_transpose{};
24
25	template <typename T, precision P, bool Aligned>
26	struct compute_transpose<tmat2x2, T, P, Aligned>
27	{
28		GLM_FUNC_QUALIFIER static tmat2x2<T, P> call(tmat2x2<T, P> const & m)
29		{
30			tmat2x2<T, P> result(uninitialize);
31			result[0][0] = m[0][0];
32			result[0][1] = m[1][0];
33			result[1][0] = m[0][1];
34			result[1][1] = m[1][1];
35			return result;
36		}
37	};
38
39	template <typename T, precision P, bool Aligned>
40	struct compute_transpose<tmat2x3, T, P, Aligned>
41	{
42		GLM_FUNC_QUALIFIER static tmat3x2<T, P> call(tmat2x3<T, P> const & m)
43		{
44			tmat3x2<T, P> result(uninitialize);
45			result[0][0] = m[0][0];
46			result[0][1] = m[1][0];
47			result[1][0] = m[0][1];
48			result[1][1] = m[1][1];
49			result[2][0] = m[0][2];
50			result[2][1] = m[1][2];
51			return result;
52		}
53	};
54
55	template <typename T, precision P, bool Aligned>
56	struct compute_transpose<tmat2x4, T, P, Aligned>
57	{
58		GLM_FUNC_QUALIFIER static tmat4x2<T, P> call(tmat2x4<T, P> const & m)
59		{
60			tmat4x2<T, P> result(uninitialize);
61			result[0][0] = m[0][0];
62			result[0][1] = m[1][0];
63			result[1][0] = m[0][1];
64			result[1][1] = m[1][1];
65			result[2][0] = m[0][2];
66			result[2][1] = m[1][2];
67			result[3][0] = m[0][3];
68			result[3][1] = m[1][3];
69			return result;
70		}
71	};
72
73	template <typename T, precision P, bool Aligned>
74	struct compute_transpose<tmat3x2, T, P, Aligned>
75	{
76		GLM_FUNC_QUALIFIER static tmat2x3<T, P> call(tmat3x2<T, P> const & m)
77		{
78			tmat2x3<T, P> result(uninitialize);
79			result[0][0] = m[0][0];
80			result[0][1] = m[1][0];
81			result[0][2] = m[2][0];
82			result[1][0] = m[0][1];
83			result[1][1] = m[1][1];
84			result[1][2] = m[2][1];
85			return result;
86		}
87	};
88
89	template <typename T, precision P, bool Aligned>
90	struct compute_transpose<tmat3x3, T, P, Aligned>
91	{
92		GLM_FUNC_QUALIFIER static tmat3x3<T, P> call(tmat3x3<T, P> const & m)
93		{
94			tmat3x3<T, P> result(uninitialize);
95			result[0][0] = m[0][0];
96			result[0][1] = m[1][0];
97			result[0][2] = m[2][0];
98
99			result[1][0] = m[0][1];
100			result[1][1] = m[1][1];
101			result[1][2] = m[2][1];
102
103			result[2][0] = m[0][2];
104			result[2][1] = m[1][2];
105			result[2][2] = m[2][2];
106			return result;
107		}
108	};
109
110	template <typename T, precision P, bool Aligned>
111	struct compute_transpose<tmat3x4, T, P, Aligned>
112	{
113		GLM_FUNC_QUALIFIER static tmat4x3<T, P> call(tmat3x4<T, P> const & m)
114		{
115			tmat4x3<T, P> result(uninitialize);
116			result[0][0] = m[0][0];
117			result[0][1] = m[1][0];
118			result[0][2] = m[2][0];
119			result[1][0] = m[0][1];
120			result[1][1] = m[1][1];
121			result[1][2] = m[2][1];
122			result[2][0] = m[0][2];
123			result[2][1] = m[1][2];
124			result[2][2] = m[2][2];
125			result[3][0] = m[0][3];
126			result[3][1] = m[1][3];
127			result[3][2] = m[2][3];
128			return result;
129		}
130	};
131
132	template <typename T, precision P, bool Aligned>
133	struct compute_transpose<tmat4x2, T, P, Aligned>
134	{
135		GLM_FUNC_QUALIFIER static tmat2x4<T, P> call(tmat4x2<T, P> const & m)
136		{
137			tmat2x4<T, P> result(uninitialize);
138			result[0][0] = m[0][0];
139			result[0][1] = m[1][0];
140			result[0][2] = m[2][0];
141			result[0][3] = m[3][0];
142			result[1][0] = m[0][1];
143			result[1][1] = m[1][1];
144			result[1][2] = m[2][1];
145			result[1][3] = m[3][1];
146			return result;
147		}
148	};
149
150	template <typename T, precision P, bool Aligned>
151	struct compute_transpose<tmat4x3, T, P, Aligned>
152	{
153		GLM_FUNC_QUALIFIER static tmat3x4<T, P> call(tmat4x3<T, P> const & m)
154		{
155			tmat3x4<T, P> result(uninitialize);
156			result[0][0] = m[0][0];
157			result[0][1] = m[1][0];
158			result[0][2] = m[2][0];
159			result[0][3] = m[3][0];
160			result[1][0] = m[0][1];
161			result[1][1] = m[1][1];
162			result[1][2] = m[2][1];
163			result[1][3] = m[3][1];
164			result[2][0] = m[0][2];
165			result[2][1] = m[1][2];
166			result[2][2] = m[2][2];
167			result[2][3] = m[3][2];
168			return result;
169		}
170	};
171
172	template <typename T, precision P, bool Aligned>
173	struct compute_transpose<tmat4x4, T, P, Aligned>
174	{
175		GLM_FUNC_QUALIFIER static tmat4x4<T, P> call(tmat4x4<T, P> const & m)
176		{
177			tmat4x4<T, P> result(uninitialize);
178			result[0][0] = m[0][0];
179			result[0][1] = m[1][0];
180			result[0][2] = m[2][0];
181			result[0][3] = m[3][0];
182
183			result[1][0] = m[0][1];
184			result[1][1] = m[1][1];
185			result[1][2] = m[2][1];
186			result[1][3] = m[3][1];
187
188			result[2][0] = m[0][2];
189			result[2][1] = m[1][2];
190			result[2][2] = m[2][2];
191			result[2][3] = m[3][2];
192
193			result[3][0] = m[0][3];
194			result[3][1] = m[1][3];
195			result[3][2] = m[2][3];
196			result[3][3] = m[3][3];
197			return result;
198		}
199	};
200
201	template <template <typename, precision> class matType, typename T, precision P, bool Aligned>
202	struct compute_determinant{};
203
204	template <typename T, precision P, bool Aligned>
205	struct compute_determinant<tmat2x2, T, P, Aligned>
206	{
207		GLM_FUNC_QUALIFIER static T call(tmat2x2<T, P> const & m)
208		{
209			return m[0][0] * m[1][1] - m[1][0] * m[0][1];
210		}
211	};
212
213	template <typename T, precision P, bool Aligned>
214	struct compute_determinant<tmat3x3, T, P, Aligned>
215	{
216		GLM_FUNC_QUALIFIER static T call(tmat3x3<T, P> const & m)
217		{
218			return
219				+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
220				- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
221				+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
222		}
223	};
224
225	template <typename T, precision P, bool Aligned>
226	struct compute_determinant<tmat4x4, T, P, Aligned>
227	{
228		GLM_FUNC_QUALIFIER static T call(tmat4x4<T, P> const & m)
229		{
230			T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
231			T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
232			T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
233			T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
234			T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
235			T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
236
237			tvec4<T, P> DetCof(
238				+ (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),
239				- (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),
240				+ (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),
241				- (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));
242
243			return
244				m[0][0] * DetCof[0] + m[0][1] * DetCof[1] +
245				m[0][2] * DetCof[2] + m[0][3] * DetCof[3];
246		}
247	};
248
249	template <template <typename, precision> class matType, typename T, precision P, bool Aligned>
250	struct compute_inverse{};
251
252	template <typename T, precision P, bool Aligned>
253	struct compute_inverse<tmat2x2, T, P, Aligned>
254	{
255		GLM_FUNC_QUALIFIER static tmat2x2<T, P> call(tmat2x2<T, P> const& m)
256		{
257			T OneOverDeterminant = static_cast<T>(1) / (
258				+ m[0][0] * m[1][1]
259				- m[1][0] * m[0][1]);
260
261			tmat2x2<T, P> Inverse(
262				+ m[1][1] * OneOverDeterminant,
263				- m[0][1] * OneOverDeterminant,
264				- m[1][0] * OneOverDeterminant,
265				+ m[0][0] * OneOverDeterminant);
266
267			return Inverse;
268		}
269	};
270
271	template <typename T, precision P, bool Aligned>
272	struct compute_inverse<tmat3x3, T, P, Aligned>
273	{
274		GLM_FUNC_QUALIFIER static tmat3x3<T, P> call(tmat3x3<T, P> const& m)
275		{
276			T OneOverDeterminant = static_cast<T>(1) / (
277				+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
278				- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
279				+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
280
281			tmat3x3<T, P> Inverse(uninitialize);
282			Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;
283			Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;
284			Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;
285			Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;
286			Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;
287			Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;
288			Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;
289			Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;
290			Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;
291
292			return Inverse;
293		}
294	};
295
296	template <typename T, precision P, bool Aligned>
297	struct compute_inverse<tmat4x4, T, P, Aligned>
298	{
299		GLM_FUNC_QUALIFIER static tmat4x4<T, P> call(tmat4x4<T, P> const& m)
300		{
301			T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
302			T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
303			T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
304
305			T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
306			T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
307			T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
308
309			T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
310			T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
311			T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
312
313			T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
314			T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
315			T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
316
317			T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
318			T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
319			T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
320
321			T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
322			T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
323			T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
324
325			tvec4<T, P> Fac0(Coef00, Coef00, Coef02, Coef03);
326			tvec4<T, P> Fac1(Coef04, Coef04, Coef06, Coef07);
327			tvec4<T, P> Fac2(Coef08, Coef08, Coef10, Coef11);
328			tvec4<T, P> Fac3(Coef12, Coef12, Coef14, Coef15);
329			tvec4<T, P> Fac4(Coef16, Coef16, Coef18, Coef19);
330			tvec4<T, P> Fac5(Coef20, Coef20, Coef22, Coef23);
331
332			tvec4<T, P> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]);
333			tvec4<T, P> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]);
334			tvec4<T, P> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]);
335			tvec4<T, P> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]);
336
337			tvec4<T, P> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2);
338			tvec4<T, P> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4);
339			tvec4<T, P> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5);
340			tvec4<T, P> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5);
341
342			tvec4<T, P> SignA(+1, -1, +1, -1);
343			tvec4<T, P> SignB(-1, +1, -1, +1);
344			tmat4x4<T, P> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB);
345
346			tvec4<T, P> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]);
347
348			tvec4<T, P> Dot0(m[0] * Row0);
349			T Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w);
350
351			T OneOverDeterminant = static_cast<T>(1) / Dot1;
352
353			return Inverse * OneOverDeterminant;
354		}
355	};
356}//namespace detail
357
358	template <typename T, precision P, template <typename, precision> class matType>
359	GLM_FUNC_QUALIFIER matType<T, P> matrixCompMult(matType<T, P> const & x, matType<T, P> const & y)
360	{
361		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'matrixCompMult' only accept floating-point inputs");
362		return detail::compute_matrixCompMult<matType, T, P, detail::is_aligned<P>::value>::call(x, y);
363	}
364
365	template<typename T, precision P, template <typename, precision> class vecTypeA, template <typename, precision> class vecTypeB>
366	GLM_FUNC_QUALIFIER typename detail::outerProduct_trait<T, P, vecTypeA, vecTypeB>::type outerProduct(vecTypeA<T, P> const & c, vecTypeB<T, P> const & r)
367	{
368		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'outerProduct' only accept floating-point inputs");
369
370		typename detail::outerProduct_trait<T, P, vecTypeA, vecTypeB>::type m(uninitialize);
371		for(length_t i = 0; i < m.length(); ++i)
372			m[i] = c * r[i];
373		return m;
374	}
375
376	template <typename T, precision P, template <typename, precision> class matType>
377	GLM_FUNC_QUALIFIER typename matType<T, P>::transpose_type transpose(matType<T, P> const & m)
378	{
379		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'transpose' only accept floating-point inputs");
380		return detail::compute_transpose<matType, T, P, detail::is_aligned<P>::value>::call(m);
381	}
382
383	template <typename T, precision P, template <typename, precision> class matType>
384	GLM_FUNC_QUALIFIER T determinant(matType<T, P> const & m)
385	{
386		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'determinant' only accept floating-point inputs");
387		return detail::compute_determinant<matType, T, P, detail::is_aligned<P>::value>::call(m);
388	}
389
390	template <typename T, precision P, template <typename, precision> class matType>
391	GLM_FUNC_QUALIFIER matType<T, P> inverse(matType<T, P> const & m)
392	{
393		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'inverse' only accept floating-point inputs");
394		return detail::compute_inverse<matType, T, P, detail::is_aligned<P>::value>::call(m);
395	}
396}//namespace glm
397
398#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
399#	include "func_matrix_simd.inl"
400#endif
401
402