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 -#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; + // Algorithm based on Quake code. + #if GDISP_INVSQRT_REAL_SLOW + #include + float invsqrt(float n) { + return 1.0/sqrt(n); + } + #else + float invsqrt(float n) { + int32_t i; + float x2; - 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; - } + 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 */