1 /*
2  * Copyright (c), Recep Aslantas.
3  *
4  * MIT License (MIT), http://opensource.org/licenses/MIT
5  * Full license can be found in the LICENSE file
6  */
7 
8 /*
9  Functions:
10    CGLM_INLINE int   glm_sign(int val);
11    CGLM_INLINE float glm_signf(float val);
12    CGLM_INLINE float glm_rad(float deg);
13    CGLM_INLINE float glm_deg(float rad);
14    CGLM_INLINE void  glm_make_rad(float *deg);
15    CGLM_INLINE void  glm_make_deg(float *rad);
16    CGLM_INLINE float glm_pow2(float x);
17    CGLM_INLINE float glm_min(float a, float b);
18    CGLM_INLINE float glm_max(float a, float b);
19    CGLM_INLINE float glm_clamp(float val, float minVal, float maxVal);
20    CGLM_INLINE float glm_clamp_zo(float val, float minVal, float maxVal);
21    CGLM_INLINE float glm_lerp(float from, float to, float t);
22    CGLM_INLINE float glm_lerpc(float from, float to, float t);
23    CGLM_INLINE float glm_step(float edge, float x);
24    CGLM_INLINE float glm_smooth(float t);
25    CGLM_INLINE float glm_smoothstep(float edge0, float edge1, float x);
26    CGLM_INLINE float glm_smoothinterp(float from, float to, float t);
27    CGLM_INLINE float glm_smoothinterpc(float from, float to, float t);
28    CGLM_INLINE bool  glm_eq(float a, float b);
29    CGLM_INLINE float glm_percent(float from, float to, float current);
30    CGLM_INLINE float glm_percentc(float from, float to, float current);
31  */
32 
33 #ifndef cglm_util_h
34 #define cglm_util_h
35 
36 #include "common.h"
37 
38 #define GLM_MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
39 #define GLM_MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
40 
41 /*!
42  * @brief get sign of 32 bit integer as +1, -1, 0
43  *
44  * Important: It returns 0 for zero input
45  *
46  * @param val integer value
47  */
48 CGLM_INLINE
49 int
glm_sign(int val)50 glm_sign(int val) {
51   return ((val >> 31) - (-val >> 31));
52 }
53 
54 /*!
55  * @brief get sign of 32 bit float as +1, -1, 0
56  *
57  * Important: It returns 0 for zero/NaN input
58  *
59  * @param val float value
60  */
61 CGLM_INLINE
62 float
glm_signf(float val)63 glm_signf(float val) {
64   return (float)((val > 0.0f) - (val < 0.0f));
65 }
66 
67 /*!
68  * @brief convert degree to radians
69  *
70  * @param[in] deg angle in degrees
71  */
72 CGLM_INLINE
73 float
glm_rad(float deg)74 glm_rad(float deg) {
75   return deg * GLM_PIf / 180.0f;
76 }
77 
78 /*!
79  * @brief convert radians to degree
80  *
81  * @param[in] rad angle in radians
82  */
83 CGLM_INLINE
84 float
glm_deg(float rad)85 glm_deg(float rad) {
86   return rad * 180.0f / GLM_PIf;
87 }
88 
89 /*!
90  * @brief convert exsisting degree to radians. this will override degrees value
91  *
92  * @param[in, out] deg pointer to angle in degrees
93  */
94 CGLM_INLINE
95 void
glm_make_rad(float * deg)96 glm_make_rad(float *deg) {
97   *deg = *deg * GLM_PIf / 180.0f;
98 }
99 
100 /*!
101  * @brief convert exsisting radians to degree. this will override radians value
102  *
103  * @param[in, out] rad pointer to angle in radians
104  */
105 CGLM_INLINE
106 void
glm_make_deg(float * rad)107 glm_make_deg(float *rad) {
108   *rad = *rad * 180.0f / GLM_PIf;
109 }
110 
111 /*!
112  * @brief multiplies given parameter with itself = x * x or powf(x, 2)
113  *
114  * @param[in] x x
115  */
116 CGLM_INLINE
117 float
glm_pow2(float x)118 glm_pow2(float x) {
119   return x * x;
120 }
121 
122 /*!
123  * @brief find minimum of given two values
124  *
125  * @param[in] a number 1
126  * @param[in] b number 2
127  */
128 CGLM_INLINE
129 float
glm_min(float a,float b)130 glm_min(float a, float b) {
131   if (a < b)
132     return a;
133   return b;
134 }
135 
136 /*!
137  * @brief find maximum of given two values
138  *
139  * @param[in] a number 1
140  * @param[in] b number 2
141  */
142 CGLM_INLINE
143 float
glm_max(float a,float b)144 glm_max(float a, float b) {
145   if (a > b)
146     return a;
147   return b;
148 }
149 
150 /*!
151  * @brief clamp a number between min and max
152  *
153  * @param[in] val    value to clamp
154  * @param[in] minVal minimum value
155  * @param[in] maxVal maximum value
156  */
157 CGLM_INLINE
158 float
glm_clamp(float val,float minVal,float maxVal)159 glm_clamp(float val, float minVal, float maxVal) {
160   return glm_min(glm_max(val, minVal), maxVal);
161 }
162 
163 /*!
164  * @brief clamp a number to zero and one
165  *
166  * @param[in] val value to clamp
167  */
168 CGLM_INLINE
169 float
glm_clamp_zo(float val)170 glm_clamp_zo(float val) {
171   return glm_clamp(val, 0.0f, 1.0f);
172 }
173 
174 /*!
175  * @brief linear interpolation between two numbers
176  *
177  * formula:  from + t * (to - from)
178  *
179  * @param[in]   from from value
180  * @param[in]   to   to value
181  * @param[in]   t    interpolant (amount)
182  */
183 CGLM_INLINE
184 float
glm_lerp(float from,float to,float t)185 glm_lerp(float from, float to, float t) {
186   return from + t * (to - from);
187 }
188 
189 /*!
190  * @brief clamped linear interpolation between two numbers
191  *
192  * formula:  from + t * (to - from)
193  *
194  * @param[in]   from    from value
195  * @param[in]   to      to value
196  * @param[in]   t       interpolant (amount) clamped between 0 and 1
197  */
198 CGLM_INLINE
199 float
glm_lerpc(float from,float to,float t)200 glm_lerpc(float from, float to, float t) {
201   return glm_lerp(from, to, glm_clamp_zo(t));
202 }
203 
204 /*!
205  * @brief threshold function
206  *
207  * @param[in]   edge    threshold
208  * @param[in]   x       value to test against threshold
209  * @return      returns 0.0 if x < edge, else 1.0
210  */
211 CGLM_INLINE
212 float
glm_step(float edge,float x)213 glm_step(float edge, float x) {
214   /* branching - no type conversion */
215   return (x < edge) ? 0.0f : 1.0f;
216   /*
217    * An alternative implementation without branching
218    * but with type conversion could be:
219    * return !(x < edge);
220    */
221 }
222 
223 /*!
224  * @brief smooth Hermite interpolation
225  *
226  * formula:  t^2 * (3-2t)
227  *
228  * @param[in]   t    interpolant (amount)
229  */
230 CGLM_INLINE
231 float
glm_smooth(float t)232 glm_smooth(float t) {
233   return t * t * (3.0f - 2.0f * t);
234 }
235 
236 /*!
237  * @brief threshold function with a smooth transition (according to OpenCL specs)
238  *
239  * formula:  t^2 * (3-2t)
240  *
241  * @param[in]   edge0 low threshold
242  * @param[in]   edge1 high threshold
243  * @param[in]   x     interpolant (amount)
244  */
245 CGLM_INLINE
246 float
glm_smoothstep(float edge0,float edge1,float x)247 glm_smoothstep(float edge0, float edge1, float x) {
248   float t;
249   t = glm_clamp_zo((x - edge0) / (edge1 - edge0));
250   return glm_smooth(t);
251 }
252 
253 /*!
254  * @brief smoothstep interpolation between two numbers
255  *
256  * formula:  from + smoothstep(t) * (to - from)
257  *
258  * @param[in]   from from value
259  * @param[in]   to   to value
260  * @param[in]   t    interpolant (amount)
261  */
262 CGLM_INLINE
263 float
glm_smoothinterp(float from,float to,float t)264 glm_smoothinterp(float from, float to, float t) {
265   return from + glm_smooth(t) * (to - from);
266 }
267 
268 /*!
269  * @brief clamped smoothstep interpolation between two numbers
270  *
271  * formula:  from + smoothstep(t) * (to - from)
272  *
273  * @param[in]   from from value
274  * @param[in]   to   to value
275  * @param[in]   t    interpolant (amount) clamped between 0 and 1
276  */
277 CGLM_INLINE
278 float
glm_smoothinterpc(float from,float to,float t)279 glm_smoothinterpc(float from, float to, float t) {
280   return glm_smoothinterp(from, to, glm_clamp_zo(t));
281 }
282 
283 /*!
284  * @brief check if two float equal with using EPSILON
285  *
286  * @param[in]   a   a
287  * @param[in]   b   b
288  */
289 CGLM_INLINE
290 bool
glm_eq(float a,float b)291 glm_eq(float a, float b) {
292   return fabsf(a - b) <= GLM_FLT_EPSILON;
293 }
294 
295 /*!
296  * @brief percentage of current value between start and end value
297  *
298  * maybe fraction could be alternative name.
299  *
300  * @param[in]   from    from value
301  * @param[in]   to      to value
302  * @param[in]   current current value
303  */
304 CGLM_INLINE
305 float
glm_percent(float from,float to,float current)306 glm_percent(float from, float to, float current) {
307   float t;
308 
309   if ((t = to - from) == 0.0f)
310     return 1.0f;
311 
312   return (current - from) / t;
313 }
314 
315 /*!
316  * @brief clamped percentage of current value between start and end value
317  *
318  * @param[in]   from    from value
319  * @param[in]   to      to value
320  * @param[in]   current current value
321  */
322 CGLM_INLINE
323 float
glm_percentc(float from,float to,float current)324 glm_percentc(float from, float to, float current) {
325   return glm_clamp_zo(glm_percent(from, to, current));
326 }
327 
328 /*!
329 * @brief swap two float values
330 *
331 * @param[in]   a float value 1 (pointer)
332 * @param[in]   b float value 2 (pointer)
333 */
334 CGLM_INLINE
335 void
glm_swapf(float * __restrict a,float * __restrict b)336 glm_swapf(float * __restrict a, float * __restrict b) {
337   float t;
338   t  = *a;
339   *a = *b;
340   *b = t;
341 }
342 
343 #endif /* cglm_util_h */
344