| TGX 1.1.0 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.
61 static_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
83 namespace 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(const T & a, const T & b) { return((a < b) ? a : b); }
150
151
153 template<typename T> TGX_INLINE inline T max(const T & a, const T & b) { return((a > b) ? a : b); }
154
155
157 template<typename T> TGX_INLINE inline T clamp(const T & v, const T & vmin, const 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
237 TGX_INLINE inline double fast_inv(double x)
238 {
239 // do not use fast approximation for double type.
240 return ((x == 0) ? 1.0 : (1.0 / x));
241 }
242
243
244
248 TGX_INLINE inline float precise_sqrt(float x)
249 {
250 return sqrtf(x);
251 }
252
253
257 TGX_INLINE inline double precise_sqrt(double x)
258 {
259 return sqrt(x);
260 }
261
262
268 TGX_INLINE inline float fast_sqrt(float x)
269 {
270#if TGX_USE_FAST_SQRT_TRICK
271 // error < 11321 ULP (8.81e-4)
272 float y = uint32_as_float(0x5f0b3892 - (float_as_uint32(x) >> 1));
273
274 return x * y * fmaf(-x, y * y, 1.89099002f);
275#else
276 return precise_sqrt(x);
277#endif
278 }
279
280
284 TGX_INLINE inline double fast_sqrt(double x)
285 {
286 // do not use fast approximation for double type.
287 return precise_sqrt(x);
288 }
289
290
296 TGX_INLINE inline float precise_invsqrt(float x)
297 {
298#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
299 // 2 NR iterations, error < 2 ULP
300 float t0, t1, t2, t3, result;
301 asm volatile (
302 "rsqrt0.s %0, %5\n\t"
303 "mul.s %1, %5, %0\n\t"
304 "const.s %2, 3\n\t"
305 "mul.s %3, %2, %0\n\t"
306 "const.s %4, 1\n\t"
307 "msub.s %4, %1, %0\n\t"
308 "madd.s %0, %3, %4\n\t"
309 "mul.s %1, %5, %0\n\t"
310 "mul.s %3, %2, %0\n\t"
311 "const.s %4, 1\n\t"
312 "msub.s %4, %1, %0\n\t"
313 "maddn.s %0, %3, %4"
314 : "=&f" (result),
315 "=&f" (t0),
316 "=&f" (t1),
317 "=&f" (t2),
318 "=&f" (t3)
319 : "f" (x)
320 );
321 return result;
322#else
323 const float s = sqrtf(x);
324 return (s == 0) ? 1.0f : (1.0f / s);
325#endif
326 }
327
328
332 TGX_INLINE inline double precise_invsqrt(double x)
333 {
334 const double s = sqrt(x);
335 return (s == 0) ? 1.0 : (1.0 / s);
336 }
337
338
344 TGX_INLINE inline float fast_invsqrt(float x)
345 {
346#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
347 // 1 NR iteration, error < 728 ULP
348 float t0, t1, t2, t3, result;
349 asm volatile (
350 "rsqrt0.s %0, %5\n\t"
351 "mul.s %1, %5, %0\n\t"
352 "const.s %2, 3\n\t"
353 "mul.s %3, %2, %0\n\t"
354 "const.s %4, 1\n\t"
355 "msub.s %4, %1, %0\n\t"
356 "maddn.s %0, %3, %4"
357 : "=&f" (result),
358 "=&f" (t0),
359 "=&f" (t1),
360 "=&f" (t2),
361 "=&f" (t3)
362 : "f" (x)
363 );
364 return result;
365#elif TGX_USE_FAST_INV_SQRT_TRICK
366 // error < 12536 ULP (8.81e-4)
367 float y = uint32_as_float(0x5f0b3892 - (float_as_uint32(x) >> 1));
368
369 return y * fmaf(-x, y * y, 1.89099002f);
370#else
371 return precise_invsqrt(x);
372#endif
373 }
374
375
379 TGX_INLINE inline double fast_invsqrt(double x)
380 {
381 // do not use fast approximation for double type.
382 return precise_invsqrt(x);
383 }
384
385
391 TGX_INLINE inline int32_t lfloorf(float x)
392 {
393#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
394 uint32_t result;
395 asm volatile (
396 "floor.s %0, %1, 0"
397 : "=a" (result)
398 : "f" (x)
399 );
400 return result;
401#else
402 return (int32_t)floorf(x);
403#endif
404 }
405}
406
407#endif
408
409#endif
410
411
tgx::lfloorf
TGX_INLINE int32_t lfloorf(float x)
Compute (int32_t)floorf(x).
Definition: Misc.h:391
tgx::min
TGX_INLINE T min(const T &a, const T &b)
Don't know why but faster than fminf() for floats.
Definition: Misc.h:149
tgx::max
TGX_INLINE T max(const T &a, const T &b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:153
tgx::clamp
TGX_INLINE T clamp(const T &v, const T &vmin, const T &vmax)
Template clamp version.
Definition: Misc.h:157
tgx::swap
TGX_INLINE void swap(T &a, T &b)
Baby let me swap you one more time...
Definition: Misc.h:145
tgx::safeMultB
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::float_as_uint32
TGX_INLINE uint32_t float_as_uint32(float f)
Reinterpret the bits of a float as a uint32_t.
Definition: Misc.h:172
tgx::fast_invsqrt
TGX_INLINE float fast_invsqrt(float x)
Compute a fast approximation of the inverse square root of a float.
Definition: Misc.h:344
tgx::precise_sqrt
TGX_INLINE float precise_sqrt(float x)
Compute the square root of a float (exact computation).
Definition: Misc.h:248
tgx::roundfp
TGX_INLINE float roundfp(const float f)
Rounding for floats.
Definition: Misc.h:164
tgx::precise_invsqrt
TGX_INLINE float precise_invsqrt(float x)
Compute the inverse square root of a float (exact computation).
Definition: Misc.h:296
tgx::fast_sqrt
TGX_INLINE float fast_sqrt(float x)
Compute a fast approximation of the square root of a float.
Definition: Misc.h:268
tgx::uint32_as_float
TGX_INLINE float uint32_as_float(uint32_t u)
Reinterpret the bits of a uint32_t as a float.
Definition: Misc.h:176
tgx::fast_inv
TGX_INLINE float fast_inv(float x)
Fast (approximate) computation of 1/x.
Definition: Misc.h:197
tgx::BigEndian16
TGX_INLINE uint16_t BigEndian16(uint16_t v)
little endian / big endian conversion
Definition: Misc.h:134
tgx_config.h
Configuration file depending on the architecture.