TGX 1.1.2
A tiny 2D/3D graphics library optimized for 32 bits microcontrollers.
Loading...
Searching...
No Matches
Misc.h
Go to the documentation of this file.
1
5//
6// Copyright 2020 Arvind Singh
7// Fast approximations copyright 2025 Ken Cooke
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12//version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; If not, see <http://www.gnu.org/licenses/>.
21
22#ifndef _TGX_MISC_H_
23#define _TGX_MISC_H_
24
25#include "tgx_config.h"
26
27#include <stdint.h>
28#include <math.h>
29#include <string.h>
30
31
32
33// c++, no plain c
34#ifdef __cplusplus
35
36
37// macro to cast indexes as 32bit when doing pointer arithmetic
38#define TGX_CAST32(a) ((int32_t)(a))
39
40#define DEPRECATED(X) [[deprecated(" " X " ")]]
41
49#ifndef TGX_FORCED_INLINE
50 #if defined(_MSC_VER)
51 #define TGX_FORCED_INLINE __forceinline
52 #elif defined(__GNUC__) || defined(__clang__)
53 #define TGX_FORCED_INLINE inline __attribute__((always_inline))
54 #else
55 #define TGX_FORCED_INLINE inline
56 #endif
57#endif
58
59
60// check that int is at least 4 bytes.
61static_assert(sizeof(int) >= 4, "The TGX library only works on 32 bits or 64 bits architecture. Sorry!");
62
63
64
65#if defined(ARDUINO_TEENSY41)
66
67 // check existence of external ram (EXTMEM).
68 extern "C" uint8_t external_psram_size;
69
70 // check is an address is in flash
71 #define TGX_IS_PROGMEM(X) ((((uint32_t)(X)) >= 0x60000000)&&(((uint32_t)(X)) < 0x70000000))
72
73 // check if an address is in external ram
74 #define TGX_IS_EXTMEM(X) ((((uint32_t)(X)) >= 0x70000000)&&(((uint32_t)(X)) < 0x80000000))
75
76#endif
77
78#ifndef M_PI
79#define M_PI 3.14159265358979323846
80#endif
81
82
83namespace tgx
84{
85
86
92 template<int N> struct DummyType
93 {
94 // nothing here :-)
95 };
96
97
103 template<bool BB1, bool BB2> struct DummyTypeBB
104 {
105 // nothing here :-)
106 };
107
108
110 template<typename T = int> struct DefaultFPType
111 {
112#if TGX_SINGLE_PRECISION_COMPUTATIONS
113 typedef float fptype;
114#else
115 typedef double fptype;
116#endif
117 };
118
119#if TGX_SINGLE_PRECISION_COMPUTATIONS
121 template<> struct DefaultFPType<double>
122 {
123 typedef double fptype;
124 };
125#endif
126
127
129 template <typename, typename> struct is_same { static const bool value = false; };
130 template <typename T> struct is_same<T, T> { static const bool value = true; };
131
132
134 TGX_INLINE inline uint16_t BigEndian16(uint16_t v)
135 {
136#ifdef __GNUC__
137 return __builtin_bswap16(v);
138#else
139 return ((v >> 8) | (v << 8));
140#endif
141 }
142
143
145 template<typename T> TGX_INLINE inline void swap(T& a, T& b) { T c(a); a = b; b = c; }
146
147
149 template<typename T> TGX_INLINE inline T min(T a, T b) { return((a < b) ? a : b); }
150
151
153 template<typename T> TGX_INLINE inline T max(T a, T b) { return((a > b) ? a : b); }
154
155
157 template<typename T> TGX_INLINE inline T clamp(T v, T vmin, T vmax)
158 {
159 return max(vmin, min(vmax, v));
160 }
161
162
164 TGX_INLINE inline float roundfp(const float f) { return roundf(f); }
165
166
168 TGX_INLINE inline double roundfp(const double f) { return round(f); }
169
170
172 TGX_INLINE inline uint32_t float_as_uint32(float f) { uint32_t u; memcpy(&u, &f, sizeof(uint32_t)); return u; }
173
174
176 TGX_INLINE inline float uint32_as_float(uint32_t u) { float f; memcpy(&f, &u, sizeof(float)); return f; }
177
178
182 TGX_INLINE inline int32_t safeMultB(int32_t A, int32_t B)
183 {
184 if ((A == 0) || (B == 0)) return B;
185 const int32_t max32 = 2147483647;
186 const int32_t nB = max32 / ((A > 0) ? A : (-A));
187 return ((B <= nB) ? B : nB);
188 }
189
190
191
197 TGX_INLINE inline float fast_inv(float x)
198 {
199#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
200 // 2 NR iterations, error < 1 ULP
201 float t, result;
202 asm volatile (
203 "recip0.s %0, %2\n\t"
204 "const.s %1, 1\n\t"
205 "msub.s %1, %2, %0\n\t"
206 "madd.s %0, %0, %1\n\t"
207 "const.s %1, 1\n\t"
208 "msub.s %1, %2, %0\n\t"
209 "maddn.s %0, %0, %1"
210 : "=&f" (result),
211 "=&f" (t)
212 : "f" (x)
213 );
214 return result;
215#elif TGX_USE_FAST_INV_TRICK
216 // error < 14.3 ULP (8.91e-7)
217 // float y = uint32_as_float(0x7ef33409 - float_as_uint32(x));
218 //
219 // y = fmaf(y, fmaf(-x, y, 1.00127125f), y);
220 // y = fmaf(y, fmaf(-x, y, 1.00000083f), y);
221
222 // error < 16.5 ULP (1.03e-6)
223 float y = uint32_as_float(0x7ef335a7 - float_as_uint32(x));
224
225 y *= fmaf(-x, y, 2.00128722f);
226 y *= fmaf(-x, y, 2.00000072f);
227 return y;
228#else
229 return ((x == 0) ? 1.0f : (1.0f / x));
230#endif
231 }
232
233
238 TGX_INLINE inline float fast_inv_approx(float x)
239 {
240#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
241 // One Newton-Raphson iteration instead of two.
242 // Less accurate than fast_inv(), but cheaper.
243 float t, result;
244 asm volatile (
245 "recip0.s %0, %2\n\t"
246 "const.s %1, 1\n\t"
247 "msub.s %1, %2, %0\n\t"
248 "madd.s %0, %0, %1"
249 : "=&f" (result),
250 "=&f" (t)
251 : "f" (x)
252 );
253 return result;
254#elif TGX_USE_FAST_INV_TRICK
255 // One correction step: faster than fast_inv(), less accurate by design.
256 float y = uint32_as_float(0x7ef335a7 - float_as_uint32(x));
257 y *= fmaf(-x, y, 2.00128722f);
258 return y;
259#else
260 return fast_inv(x);
261#endif
262 }
263
264
265
266
267
271 TGX_INLINE inline double fast_inv(double x)
272 {
273 // do not use fast approximation for double type.
274 return ((x == 0) ? 1.0 : (1.0 / x));
275 }
276
277
278
282 TGX_INLINE inline float precise_sqrt(float x)
283 {
284 return sqrtf(x);
285 }
286
287
291 TGX_INLINE inline double precise_sqrt(double x)
292 {
293 return sqrt(x);
294 }
295
296
302 TGX_INLINE inline float fast_sqrt(float x)
303 {
304#if TGX_USE_FAST_SQRT_TRICK
305 // error < 11321 ULP (8.81e-4)
306 float y = uint32_as_float(0x5f0b3892 - (float_as_uint32(x) >> 1));
307
308 return x * y * fmaf(-x, y * y, 1.89099002f);
309#else
310 return precise_sqrt(x);
311#endif
312 }
313
314
318 TGX_INLINE inline double fast_sqrt(double x)
319 {
320 // do not use fast approximation for double type.
321 return precise_sqrt(x);
322 }
323
324
330 TGX_INLINE inline float precise_invsqrt(float x)
331 {
332#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
333 // 2 NR iterations, error < 2 ULP
334 float t0, t1, t2, t3, result;
335 asm volatile (
336 "rsqrt0.s %0, %5\n\t"
337 "mul.s %1, %5, %0\n\t"
338 "const.s %2, 3\n\t"
339 "mul.s %3, %2, %0\n\t"
340 "const.s %4, 1\n\t"
341 "msub.s %4, %1, %0\n\t"
342 "madd.s %0, %3, %4\n\t"
343 "mul.s %1, %5, %0\n\t"
344 "mul.s %3, %2, %0\n\t"
345 "const.s %4, 1\n\t"
346 "msub.s %4, %1, %0\n\t"
347 "maddn.s %0, %3, %4"
348 : "=&f" (result),
349 "=&f" (t0),
350 "=&f" (t1),
351 "=&f" (t2),
352 "=&f" (t3)
353 : "f" (x)
354 );
355 return result;
356#else
357 const float s = sqrtf(x);
358 return (s == 0) ? 1.0f : (1.0f / s);
359#endif
360 }
361
362
366 TGX_INLINE inline double precise_invsqrt(double x)
367 {
368 const double s = sqrt(x);
369 return (s == 0) ? 1.0 : (1.0 / s);
370 }
371
372
378 TGX_INLINE inline float fast_invsqrt(float x)
379 {
380#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
381 // 1 NR iteration, error < 728 ULP
382 float t0, t1, t2, t3, result;
383 asm volatile (
384 "rsqrt0.s %0, %5\n\t"
385 "mul.s %1, %5, %0\n\t"
386 "const.s %2, 3\n\t"
387 "mul.s %3, %2, %0\n\t"
388 "const.s %4, 1\n\t"
389 "msub.s %4, %1, %0\n\t"
390 "maddn.s %0, %3, %4"
391 : "=&f" (result),
392 "=&f" (t0),
393 "=&f" (t1),
394 "=&f" (t2),
395 "=&f" (t3)
396 : "f" (x)
397 );
398 return result;
399#elif TGX_USE_FAST_INV_SQRT_TRICK
400 // error < 12536 ULP (8.81e-4)
401 float y = uint32_as_float(0x5f0b3892 - (float_as_uint32(x) >> 1));
402
403 return y * fmaf(-x, y * y, 1.89099002f);
404#else
405 return precise_invsqrt(x);
406#endif
407 }
408
409
413 TGX_INLINE inline double fast_invsqrt(double x)
414 {
415 // do not use fast approximation for double type.
416 return precise_invsqrt(x);
417 }
418
419
425 TGX_INLINE inline int32_t lfloorf(float x)
426 {
427#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
428 uint32_t result;
429 asm volatile (
430 "floor.s %0, %1, 0"
431 : "=a" (result)
432 : "f" (x)
433 );
434 return result;
435#else
436 #if 0 // defined (TGX_RUN_ON_ESP32S2) || defined (TGX_RUN_ON_RP2040) || defined (TGX_RUN_ON_RP2350)
437 const int32_t i = (int32_t)x;
438 return i - ((float)i > x);
439 #else
440 return (int32_t)floorf(x);
441 #endif
442#endif
443 }
444}
445
446#endif
447
448#endif
449
450
TGX_INLINE int32_t lfloorf(float x)
Compute (int32_t)floorf(x).
Definition: Misc.h:425
TGX_INLINE T max(T a, T b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:153
TGX_INLINE void swap(T &a, T &b)
Baby let me swap you one more time...
Definition: Misc.h:145
TGX_INLINE int32_t safeMultB(int32_t A, int32_t B)
Return a value smaller or equal to B such that the multiplication by A is safe (no overflow with int3...
Definition: Misc.h:182
TGX_INLINE uint32_t float_as_uint32(float f)
Reinterpret the bits of a float as a uint32_t.
Definition: Misc.h:172
TGX_INLINE float fast_invsqrt(float x)
Compute a fast approximation of the inverse square root of a float.
Definition: Misc.h:378
TGX_INLINE float precise_sqrt(float x)
Compute the square root of a float (exact computation).
Definition: Misc.h:282
TGX_INLINE T clamp(T v, T vmin, T vmax)
Template clamp version.
Definition: Misc.h:157
TGX_INLINE float roundfp(const float f)
Rounding for floats.
Definition: Misc.h:164
TGX_INLINE T min(T a, T b)
Don't know why but faster than fminf() for floats.
Definition: Misc.h:149
TGX_INLINE float precise_invsqrt(float x)
Compute the inverse square root of a float (exact computation).
Definition: Misc.h:330
TGX_INLINE float fast_sqrt(float x)
Compute a fast approximation of the square root of a float.
Definition: Misc.h:302
TGX_INLINE float uint32_as_float(uint32_t u)
Reinterpret the bits of a uint32_t as a float.
Definition: Misc.h:176
TGX_INLINE float fast_inv(float x)
Fast (approximate) computation of 1/x.
Definition: Misc.h:197
TGX_INLINE float fast_inv_approx(float x)
Fast (very approximate) computation of 1/x.
Definition: Misc.h:238
TGX_INLINE uint16_t BigEndian16(uint16_t v)
little endian / big endian conversion
Definition: Misc.h:134
Configuration file depending on the architecture.