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