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_geometric.inl
25/// @date 2008-08-03 / 2011-06-15
26/// @author Christophe Riccio
27///////////////////////////////////////////////////////////////////////////////////
28
29#include "func_exponential.hpp"
30#include "func_common.hpp"
31#include "type_vec2.hpp"
32#include "type_vec4.hpp"
33#include "type_float.hpp"
34
35namespace glm{
36namespace detail
37{
38	template <template <class, precision> class vecType, typename T, precision P>
39	struct compute_dot{};
40
41	template <typename T, precision P>
42	struct compute_dot<detail::tvec1, T, P>
43	{
44		GLM_FUNC_QUALIFIER static T call(detail::tvec1<T, P> const & x, detail::tvec1<T, P> const & y)
45		{
46#			ifdef __CUDACC__ // Wordaround for a CUDA compiler bug up to CUDA6
47				detail::tvec1<T, P> tmp(x * y);
48				return tmp.x;
49#			else
50				return detail::tvec1<T, P>(x * y).x;
51#			endif
52		}
53	};
54
55	template <typename T, precision P>
56	struct compute_dot<detail::tvec2, T, P>
57	{
58		GLM_FUNC_QUALIFIER static T call(detail::tvec2<T, P> const & x, detail::tvec2<T, P> const & y)
59		{
60			detail::tvec2<T, P> tmp(x * y);
61			return tmp.x + tmp.y;
62		}
63	};
64
65	template <typename T, precision P>
66	struct compute_dot<detail::tvec3, T, P>
67	{
68		GLM_FUNC_QUALIFIER static T call(detail::tvec3<T, P> const & x, detail::tvec3<T, P> const & y)
69		{
70			detail::tvec3<T, P> tmp(x * y);
71			return tmp.x + tmp.y + tmp.z;
72		}
73	};
74
75	template <typename T, precision P>
76	struct compute_dot<detail::tvec4, T, P>
77	{
78		GLM_FUNC_QUALIFIER static T call(detail::tvec4<T, P> const & x, detail::tvec4<T, P> const & y)
79		{
80			detail::tvec4<T, P> tmp(x * y);
81			return (tmp.x + tmp.y) + (tmp.z + tmp.w);
82		}
83	};
84}//namespace detail
85
86	// length
87	template <typename genType>
88	GLM_FUNC_QUALIFIER genType length
89	(
90		genType const & x
91	)
92	{
93		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'length' only accept floating-point inputs");
94
95		genType sqr = x * x;
96		return sqrt(sqr);
97	}
98
99	template <typename T, precision P>
100	GLM_FUNC_QUALIFIER T length(detail::tvec2<T, P> const & v)
101	{
102		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'length' only accept floating-point inputs");
103
104		T sqr = v.x * v.x + v.y * v.y;
105		return sqrt(sqr);
106	}
107
108	template <typename T, precision P>
109	GLM_FUNC_QUALIFIER T length(detail::tvec3<T, P> const & v)
110	{
111		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'length' only accept floating-point inputs");
112
113		T sqr = v.x * v.x + v.y * v.y + v.z * v.z;
114		return sqrt(sqr);
115	}
116
117	template <typename T, precision P>
118	GLM_FUNC_QUALIFIER T length(detail::tvec4<T, P> const & v)
119	{
120		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'length' only accept floating-point inputs");
121
122		T sqr = v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;
123		return sqrt(sqr);
124	}
125
126	// distance
127	template <typename genType>
128	GLM_FUNC_QUALIFIER genType distance
129	(
130		genType const & p0,
131		genType const & p1
132	)
133	{
134		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'distance' only accept floating-point inputs");
135
136		return length(p1 - p0);
137	}
138
139	template <typename T, precision P>
140	GLM_FUNC_QUALIFIER T distance
141	(
142		detail::tvec2<T, P> const & p0,
143		detail::tvec2<T, P> const & p1
144	)
145	{
146		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'distance' only accept floating-point inputs");
147
148		return length(p1 - p0);
149	}
150
151	template <typename T, precision P>
152	GLM_FUNC_QUALIFIER T distance
153	(
154		detail::tvec3<T, P> const & p0,
155		detail::tvec3<T, P> const & p1
156	)
157	{
158		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'distance' only accept floating-point inputs");
159
160		return length(p1 - p0);
161	}
162
163	template <typename T, precision P>
164	GLM_FUNC_QUALIFIER T distance
165	(
166		detail::tvec4<T, P> const & p0,
167		detail::tvec4<T, P> const & p1
168	)
169	{
170		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'distance' only accept floating-point inputs");
171
172		return length(p1 - p0);
173	}
174
175	// dot
176	template <typename T>
177	GLM_FUNC_QUALIFIER T dot
178	(
179		T const & x,
180		T const & y
181	)
182	{
183		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'dot' only accept floating-point inputs");
184		return detail::compute_dot<detail::tvec1, T, highp>::call(x, y);
185	}
186
187	template <typename T, precision P, template <typename, precision> class vecType>
188	GLM_FUNC_QUALIFIER T dot
189	(
190		vecType<T, P> const & x,
191		vecType<T, P> const & y
192	)
193	{
194		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'dot' only accept floating-point inputs");
195		return detail::compute_dot<vecType, T, P>::call(x, y);
196	}
197
198/* // SSE3
199	GLM_FUNC_QUALIFIER float dot(const tvec4<float>& x, const tvec4<float>& y)
200	{
201		float Result;
202		__asm
203		{
204			mov		esi, x
205			mov		edi, y
206			movaps	xmm0, [esi]
207			mulps	xmm0, [edi]
208			haddps(	_xmm0, _xmm0 )
209			haddps(	_xmm0, _xmm0 )
210			movss	Result, xmm0
211		}
212		return Result;
213	}
214*/
215	// cross
216	template <typename T, precision P>
217	GLM_FUNC_QUALIFIER detail::tvec3<T, P> cross
218	(
219		detail::tvec3<T, P> const & x,
220		detail::tvec3<T, P> const & y
221	)
222	{
223		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'cross' only accept floating-point inputs");
224
225		return detail::tvec3<T, P>(
226			x.y * y.z - y.y * x.z,
227			x.z * y.x - y.z * x.x,
228			x.x * y.y - y.x * x.y);
229	}
230
231	// normalize
232	template <typename genType>
233	GLM_FUNC_QUALIFIER genType normalize
234	(
235		genType const & x
236	)
237	{
238		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'normalize' only accept floating-point inputs");
239
240		return x < genType(0) ? genType(-1) : genType(1);
241	}
242
243	// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefine and generate an error
244	template <typename T, precision P>
245	GLM_FUNC_QUALIFIER detail::tvec2<T, P> normalize
246	(
247		detail::tvec2<T, P> const & x
248	)
249	{
250		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' only accept floating-point inputs");
251
252		T sqr = x.x * x.x + x.y * x.y;
253		return x * inversesqrt(sqr);
254	}
255
256	template <typename T, precision P>
257	GLM_FUNC_QUALIFIER detail::tvec3<T, P> normalize
258	(
259		detail::tvec3<T, P> const & x
260	)
261	{
262		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' only accept floating-point inputs");
263
264		T sqr = x.x * x.x + x.y * x.y + x.z * x.z;
265		return x * inversesqrt(sqr);
266	}
267
268	template <typename T, precision P>
269	GLM_FUNC_QUALIFIER detail::tvec4<T, P> normalize
270	(
271		detail::tvec4<T, P> const & x
272	)
273	{
274		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' only accept floating-point inputs");
275
276		T sqr = x.x * x.x + x.y * x.y + x.z * x.z + x.w * x.w;
277		return x * inversesqrt(sqr);
278	}
279
280	// faceforward
281	template <typename genType>
282	GLM_FUNC_QUALIFIER genType faceforward
283	(
284		genType const & N,
285		genType const & I,
286		genType const & Nref
287	)
288	{
289		return dot(Nref, I) < 0 ? N : -N;
290	}
291
292	// reflect
293	template <typename genType>
294	GLM_FUNC_QUALIFIER genType reflect
295	(
296		genType const & I,
297		genType const & N
298	)
299	{
300		return I - N * dot(N, I) * genType(2);
301	}
302
303	// refract
304	template <typename genType>
305	GLM_FUNC_QUALIFIER genType refract
306	(
307		genType const & I,
308		genType const & N,
309		genType const & eta
310	)
311	{
312		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'refract' only accept floating-point inputs");
313
314		genType dotValue = dot(N, I);
315		genType k = genType(1) - eta * eta * (genType(1) - dotValue * dotValue);
316		if(k < genType(0))
317			return genType(0);
318		else
319			return eta * I - (eta * dotValue + sqrt(k)) * N;
320	}
321
322	template <typename T, precision P, template <typename, precision> class vecType>
323	GLM_FUNC_QUALIFIER vecType<T, P> refract
324	(
325		vecType<T, P> const & I,
326		vecType<T, P> const & N,
327		T const & eta
328	)
329	{
330		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'refract' only accept floating-point inputs");
331
332		T dotValue = dot(N, I);
333		T k = T(1) - eta * eta * (T(1) - dotValue * dotValue);
334		if(k < T(0))
335			return vecType<T, P>(0);
336		else
337			return eta * I - (eta * dotValue + std::sqrt(k)) * N;
338	}
339
340}//namespace glm
341