1///////////////////////////////////////////////////////////////////////////////////
2/// OpenGL Mathematics (glm.g-truc.net)
3///
4/// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net)
5/// Permission is hereby granted, free of charge, to any person obtaining a copy
6/// of this software and associated documentation files (the "Software"), to deal
7/// in the Software without restriction, including without limitation the rights
8/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9/// copies of the Software, and to permit persons to whom the Software is
10/// furnished to do so, subject to the following conditions:
11///
12/// The above copyright notice and this permission notice shall be included in
13/// all copies or substantial portions of the Software.
14///
15/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21/// THE SOFTWARE.
22///
23/// @ref core
24/// @file glm/core/func_matrix.inl
25/// @date 2008-03-08 / 2011-06-15
26/// @author Christophe Riccio
27///////////////////////////////////////////////////////////////////////////////////
28
29#include "../geometric.hpp"
30#include <limits>
31
32namespace glm{
33namespace detail
34{
35	template
36	<
37		template <class, precision> class vecTypeA,
38		template <class, precision> class vecTypeB,
39		typename T, precision P
40	>
41	struct compute_outerProduct{};
42
43	template <typename T, precision P>
44	struct compute_outerProduct<detail::tvec2, detail::tvec2, T, P>
45	{
46		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec2, detail::tvec2>::type call(detail::tvec2<T, P> const & c, detail::tvec2<T, P> const & r)
47		{
48			detail::tmat2x2<T, P> m(detail::tmat2x2<T, P>::_null);
49			m[0][0] = c[0] * r[0];
50			m[0][1] = c[1] * r[0];
51			m[1][0] = c[0] * r[1];
52			m[1][1] = c[1] * r[1];
53			return m;
54		}
55	};
56
57	template <typename T, precision P>
58	struct compute_outerProduct<detail::tvec3, detail::tvec3, T, P>
59	{
60		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec3, detail::tvec3>::type call(detail::tvec3<T, P> const & c, detail::tvec3<T, P> const & r)
61		{
62			detail::tmat3x3<T, P> m(detail::tmat3x3<T, P>::_null);
63			for(length_t i(0); i < m.length(); ++i)
64				m[i] = c * r[i];
65			return m;
66		}
67	};
68
69	template <typename T, precision P>
70	struct compute_outerProduct<detail::tvec4, detail::tvec4, T, P>
71	{
72		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec4, detail::tvec4>::type call(detail::tvec4<T, P> const & c, detail::tvec4<T, P> const & r)
73		{
74			detail::tmat4x4<T, P> m(detail::tmat4x4<T, P>::_null);
75			for(length_t i(0); i < m.length(); ++i)
76				m[i] = c * r[i];
77			return m;
78		}
79	};
80
81	template <typename T, precision P>
82	struct compute_outerProduct<detail::tvec3, detail::tvec2, T, P>
83	{
84		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec3, detail::tvec2>::type call(detail::tvec3<T, P> const & c, detail::tvec2<T, P> const & r)
85		{
86			detail::tmat2x3<T, P> m(detail::tmat2x3<T, P>::_null);
87			m[0][0] = c.x * r.x;
88			m[0][1] = c.y * r.x;
89			m[0][2] = c.z * r.x;
90			m[1][0] = c.x * r.y;
91			m[1][1] = c.y * r.y;
92			m[1][2] = c.z * r.y;
93			return m;
94		}
95	};
96
97	template <typename T, precision P>
98	struct compute_outerProduct<detail::tvec2, detail::tvec3, T, P>
99	{
100		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec2, detail::tvec3>::type call(detail::tvec2<T, P> const & c, detail::tvec3<T, P> const & r)
101		{
102			detail::tmat3x2<T, P> m(detail::tmat3x2<T, P>::_null);
103			m[0][0] = c.x * r.x;
104			m[0][1] = c.y * r.x;
105			m[1][0] = c.x * r.y;
106			m[1][1] = c.y * r.y;
107			m[2][0] = c.x * r.z;
108			m[2][1] = c.y * r.z;
109			return m;
110		}
111	};
112
113	template <typename T, precision P>
114	struct compute_outerProduct<detail::tvec4, detail::tvec2, T, P>
115	{
116		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec4, detail::tvec2>::type call(detail::tvec4<T, P> const & c, detail::tvec2<T, P> const & r)
117		{
118			detail::tmat2x4<T, P> m(detail::tmat2x4<T, P>::_null);
119			m[0][0] = c.x * r.x;
120			m[0][1] = c.y * r.x;
121			m[0][2] = c.z * r.x;
122			m[0][3] = c.w * r.x;
123			m[1][0] = c.x * r.y;
124			m[1][1] = c.y * r.y;
125			m[1][2] = c.z * r.y;
126			m[1][3] = c.w * r.y;
127			return m;
128		}
129	};
130
131	template <typename T, precision P>
132	struct compute_outerProduct<detail::tvec2, detail::tvec4, T, P>
133	{
134		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec2, detail::tvec4>::type call(detail::tvec2<T, P> const & c, detail::tvec4<T, P> const & r)
135		{
136			detail::tmat4x2<T, P> m(detail::tmat4x2<T, P>::_null);
137			m[0][0] = c.x * r.x;
138			m[0][1] = c.y * r.x;
139			m[1][0] = c.x * r.y;
140			m[1][1] = c.y * r.y;
141			m[2][0] = c.x * r.z;
142			m[2][1] = c.y * r.z;
143			m[3][0] = c.x * r.w;
144			m[3][1] = c.y * r.w;
145			return m;
146		}
147	};
148
149	template <typename T, precision P>
150	struct compute_outerProduct<detail::tvec4, detail::tvec3, T, P>
151	{
152		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec4, detail::tvec3>::type call(detail::tvec4<T, P> const & c, detail::tvec3<T, P> const & r)
153		{
154			detail::tmat3x4<T, P> m(detail::tmat3x4<T, P>::_null);
155			m[0][0] = c.x * r.x;
156			m[0][1] = c.y * r.x;
157			m[0][2] = c.z * r.x;
158			m[0][3] = c.w * r.x;
159			m[1][0] = c.x * r.y;
160			m[1][1] = c.y * r.y;
161			m[1][2] = c.z * r.y;
162			m[1][3] = c.w * r.y;
163			m[2][0] = c.x * r.z;
164			m[2][1] = c.y * r.z;
165			m[2][2] = c.z * r.z;
166			m[2][3] = c.w * r.z;
167			return m;
168		}
169	};
170
171	template <typename T, precision P>
172	struct compute_outerProduct<detail::tvec3, detail::tvec4, T, P>
173	{
174		GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait<T, P, detail::tvec3, detail::tvec4>::type call(detail::tvec3<T, P> const & c, detail::tvec4<T, P> const & r)
175		{
176			detail::tmat4x3<T, P> m(detail::tmat4x3<T, P>::_null);
177			m[0][0] = c.x * r.x;
178			m[0][1] = c.y * r.x;
179			m[0][2] = c.z * r.x;
180			m[1][0] = c.x * r.y;
181			m[1][1] = c.y * r.y;
182			m[1][2] = c.z * r.y;
183			m[2][0] = c.x * r.z;
184			m[2][1] = c.y * r.z;
185			m[2][2] = c.z * r.z;
186			m[3][0] = c.x * r.w;
187			m[3][1] = c.y * r.w;
188			m[3][2] = c.z * r.w;
189			return m;
190		}
191	};
192
193	template <template <class, precision> class matType, typename T, precision P>
194	struct compute_transpose{};
195
196	template <typename T, precision P>
197	struct compute_transpose<detail::tmat2x2, T, P>
198	{
199		GLM_FUNC_QUALIFIER static detail::tmat2x2<T, P> call(detail::tmat2x2<T, P> const & m)
200		{
201			detail::tmat2x2<T, P> result(detail::tmat2x2<T, P>::_null);
202			result[0][0] = m[0][0];
203			result[0][1] = m[1][0];
204			result[1][0] = m[0][1];
205			result[1][1] = m[1][1];
206			return result;
207		}
208	};
209
210	template <typename T, precision P>
211	struct compute_transpose<detail::tmat2x3, T, P>
212	{
213		GLM_FUNC_QUALIFIER static detail::tmat3x2<T, P> call(detail::tmat2x3<T, P> const & m)
214		{
215			detail::tmat3x2<T, P> result(detail::tmat3x2<T, P>::_null);
216			result[0][0] = m[0][0];
217			result[0][1] = m[1][0];
218			result[1][0] = m[0][1];
219			result[1][1] = m[1][1];
220			result[2][0] = m[0][2];
221			result[2][1] = m[1][2];
222			return result;
223		}
224	};
225
226	template <typename T, precision P>
227	struct compute_transpose<detail::tmat2x4, T, P>
228	{
229		GLM_FUNC_QUALIFIER static detail::tmat4x2<T, P> call(detail::tmat2x4<T, P> const & m)
230		{
231			detail::tmat4x2<T, P> result(detail::tmat4x2<T, P>::_null);
232			result[0][0] = m[0][0];
233			result[0][1] = m[1][0];
234			result[1][0] = m[0][1];
235			result[1][1] = m[1][1];
236			result[2][0] = m[0][2];
237			result[2][1] = m[1][2];
238			result[3][0] = m[0][3];
239			result[3][1] = m[1][3];
240			return result;
241		}
242	};
243
244	template <typename T, precision P>
245	struct compute_transpose<detail::tmat3x2, T, P>
246	{
247		GLM_FUNC_QUALIFIER static detail::tmat2x3<T, P> call(detail::tmat3x2<T, P> const & m)
248		{
249			detail::tmat2x3<T, P> result(detail::tmat2x3<T, P>::_null);
250			result[0][0] = m[0][0];
251			result[0][1] = m[1][0];
252			result[0][2] = m[2][0];
253			result[1][0] = m[0][1];
254			result[1][1] = m[1][1];
255			result[1][2] = m[2][1];
256			return result;
257		}
258	};
259
260	template <typename T, precision P>
261	struct compute_transpose<detail::tmat3x3, T, P>
262	{
263		GLM_FUNC_QUALIFIER static detail::tmat3x3<T, P> call(detail::tmat3x3<T, P> const & m)
264		{
265			detail::tmat3x3<T, P> result(detail::tmat3x3<T, P>::_null);
266			result[0][0] = m[0][0];
267			result[0][1] = m[1][0];
268			result[0][2] = m[2][0];
269
270			result[1][0] = m[0][1];
271			result[1][1] = m[1][1];
272			result[1][2] = m[2][1];
273
274			result[2][0] = m[0][2];
275			result[2][1] = m[1][2];
276			result[2][2] = m[2][2];
277			return result;
278		}
279	};
280
281	template <typename T, precision P>
282	struct compute_transpose<detail::tmat3x4, T, P>
283	{
284		GLM_FUNC_QUALIFIER static detail::tmat4x3<T, P> call(detail::tmat3x4<T, P> const & m)
285		{
286			detail::tmat4x3<T, P> result(detail::tmat4x3<T, P>::_null);
287			result[0][0] = m[0][0];
288			result[0][1] = m[1][0];
289			result[0][2] = m[2][0];
290			result[1][0] = m[0][1];
291			result[1][1] = m[1][1];
292			result[1][2] = m[2][1];
293			result[2][0] = m[0][2];
294			result[2][1] = m[1][2];
295			result[2][2] = m[2][2];
296			result[3][0] = m[0][3];
297			result[3][1] = m[1][3];
298			result[3][2] = m[2][3];
299			return result;
300		}
301	};
302
303	template <typename T, precision P>
304	struct compute_transpose<detail::tmat4x2, T, P>
305	{
306		GLM_FUNC_QUALIFIER static detail::tmat2x4<T, P> call(detail::tmat4x2<T, P> const & m)
307		{
308			detail::tmat2x4<T, P> result(detail::tmat2x4<T, P>::_null);
309			result[0][0] = m[0][0];
310			result[0][1] = m[1][0];
311			result[0][2] = m[2][0];
312			result[0][3] = m[3][0];
313			result[1][0] = m[0][1];
314			result[1][1] = m[1][1];
315			result[1][2] = m[2][1];
316			result[1][3] = m[3][1];
317			return result;
318		}
319	};
320
321	template <typename T, precision P>
322	struct compute_transpose<detail::tmat4x3, T, P>
323	{
324		GLM_FUNC_QUALIFIER static detail::tmat3x4<T, P> call(detail::tmat4x3<T, P> const & m)
325		{
326			detail::tmat3x4<T, P> result(detail::tmat3x4<T, P>::_null);
327			result[0][0] = m[0][0];
328			result[0][1] = m[1][0];
329			result[0][2] = m[2][0];
330			result[0][3] = m[3][0];
331			result[1][0] = m[0][1];
332			result[1][1] = m[1][1];
333			result[1][2] = m[2][1];
334			result[1][3] = m[3][1];
335			result[2][0] = m[0][2];
336			result[2][1] = m[1][2];
337			result[2][2] = m[2][2];
338			result[2][3] = m[3][2];
339			return result;
340		}
341	};
342
343	template <typename T, precision P>
344	struct compute_transpose<detail::tmat4x4, T, P>
345	{
346		GLM_FUNC_QUALIFIER static detail::tmat4x4<T, P> call(detail::tmat4x4<T, P> const & m)
347		{
348			detail::tmat4x4<T, P> result(detail::tmat4x4<T, P>::_null);
349			result[0][0] = m[0][0];
350			result[0][1] = m[1][0];
351			result[0][2] = m[2][0];
352			result[0][3] = m[3][0];
353
354			result[1][0] = m[0][1];
355			result[1][1] = m[1][1];
356			result[1][2] = m[2][1];
357			result[1][3] = m[3][1];
358
359			result[2][0] = m[0][2];
360			result[2][1] = m[1][2];
361			result[2][2] = m[2][2];
362			result[2][3] = m[3][2];
363
364			result[3][0] = m[0][3];
365			result[3][1] = m[1][3];
366			result[3][2] = m[2][3];
367			result[3][3] = m[3][3];
368			return result;
369		}
370	};
371
372	template <template <class, precision> class matType, typename T, precision P>
373	struct compute_determinant{};
374
375	template <typename T, precision P>
376	struct compute_determinant<detail::tmat2x2, T, P>
377	{
378		GLM_FUNC_QUALIFIER static T call(detail::tmat2x2<T, P> const & m)
379		{
380			return m[0][0] * m[1][1] - m[1][0] * m[0][1];
381		}
382	};
383
384	template <typename T, precision P>
385	struct compute_determinant<detail::tmat3x3, T, P>
386	{
387		GLM_FUNC_QUALIFIER static T call(detail::tmat3x3<T, P> const & m)
388		{
389			return
390				+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
391				- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
392				+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
393		}
394	};
395
396	template <typename T, precision P>
397	struct compute_determinant<detail::tmat4x4, T, P>
398	{
399		GLM_FUNC_QUALIFIER static T call(detail::tmat4x4<T, P> const & m)
400		{
401			T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
402			T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
403			T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
404			T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
405			T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
406			T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
407
408			detail::tvec4<T, P> DetCof(
409				+ (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),
410				- (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),
411				+ (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),
412				- (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));
413
414			return
415				m[0][0] * DetCof[0] + m[0][1] * DetCof[1] +
416				m[0][2] * DetCof[2] + m[0][3] * DetCof[3];
417		}
418	};
419}//namespace detail
420
421	template <typename T, precision P, template <typename, precision> class matType>
422	GLM_FUNC_QUALIFIER matType<T, P> matrixCompMult(matType<T, P> const & x, matType<T, P> const & y)
423	{
424		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'matrixCompMult' only accept floating-point inputs");
425
426		matType<T, P> result(matType<T, P>::_null);
427		for(length_t i = 0; i < result.length(); ++i)
428			result[i] = x[i] * y[i];
429		return result;
430	}
431
432	template<typename T, precision P, template <typename, precision> class vecTypeA, template <typename, precision> class vecTypeB>
433	GLM_FUNC_QUALIFIER typename detail::outerProduct_trait<T, P, vecTypeA, vecTypeB>::type outerProduct(vecTypeA<T, P> const & c, vecTypeB<T, P> const & r)
434	{
435		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'outerProduct' only accept floating-point inputs");
436		return detail::compute_outerProduct<vecTypeA, vecTypeB, T, P>::call(c, r);
437	}
438
439	template <typename T, precision P, template <typename, precision> class matType>
440	GLM_FUNC_QUALIFIER typename matType<T, P>::transpose_type transpose(matType<T, P> const & m)
441	{
442		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'transpose' only accept floating-point inputs");
443		return detail::compute_transpose<matType, T, P>::call(m);
444	}
445
446	template <typename T, precision P, template <typename, precision> class matType>
447	GLM_FUNC_QUALIFIER T determinant(matType<T, P> const & m)
448	{
449		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'determinant' only accept floating-point inputs");
450		return detail::compute_determinant<matType, T, P>::call(m);
451	}
452
453	template <typename T, precision P, template <typename, precision> class matType>
454	GLM_FUNC_QUALIFIER matType<T, P> inverse(matType<T, P> const & m)
455	{
456		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'inverse' only accept floating-point inputs");
457		return detail::compute_inverse<matType, T, P>::call(m);
458	}
459
460}//namespace glm
461