| TGX 1.0.7 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
42
43// check that int is at least 4 bytes.
44 static_assert(sizeof(int) >= 4, "The TGX library only works on 32 bits or 64 bits architecture. Sorry!");
45
46
47
48#if defined(ARDUINO_TEENSY41)
49
50 // check existence of external ram (EXTMEM).
51 extern "C" uint8_t external_psram_size;
52
53 // check is an address is in flash
54 #define TGX_IS_PROGMEM(X) ((((uint32_t)(X)) >= 0x60000000)&&(((uint32_t)(X)) < 0x70000000))
55
56 // check if an address is in external ram
57 #define TGX_IS_EXTMEM(X) ((((uint32_t)(X)) >= 0x70000000)&&(((uint32_t)(X)) < 0x80000000))
58
59#endif
60
61#ifndef M_PI
62#define M_PI 3.14159265358979323846
63#endif
64
65
66 namespace tgx
67{
68
69
75 template<int N> struct DummyType
76 {
77 // nothing here :-)
78 };
79
80
86 template<bool BB1, bool BB2> struct DummyTypeBB
87 {
88 // nothing here :-)
89 };
90
91
93 template<typename T = int> struct DefaultFPType
94 {
95#if TGX_SINGLE_PRECISION_COMPUTATIONS
96 typedef float fptype;
97#else
98 typedef double fptype;
99#endif
100 };
101
102#if TGX_SINGLE_PRECISION_COMPUTATIONS
104 template<> struct DefaultFPType<double>
105 {
106 typedef double fptype;
107 };
108#endif
109
110
112 template <typename, typename> struct is_same { static const bool value = false; };
113 template <typename T> struct is_same<T, T> { static const bool value = true; };
114
115
117 TGX_INLINE inline uint16_t BigEndian16(uint16_t v)
118 {
119#ifdef __GNUC__
120 return __builtin_bswap16(v);
121#else
122 return ((v >> 8) | (v << 8));
123#endif
124 }
125
126
128 template<typename T> TGX_INLINE inline void swap(T& a, T& b) { T c(a); a = b; b = c; }
129
130
132 template<typename T> TGX_INLINE inline T min(const T & a, const T & b) { return((a < b) ? a : b); }
133
134
136 template<typename T> TGX_INLINE inline T max(const T & a, const T & b) { return((a > b) ? a : b); }
137
138
140 template<typename T> TGX_INLINE inline T clamp(const T & v, const T & vmin, const T & vmax)
141 {
142 return max(vmin, min(vmax, v));
143 }
144
145
147 TGX_INLINE inline float roundfp(const float f) { return roundf(f); }
148
149
151 TGX_INLINE inline double roundfp(const double f) { return round(f); }
152
153
155 TGX_INLINE inline uint32_t float_as_uint32(float f) { uint32_t u; memcpy(&u, &f, sizeof(uint32_t)); return u; }
156
157
159 TGX_INLINE inline float uint32_as_float(uint32_t u) { float f; memcpy(&f, &u, sizeof(float)); return f; }
160
161
165 TGX_INLINE inline int32_t safeMultB(int32_t A, int32_t B)
166 {
167 if ((A == 0) || (B == 0)) return B;
168 const int32_t max32 = 2147483647;
169 const int32_t nB = max32 / ((A > 0) ? A : (-A));
170 return ((B <= nB) ? B : nB);
171 }
172
173
174
180 TGX_INLINE inline float fast_inv(float x)
181 {
182#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
183 // 2 NR iterations, error < 1 ULP
184 float t, result;
185 asm volatile (
186 "recip0.s %0, %2\n\t"
187 "const.s %1, 1\n\t"
188 "msub.s %1, %2, %0\n\t"
189 "madd.s %0, %0, %1\n\t"
190 "const.s %1, 1\n\t"
191 "msub.s %1, %2, %0\n\t"
192 "maddn.s %0, %0, %1"
193 : "=&f" (result),
194 "=&f" (t)
195 : "f" (x)
196 );
197 return result;
198#elif TGX_USE_FAST_INV_TRICK
199 // error < 14.3 ULP (8.91e-7)
200 // float y = uint32_as_float(0x7ef33409 - float_as_uint32(x));
201 //
202 // y = fmaf(y, fmaf(-x, y, 1.00127125f), y);
203 // y = fmaf(y, fmaf(-x, y, 1.00000083f), y);
204
205 // error < 16.5 ULP (1.03e-6)
206 float y = uint32_as_float(0x7ef335a7 - float_as_uint32(x));
207
208 y *= fmaf(-x, y, 2.00128722f);
209 y *= fmaf(-x, y, 2.00000072f);
210 return y;
211#else
212 return ((x == 0) ? 1.0f : (1.0f / x));
213#endif
214 }
215
216
220 TGX_INLINE inline double fast_inv(double x)
221 {
222 // do not use fast approximation for double type.
223 return ((x == 0) ? 1.0 : (1.0 / x));
224 }
225
226
227
231 TGX_INLINE inline float precise_sqrt(float x)
232 {
233 return sqrtf(x);
234 }
235
236
240 TGX_INLINE inline double precise_sqrt(double x)
241 {
242 return sqrt(x);
243 }
244
245
251 TGX_INLINE inline float fast_sqrt(float x)
252 {
253#if TGX_USE_FAST_SQRT_TRICK
254 // error < 11321 ULP (8.81e-4)
255 float y = uint32_as_float(0x5f0b3892 - (float_as_uint32(x) >> 1));
256
257 return x * y * fmaf(-x, y * y, 1.89099002f);
258#else
259 return precise_sqrt(x);
260#endif
261 }
262
263
267 TGX_INLINE inline double fast_sqrt(double x)
268 {
269 // do not use fast approximation for double type.
270 return precise_sqrt(x);
271 }
272
273
279 TGX_INLINE inline float precise_invsqrt(float x)
280 {
281#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
282 // 2 NR iterations, error < 2 ULP
283 float t0, t1, t2, t3, result;
284 asm volatile (
285 "rsqrt0.s %0, %5\n\t"
286 "mul.s %1, %5, %0\n\t"
287 "const.s %2, 3\n\t"
288 "mul.s %3, %2, %0\n\t"
289 "const.s %4, 1\n\t"
290 "msub.s %4, %1, %0\n\t"
291 "madd.s %0, %3, %4\n\t"
292 "mul.s %1, %5, %0\n\t"
293 "mul.s %3, %2, %0\n\t"
294 "const.s %4, 1\n\t"
295 "msub.s %4, %1, %0\n\t"
296 "maddn.s %0, %3, %4"
297 : "=&f" (result),
298 "=&f" (t0),
299 "=&f" (t1),
300 "=&f" (t2),
301 "=&f" (t3)
302 : "f" (x)
303 );
304 return result;
305#else
306 const float s = sqrtf(x);
307 return (s == 0) ? 1.0f : (1.0f / s);
308#endif
309 }
310
311
315 TGX_INLINE inline double precise_invsqrt(double x)
316 {
317 const double s = sqrt(x);
318 return (s == 0) ? 1.0 : (1.0 / sqrt(s));
319 }
320
321
327 TGX_INLINE inline float fast_invsqrt(float x)
328 {
329#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
330 // 1 NR iteration, error < 728 ULP
331 float t0, t1, t2, t3, result;
332 asm volatile (
333 "rsqrt0.s %0, %5\n\t"
334 "mul.s %1, %5, %0\n\t"
335 "const.s %2, 3\n\t"
336 "mul.s %3, %2, %0\n\t"
337 "const.s %4, 1\n\t"
338 "msub.s %4, %1, %0\n\t"
339 "maddn.s %0, %3, %4"
340 : "=&f" (result),
341 "=&f" (t0),
342 "=&f" (t1),
343 "=&f" (t2),
344 "=&f" (t3)
345 : "f" (x)
346 );
347 return result;
348#elif TGX_USE_FAST_INV_SQRT_TRICK
349 // error < 12536 ULP (8.81e-4)
350 float y = uint32_as_float(0x5f0b3892 - (float_as_uint32(x) >> 1));
351
352 return y * fmaf(-x, y * y, 1.89099002f);
353#else
354 return precise_invsqrt(x);
355#endif
356 }
357
358
362 TGX_INLINE inline double fast_invsqrt(double x)
363 {
364 // do not use fast approximation for double type.
365 return precise_invsqrt(x);
366 }
367
368
374 TGX_INLINE inline int32_t lfloorf(float x)
375 {
376#if defined(__XTENSA__) && !defined(__XTENSA_SOFT_FLOAT__)
377 uint32_t result;
378 asm volatile (
379 "floor.s %0, %1, 0"
380 : "=a" (result)
381 : "f" (x)
382 );
383 return result;
384#else
385 return (int32_t)floorf(x);
386#endif
387 }
388}
389
390#endif
391
392#endif
393
394
tgx::lfloorf
TGX_INLINE int32_t lfloorf(float x)
Compute (int32_t)floorf(x).
Definition: Misc.h:374
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:132
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:136
tgx::clamp
TGX_INLINE T clamp(const T &v, const T &vmin, const T &vmax)
Template clamp version.
Definition: Misc.h:140
tgx::swap
TGX_INLINE void swap(T &a, T &b)
Baby let me swap you one more time...
Definition: Misc.h:128
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:165
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:155
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:327
tgx::precise_sqrt
TGX_INLINE float precise_sqrt(float x)
Compute the square root of a float (exact computation).
Definition: Misc.h:231
tgx::roundfp
TGX_INLINE float roundfp(const float f)
Rounding for floats.
Definition: Misc.h:147
tgx::precise_invsqrt
TGX_INLINE float precise_invsqrt(float x)
Compute the inverse square root of a float (exact computation).
Definition: Misc.h:279
tgx::fast_sqrt
TGX_INLINE float fast_sqrt(float x)
Compute a fast approximation of the square root of a float.
Definition: Misc.h:251
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:159
tgx::fast_inv
TGX_INLINE float fast_inv(float x)
Fast (approximate) computation of 1/x.
Definition: Misc.h:180
tgx::BigEndian16
TGX_INLINE uint16_t BigEndian16(uint16_t v)
little endian / big endian conversion
Definition: Misc.h:117
tgx_config.h
Configuration file depending on the architecture.