1/// @ref core
2/// @file glm/detail/func_common.inl
3
4#include "func_vector_relational.hpp"
5#include "type_vec2.hpp"
6#include "type_vec3.hpp"
7#include "type_vec4.hpp"
8#include "_vectorize.hpp"
9#include <limits>
10
11namespace glm
12{
13	// min
14	template <typename genType>
15	GLM_FUNC_QUALIFIER genType min(genType x, genType y)
16	{
17		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'min' only accept floating-point or integer inputs");
18		return x < y ? x : y;
19	}
20
21	// max
22	template <typename genType>
23	GLM_FUNC_QUALIFIER genType max(genType x, genType y)
24	{
25		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'max' only accept floating-point or integer inputs");
26
27		return x > y ? x : y;
28	}
29
30	// abs
31	template <>
32	GLM_FUNC_QUALIFIER int32 abs(int32 x)
33	{
34		int32 const y = x >> 31;
35		return (x ^ y) - y;
36	}
37
38	// round
39#	if GLM_HAS_CXX11_STL
40		using ::std::round;
41#	else
42		template <typename genType>
43		GLM_FUNC_QUALIFIER genType round(genType x)
44		{
45			GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'round' only accept floating-point inputs");
46
47			return x < static_cast<genType>(0) ? static_cast<genType>(int(x - static_cast<genType>(0.5))) : static_cast<genType>(int(x + static_cast<genType>(0.5)));
48		}
49#	endif
50
51	// trunc
52#	if GLM_HAS_CXX11_STL
53		using ::std::trunc;
54#	else
55		template <typename genType>
56		GLM_FUNC_QUALIFIER genType trunc(genType x)
57		{
58			GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'trunc' only accept floating-point inputs");
59
60			return x < static_cast<genType>(0) ? -std::floor(-x) : std::floor(x);
61		}
62#	endif
63
64}//namespace glm
65
66namespace glm{
67namespace detail
68{
69	template <typename genFIType, bool /*signed*/>
70	struct compute_abs
71	{};
72
73	template <typename genFIType>
74	struct compute_abs<genFIType, true>
75	{
76		GLM_FUNC_QUALIFIER static genFIType call(genFIType x)
77		{
78			GLM_STATIC_ASSERT(
79				std::numeric_limits<genFIType>::is_iec559 || std::numeric_limits<genFIType>::is_signed || GLM_UNRESTRICTED_GENTYPE,
80				"'abs' only accept floating-point and integer scalar or vector inputs");
81
82			return x >= genFIType(0) ? x : -x;
83			// TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff;
84		}
85	};
86
87	#if GLM_COMPILER & GLM_COMPILER_CUDA
88	template <>
89	struct compute_abs<float, true>
90	{
91		GLM_FUNC_QUALIFIER static float call(float x)
92		{
93			return fabsf(x);
94		}
95	};
96	#endif
97
98	template <typename genFIType>
99	struct compute_abs<genFIType, false>
100	{
101		GLM_FUNC_QUALIFIER static genFIType call(genFIType x)
102		{
103			GLM_STATIC_ASSERT(
104				(!std::numeric_limits<genFIType>::is_signed && std::numeric_limits<genFIType>::is_integer) || GLM_UNRESTRICTED_GENTYPE,
105				"'abs' only accept floating-point and integer scalar or vector inputs");
106			return x;
107		}
108	};
109
110	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
111	struct compute_abs_vector
112	{
113		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
114		{
115			return detail::functor1<T, T, P, vecType>::call(abs, x);
116		}
117	};
118
119	template <typename T, typename U, precision P, template <typename, precision> class vecType, bool Aligned>
120	struct compute_mix_vector
121	{
122		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, vecType<U, P> const & a)
123		{
124			GLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a");
125
126			return vecType<T, P>(vecType<U, P>(x) + a * vecType<U, P>(y - x));
127		}
128	};
129
130	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
131	struct compute_mix_vector<T, bool, P, vecType, Aligned>
132	{
133		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, vecType<bool, P> const & a)
134		{
135			vecType<T, P> Result(uninitialize);
136			for(length_t i = 0; i < x.length(); ++i)
137				Result[i] = a[i] ? y[i] : x[i];
138			return Result;
139		}
140	};
141
142	template <typename T, typename U, precision P, template <typename, precision> class vecType, bool Aligned>
143	struct compute_mix_scalar
144	{
145		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, U const & a)
146		{
147			GLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a");
148
149			return vecType<T, P>(vecType<U, P>(x) + a * vecType<U, P>(y - x));
150		}
151	};
152
153	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
154	struct compute_mix_scalar<T, bool, P, vecType, Aligned>
155	{
156		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, bool const & a)
157		{
158			return a ? y : x;
159		}
160	};
161
162	template <typename T, typename U>
163	struct compute_mix
164	{
165		GLM_FUNC_QUALIFIER static T call(T const & x, T const & y, U const & a)
166		{
167			GLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a");
168
169			return static_cast<T>(static_cast<U>(x) + a * static_cast<U>(y - x));
170		}
171	};
172
173	template <typename T>
174	struct compute_mix<T, bool>
175	{
176		GLM_FUNC_QUALIFIER static T call(T const & x, T const & y, bool const & a)
177		{
178			return a ? y : x;
179		}
180	};
181
182	template <typename T, precision P, template <typename, precision> class vecType, bool isFloat, bool Aligned>
183	struct compute_sign
184	{
185		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
186		{
187			return vecType<T, P>(glm::lessThan(vecType<T, P>(0), x)) - vecType<T, P>(glm::lessThan(x, vecType<T, P>(0)));
188		}
189	};
190
191#	if GLM_ARCH == GLM_ARCH_X86
192	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
193	struct compute_sign<T, P, vecType, false, Aligned>
194	{
195		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
196		{
197			T const Shift(static_cast<T>(sizeof(T) * 8 - 1));
198			vecType<T, P> const y(vecType<typename make_unsigned<T>::type, P>(-x) >> typename make_unsigned<T>::type(Shift));
199
200			return (x >> Shift) | y;
201		}
202	};
203#	endif
204
205	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
206	struct compute_floor
207	{
208		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
209		{
210			return detail::functor1<T, T, P, vecType>::call(std::floor, x);
211		}
212	};
213
214	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
215	struct compute_ceil
216	{
217		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
218		{
219			return detail::functor1<T, T, P, vecType>::call(std::ceil, x);
220		}
221	};
222
223	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
224	struct compute_fract
225	{
226		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
227		{
228			return x - floor(x);
229		}
230	};
231
232	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
233	struct compute_trunc
234	{
235		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
236		{
237			return detail::functor1<T, T, P, vecType>::call(trunc, x);
238		}
239	};
240
241	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
242	struct compute_round
243	{
244		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
245		{
246			return detail::functor1<T, T, P, vecType>::call(round, x);
247		}
248	};
249
250	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
251	struct compute_mod
252	{
253		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & a, vecType<T, P> const & b)
254		{
255			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'mod' only accept floating-point inputs. Include <glm/gtc/integer.hpp> for integer inputs.");
256			return a - b * floor(a / b);
257		}
258	};
259
260	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
261	struct compute_min_vector
262	{
263		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y)
264		{
265			return detail::functor2<T, P, vecType>::call(min, x, y);
266		}
267	};
268
269	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
270	struct compute_max_vector
271	{
272		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y)
273		{
274			return detail::functor2<T, P, vecType>::call(max, x, y);
275		}
276	};
277
278	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
279	struct compute_clamp_vector
280	{
281		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & minVal, vecType<T, P> const & maxVal)
282		{
283			return min(max(x, minVal), maxVal);
284		}
285	};
286
287	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
288	struct compute_step_vector
289	{
290		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & edge, vecType<T, P> const & x)
291		{
292			return mix(vecType<T, P>(1), vecType<T, P>(0), glm::lessThan(x, edge));
293		}
294	};
295
296	template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
297	struct compute_smoothstep_vector
298	{
299		GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & edge0, vecType<T, P> const & edge1, vecType<T, P> const & x)
300		{
301			GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'step' only accept floating-point inputs");
302			vecType<T, P> const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast<T>(0), static_cast<T>(1)));
303			return tmp * tmp * (static_cast<T>(3) - static_cast<T>(2) * tmp);
304		}
305	};
306}//namespace detail
307
308	template <typename genFIType>
309	GLM_FUNC_QUALIFIER genFIType abs(genFIType x)
310	{
311		return detail::compute_abs<genFIType, std::numeric_limits<genFIType>::is_signed>::call(x);
312	}
313
314	template <typename T, precision P, template <typename, precision> class vecType>
315	GLM_FUNC_QUALIFIER vecType<T, P> abs(vecType<T, P> const & x)
316	{
317		return detail::compute_abs_vector<T, P, vecType, detail::is_aligned<P>::value>::call(x);
318	}
319
320	// sign
321	// fast and works for any type
322	template <typename genFIType>
323	GLM_FUNC_QUALIFIER genFIType sign(genFIType x)
324	{
325		GLM_STATIC_ASSERT(
326			std::numeric_limits<genFIType>::is_iec559 || (std::numeric_limits<genFIType>::is_signed && std::numeric_limits<genFIType>::is_integer),
327			"'sign' only accept signed inputs");
328
329		return detail::compute_sign<genFIType, defaultp, tvec1, std::numeric_limits<genFIType>::is_iec559, highp>::call(tvec1<genFIType>(x)).x;
330	}
331
332	template <typename T, precision P, template <typename, precision> class vecType>
333	GLM_FUNC_QUALIFIER vecType<T, P> sign(vecType<T, P> const & x)
334	{
335		GLM_STATIC_ASSERT(
336			std::numeric_limits<T>::is_iec559 || (std::numeric_limits<T>::is_signed && std::numeric_limits<T>::is_integer),
337			"'sign' only accept signed inputs");
338
339		return detail::compute_sign<T, P, vecType, std::numeric_limits<T>::is_iec559, detail::is_aligned<P>::value>::call(x);
340	}
341
342	// floor
343	using ::std::floor;
344	template <typename T, precision P, template <typename, precision> class vecType>
345	GLM_FUNC_QUALIFIER vecType<T, P> floor(vecType<T, P> const & x)
346	{
347		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'floor' only accept floating-point inputs.");
348		return detail::compute_floor<T, P, vecType, detail::is_aligned<P>::value>::call(x);
349	}
350
351	template <typename T, precision P, template <typename, precision> class vecType>
352	GLM_FUNC_QUALIFIER vecType<T, P> trunc(vecType<T, P> const & x)
353	{
354		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'trunc' only accept floating-point inputs");
355		return detail::compute_trunc<T, P, vecType, detail::is_aligned<P>::value>::call(x);
356	}
357
358	template <typename T, precision P, template <typename, precision> class vecType>
359	GLM_FUNC_QUALIFIER vecType<T, P> round(vecType<T, P> const & x)
360	{
361		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'round' only accept floating-point inputs");
362		return detail::compute_round<T, P, vecType, detail::is_aligned<P>::value>::call(x);
363	}
364
365/*
366	// roundEven
367	template <typename genType>
368	GLM_FUNC_QUALIFIER genType roundEven(genType const& x)
369	{
370		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'roundEven' only accept floating-point inputs");
371
372		return genType(int(x + genType(int(x) % 2)));
373	}
374*/
375
376	// roundEven
377	template <typename genType>
378	GLM_FUNC_QUALIFIER genType roundEven(genType x)
379	{
380		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'roundEven' only accept floating-point inputs");
381
382		int Integer = static_cast<int>(x);
383		genType IntegerPart = static_cast<genType>(Integer);
384		genType FractionalPart = fract(x);
385
386		if(FractionalPart > static_cast<genType>(0.5) || FractionalPart < static_cast<genType>(0.5))
387		{
388			return round(x);
389		}
390		else if((Integer % 2) == 0)
391		{
392			return IntegerPart;
393		}
394		else if(x <= static_cast<genType>(0)) // Work around...
395		{
396			return IntegerPart - static_cast<genType>(1);
397		}
398		else
399		{
400			return IntegerPart + static_cast<genType>(1);
401		}
402		//else // Bug on MinGW 4.5.2
403		//{
404		//	return mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0));
405		//}
406	}
407
408	template <typename T, precision P, template <typename, precision> class vecType>
409	GLM_FUNC_QUALIFIER vecType<T, P> roundEven(vecType<T, P> const & x)
410	{
411		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'roundEven' only accept floating-point inputs");
412		return detail::functor1<T, T, P, vecType>::call(roundEven, x);
413	}
414
415	// ceil
416	using ::std::ceil;
417	template <typename T, precision P, template <typename, precision> class vecType>
418	GLM_FUNC_QUALIFIER vecType<T, P> ceil(vecType<T, P> const & x)
419	{
420		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'ceil' only accept floating-point inputs");
421		return detail::compute_ceil<T, P, vecType, detail::is_aligned<P>::value>::call(x);
422	}
423
424	// fract
425	template <typename genType>
426	GLM_FUNC_QUALIFIER genType fract(genType x)
427	{
428		return fract(tvec1<genType>(x)).x;
429	}
430
431	template <typename T, precision P, template <typename, precision> class vecType>
432	GLM_FUNC_QUALIFIER vecType<T, P> fract(vecType<T, P> const & x)
433	{
434		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fract' only accept floating-point inputs");
435		return detail::compute_fract<T, P, vecType, detail::is_aligned<P>::value>::call(x);
436	}
437
438	// mod
439	template <typename genType>
440	GLM_FUNC_QUALIFIER genType mod(genType x, genType y)
441	{
442#		if GLM_COMPILER & GLM_COMPILER_CUDA
443			// Another Cuda compiler bug https://github.com/g-truc/glm/issues/530
444			tvec1<genType, defaultp> Result(mod(tvec1<genType, defaultp>(x), y));
445			return Result.x;
446#		else
447			return mod(tvec1<genType, defaultp>(x), y).x;
448#		endif
449	}
450
451	template <typename T, precision P, template <typename, precision> class vecType>
452	GLM_FUNC_QUALIFIER vecType<T, P> mod(vecType<T, P> const & x, T y)
453	{
454		return detail::compute_mod<T, P, vecType, detail::is_aligned<P>::value>::call(x, vecType<T, P>(y));
455	}
456
457	template <typename T, precision P, template <typename, precision> class vecType>
458	GLM_FUNC_QUALIFIER vecType<T, P> mod(vecType<T, P> const & x, vecType<T, P> const & y)
459	{
460		return detail::compute_mod<T, P, vecType, detail::is_aligned<P>::value>::call(x, y);
461	}
462
463	// modf
464	template <typename genType>
465	GLM_FUNC_QUALIFIER genType modf(genType x, genType & i)
466	{
467		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'modf' only accept floating-point inputs");
468		return std::modf(x, &i);
469	}
470
471	template <typename T, precision P>
472	GLM_FUNC_QUALIFIER tvec1<T, P> modf(tvec1<T, P> const & x, tvec1<T, P> & i)
473	{
474		return tvec1<T, P>(
475			modf(x.x, i.x));
476	}
477
478	template <typename T, precision P>
479	GLM_FUNC_QUALIFIER tvec2<T, P> modf(tvec2<T, P> const & x, tvec2<T, P> & i)
480	{
481		return tvec2<T, P>(
482			modf(x.x, i.x),
483			modf(x.y, i.y));
484	}
485
486	template <typename T, precision P>
487	GLM_FUNC_QUALIFIER tvec3<T, P> modf(tvec3<T, P> const & x, tvec3<T, P> & i)
488	{
489		return tvec3<T, P>(
490			modf(x.x, i.x),
491			modf(x.y, i.y),
492			modf(x.z, i.z));
493	}
494
495	template <typename T, precision P>
496	GLM_FUNC_QUALIFIER tvec4<T, P> modf(tvec4<T, P> const & x, tvec4<T, P> & i)
497	{
498		return tvec4<T, P>(
499			modf(x.x, i.x),
500			modf(x.y, i.y),
501			modf(x.z, i.z),
502			modf(x.w, i.w));
503	}
504
505	//// Only valid if (INT_MIN <= x-y <= INT_MAX)
506	//// min(x,y)
507	//r = y + ((x - y) & ((x - y) >> (sizeof(int) *
508	//CHAR_BIT - 1)));
509	//// max(x,y)
510	//r = x - ((x - y) & ((x - y) >> (sizeof(int) *
511	//CHAR_BIT - 1)));
512
513	// min
514	template <typename T, precision P, template <typename, precision> class vecType>
515	GLM_FUNC_QUALIFIER vecType<T, P> min(vecType<T, P> const & a, T b)
516	{
517		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'min' only accept floating-point inputs for the interpolator a");
518		return detail::compute_min_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, vecType<T, P>(b));
519	}
520
521	template <typename T, precision P, template <typename, precision> class vecType>
522	GLM_FUNC_QUALIFIER vecType<T, P> min(vecType<T, P> const & a, vecType<T, P> const & b)
523	{
524		return detail::compute_min_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, b);
525	}
526
527	// max
528	template <typename T, precision P, template <typename, precision> class vecType>
529	GLM_FUNC_QUALIFIER vecType<T, P> max(vecType<T, P> const & a, T b)
530	{
531		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'max' only accept floating-point inputs for the interpolator a");
532		return detail::compute_max_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, vecType<T, P>(b));
533	}
534
535	template <typename T, precision P, template <typename, precision> class vecType>
536	GLM_FUNC_QUALIFIER vecType<T, P> max(vecType<T, P> const & a, vecType<T, P> const & b)
537	{
538		return detail::compute_max_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, b);
539	}
540
541	// clamp
542	template <typename genType>
543	GLM_FUNC_QUALIFIER genType clamp(genType x, genType minVal, genType maxVal)
544	{
545		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'clamp' only accept floating-point or integer inputs");
546		return min(max(x, minVal), maxVal);
547	}
548
549	template <typename T, precision P, template <typename, precision> class vecType>
550	GLM_FUNC_QUALIFIER vecType<T, P> clamp(vecType<T, P> const & x, T minVal, T maxVal)
551	{
552		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'clamp' only accept floating-point or integer inputs");
553		return detail::compute_clamp_vector<T, P, vecType, detail::is_aligned<P>::value>::call(x, vecType<T, P>(minVal), vecType<T, P>(maxVal));
554	}
555
556	template <typename T, precision P, template <typename, precision> class vecType>
557	GLM_FUNC_QUALIFIER vecType<T, P> clamp(vecType<T, P> const & x, vecType<T, P> const & minVal, vecType<T, P> const & maxVal)
558	{
559		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'clamp' only accept floating-point or integer inputs");
560		return detail::compute_clamp_vector<T, P, vecType, detail::is_aligned<P>::value>::call(x, minVal, maxVal);
561	}
562
563	template <typename genTypeT, typename genTypeU>
564	GLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a)
565	{
566		return detail::compute_mix<genTypeT, genTypeU>::call(x, y, a);
567	}
568
569	template <typename T, typename U, precision P, template <typename, precision> class vecType>
570	GLM_FUNC_QUALIFIER vecType<T, P> mix(vecType<T, P> const & x, vecType<T, P> const & y, U a)
571	{
572		return detail::compute_mix_scalar<T, U, P, vecType, detail::is_aligned<P>::value>::call(x, y, a);
573	}
574
575	template <typename T, typename U, precision P, template <typename, precision> class vecType>
576	GLM_FUNC_QUALIFIER vecType<T, P> mix(vecType<T, P> const & x, vecType<T, P> const & y, vecType<U, P> const & a)
577	{
578		return detail::compute_mix_vector<T, U, P, vecType, detail::is_aligned<P>::value>::call(x, y, a);
579	}
580
581	// step
582	template <typename genType>
583	GLM_FUNC_QUALIFIER genType step(genType edge, genType x)
584	{
585		return mix(static_cast<genType>(1), static_cast<genType>(0), glm::lessThan(x, edge));
586	}
587
588	template <template <typename, precision> class vecType, typename T, precision P>
589	GLM_FUNC_QUALIFIER vecType<T, P> step(T edge, vecType<T, P> const & x)
590	{
591		return detail::compute_step_vector<T, P, vecType, detail::is_aligned<P>::value>::call(vecType<T, P>(edge), x);
592	}
593
594	template <template <typename, precision> class vecType, typename T, precision P>
595	GLM_FUNC_QUALIFIER vecType<T, P> step(vecType<T, P> const & edge, vecType<T, P> const & x)
596	{
597		return detail::compute_step_vector<T, P, vecType, detail::is_aligned<P>::value>::call(edge, x);
598	}
599
600	// smoothstep
601	template <typename genType>
602	GLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x)
603	{
604		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs");
605
606		genType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1)));
607		return tmp * tmp * (genType(3) - genType(2) * tmp);
608	}
609
610	template <typename T, precision P, template <typename, precision> class vecType>
611	GLM_FUNC_QUALIFIER vecType<T, P> smoothstep(T edge0, T edge1, vecType<T, P> const & x)
612	{
613		return detail::compute_smoothstep_vector<T, P, vecType, detail::is_aligned<P>::value>::call(vecType<T, P>(edge0), vecType<T, P>(edge1), x);
614	}
615
616	template <typename T, precision P, template <typename, precision> class vecType>
617	GLM_FUNC_QUALIFIER vecType<T, P> smoothstep(vecType<T, P> const & edge0, vecType<T, P> const & edge1, vecType<T, P> const & x)
618	{
619		return detail::compute_smoothstep_vector<T, P, vecType, detail::is_aligned<P>::value>::call(edge0, edge1, x);
620	}
621
622#	if GLM_HAS_CXX11_STL
623		using std::isnan;
624#	else
625		template <typename genType>
626		GLM_FUNC_QUALIFIER bool isnan(genType x)
627		{
628			GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'isnan' only accept floating-point inputs");
629
630#			if GLM_HAS_CXX11_STL
631				return std::isnan(x);
632#			elif GLM_COMPILER & GLM_COMPILER_VC
633				return _isnan(x) != 0;
634#			elif GLM_COMPILER & GLM_COMPILER_INTEL
635#				if GLM_PLATFORM & GLM_PLATFORM_WINDOWS
636					return _isnan(x) != 0;
637#				else
638					return ::isnan(x) != 0;
639#				endif
640#			elif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L
641				return _isnan(x) != 0;
642#			elif GLM_COMPILER & GLM_COMPILER_CUDA
643				return isnan(x) != 0;
644#			else
645				return std::isnan(x);
646#			endif
647		}
648#	endif
649
650	template <typename T, precision P, template <typename, precision> class vecType>
651	GLM_FUNC_QUALIFIER vecType<bool, P> isnan(vecType<T, P> const & x)
652	{
653		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isnan' only accept floating-point inputs");
654
655		return detail::functor1<bool, T, P, vecType>::call(isnan, x);
656	}
657
658#	if GLM_HAS_CXX11_STL
659		using std::isinf;
660#	else
661		template <typename genType>
662		GLM_FUNC_QUALIFIER bool isinf(genType x)
663		{
664			GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'isinf' only accept floating-point inputs");
665
666#			if GLM_HAS_CXX11_STL
667				return std::isinf(x);
668#			elif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC)
669#				if(GLM_PLATFORM & GLM_PLATFORM_WINDOWS)
670					return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF;
671#				else
672					return ::isinf(x);
673#				endif
674#			elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)
675#				if(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L)
676					return _isinf(x) != 0;
677#				else
678					return std::isinf(x);
679#				endif
680#			elif GLM_COMPILER & GLM_COMPILER_CUDA
681				// http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab
682				return isinf(double(x)) != 0;
683#			else
684				return std::isinf(x);
685#			endif
686	}
687#	endif
688
689	template <typename T, precision P, template <typename, precision> class vecType>
690	GLM_FUNC_QUALIFIER vecType<bool, P> isinf(vecType<T, P> const & x)
691	{
692		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isnan' only accept floating-point inputs");
693
694		return detail::functor1<bool, T, P, vecType>::call(isinf, x);
695	}
696
697	GLM_FUNC_QUALIFIER int floatBitsToInt(float const & v)
698	{
699		return reinterpret_cast<int&>(const_cast<float&>(v));
700	}
701
702	template <template <typename, precision> class vecType, precision P>
703	GLM_FUNC_QUALIFIER vecType<int, P> floatBitsToInt(vecType<float, P> const & v)
704	{
705		return reinterpret_cast<vecType<int, P>&>(const_cast<vecType<float, P>&>(v));
706	}
707
708	GLM_FUNC_QUALIFIER uint floatBitsToUint(float const & v)
709	{
710		return reinterpret_cast<uint&>(const_cast<float&>(v));
711	}
712
713	template <template <typename, precision> class vecType, precision P>
714	GLM_FUNC_QUALIFIER vecType<uint, P> floatBitsToUint(vecType<float, P> const & v)
715	{
716		return reinterpret_cast<vecType<uint, P>&>(const_cast<vecType<float, P>&>(v));
717	}
718
719	GLM_FUNC_QUALIFIER float intBitsToFloat(int const & v)
720	{
721		return reinterpret_cast<float&>(const_cast<int&>(v));
722	}
723
724	template <template <typename, precision> class vecType, precision P>
725	GLM_FUNC_QUALIFIER vecType<float, P> intBitsToFloat(vecType<int, P> const & v)
726	{
727		return reinterpret_cast<vecType<float, P>&>(const_cast<vecType<int, P>&>(v));
728	}
729
730	GLM_FUNC_QUALIFIER float uintBitsToFloat(uint const & v)
731	{
732		return reinterpret_cast<float&>(const_cast<uint&>(v));
733	}
734
735	template <template <typename, precision> class vecType, precision P>
736	GLM_FUNC_QUALIFIER vecType<float, P> uintBitsToFloat(vecType<uint, P> const & v)
737	{
738		return reinterpret_cast<vecType<float, P>&>(const_cast<vecType<uint, P>&>(v));
739	}
740
741	template <typename genType>
742	GLM_FUNC_QUALIFIER genType fma(genType const & a, genType const & b, genType const & c)
743	{
744		return a * b + c;
745	}
746
747	template <typename genType>
748	GLM_FUNC_QUALIFIER genType frexp(genType x, int & exp)
749	{
750		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
751
752		return std::frexp(x, &exp);
753	}
754
755	template <typename T, precision P>
756	GLM_FUNC_QUALIFIER tvec1<T, P> frexp(tvec1<T, P> const & x, tvec1<int, P> & exp)
757	{
758		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
759
760		return tvec1<T, P>(std::frexp(x.x, &exp.x));
761	}
762
763	template <typename T, precision P>
764	GLM_FUNC_QUALIFIER tvec2<T, P> frexp(tvec2<T, P> const & x, tvec2<int, P> & exp)
765	{
766		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
767
768		return tvec2<T, P>(
769			frexp(x.x, exp.x),
770			frexp(x.y, exp.y));
771	}
772
773	template <typename T, precision P>
774	GLM_FUNC_QUALIFIER tvec3<T, P> frexp(tvec3<T, P> const & x, tvec3<int, P> & exp)
775	{
776		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
777
778		return tvec3<T, P>(
779			frexp(x.x, exp.x),
780			frexp(x.y, exp.y),
781			frexp(x.z, exp.z));
782	}
783
784	template <typename T, precision P>
785	GLM_FUNC_QUALIFIER tvec4<T, P> frexp(tvec4<T, P> const & x, tvec4<int, P> & exp)
786	{
787		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
788
789		return tvec4<T, P>(
790			frexp(x.x, exp.x),
791			frexp(x.y, exp.y),
792			frexp(x.z, exp.z),
793			frexp(x.w, exp.w));
794	}
795
796	template <typename genType>
797	GLM_FUNC_QUALIFIER genType ldexp(genType const & x, int const & exp)
798	{
799		GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
800
801		return std::ldexp(x, exp);
802	}
803
804	template <typename T, precision P>
805	GLM_FUNC_QUALIFIER tvec1<T, P> ldexp(tvec1<T, P> const & x, tvec1<int, P> const & exp)
806	{
807		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
808
809		return tvec1<T, P>(
810			ldexp(x.x, exp.x));
811	}
812
813	template <typename T, precision P>
814	GLM_FUNC_QUALIFIER tvec2<T, P> ldexp(tvec2<T, P> const & x, tvec2<int, P> const & exp)
815	{
816		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
817
818		return tvec2<T, P>(
819			ldexp(x.x, exp.x),
820			ldexp(x.y, exp.y));
821	}
822
823	template <typename T, precision P>
824	GLM_FUNC_QUALIFIER tvec3<T, P> ldexp(tvec3<T, P> const & x, tvec3<int, P> const & exp)
825	{
826		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
827
828		return tvec3<T, P>(
829			ldexp(x.x, exp.x),
830			ldexp(x.y, exp.y),
831			ldexp(x.z, exp.z));
832	}
833
834	template <typename T, precision P>
835	GLM_FUNC_QUALIFIER tvec4<T, P> ldexp(tvec4<T, P> const & x, tvec4<int, P> const & exp)
836	{
837		GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
838
839		return tvec4<T, P>(
840			ldexp(x.x, exp.x),
841			ldexp(x.y, exp.y),
842			ldexp(x.z, exp.z),
843			ldexp(x.w, exp.w));
844	}
845}//namespace glm
846
847#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
848#	include "func_common_simd.inl"
849#endif
850