1/// @ref core
2/// @file glm/detail/func_geometric.inl
3
4#include "func_exponential.hpp"
5#include "func_common.hpp"
6#include "type_vec2.hpp"
7#include "type_vec4.hpp"
8#include "type_float.hpp"
9
10namespace glm{
11namespace detail
12{
13	template <template <typename, precision> class vecType, typename T, precision P, bool Aligned>
14	struct compute_length
15	{
16		GLM_FUNC_QUALIFIER static T call(vecType<T, P> const & v)
17		{
18			return sqrt(dot(v, v));
19		}
20	};
21
22	template <template <typename, precision> class vecType, typename T, precision P, bool Aligned>
23	struct compute_distance
24	{
25		GLM_FUNC_QUALIFIER static T call(vecType<T, P> const & p0, vecType<T, P> const & p1)
26		{
27			return length(p1 - p0);
28		}
29	};
30
31	template <template <class, precision> class vecType, typename T, precision P, bool Aligned>
32	struct compute_dot{};
33
34	template <typename T, precision P, bool Aligned>
35	struct compute_dot<tvec1, T, P, Aligned>
36	{
37		GLM_FUNC_QUALIFIER static T call(tvec1<T, P> const & a, tvec1<T, P> const & b)
38		{
39			return a.x * b.x;
40		}
41	};
42
43	template <typename T, precision P, bool Aligned>
44	struct compute_dot<tvec2, T, P, Aligned>
45	{
46		GLM_FUNC_QUALIFIER static T call(tvec2<T, P> const & x, tvec2<T, P> const & y)
47		{
48			tvec2<T, P> tmp(x * y);
49			return tmp.x + tmp.y;
50		}
51	};
52
53	template <typename T, precision P, bool Aligned>
54	struct compute_dot<tvec3, T, P, Aligned>
55	{
56		GLM_FUNC_QUALIFIER static T call(tvec3<T, P> const & x, tvec3<T, P> const & y)
57		{
58			tvec3<T, P> tmp(x * y);
59			return tmp.x + tmp.y + tmp.z;
60		}
61	};
62
63	template <typename T, precision P, bool Aligned>
64	struct compute_dot<tvec4, T, P, Aligned>
65	{
66		GLM_FUNC_QUALIFIER static T call(tvec4<T, P> const & x, tvec4<T, P> const & y)
67		{
68			tvec4<T, P> tmp(x * y);
69			return (tmp.x + tmp.y) + (tmp.z + tmp.w);
70		}
71	};
72
73	template <typename T, precision P, bool Aligned>
74	struct compute_cross
75	{
76		GLM_FUNC_QUALIFIER static tvec3<T, P> call(tvec3<T, P> const & x, tvec3<T, P> const & y)
77		{
78			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'cross' accepts only floating-point inputs");
79
80			return tvec3<T, P>(
81				x.y * y.z - y.y * x.z,
82				x.z * y.x - y.z * x.x,
83				x.x * y.y - y.x * x.y);
84		}
85	};
86
87	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
88	struct compute_normalize
89	{
90		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v)
91		{
92			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' accepts only floating-point inputs");
93
94			return v * inversesqrt(dot(v, v));
95		}
96	};
97
98	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
99	struct compute_faceforward
100	{
101		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & N, vecType<T, P> const & I, vecType<T, P> const & Nref)
102		{
103			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' accepts only floating-point inputs");
104
105			return dot(Nref, I) < static_cast<T>(0) ? N : -N;
106		}
107	};
108
109	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
110	struct compute_reflect
111	{
112		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & I, vecType<T, P> const & N)
113		{
114			return I - N * dot(N, I) * static_cast<T>(2);
115		}
116	};
117
118	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
119	struct compute_refract
120	{
121		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & I, vecType<T, P> const & N, T eta)
122		{
123			T const dotValue(dot(N, I));
124			T const k(static_cast<T>(1) - eta * eta * (static_cast<T>(1) - dotValue * dotValue));
125			return (eta * I - (eta * dotValue + std::sqrt(k)) * N) * static_cast<T>(k >= static_cast<T>(0));
126		}
127	};
128}//namespace detail
129
130	// length
131	template <typename genType>
132	GLM_FUNC_QUALIFIER genType length(genType x)
133	{
134		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'length' accepts only floating-point inputs");
135
136		return abs(x);
137	}
138
139	template <typename T, precision P, template <typename, precision> class vecType>
140	GLM_FUNC_QUALIFIER T length(vecType<T, P> const & v)
141	{
142		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'length' accepts only floating-point inputs");
143
144		return detail::compute_length<vecType, T, P, detail::is_aligned<P>::value>::call(v);
145	}
146
147	// distance
148	template <typename genType>
149	GLM_FUNC_QUALIFIER genType distance(genType const & p0, genType const & p1)
150	{
151		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'distance' accepts only floating-point inputs");
152
153		return length(p1 - p0);
154	}
155
156	template <typename T, precision P, template <typename, precision> class vecType>
157	GLM_FUNC_QUALIFIER T distance(vecType<T, P> const & p0, vecType<T, P> const & p1)
158	{
159		return detail::compute_distance<vecType, T, P, detail::is_aligned<P>::value>::call(p0, p1);
160	}
161
162	// dot
163	template <typename T>
164	GLM_FUNC_QUALIFIER T dot(T x, T y)
165	{
166		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'dot' accepts only floating-point inputs");
167		return x * y;
168	}
169
170	template <typename T, precision P, template <typename, precision> class vecType>
171	GLM_FUNC_QUALIFIER T dot(vecType<T, P> const & x, vecType<T, P> const & y)
172	{
173		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'dot' accepts only floating-point inputs");
174		return detail::compute_dot<vecType, T, P, detail::is_aligned<P>::value>::call(x, y);
175	}
176
177	// cross
178	template <typename T, precision P>
179	GLM_FUNC_QUALIFIER tvec3<T, P> cross(tvec3<T, P> const & x, tvec3<T, P> const & y)
180	{
181		return detail::compute_cross<T, P, detail::is_aligned<P>::value>::call(x, y);
182	}
183
184	// normalize
185	template <typename genType>
186	GLM_FUNC_QUALIFIER genType normalize(genType const & x)
187	{
188		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'normalize' accepts only floating-point inputs");
189
190		return x < genType(0) ? genType(-1) : genType(1);
191	}
192
193	template <typename T, precision P, template <typename, precision> class vecType>
194	GLM_FUNC_QUALIFIER vecType<T, P> normalize(vecType<T, P> const & x)
195	{
196		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' accepts only floating-point inputs");
197
198		return detail::compute_normalize<T, P, vecType, detail::is_aligned<P>::value>::call(x);
199	}
200
201	// faceforward
202	template <typename genType>
203	GLM_FUNC_QUALIFIER genType faceforward(genType const & N, genType const & I, genType const & Nref)
204	{
205		return dot(Nref, I) < static_cast<genType>(0) ? N : -N;
206	}
207
208	template <typename T, precision P, template <typename, precision> class vecType>
209	GLM_FUNC_QUALIFIER vecType<T, P> faceforward(vecType<T, P> const & N, vecType<T, P> const & I, vecType<T, P> const & Nref)
210	{
211		return detail::compute_faceforward<T, P, vecType, detail::is_aligned<P>::value>::call(N, I, Nref);
212	}
213
214	// reflect
215	template <typename genType>
216	GLM_FUNC_QUALIFIER genType reflect(genType const & I, genType const & N)
217	{
218		return I - N * dot(N, I) * genType(2);
219	}
220
221	template <typename T, precision P, template <typename, precision> class vecType>
222	GLM_FUNC_QUALIFIER vecType<T, P> reflect(vecType<T, P> const & I, vecType<T, P> const & N)
223	{
224		return detail::compute_reflect<T, P, vecType, detail::is_aligned<P>::value>::call(I, N);
225	}
226
227	// refract
228	template <typename genType>
229	GLM_FUNC_QUALIFIER genType refract(genType const & I, genType const & N, genType eta)
230	{
231		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'refract' accepts only floating-point inputs");
232		genType const dotValue(dot(N, I));
233		genType const k(static_cast<genType>(1) - eta * eta * (static_cast<genType>(1) - dotValue * dotValue));
234		return (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast<genType>(k >= static_cast<genType>(0));
235	}
236
237	template <typename T, precision P, template <typename, precision> class vecType>
238	GLM_FUNC_QUALIFIER vecType<T, P> refract(vecType<T, P> const & I, vecType<T, P> const & N, T eta)
239	{
240		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'refract' accepts only floating-point inputs");
241		return detail::compute_refract<T, P, vecType, detail::is_aligned<P>::value>::call(I, N, eta);
242	}
243}//namespace glm
244
245#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
246#	include "func_geometric_simd.inl"
247#endif
248