aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/modules/gdisp/gdisp_streaming/gfxconf.h10
-rw-r--r--demos/modules/gdisp/gdisp_streaming/main.c32
-rw-r--r--gfxconf.example.h3
-rw-r--r--include/gmisc/options.h27
-rw-r--r--src/gmisc/trig.c56
5 files changed, 98 insertions, 30 deletions
diff --git a/demos/modules/gdisp/gdisp_streaming/gfxconf.h b/demos/modules/gdisp/gdisp_streaming/gfxconf.h
index 4db07fb9..b38be854 100644
--- a/demos/modules/gdisp/gdisp_streaming/gfxconf.h
+++ b/demos/modules/gdisp/gdisp_streaming/gfxconf.h
@@ -35,9 +35,11 @@
/* Builtin Fonts */
#define GDISP_INCLUDE_FONT_UI2 FALSE
-#define GFX_USE_GMISC TRUE
-#define GMISC_NEED_FIXEDTRIG FALSE
-#define GMISC_NEED_FASTTRIG FALSE
-#define GMISC_NEED_INVSQRT TRUE
+#define GFX_USE_GMISC TRUE
+#define GMISC_NEED_FIXEDTRIG FALSE
+#define GMISC_NEED_FASTTRIG FALSE
+#define GMISC_NEED_INVSQRT TRUE
+//#define GDISP_INVSQRT_MIXED_ENDIAN TRUE
+//#define GDISP_INVSQRT_REAL_SLOW TRUE
#endif /* _GFXCONF_H */
diff --git a/demos/modules/gdisp/gdisp_streaming/main.c b/demos/modules/gdisp/gdisp_streaming/main.c
index 774ee833..5b857eeb 100644
--- a/demos/modules/gdisp/gdisp_streaming/main.c
+++ b/demos/modules/gdisp/gdisp_streaming/main.c
@@ -31,15 +31,29 @@
#include "gfx.h"
#include <math.h>
-#define Lightgrey ()
-#define Midgrey ()
-#define Darkgrey (HTML2COLOR(0x303030))
-
-#define BALLCOLOR1 Red
-#define BALLCOLOR2 Yellow
-#define WALLCOLOR HTML2COLOR(0x303030)
-#define BACKCOLOR HTML2COLOR(0xC0C0C0)
-#define FLOORCOLOR HTML2COLOR(0x606060)
+/**
+ * NOTE:
+ *
+ * This demo uses floating point operations. Don't expect it to work with any
+ * speed unless your processor has an FPU.
+ *
+ * If you see garbage inside the ball as it is running rather than the red and yellow
+ * checkerboard pattern then the fast invsqrt() function in GMISC does not work on
+ * your processor.
+ *
+ * You can modify the implementation of invsqrt() by firstly defining
+ * #define GDISP_INVSQRT_MIXED_ENDIAN TRUE
+ * in your gfxconf.h file.
+ *
+ * If it still doesn't work then instead define
+ * #define GDISP_INVSQRT_REAL_SLOW TRUE
+ * in your gfxconf.h file. This should always work although it will probably be slow.
+ */
+#define BALLCOLOR1 Red
+#define BALLCOLOR2 Yellow
+#define WALLCOLOR HTML2COLOR(0x303030)
+#define BACKCOLOR HTML2COLOR(0xC0C0C0)
+#define FLOORCOLOR HTML2COLOR(0x606060)
#define SHADOWALPHA (255-255*0.2)
int main(void) {
diff --git a/gfxconf.example.h b/gfxconf.example.h
index d5b4af5c..1b9faca2 100644
--- a/gfxconf.example.h
+++ b/gfxconf.example.h
@@ -181,11 +181,12 @@
#define GWIN_CONSOLE_USE_BASESTREAM FALSE
#define GWIN_CONSOLE_USE_FLOAT FALSE
#define GWIN_NEED_IMAGE_ANIMATION FALSE
+ #define GDISP_INVSQRT_MIXED_ENDIAN FALSE
+ #define GDISP_INVSQRT_REAL_SLOW FALSE
*/
/* Optional Low Level Driver Definitions */
/*
- #define GDISP_USE_CUSTOM_BOARD FALSE
#define GDISP_SCREEN_WIDTH 320
#define GDISP_SCREEN_HEIGHT 240
#define GDISP_USE_FSMC
diff --git a/include/gmisc/options.h b/include/gmisc/options.h
index 73b41800..9c309487 100644
--- a/include/gmisc/options.h
+++ b/include/gmisc/options.h
@@ -44,9 +44,34 @@
/**
* @}
*
- * @name GMISC Optional Sizing Parameters
+ * @name GMISC Optional Parameters
* @{
*/
+ /**
+ * @brief Modifies the @p invsqrt() function to assume a different integer to floating point endianness.
+ * @note Normally the floating point format and the integer format have
+ * the same endianness. Unfortunately there are some strange
+ * processors that don't eg. some very early ARM devices.
+ * For those where the endianness doesn't match you can fix it by
+ * defining GDISP_INVSQRT_MIXED_ENDIAN.
+ * @note This still assumes the processor is using an ieee floating point format.
+ *
+ * If you have a software floating point that uses a non-standard
+ * floating point format (or very strange hardware) then define
+ * GDISP_INVSQRT_REAL_SLOW and it will do it the hard way.
+ */
+ #ifndef GDISP_INVSQRT_MIXED_ENDIAN
+ #define GDISP_INVSQRT_MIXED_ENDIAN FALSE
+ #endif
+ /**
+ * @brief Modifies the @p invsqrt() function to do things the long slow way.
+ * @note This causes the @p invsqrt() function to work regardless of the
+ * processor floating point format.
+ * @note This makes the @p invsqrt() function very slow.
+ */
+ #ifndef GDISP_INVSQRT_REAL_SLOW
+ #define GDISP_INVSQRT_REAL_SLOW FALSE
+ #endif
/** @} */
#endif /* _GMISC_OPTIONS_H */
diff --git a/src/gmisc/trig.c b/src/gmisc/trig.c
index 00b6365a..cd35bdc0 100644
--- a/src/gmisc/trig.c
+++ b/src/gmisc/trig.c
@@ -143,21 +143,47 @@
#endif
#if GMISC_NEED_INVSQRT
- // Algorithm based on Quake code
- float invsqrt(float n) {
- long i;
- float x2, y;
- const float threehalfs = 1.5F;
-
- x2 = n * 0.5F;
- y = n;
- i = * ( long * ) &y; // evil floating point bit level hacking
- i = 0x5f3759df - ( i >> 1 ); // what the?
- y = * ( float * ) &i;
- y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
- //y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration for extra precision, this can be removed
- return y;
- }
+ // Algorithm based on Quake code.
+ #if GDISP_INVSQRT_REAL_SLOW
+ #include <math.h>
+ float invsqrt(float n) {
+ return 1.0/sqrt(n);
+ }
+ #else
+ float invsqrt(float n) {
+ int32_t i;
+ float x2;
+
+ x2 = n * 0.5F;
+
+ // Convert into an int32 (no binary format conversion)
+ #if GDISP_INVSQRT_MIXED_ENDIAN
+ ((char *)&i)[0] = ((char *)&n)[3];
+ ((char *)&i)[1] = ((char *)&n)[2];
+ ((char *)&i)[2] = ((char *)&n)[1];
+ ((char *)&i)[3] = ((char *)&n)[0];
+ #else
+ i = *(int32_t *)&n;
+ #endif
+
+ // evil floating point bit level hacking
+ i = 0x5F3759DF - (i >> 1);
+
+ // Convert back to a float (no binary format conversion)
+ #if GDISP_INVSQRT_MIXED_ENDIAN
+ ((char *)&n)[0] = ((char *)&i)[3];
+ ((char *)&n)[1] = ((char *)&i)[2];
+ ((char *)&n)[2] = ((char *)&i)[1];
+ ((char *)&n)[3] = ((char *)&i)[0];
+ #else
+ n = *(float *)&i;
+ #endif
+
+ n = n * (1.5F - (x2 * n * n)); // 1st iteration
+ //n = n * (1.5F - (x2 * n * n)); // 2nd iteration for extra precision, this can be removed
+ return n;
+ }
+ #endif
#endif
#endif /* GFX_USE_GMISC */