blob: 25f137511b79da1633b57c35607e611c7f4aa886 [file] [log] [blame]
Dan Albert287553d2017-02-16 10:47:51 -08001///////////////////////////////////////////////////////////////////////////////////
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 gtc_matrix_transform
24/// @file glm/gtc/matrix_transform.inl
25/// @date 2009-04-29 / 2011-06-15
26/// @author Christophe Riccio
27///////////////////////////////////////////////////////////////////////////////////
28
29#include "../geometric.hpp"
30#include "../trigonometric.hpp"
31#include "../matrix.hpp"
32
33namespace glm
34{
35 template <typename T, precision P>
36 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> translate
37 (
38 detail::tmat4x4<T, P> const & m,
39 detail::tvec3<T, P> const & v
40 )
41 {
42 detail::tmat4x4<T, P> Result(m);
43 Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
44 return Result;
45 }
46
47 template <typename T, precision P>
48 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> rotate
49 (
50 detail::tmat4x4<T, P> const & m,
51 T const & angle,
52 detail::tvec3<T, P> const & v
53 )
54 {
55#ifdef GLM_FORCE_RADIANS
56 T a = angle;
57#else
58# pragma message("GLM: rotate function taking degrees as a parameter is deprecated. #define GLM_FORCE_RADIANS before including GLM headers to remove this message.")
59 T a = radians(angle);
60#endif
61 T c = cos(a);
62 T s = sin(a);
63
64 detail::tvec3<T, P> axis(normalize(v));
65 detail::tvec3<T, P> temp((T(1) - c) * axis);
66
67 detail::tmat4x4<T, P> Rotate(detail::tmat4x4<T, P>::_null);
68 Rotate[0][0] = c + temp[0] * axis[0];
69 Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];
70 Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];
71
72 Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];
73 Rotate[1][1] = c + temp[1] * axis[1];
74 Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];
75
76 Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];
77 Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];
78 Rotate[2][2] = c + temp[2] * axis[2];
79
80 detail::tmat4x4<T, P> Result(detail::tmat4x4<T, P>::_null);
81 Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
82 Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
83 Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
84 Result[3] = m[3];
85 return Result;
86 }
87
88 template <typename T, precision P>
89 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> rotate_slow
90 (
91 detail::tmat4x4<T, P> const & m,
92 T const & angle,
93 detail::tvec3<T, P> const & v
94 )
95 {
96#ifdef GLM_FORCE_RADIANS
97 T const a = angle;
98#else
99# pragma message("GLM: rotate_slow function taking degrees as a parameter is deprecated. #define GLM_FORCE_RADIANS before including GLM headers to remove this message.")
100 T const a = radians(angle);
101#endif
102 T c = cos(a);
103 T s = sin(a);
104 detail::tmat4x4<T, P> Result;
105
106 detail::tvec3<T, P> axis = normalize(v);
107
108 Result[0][0] = c + (1 - c) * axis.x * axis.x;
109 Result[0][1] = (1 - c) * axis.x * axis.y + s * axis.z;
110 Result[0][2] = (1 - c) * axis.x * axis.z - s * axis.y;
111 Result[0][3] = 0;
112
113 Result[1][0] = (1 - c) * axis.y * axis.x - s * axis.z;
114 Result[1][1] = c + (1 - c) * axis.y * axis.y;
115 Result[1][2] = (1 - c) * axis.y * axis.z + s * axis.x;
116 Result[1][3] = 0;
117
118 Result[2][0] = (1 - c) * axis.z * axis.x + s * axis.y;
119 Result[2][1] = (1 - c) * axis.z * axis.y - s * axis.x;
120 Result[2][2] = c + (1 - c) * axis.z * axis.z;
121 Result[2][3] = 0;
122
123 Result[3] = detail::tvec4<T, P>(0, 0, 0, 1);
124 return m * Result;
125 }
126
127 template <typename T, precision P>
128 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> scale
129 (
130 detail::tmat4x4<T, P> const & m,
131 detail::tvec3<T, P> const & v
132 )
133 {
134 detail::tmat4x4<T, P> Result(detail::tmat4x4<T, P>::_null);
135 Result[0] = m[0] * v[0];
136 Result[1] = m[1] * v[1];
137 Result[2] = m[2] * v[2];
138 Result[3] = m[3];
139 return Result;
140 }
141
142 template <typename T, precision P>
143 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> scale_slow
144 (
145 detail::tmat4x4<T, P> const & m,
146 detail::tvec3<T, P> const & v
147 )
148 {
149 detail::tmat4x4<T, P> Result(T(1));
150 Result[0][0] = v.x;
151 Result[1][1] = v.y;
152 Result[2][2] = v.z;
153 return m * Result;
154 }
155
156 template <typename T>
157 GLM_FUNC_QUALIFIER detail::tmat4x4<T, defaultp> ortho
158 (
159 T const & left,
160 T const & right,
161 T const & bottom,
162 T const & top,
163 T const & zNear,
164 T const & zFar
165 )
166 {
167 detail::tmat4x4<T, defaultp> Result(1);
168 Result[0][0] = static_cast<T>(2) / (right - left);
169 Result[1][1] = static_cast<T>(2) / (top - bottom);
170 Result[2][2] = - T(2) / (zFar - zNear);
171 Result[3][0] = - (right + left) / (right - left);
172 Result[3][1] = - (top + bottom) / (top - bottom);
173 Result[3][2] = - (zFar + zNear) / (zFar - zNear);
174 return Result;
175 }
176
177 template <typename T>
178 GLM_FUNC_QUALIFIER detail::tmat4x4<T, defaultp> ortho
179 (
180 T const & left,
181 T const & right,
182 T const & bottom,
183 T const & top
184 )
185 {
186 detail::tmat4x4<T, defaultp> Result(1);
187 Result[0][0] = static_cast<T>(2) / (right - left);
188 Result[1][1] = static_cast<T>(2) / (top - bottom);
189 Result[2][2] = - T(1);
190 Result[3][0] = - (right + left) / (right - left);
191 Result[3][1] = - (top + bottom) / (top - bottom);
192 return Result;
193 }
194
195 template <typename valType>
196 GLM_FUNC_QUALIFIER detail::tmat4x4<valType, defaultp> frustum
197 (
198 valType const & left,
199 valType const & right,
200 valType const & bottom,
201 valType const & top,
202 valType const & nearVal,
203 valType const & farVal
204 )
205 {
206 detail::tmat4x4<valType, defaultp> Result(0);
207 Result[0][0] = (valType(2) * nearVal) / (right - left);
208 Result[1][1] = (valType(2) * nearVal) / (top - bottom);
209 Result[2][0] = (right + left) / (right - left);
210 Result[2][1] = (top + bottom) / (top - bottom);
211 Result[2][2] = -(farVal + nearVal) / (farVal - nearVal);
212 Result[2][3] = valType(-1);
213 Result[3][2] = -(valType(2) * farVal * nearVal) / (farVal - nearVal);
214 return Result;
215 }
216
217 template <typename valType>
218 GLM_FUNC_QUALIFIER detail::tmat4x4<valType, defaultp> perspective
219 (
220 valType const & fovy,
221 valType const & aspect,
222 valType const & zNear,
223 valType const & zFar
224 )
225 {
226 assert(aspect != valType(0));
227 assert(zFar != zNear);
228
229#ifdef GLM_FORCE_RADIANS
230 valType const rad = fovy;
231#else
232# pragma message("GLM: perspective function taking degrees as a parameter is deprecated. #define GLM_FORCE_RADIANS before including GLM headers to remove this message.")
233 valType const rad = glm::radians(fovy);
234#endif
235
236 valType tanHalfFovy = tan(rad / valType(2));
237
238 detail::tmat4x4<valType, defaultp> Result(valType(0));
239 Result[0][0] = valType(1) / (aspect * tanHalfFovy);
240 Result[1][1] = valType(1) / (tanHalfFovy);
241 Result[2][2] = - (zFar + zNear) / (zFar - zNear);
242 Result[2][3] = - valType(1);
243 Result[3][2] = - (valType(2) * zFar * zNear) / (zFar - zNear);
244 return Result;
245 }
246
247 template <typename valType>
248 GLM_FUNC_QUALIFIER detail::tmat4x4<valType, defaultp> perspectiveFov
249 (
250 valType const & fov,
251 valType const & width,
252 valType const & height,
253 valType const & zNear,
254 valType const & zFar
255 )
256 {
257 assert(width > valType(0));
258 assert(height > valType(0));
259 assert(fov > valType(0));
260
261#ifdef GLM_FORCE_RADIANS
262 valType rad = fov;
263#else
264# pragma message("GLM: perspectiveFov function taking degrees as a parameter is deprecated. #define GLM_FORCE_RADIANS before including GLM headers to remove this message.")
265 valType rad = glm::radians(fov);
266#endif
267 valType h = glm::cos(valType(0.5) * rad) / glm::sin(valType(0.5) * rad);
268 valType w = h * height / width; ///todo max(width , Height) / min(width , Height)?
269
270 detail::tmat4x4<valType, defaultp> Result(valType(0));
271 Result[0][0] = w;
272 Result[1][1] = h;
273 Result[2][2] = - (zFar + zNear) / (zFar - zNear);
274 Result[2][3] = - valType(1);
275 Result[3][2] = - (valType(2) * zFar * zNear) / (zFar - zNear);
276 return Result;
277 }
278
279 template <typename T>
280 GLM_FUNC_QUALIFIER detail::tmat4x4<T, defaultp> infinitePerspective
281 (
282 T fovy,
283 T aspect,
284 T zNear
285 )
286 {
287#ifdef GLM_FORCE_RADIANS
288 T const range = tan(fovy / T(2)) * zNear;
289#else
290# pragma message("GLM: infinitePerspective function taking degrees as a parameter is deprecated. #define GLM_FORCE_RADIANS before including GLM headers to remove this message.")
291 T const range = tan(radians(fovy / T(2))) * zNear;
292#endif
293 T left = -range * aspect;
294 T right = range * aspect;
295 T bottom = -range;
296 T top = range;
297
298 detail::tmat4x4<T, defaultp> Result(T(0));
299 Result[0][0] = (T(2) * zNear) / (right - left);
300 Result[1][1] = (T(2) * zNear) / (top - bottom);
301 Result[2][2] = - T(1);
302 Result[2][3] = - T(1);
303 Result[3][2] = - T(2) * zNear;
304 return Result;
305 }
306
307 template <typename T>
308 GLM_FUNC_QUALIFIER detail::tmat4x4<T, defaultp> tweakedInfinitePerspective
309 (
310 T fovy,
311 T aspect,
312 T zNear
313 )
314 {
315#ifdef GLM_FORCE_RADIANS
316 T range = tan(fovy / T(2)) * zNear;
317#else
318# pragma message("GLM: tweakedInfinitePerspective function taking degrees as a parameter is deprecated. #define GLM_FORCE_RADIANS before including GLM headers to remove this message.")
319 T range = tan(radians(fovy / T(2))) * zNear;
320#endif
321 T left = -range * aspect;
322 T right = range * aspect;
323 T bottom = -range;
324 T top = range;
325
326 detail::tmat4x4<T, defaultp> Result(T(0));
327 Result[0][0] = (T(2) * zNear) / (right - left);
328 Result[1][1] = (T(2) * zNear) / (top - bottom);
329 Result[2][2] = static_cast<T>(0.0001) - T(1);
330 Result[2][3] = static_cast<T>(-1);
331 Result[3][2] = - (T(0.0001) - T(2)) * zNear;
332 return Result;
333 }
334
335 template <typename T, typename U, precision P>
336 GLM_FUNC_QUALIFIER detail::tvec3<T, P> project
337 (
338 detail::tvec3<T, P> const & obj,
339 detail::tmat4x4<T, P> const & model,
340 detail::tmat4x4<T, P> const & proj,
341 detail::tvec4<U, P> const & viewport
342 )
343 {
344 detail::tvec4<T, P> tmp = detail::tvec4<T, P>(obj, T(1));
345 tmp = model * tmp;
346 tmp = proj * tmp;
347
348 tmp /= tmp.w;
349 tmp = tmp * T(0.5) + T(0.5);
350 tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]);
351 tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]);
352
353 return detail::tvec3<T, P>(tmp);
354 }
355
356 template <typename T, typename U, precision P>
357 GLM_FUNC_QUALIFIER detail::tvec3<T, P> unProject
358 (
359 detail::tvec3<T, P> const & win,
360 detail::tmat4x4<T, P> const & model,
361 detail::tmat4x4<T, P> const & proj,
362 detail::tvec4<U, P> const & viewport
363 )
364 {
365 detail::tmat4x4<T, P> Inverse = inverse(proj * model);
366
367 detail::tvec4<T, P> tmp = detail::tvec4<T, P>(win, T(1));
368 tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]);
369 tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]);
370 tmp = tmp * T(2) - T(1);
371
372 detail::tvec4<T, P> obj = Inverse * tmp;
373 obj /= obj.w;
374
375 return detail::tvec3<T, P>(obj);
376 }
377
378 template <typename T, precision P, typename U>
379 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> pickMatrix
380 (
381 detail::tvec2<T, P> const & center,
382 detail::tvec2<T, P> const & delta,
383 detail::tvec4<U, P> const & viewport
384 )
385 {
386 assert(delta.x > T(0) && delta.y > T(0));
387 detail::tmat4x4<T, P> Result(1.0f);
388
389 if(!(delta.x > T(0) && delta.y > T(0)))
390 return Result; // Error
391
392 detail::tvec3<T, P> Temp(
393 (T(viewport[2]) - T(2) * (center.x - T(viewport[0]))) / delta.x,
394 (T(viewport[3]) - T(2) * (center.y - T(viewport[1]))) / delta.y,
395 T(0));
396
397 // Translate and scale the picked region to the entire window
398 Result = translate(Result, Temp);
399 return scale(Result, detail::tvec3<T, P>(T(viewport[2]) / delta.x, T(viewport[3]) / delta.y, T(1)));
400 }
401
402 template <typename T, precision P>
403 GLM_FUNC_QUALIFIER detail::tmat4x4<T, P> lookAt
404 (
405 detail::tvec3<T, P> const & eye,
406 detail::tvec3<T, P> const & center,
407 detail::tvec3<T, P> const & up
408 )
409 {
410 detail::tvec3<T, P> f(normalize(center - eye));
411 detail::tvec3<T, P> s(normalize(cross(f, up)));
412 detail::tvec3<T, P> u(cross(s, f));
413
414 detail::tmat4x4<T, P> Result(1);
415 Result[0][0] = s.x;
416 Result[1][0] = s.y;
417 Result[2][0] = s.z;
418 Result[0][1] = u.x;
419 Result[1][1] = u.y;
420 Result[2][1] = u.z;
421 Result[0][2] =-f.x;
422 Result[1][2] =-f.y;
423 Result[2][2] =-f.z;
424 Result[3][0] =-dot(s, eye);
425 Result[3][1] =-dot(u, eye);
426 Result[3][2] = dot(f, eye);
427 return Result;
428 }
429}//namespace glm