1/// @ref gtc_matrix_transform
2/// @file glm/gtc/matrix_transform.inl
3
4#include "../geometric.hpp"
5#include "../trigonometric.hpp"
6#include "../matrix.hpp"
7
8namespace glm
9{
10	template<typename T, qualifier Q>
11	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)
12	{
13		mat<4, 4, T, Q> Result(m);
14		Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
15		return Result;
16	}
17
18	template<typename T, qualifier Q>
19	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v)
20	{
21		T const a = angle;
22		T const c = cos(a);
23		T const s = sin(a);
24
25		vec<3, T, Q> axis(normalize(v));
26		vec<3, T, Q> temp((T(1) - c) * axis);
27
28		mat<4, 4, T, Q> Rotate;
29		Rotate[0][0] = c + temp[0] * axis[0];
30		Rotate[0][1] = temp[0] * axis[1] + s * axis[2];
31		Rotate[0][2] = temp[0] * axis[2] - s * axis[1];
32
33		Rotate[1][0] = temp[1] * axis[0] - s * axis[2];
34		Rotate[1][1] = c + temp[1] * axis[1];
35		Rotate[1][2] = temp[1] * axis[2] + s * axis[0];
36
37		Rotate[2][0] = temp[2] * axis[0] + s * axis[1];
38		Rotate[2][1] = temp[2] * axis[1] - s * axis[0];
39		Rotate[2][2] = c + temp[2] * axis[2];
40
41		mat<4, 4, T, Q> Result;
42		Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
43		Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
44		Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
45		Result[3] = m[3];
46		return Result;
47	}
48
49	template<typename T, qualifier Q>
50	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v)
51	{
52		T const a = angle;
53		T const c = cos(a);
54		T const s = sin(a);
55		mat<4, 4, T, Q> Result;
56
57		vec<3, T, Q> axis = normalize(v);
58
59		Result[0][0] = c + (static_cast<T>(1) - c)      * axis.x     * axis.x;
60		Result[0][1] = (static_cast<T>(1) - c) * axis.x * axis.y + s * axis.z;
61		Result[0][2] = (static_cast<T>(1) - c) * axis.x * axis.z - s * axis.y;
62		Result[0][3] = static_cast<T>(0);
63
64		Result[1][0] = (static_cast<T>(1) - c) * axis.y * axis.x - s * axis.z;
65		Result[1][1] = c + (static_cast<T>(1) - c) * axis.y * axis.y;
66		Result[1][2] = (static_cast<T>(1) - c) * axis.y * axis.z + s * axis.x;
67		Result[1][3] = static_cast<T>(0);
68
69		Result[2][0] = (static_cast<T>(1) - c) * axis.z * axis.x + s * axis.y;
70		Result[2][1] = (static_cast<T>(1) - c) * axis.z * axis.y - s * axis.x;
71		Result[2][2] = c + (static_cast<T>(1) - c) * axis.z * axis.z;
72		Result[2][3] = static_cast<T>(0);
73
74		Result[3] = vec<4, T, Q>(0, 0, 0, 1);
75		return m * Result;
76	}
77
78	template<typename T, qualifier Q>
79	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)
80	{
81		mat<4, 4, T, Q> Result;
82		Result[0] = m[0] * v[0];
83		Result[1] = m[1] * v[1];
84		Result[2] = m[2] * v[2];
85		Result[3] = m[3];
86		return Result;
87	}
88
89	template<typename T, qualifier Q>
90	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)
91	{
92		mat<4, 4, T, Q> Result(T(1));
93		Result[0][0] = v.x;
94		Result[1][1] = v.y;
95		Result[2][2] = v.z;
96		return m * Result;
97	}
98
99	template<typename T>
100	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top)
101	{
102		mat<4, 4, T, defaultp> Result(static_cast<T>(1));
103		Result[0][0] = static_cast<T>(2) / (right - left);
104		Result[1][1] = static_cast<T>(2) / (top - bottom);
105		Result[3][0] = - (right + left) / (right - left);
106		Result[3][1] = - (top + bottom) / (top - bottom);
107		return Result;
108	}
109
110	template<typename T>
111	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar)
112	{
113		mat<4, 4, T, defaultp> Result(1);
114		Result[0][0] = static_cast<T>(2) / (right - left);
115		Result[1][1] = static_cast<T>(2) / (top - bottom);
116		Result[2][2] = static_cast<T>(1) / (zFar - zNear);
117		Result[3][0] = - (right + left) / (right - left);
118		Result[3][1] = - (top + bottom) / (top - bottom);
119		Result[3][2] = - zNear / (zFar - zNear);
120		return Result;
121	}
122
123	template<typename T>
124	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar)
125	{
126		mat<4, 4, T, defaultp> Result(1);
127		Result[0][0] = static_cast<T>(2) / (right - left);
128		Result[1][1] = static_cast<T>(2) / (top - bottom);
129		Result[2][2] = static_cast<T>(2) / (zFar - zNear);
130		Result[3][0] = - (right + left) / (right - left);
131		Result[3][1] = - (top + bottom) / (top - bottom);
132		Result[3][2] = - (zFar + zNear) / (zFar - zNear);
133		return Result;
134	}
135
136	template<typename T>
137	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar)
138	{
139		mat<4, 4, T, defaultp> Result(1);
140		Result[0][0] = static_cast<T>(2) / (right - left);
141		Result[1][1] = static_cast<T>(2) / (top - bottom);
142		Result[2][2] = - static_cast<T>(1) / (zFar - zNear);
143		Result[3][0] = - (right + left) / (right - left);
144		Result[3][1] = - (top + bottom) / (top - bottom);
145		Result[3][2] = - zNear / (zFar - zNear);
146		return Result;
147	}
148
149	template<typename T>
150	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar)
151	{
152		mat<4, 4, T, defaultp> Result(1);
153		Result[0][0] = static_cast<T>(2) / (right - left);
154		Result[1][1] = static_cast<T>(2) / (top - bottom);
155		Result[2][2] = - static_cast<T>(2) / (zFar - zNear);
156		Result[3][0] = - (right + left) / (right - left);
157		Result[3][1] = - (top + bottom) / (top - bottom);
158		Result[3][2] = - (zFar + zNear) / (zFar - zNear);
159		return Result;
160	}
161
162	template<typename T>
163	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar)
164	{
165#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
166			return orthoLH_ZO(left, right, bottom, top, zNear, zFar);
167#		else
168			return orthoRH_ZO(left, right, bottom, top, zNear, zFar);
169#		endif
170	}
171
172	template<typename T>
173	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar)
174	{
175#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
176			return orthoLH_NO(left, right, bottom, top, zNear, zFar);
177#		else
178			return orthoRH_NO(left, right, bottom, top, zNear, zFar);
179#		endif
180	}
181
182	template<typename T>
183	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar)
184	{
185#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
186			return orthoLH_ZO(left, right, bottom, top, zNear, zFar);
187#		else
188			return orthoLH_NO(left, right, bottom, top, zNear, zFar);
189#		endif
190	}
191
192	template<typename T>
193	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar)
194	{
195#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
196			return orthoRH_ZO(left, right, bottom, top, zNear, zFar);
197#		else
198			return orthoRH_NO(left, right, bottom, top, zNear, zFar);
199#		endif
200	}
201
202	template<typename T>
203	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar)
204	{
205#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
206			return orthoLH_ZO(left, right, bottom, top, zNear, zFar);
207#		elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
208			return orthoLH_NO(left, right, bottom, top, zNear, zFar);
209#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
210			return orthoRH_ZO(left, right, bottom, top, zNear, zFar);
211#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
212			return orthoRH_NO(left, right, bottom, top, zNear, zFar);
213#		endif
214	}
215
216	template<typename T>
217	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal)
218	{
219		mat<4, 4, T, defaultp> Result(0);
220		Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
221		Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
222		Result[2][0] = (right + left) / (right - left);
223		Result[2][1] = (top + bottom) / (top - bottom);
224		Result[2][2] = farVal / (farVal - nearVal);
225		Result[2][3] = static_cast<T>(1);
226		Result[3][2] = -(farVal * nearVal) / (farVal - nearVal);
227		return Result;
228	}
229
230	template<typename T>
231	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal)
232	{
233		mat<4, 4, T, defaultp> Result(0);
234		Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
235		Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
236		Result[2][0] = (right + left) / (right - left);
237		Result[2][1] = (top + bottom) / (top - bottom);
238		Result[2][2] = (farVal + nearVal) / (farVal - nearVal);
239		Result[2][3] = static_cast<T>(1);
240		Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);
241		return Result;
242	}
243
244	template<typename T>
245	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal)
246	{
247		mat<4, 4, T, defaultp> Result(0);
248		Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
249		Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
250		Result[2][0] = (right + left) / (right - left);
251		Result[2][1] = (top + bottom) / (top - bottom);
252		Result[2][2] = farVal / (nearVal - farVal);
253		Result[2][3] = static_cast<T>(-1);
254		Result[3][2] = -(farVal * nearVal) / (farVal - nearVal);
255		return Result;
256	}
257
258	template<typename T>
259	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal)
260	{
261		mat<4, 4, T, defaultp> Result(0);
262		Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
263		Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
264		Result[2][0] = (right + left) / (right - left);
265		Result[2][1] = (top + bottom) / (top - bottom);
266		Result[2][2] = - (farVal + nearVal) / (farVal - nearVal);
267		Result[2][3] = static_cast<T>(-1);
268		Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);
269		return Result;
270	}
271
272	template<typename T>
273	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal)
274	{
275#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
276			return frustumLH_ZO(left, right, bottom, top, nearVal, farVal);
277#		else
278			return frustumRH_ZO(left, right, bottom, top, nearVal, farVal);
279#		endif
280	}
281
282	template<typename T>
283	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal)
284	{
285#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
286			return frustumLH_NO(left, right, bottom, top, nearVal, farVal);
287#		else
288			return frustumRH_NO(left, right, bottom, top, nearVal, farVal);
289#		endif
290	}
291
292	template<typename T>
293	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal)
294	{
295#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
296			return frustumLH_ZO(left, right, bottom, top, nearVal, farVal);
297#		else
298			return frustumLH_NO(left, right, bottom, top, nearVal, farVal);
299#		endif
300	}
301
302	template<typename T>
303	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal)
304	{
305#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
306			return frustumRH_ZO(left, right, bottom, top, nearVal, farVal);
307#		else
308			return frustumRH_NO(left, right, bottom, top, nearVal, farVal);
309#		endif
310	}
311
312	template<typename T>
313	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal)
314	{
315#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
316			return frustumLH_ZO(left, right, bottom, top, nearVal, farVal);
317#		elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
318			return frustumLH_NO(left, right, bottom, top, nearVal, farVal);
319#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
320			return frustumRH_ZO(left, right, bottom, top, nearVal, farVal);
321#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
322			return frustumRH_NO(left, right, bottom, top, nearVal, farVal);
323#		endif
324	}
325
326	template<typename T>
327	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar)
328	{
329		assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
330
331		T const tanHalfFovy = tan(fovy / static_cast<T>(2));
332
333		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
334		Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
335		Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
336		Result[2][2] = zFar / (zNear - zFar);
337		Result[2][3] = - static_cast<T>(1);
338		Result[3][2] = -(zFar * zNear) / (zFar - zNear);
339		return Result;
340	}
341
342	template<typename T>
343	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar)
344	{
345		assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
346
347		T const tanHalfFovy = tan(fovy / static_cast<T>(2));
348
349		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
350		Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
351		Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
352		Result[2][2] = - (zFar + zNear) / (zFar - zNear);
353		Result[2][3] = - static_cast<T>(1);
354		Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
355		return Result;
356	}
357
358	template<typename T>
359	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar)
360	{
361		assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
362
363		T const tanHalfFovy = tan(fovy / static_cast<T>(2));
364
365		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
366		Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
367		Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
368		Result[2][2] = zFar / (zFar - zNear);
369		Result[2][3] = static_cast<T>(1);
370		Result[3][2] = -(zFar * zNear) / (zFar - zNear);
371		return Result;
372	}
373
374	template<typename T>
375	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar)
376	{
377		assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
378
379		T const tanHalfFovy = tan(fovy / static_cast<T>(2));
380
381		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
382		Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
383		Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
384		Result[2][2] = (zFar + zNear) / (zFar - zNear);
385		Result[2][3] = static_cast<T>(1);
386		Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
387		return Result;
388	}
389
390	template<typename T>
391	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar)
392	{
393#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
394			return perspectiveLH_ZO(fovy, aspect, zNear, zFar);
395#		else
396			return perspectiveRH_ZO(fovy, aspect, zNear, zFar);
397#		endif
398	}
399
400	template<typename T>
401	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar)
402	{
403#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
404			return perspectiveLH_NO(fovy, aspect, zNear, zFar);
405#		else
406			return perspectiveRH_NO(fovy, aspect, zNear, zFar);
407#		endif
408	}
409
410	template<typename T>
411	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar)
412	{
413#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
414			return perspectiveLH_ZO(fovy, aspect, zNear, zFar);
415#		else
416			return perspectiveLH_NO(fovy, aspect, zNear, zFar);
417#		endif
418	}
419
420	template<typename T>
421	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar)
422	{
423#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
424			return perspectiveRH_ZO(fovy, aspect, zNear, zFar);
425#		else
426			return perspectiveRH_NO(fovy, aspect, zNear, zFar);
427#		endif
428	}
429
430	template<typename T>
431	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar)
432	{
433#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
434			return perspectiveLH_ZO(fovy, aspect, zNear, zFar);
435#		elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
436			return perspectiveLH_NO(fovy, aspect, zNear, zFar);
437#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
438			return perspectiveRH_ZO(fovy, aspect, zNear, zFar);
439#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
440			return perspectiveRH_NO(fovy, aspect, zNear, zFar);
441#		endif
442	}
443
444	template<typename T>
445	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar)
446	{
447		assert(width > static_cast<T>(0));
448		assert(height > static_cast<T>(0));
449		assert(fov > static_cast<T>(0));
450
451		T const rad = fov;
452		T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);
453		T const w = h * height / width; ///todo max(width , Height) / min(width , Height)?
454
455		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
456		Result[0][0] = w;
457		Result[1][1] = h;
458		Result[2][2] = zFar / (zNear - zFar);
459		Result[2][3] = - static_cast<T>(1);
460		Result[3][2] = -(zFar * zNear) / (zFar - zNear);
461		return Result;
462	}
463
464	template<typename T>
465	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar)
466	{
467		assert(width > static_cast<T>(0));
468		assert(height > static_cast<T>(0));
469		assert(fov > static_cast<T>(0));
470
471		T const rad = fov;
472		T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);
473		T const w = h * height / width; ///todo max(width , Height) / min(width , Height)?
474
475		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
476		Result[0][0] = w;
477		Result[1][1] = h;
478		Result[2][2] = - (zFar + zNear) / (zFar - zNear);
479		Result[2][3] = - static_cast<T>(1);
480		Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
481		return Result;
482	}
483
484	template<typename T>
485	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar)
486	{
487		assert(width > static_cast<T>(0));
488		assert(height > static_cast<T>(0));
489		assert(fov > static_cast<T>(0));
490
491		T const rad = fov;
492		T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);
493		T const w = h * height / width; ///todo max(width , Height) / min(width , Height)?
494
495		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
496		Result[0][0] = w;
497		Result[1][1] = h;
498		Result[2][2] = zFar / (zFar - zNear);
499		Result[2][3] = static_cast<T>(1);
500		Result[3][2] = -(zFar * zNear) / (zFar - zNear);
501		return Result;
502	}
503
504	template<typename T>
505	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar)
506	{
507		assert(width > static_cast<T>(0));
508		assert(height > static_cast<T>(0));
509		assert(fov > static_cast<T>(0));
510
511		T const rad = fov;
512		T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);
513		T const w = h * height / width; ///todo max(width , Height) / min(width , Height)?
514
515		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
516		Result[0][0] = w;
517		Result[1][1] = h;
518		Result[2][2] = (zFar + zNear) / (zFar - zNear);
519		Result[2][3] = static_cast<T>(1);
520		Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
521		return Result;
522	}
523
524	template<typename T>
525	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar)
526	{
527#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
528			return perspectiveFovLH_ZO(fov, width, height, zNear, zFar);
529#		else
530			return perspectiveFovRH_ZO(fov, width, height, zNear, zFar);
531#		endif
532	}
533
534	template<typename T>
535	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar)
536	{
537#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
538			return perspectiveFovLH_NO(fov, width, height, zNear, zFar);
539#		else
540			return perspectiveFovRH_NO(fov, width, height, zNear, zFar);
541#		endif
542	}
543
544	template<typename T>
545	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar)
546	{
547#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
548			return perspectiveFovLH_ZO(fov, width, height, zNear, zFar);
549#		else
550			return perspectiveFovLH_NO(fov, width, height, zNear, zFar);
551#		endif
552	}
553
554	template<typename T>
555	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar)
556	{
557#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
558			return perspectiveFovRH_ZO(fov, width, height, zNear, zFar);
559#		else
560			return perspectiveFovRH_NO(fov, width, height, zNear, zFar);
561#		endif
562	}
563
564	template<typename T>
565	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar)
566	{
567#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
568			return perspectiveFovLH_ZO(fov, width, height, zNear, zFar);
569#		elif GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
570			return perspectiveFovLH_NO(fov, width, height, zNear, zFar);
571#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
572			return perspectiveFovRH_ZO(fov, width, height, zNear, zFar);
573#		elif GLM_COORDINATE_SYSTEM == GLM_RIGHT_HANDED && GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_NEGATIVE_ONE_TO_ONE
574			return perspectiveFovRH_NO(fov, width, height, zNear, zFar);
575#		endif
576	}
577
578	template<typename T>
579	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear)
580	{
581		T const range = tan(fovy / static_cast<T>(2)) * zNear;
582		T const left = -range * aspect;
583		T const right = range * aspect;
584		T const bottom = -range;
585		T const top = range;
586
587		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
588		Result[0][0] = (static_cast<T>(2) * zNear) / (right - left);
589		Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);
590		Result[2][2] = - static_cast<T>(1);
591		Result[2][3] = - static_cast<T>(1);
592		Result[3][2] = - static_cast<T>(2) * zNear;
593		return Result;
594	}
595
596	template<typename T>
597	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear)
598	{
599		T const range = tan(fovy / static_cast<T>(2)) * zNear;
600		T const left = -range * aspect;
601		T const right = range * aspect;
602		T const bottom = -range;
603		T const top = range;
604
605		mat<4, 4, T, defaultp> Result(T(0));
606		Result[0][0] = (static_cast<T>(2) * zNear) / (right - left);
607		Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);
608		Result[2][2] = static_cast<T>(1);
609		Result[2][3] = static_cast<T>(1);
610		Result[3][2] = - static_cast<T>(2) * zNear;
611		return Result;
612	}
613
614	template<typename T>
615	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear)
616	{
617#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
618			return infinitePerspectiveLH(fovy, aspect, zNear);
619#		else
620			return infinitePerspectiveRH(fovy, aspect, zNear);
621#		endif
622	}
623
624	// Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf
625	template<typename T>
626	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep)
627	{
628		T const range = tan(fovy / static_cast<T>(2)) * zNear;
629		T const left = -range * aspect;
630		T const right = range * aspect;
631		T const bottom = -range;
632		T const top = range;
633
634		mat<4, 4, T, defaultp> Result(static_cast<T>(0));
635		Result[0][0] = (static_cast<T>(2) * zNear) / (right - left);
636		Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);
637		Result[2][2] = ep - static_cast<T>(1);
638		Result[2][3] = static_cast<T>(-1);
639		Result[3][2] = (ep - static_cast<T>(2)) * zNear;
640		return Result;
641	}
642
643	template<typename T>
644	GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear)
645	{
646		return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon<T>());
647	}
648
649	template<typename T, typename U, qualifier Q>
650	GLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)
651	{
652		vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast<T>(1));
653		tmp = model * tmp;
654		tmp = proj * tmp;
655
656		tmp /= tmp.w;
657		tmp.x = tmp.x * static_cast<T>(0.5) + static_cast<T>(0.5);
658		tmp.y = tmp.y * static_cast<T>(0.5) + static_cast<T>(0.5);
659
660		tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]);
661		tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]);
662
663		return vec<3, T, Q>(tmp);
664	}
665
666	template<typename T, typename U, qualifier Q>
667	GLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)
668	{
669		vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast<T>(1));
670		tmp = model * tmp;
671		tmp = proj * tmp;
672
673		tmp /= tmp.w;
674		tmp = tmp * static_cast<T>(0.5) + static_cast<T>(0.5);
675		tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]);
676		tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]);
677
678		return vec<3, T, Q>(tmp);
679	}
680
681	template<typename T, typename U, qualifier Q>
682	GLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)
683	{
684#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
685			return projectZO(obj, model, proj, viewport);
686#		else
687			return projectNO(obj, model, proj, viewport);
688#		endif
689	}
690
691	template<typename T, typename U, qualifier Q>
692	GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)
693	{
694		mat<4, 4, T, Q> Inverse = inverse(proj * model);
695
696		vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1));
697		tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]);
698		tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]);
699		tmp.x = tmp.x * static_cast<T>(2) - static_cast<T>(1);
700		tmp.y = tmp.y * static_cast<T>(2) - static_cast<T>(1);
701
702		vec<4, T, Q> obj = Inverse * tmp;
703		obj /= obj.w;
704
705		return vec<3, T, Q>(obj);
706	}
707
708	template<typename T, typename U, qualifier Q>
709	GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)
710	{
711		mat<4, 4, T, Q> Inverse = inverse(proj * model);
712
713		vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1));
714		tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]);
715		tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]);
716		tmp = tmp * static_cast<T>(2) - static_cast<T>(1);
717
718		vec<4, T, Q> obj = Inverse * tmp;
719		obj /= obj.w;
720
721		return vec<3, T, Q>(obj);
722	}
723
724	template<typename T, typename U, qualifier Q>
725	GLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)
726	{
727#		if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
728			return unProjectZO(win, model, proj, viewport);
729#		else
730			return unProjectNO(win, model, proj, viewport);
731#		endif
732	}
733
734	template<typename T, qualifier Q, typename U>
735	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport)
736	{
737		assert(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0));
738		mat<4, 4, T, Q> Result(static_cast<T>(1));
739
740		if(!(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0)))
741			return Result; // Error
742
743		vec<3, T, Q> Temp(
744			(static_cast<T>(viewport[2]) - static_cast<T>(2) * (center.x - static_cast<T>(viewport[0]))) / delta.x,
745			(static_cast<T>(viewport[3]) - static_cast<T>(2) * (center.y - static_cast<T>(viewport[1]))) / delta.y,
746			static_cast<T>(0));
747
748		// Translate and scale the picked region to the entire window
749		Result = translate(Result, Temp);
750		return scale(Result, vec<3, T, Q>(static_cast<T>(viewport[2]) / delta.x, static_cast<T>(viewport[3]) / delta.y, static_cast<T>(1)));
751	}
752
753	template<typename T, qualifier Q>
754	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
755	{
756		vec<3, T, Q> const f(normalize(center - eye));
757		vec<3, T, Q> const s(normalize(cross(f, up)));
758		vec<3, T, Q> const u(cross(s, f));
759
760		mat<4, 4, T, Q> Result(1);
761		Result[0][0] = s.x;
762		Result[1][0] = s.y;
763		Result[2][0] = s.z;
764		Result[0][1] = u.x;
765		Result[1][1] = u.y;
766		Result[2][1] = u.z;
767		Result[0][2] =-f.x;
768		Result[1][2] =-f.y;
769		Result[2][2] =-f.z;
770		Result[3][0] =-dot(s, eye);
771		Result[3][1] =-dot(u, eye);
772		Result[3][2] = dot(f, eye);
773		return Result;
774	}
775
776	template<typename T, qualifier Q>
777	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
778	{
779		vec<3, T, Q> const f(normalize(center - eye));
780		vec<3, T, Q> const s(normalize(cross(up, f)));
781		vec<3, T, Q> const u(cross(f, s));
782
783		mat<4, 4, T, Q> Result(1);
784		Result[0][0] = s.x;
785		Result[1][0] = s.y;
786		Result[2][0] = s.z;
787		Result[0][1] = u.x;
788		Result[1][1] = u.y;
789		Result[2][1] = u.z;
790		Result[0][2] = f.x;
791		Result[1][2] = f.y;
792		Result[2][2] = f.z;
793		Result[3][0] = -dot(s, eye);
794		Result[3][1] = -dot(u, eye);
795		Result[3][2] = -dot(f, eye);
796		return Result;
797	}
798
799	template<typename T, qualifier Q>
800	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
801	{
802#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
803			return lookAtLH(eye, center, up);
804#		else
805			return lookAtRH(eye, center, up);
806#		endif
807	}
808}//namespace glm
809