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