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/type_mat3x3.inl
25/// @date 2005-01-27 / 2011-06-15
26/// @author Christophe Riccio
27///////////////////////////////////////////////////////////////////////////////////
28
29namespace glm{
30namespace detail
31{
32	template <typename T, precision P>
33	GLM_FUNC_QUALIFIER GLM_CONSTEXPR length_t tmat3x3<T, P>::length() const
34	{
35		return 3;
36	}
37
38	//////////////////////////////////////
39	// Accesses
40
41	template <typename T, precision P>
42	GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type &
43	tmat3x3<T, P>::operator[]
44	(
45		length_t i
46	)
47	{
48		assert(i < this->length());
49		return this->value[i];
50	}
51
52	template <typename T, precision P>
53	GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type const &
54	tmat3x3<T, P>::operator[]
55	(
56		length_t i
57	) const
58	{
59		assert(i < this->length());
60		return this->value[i];
61	}
62
63	//////////////////////////////////////////////////////////////
64	// Constructors
65
66	template <typename T, precision P>
67	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3()
68	{
69		value_type const Zero(0);
70		value_type const One(1);
71		this->value[0] = col_type(One, Zero, Zero);
72		this->value[1] = col_type(Zero, One, Zero);
73		this->value[2] = col_type(Zero, Zero, One);
74	}
75
76	template <typename T, precision P>
77	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
78	(
79		tmat3x3<T, P> const & m
80	)
81	{
82		this->value[0] = m.value[0];
83		this->value[1] = m.value[1];
84		this->value[2] = m.value[2];
85	}
86
87	template <typename T, precision P>
88	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
89	(
90		ctor
91	)
92	{}
93
94	template <typename T, precision P>
95	template <precision Q>
96	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(
97		tmat3x3<T, Q> const & m)
98	{
99		this->value[0] = m.value[0];
100		this->value[1] = m.value[1];
101		this->value[2] = m.value[2];
102	}
103
104	template <typename T, precision P>
105	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
106	(
107		T const & s
108	)
109	{
110		value_type const Zero(0);
111		this->value[0] = col_type(s, Zero, Zero);
112		this->value[1] = col_type(Zero, s, Zero);
113		this->value[2] = col_type(Zero, Zero, s);
114	}
115
116	template <typename T, precision P>
117	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
118	(
119		T const & x0, T const & y0, T const & z0,
120		T const & x1, T const & y1, T const & z1,
121		T const & x2, T const & y2, T const & z2
122	)
123	{
124		this->value[0] = col_type(x0, y0, z0);
125		this->value[1] = col_type(x1, y1, z1);
126		this->value[2] = col_type(x2, y2, z2);
127	}
128
129	template <typename T, precision P>
130	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
131	(
132		col_type const & v0,
133		col_type const & v1,
134		col_type const & v2
135	)
136	{
137		this->value[0] = v0;
138		this->value[1] = v1;
139		this->value[2] = v2;
140	}
141
142	//////////////////////////////////////
143	// Conversion constructors
144	template <typename T, precision P>
145	template <
146		typename X1, typename Y1, typename Z1,
147		typename X2, typename Y2, typename Z2,
148		typename X3, typename Y3, typename Z3>
149	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
150	(
151		X1 const & x1, Y1 const & y1, Z1 const & z1,
152		X2 const & x2, Y2 const & y2, Z2 const & z2,
153		X3 const & x3, Y3 const & y3, Z3 const & z3
154	)
155	{
156		this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1));
157		this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2));
158		this->value[2] = col_type(static_cast<T>(x3), value_type(y3), value_type(z3));
159	}
160
161	template <typename T, precision P>
162	template <typename V1, typename V2, typename V3>
163	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
164	(
165		tvec3<V1, P> const & v1,
166		tvec3<V2, P> const & v2,
167		tvec3<V3, P> const & v3
168	)
169	{
170		this->value[0] = col_type(v1);
171		this->value[1] = col_type(v2);
172		this->value[2] = col_type(v3);
173	}
174
175	//////////////////////////////////////////////////////////////
176	// Conversions
177
178	template <typename T, precision P>
179	template <typename U, precision Q>
180	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
181	(
182		tmat3x3<U, Q> const & m
183	)
184	{
185		this->value[0] = col_type(m[0]);
186		this->value[1] = col_type(m[1]);
187		this->value[2] = col_type(m[2]);
188	}
189
190	template <typename T, precision P>
191	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
192	(
193		tmat2x2<T, P> const & m
194	)
195	{
196		this->value[0] = col_type(m[0], value_type(0));
197		this->value[1] = col_type(m[1], value_type(0));
198		this->value[2] = col_type(detail::tvec2<T, P>(0), value_type(1));
199	}
200
201	template <typename T, precision P>
202	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
203	(
204		tmat4x4<T, P> const & m
205	)
206	{
207		this->value[0] = col_type(m[0]);
208		this->value[1] = col_type(m[1]);
209		this->value[2] = col_type(m[2]);
210	}
211
212	template <typename T, precision P>
213	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
214	(
215		tmat2x3<T, P> const & m
216	)
217	{
218		this->value[0] = m[0];
219		this->value[1] = m[1];
220		this->value[2] = col_type(detail::tvec2<T, P>(0), value_type(1));
221	}
222
223	template <typename T, precision P>
224	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
225	(
226		tmat3x2<T, P> const & m
227	)
228	{
229		this->value[0] = col_type(m[0], value_type(0));
230		this->value[1] = col_type(m[1], value_type(0));
231		this->value[2] = col_type(m[2], value_type(1));
232	}
233
234	template <typename T, precision P>
235	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
236	(
237		tmat2x4<T, P> const & m
238	)
239	{
240		this->value[0] = col_type(m[0]);
241		this->value[1] = col_type(m[1]);
242		this->value[2] = col_type(detail::tvec2<T, P>(0), value_type(1));
243	}
244
245	template <typename T, precision P>
246	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
247	(
248		tmat4x2<T, P> const & m
249	)
250	{
251		this->value[0] = col_type(m[0], value_type(0));
252		this->value[1] = col_type(m[1], value_type(0));
253		this->value[2] = col_type(m[2], value_type(1));
254	}
255
256	template <typename T, precision P>
257	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
258	(
259		tmat3x4<T, P> const & m
260	)
261	{
262		this->value[0] = col_type(m[0]);
263		this->value[1] = col_type(m[1]);
264		this->value[2] = col_type(m[2]);
265	}
266
267	template <typename T, precision P>
268	GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
269	(
270		tmat4x3<T, P> const & m
271	)
272	{
273		this->value[0] = m[0];
274		this->value[1] = m[1];
275		this->value[2] = m[2];
276	}
277
278	//////////////////////////////////////////////////////////////
279	// Operators
280
281	template <typename T, precision P>
282	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator= (tmat3x3<T, P> const & m)
283	{
284		this->value[0] = m[0];
285		this->value[1] = m[1];
286		this->value[2] = m[2];
287		return *this;
288	}
289
290	template <typename T, precision P>
291	template <typename U>
292	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator= (tmat3x3<U, P> const & m)
293	{
294		this->value[0] = m[0];
295		this->value[1] = m[1];
296		this->value[2] = m[2];
297		return *this;
298	}
299
300	template <typename T, precision P>
301	template <typename U>
302	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator+= (U s)
303	{
304		this->value[0] += s;
305		this->value[1] += s;
306		this->value[2] += s;
307		return *this;
308	}
309
310	template <typename T, precision P>
311	template <typename U>
312	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator+= (tmat3x3<U, P> const & m)
313	{
314		this->value[0] += m[0];
315		this->value[1] += m[1];
316		this->value[2] += m[2];
317		return *this;
318	}
319
320	template <typename T, precision P>
321	template <typename U>
322	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator-= (U s)
323	{
324		this->value[0] -= s;
325		this->value[1] -= s;
326		this->value[2] -= s;
327		return *this;
328	}
329
330	template <typename T, precision P>
331	template <typename U>
332	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator-= (tmat3x3<U, P> const & m)
333	{
334		this->value[0] -= m[0];
335		this->value[1] -= m[1];
336		this->value[2] -= m[2];
337		return *this;
338	}
339
340	template <typename T, precision P>
341	template <typename U>
342	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator*= (U s)
343	{
344		this->value[0] *= s;
345		this->value[1] *= s;
346		this->value[2] *= s;
347		return *this;
348	}
349
350	template <typename T, precision P>
351	template <typename U>
352	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator*= (tmat3x3<U, P> const & m)
353	{
354		return (*this = *this * m);
355	}
356
357	template <typename T, precision P>
358	template <typename U>
359	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator/= (U s)
360	{
361		this->value[0] /= s;
362		this->value[1] /= s;
363		this->value[2] /= s;
364		return *this;
365	}
366
367	template <typename T, precision P>
368	template <typename U>
369	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator/= (tmat3x3<U, P> const & m)
370	{
371		return (*this = *this * detail::compute_inverse<detail::tmat3x3, T, P>::call(m));
372	}
373
374	template <typename T, precision P>
375	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator++ ()
376	{
377		++this->value[0];
378		++this->value[1];
379		++this->value[2];
380		return *this;
381	}
382
383	template <typename T, precision P>
384	GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator--()
385	{
386		--this->value[0];
387		--this->value[1];
388		--this->value[2];
389		return *this;
390	}
391
392	template <typename T, precision P>
393	GLM_FUNC_QUALIFIER tmat3x3<T, P> tmat3x3<T, P>::operator++(int)
394	{
395		tmat3x3<T, P> Result(*this);
396		++*this;
397		return Result;
398	}
399
400	template <typename T, precision P>
401	GLM_FUNC_QUALIFIER tmat3x3<T, P> tmat3x3<T, P>::operator--(int)
402	{
403		tmat3x3<T, P> Result(*this);
404		--*this;
405		return Result;
406	}
407
408	template <typename T, precision P>
409	struct compute_inverse<detail::tmat3x3, T, P>
410	{
411		static detail::tmat3x3<T, P> call(detail::tmat3x3<T, P> const & m)
412		{
413			T OneOverDeterminant = static_cast<T>(1) / (
414				+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
415				- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
416				+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
417
418			detail::tmat3x3<T, P> Inverse(detail::tmat3x3<T, P>::_null);
419			Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;
420			Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;
421			Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;
422			Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;
423			Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;
424			Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;
425			Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;
426			Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;
427			Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;
428
429			return Inverse;
430		}
431	};
432
433	template <typename T, precision P>
434	GLM_FUNC_QUALIFIER tmat3x3<T, P> compute_inverse_mat3(tmat3x3<T, P> const & m)
435	{
436		T S00 = m[0][0];
437		T S01 = m[0][1];
438		T S02 = m[0][2];
439
440		T S10 = m[1][0];
441		T S11 = m[1][1];
442		T S12 = m[1][2];
443
444		T S20 = m[2][0];
445		T S21 = m[2][1];
446		T S22 = m[2][2];
447/*
448		tmat3x3<T, P> Inverse(
449			+ (S11 * S22 - S21 * S12),
450			- (S10 * S22 - S20 * S12),
451			+ (S10 * S21 - S20 * S11),
452			- (S01 * S22 - S21 * S02),
453			+ (S00 * S22 - S20 * S02),
454			- (S00 * S21 - S20 * S01),
455			+ (S01 * S12 - S11 * S02),
456			- (S00 * S12 - S10 * S02),
457			+ (S00 * S11 - S10 * S01));
458*/
459		tmat3x3<T, P> Inverse(
460			S11 * S22 - S21 * S12,
461			S12 * S20 - S22 * S10,
462			S10 * S21 - S20 * S11,
463			S02 * S21 - S01 * S22,
464			S00 * S22 - S02 * S20,
465			S01 * S20 - S00 * S21,
466			S12 * S01 - S11 * S02,
467			S10 * S02 - S12 * S00,
468			S11 * S00 - S10 * S01);
469
470		T Determinant =
471			+ S00 * (S11 * S22 - S21 * S12)
472			- S10 * (S01 * S22 - S21 * S02)
473			+ S20 * (S01 * S12 - S11 * S02);
474
475		Inverse /= Determinant;
476		return Inverse;
477	}
478
479	//////////////////////////////////////////////////////////////
480	// Binary operators
481
482	template <typename T, precision P>
483	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+
484	(
485		tmat3x3<T, P> const & m,
486		T const & s
487	)
488	{
489		return tmat3x3<T, P>(
490			m[0] + s,
491			m[1] + s,
492			m[2] + s);
493	}
494
495	template <typename T, precision P>
496	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+
497	(
498		T const & s,
499		tmat3x3<T, P> const & m
500	)
501	{
502		return tmat3x3<T, P>(
503			m[0] + s,
504			m[1] + s,
505			m[2] + s);
506	}
507
508	template <typename T, precision P>
509	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+
510	(
511		tmat3x3<T, P> const & m1,
512		tmat3x3<T, P> const & m2
513	)
514	{
515		return tmat3x3<T, P>(
516			m1[0] + m2[0],
517			m1[1] + m2[1],
518			m1[2] + m2[2]);
519	}
520
521	template <typename T, precision P>
522	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-
523	(
524		tmat3x3<T, P> const & m,
525		T const & s
526	)
527	{
528		return tmat3x3<T, P>(
529			m[0] - s,
530			m[1] - s,
531			m[2] - s);
532	}
533
534	template <typename T, precision P>
535	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-
536	(
537		T const & s,
538		tmat3x3<T, P> const & m
539	)
540	{
541		return tmat3x3<T, P>(
542			s - m[0],
543			s - m[1],
544			s - m[2]);
545	}
546
547	template <typename T, precision P>
548	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-
549	(
550		tmat3x3<T, P> const & m1,
551		tmat3x3<T, P> const & m2
552	)
553	{
554		return tmat3x3<T, P>(
555			m1[0] - m2[0],
556			m1[1] - m2[1],
557			m1[2] - m2[2]);
558	}
559
560	template <typename T, precision P>
561	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*
562	(
563		tmat3x3<T, P> const & m,
564		T const & s
565	)
566	{
567		return tmat3x3<T, P>(
568			m[0] * s,
569			m[1] * s,
570			m[2] * s);
571	}
572
573	template <typename T, precision P>
574	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*
575	(
576		T const & s,
577		tmat3x3<T, P> const & m
578	)
579	{
580		return tmat3x3<T, P>(
581			m[0] * s,
582			m[1] * s,
583			m[2] * s);
584	}
585
586	template <typename T, precision P>
587	GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type operator*
588	(
589		tmat3x3<T, P> const & m,
590		typename tmat3x3<T, P>::row_type const & v
591	)
592	{
593		return typename tmat3x3<T, P>::col_type(
594			m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,
595			m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z,
596			m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z);
597	}
598
599	template <typename T, precision P>
600	GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::row_type operator*
601	(
602		typename tmat3x3<T, P>::col_type const & v,
603		tmat3x3<T, P> const & m
604	)
605	{
606		return typename tmat3x3<T, P>::row_type(
607			m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,
608			m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
609			m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);
610	}
611
612	template <typename T, precision P>
613	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*
614	(
615		tmat3x3<T, P> const & m1,
616		tmat3x3<T, P> const & m2
617	)
618	{
619		T const SrcA00 = m1[0][0];
620		T const SrcA01 = m1[0][1];
621		T const SrcA02 = m1[0][2];
622		T const SrcA10 = m1[1][0];
623		T const SrcA11 = m1[1][1];
624		T const SrcA12 = m1[1][2];
625		T const SrcA20 = m1[2][0];
626		T const SrcA21 = m1[2][1];
627		T const SrcA22 = m1[2][2];
628
629		T const SrcB00 = m2[0][0];
630		T const SrcB01 = m2[0][1];
631		T const SrcB02 = m2[0][2];
632		T const SrcB10 = m2[1][0];
633		T const SrcB11 = m2[1][1];
634		T const SrcB12 = m2[1][2];
635		T const SrcB20 = m2[2][0];
636		T const SrcB21 = m2[2][1];
637		T const SrcB22 = m2[2][2];
638
639		tmat3x3<T, P> Result(tmat3x3<T, P>::_null);
640		Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;
641		Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;
642		Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02;
643		Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;
644		Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;
645		Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12;
646		Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22;
647		Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22;
648		Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22;
649		return Result;
650	}
651
652	template <typename T, precision P>
653	GLM_FUNC_QUALIFIER tmat2x3<T, P> operator*
654	(
655		tmat3x3<T, P> const & m1,
656		tmat2x3<T, P> const & m2
657	)
658	{
659		return tmat2x3<T, P>(
660			m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
661			m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
662			m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],
663			m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
664			m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
665			m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]);
666	}
667
668	template <typename T, precision P>
669	GLM_FUNC_QUALIFIER tmat4x3<T, P> operator*
670	(
671		tmat3x3<T, P> const & m1,
672		tmat4x3<T, P> const & m2
673	)
674	{
675		return tmat4x3<T, P>(
676			m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
677			m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
678			m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],
679			m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
680			m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
681			m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],
682			m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],
683			m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],
684			m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2],
685			m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2],
686			m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2],
687			m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]);
688	}
689
690	template <typename T, precision P>
691	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator/
692	(
693		tmat3x3<T, P> const & m,
694		T const & s
695	)
696	{
697		return tmat3x3<T, P>(
698			m[0] / s,
699			m[1] / s,
700			m[2] / s);
701	}
702
703	template <typename T, precision P>
704	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator/
705	(
706		T const & s,
707		tmat3x3<T, P> const & m
708	)
709	{
710		return tmat3x3<T, P>(
711			s / m[0],
712			s / m[1],
713			s / m[2]);
714	}
715
716	template <typename T, precision P>
717	GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type operator/
718	(
719		tmat3x3<T, P> const & m,
720		typename tmat3x3<T, P>::row_type const & v
721	)
722	{
723		return detail::compute_inverse<detail::tmat3x3, T, P>::call(m) * v;
724	}
725
726	template <typename T, precision P>
727	GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::row_type operator/
728	(
729		typename tmat3x3<T, P>::col_type const & v,
730		tmat3x3<T, P> const & m
731	)
732	{
733		return v * detail::compute_inverse<detail::tmat3x3, T, P>::call(m);
734	}
735
736	template <typename T, precision P>
737	GLM_FUNC_QUALIFIER tmat3x3<T, P> operator/
738	(
739		tmat3x3<T, P> const & m1,
740		tmat3x3<T, P> const & m2
741	)
742	{
743		tmat3x3<T, P> m1_copy(m1);
744		return m1_copy /= m2;
745	}
746
747	// Unary constant operators
748	template <typename T, precision P>
749	GLM_FUNC_QUALIFIER tmat3x3<T, P> const operator-
750	(
751		tmat3x3<T, P> const & m
752	)
753	{
754		return tmat3x3<T, P>(
755			-m[0],
756			-m[1],
757			-m[2]);
758	}
759
760	//////////////////////////////////////
761	// Boolean operators
762
763	template <typename T, precision P>
764	GLM_FUNC_QUALIFIER bool operator==
765	(
766		tmat3x3<T, P> const & m1,
767		tmat3x3<T, P> const & m2
768	)
769	{
770		return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);
771	}
772
773	template <typename T, precision P>
774	GLM_FUNC_QUALIFIER bool operator!=
775	(
776		tmat3x3<T, P> const & m1,
777		tmat3x3<T, P> const & m2
778	)
779	{
780		return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);
781	}
782
783} //namespace detail
784} //namespace glm
785