From 7f23d71b6afe92555fd535e875b05ef37f0aa6d3 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 29 Dec 2022 21:39:08 -0800 Subject: [PATCH] Added SDL_modf() and SDL_modff() This function is useful for accumulating relative mouse motion if you want to only handle whole pixel movement. e.g. static float dx_frac, dy_frac; float dx, dy; /* Accumulate new motion with previous sub-pixel motion */ dx = event.motion.xrel + dx_frac; dy = event.motion.yrel + dy_frac; /* Split the integral and fractional motion, dx and dy will contain whole pixel deltas */ dx_frac = SDL_modff(dx, &dx); dy_frac = SDL_modff(dy, &dy); if (dx != 0.0f || dy != 0.0f) { ... } --- CMakeLists.txt | 4 +- VisualC-GDK/SDL/SDL.vcxproj | 1 + VisualC-GDK/SDL/SDL.vcxproj.filters | 3 + VisualC/SDL/SDL.vcxproj | 1 + VisualC/SDL/SDL.vcxproj.filters | 3 + WhatsNew.txt | 1 + include/SDL3/SDL_stdinc.h | 2 + include/build_config/SDL_build_config.h.cmake | 2 + .../build_config/SDL_build_config_android.h | 1 + include/build_config/SDL_build_config_ios.h | 1 + include/build_config/SDL_build_config_macos.h | 1 + include/build_config/SDL_build_config_winrt.h | 1 + src/dynapi/SDL_dynapi.sym | 2 + src/dynapi/SDL_dynapi_overrides.h | 2 + src/dynapi/SDL_dynapi_procs.h | 2 + src/libm/math_libm.h | 11 +-- src/libm/math_private.h | 1 + src/libm/s_modf.c | 68 +++++++++++++++++++ src/stdlib/SDL_stdlib.c | 22 ++++++ test/testautomation_math.c | 27 ++++++++ 20 files changed, 149 insertions(+), 7 deletions(-) create mode 100644 src/libm/s_modf.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 65385da8e..9a4452c73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -962,8 +962,8 @@ if(SDL_LIBC) _stricmp _strnicmp sscanf acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf fmod fmodf - log logf log10 log10f lround lroundf pow powf round roundf scalbn scalbnf - sin sinf sqrt sqrtf tan tanf trunc truncf) + log logf log10 log10f lround lroundf modf modff pow powf round roundf + scalbn scalbnf sin sinf sqrt sqrtf tan tanf trunc truncf) string(TOUPPER ${_FN} _UPPER) set(HAVE_${_UPPER} 1) endforeach() diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj index 381213fc0..d6df2314d 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj +++ b/VisualC-GDK/SDL/SDL.vcxproj @@ -666,6 +666,7 @@ + diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters index 40c9fd6a7..4db42dd26 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj.filters +++ b/VisualC-GDK/SDL/SDL.vcxproj.filters @@ -976,6 +976,9 @@ libm + + libm + libm diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index 798033270..756ea5934 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -546,6 +546,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters index eb48c1e2d..acb558a16 100644 --- a/VisualC/SDL/SDL.vcxproj.filters +++ b/VisualC/SDL/SDL.vcxproj.filters @@ -964,6 +964,9 @@ libm + + libm + libm diff --git a/WhatsNew.txt b/WhatsNew.txt index 10625d97a..6733ad8d9 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -19,3 +19,4 @@ General: * Added SDL_GetTicksNS() to return the number of nanoseconds since the SDL library initialized * Added SDL_DelayNS() to specify a delay in nanoseconds, to the highest precision the system will support * The timestamp member of the SDL_Event structure is now in nanoseconds, filled in with the time the event was generated, or the time it was queued if that's not available +* Added SDL_modf() and SDL_modff() to separate the whole and fractional portions of a floating point number diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h index 75df76aae..75fc0b5eb 100644 --- a/include/SDL3/SDL_stdinc.h +++ b/include/SDL3/SDL_stdinc.h @@ -580,6 +580,8 @@ extern DECLSPEC double SDLCALL SDL_log(double x); extern DECLSPEC float SDLCALL SDL_logf(float x); extern DECLSPEC double SDLCALL SDL_log10(double x); extern DECLSPEC float SDLCALL SDL_log10f(float x); +extern DECLSPEC double SDLCALL SDL_modf(double x, double *y); +extern DECLSPEC float SDLCALL SDL_modff(float x, float *y); extern DECLSPEC double SDLCALL SDL_pow(double x, double y); extern DECLSPEC float SDLCALL SDL_powf(float x, float y); extern DECLSPEC double SDLCALL SDL_round(double x); diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 96eb44e51..87e9c65d7 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -171,6 +171,8 @@ #cmakedefine HAVE_LOG10F 1 #cmakedefine HAVE_LROUND 1 #cmakedefine HAVE_LROUNDF 1 +#cmakedefine HAVE_MODF 1 +#cmakedefine HAVE_MODFF 1 #cmakedefine HAVE_POW 1 #cmakedefine HAVE_POWF 1 #cmakedefine HAVE_ROUND 1 diff --git a/include/build_config/SDL_build_config_android.h b/include/build_config/SDL_build_config_android.h index dd5ea3efd..4572f9aa9 100644 --- a/include/build_config/SDL_build_config_android.h +++ b/include/build_config/SDL_build_config_android.h @@ -120,6 +120,7 @@ #define HAVE_LOG10F 1 #define HAVE_LROUND 1 #define HAVE_LROUNDF 1 +#define HAVE_MODF 1 #define HAVE_POW 1 #define HAVE_POWF 1 #define HAVE_ROUND 1 diff --git a/include/build_config/SDL_build_config_ios.h b/include/build_config/SDL_build_config_ios.h index 0bb63efc3..d4f14c28f 100644 --- a/include/build_config/SDL_build_config_ios.h +++ b/include/build_config/SDL_build_config_ios.h @@ -114,6 +114,7 @@ #define HAVE_LOG10F 1 #define HAVE_LROUND 1 #define HAVE_LROUNDF 1 +#define HAVE_MODF 1 #define HAVE_POW 1 #define HAVE_POWF 1 #define HAVE_ROUND 1 diff --git a/include/build_config/SDL_build_config_macos.h b/include/build_config/SDL_build_config_macos.h index 576c4dc5b..f2878db25 100644 --- a/include/build_config/SDL_build_config_macos.h +++ b/include/build_config/SDL_build_config_macos.h @@ -116,6 +116,7 @@ #define HAVE_LOG10F 1 #define HAVE_LROUND 1 #define HAVE_LROUNDF 1 +#define HAVE_MODF 1 #define HAVE_POW 1 #define HAVE_POWF 1 #define HAVE_ROUND 1 diff --git a/include/build_config/SDL_build_config_winrt.h b/include/build_config/SDL_build_config_winrt.h index 4256cea42..01bff80e1 100644 --- a/include/build_config/SDL_build_config_winrt.h +++ b/include/build_config/SDL_build_config_winrt.h @@ -134,6 +134,7 @@ #define HAVE_LOG10F 1 #define HAVE_LROUND 1 #define HAVE_LROUNDF 1 +#define HAVE_MODF 1 #define HAVE_POW 1 #define HAVE_POWF 1 #define HAVE_ROUND 1 diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 2876dea5d..540c00ebf 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -859,6 +859,8 @@ SDL3_0.0.0 { SDL_wcsncasecmp; SDL_wcsncmp; SDL_wcsstr; + SDL_modf; + SDL_modff; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 1228b3ba7..2bc07ba4f 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -887,3 +887,5 @@ #define SDL_wcsstr SDL_wcsstr_REAL /* New API symbols are added at the end */ +#define SDL_modf SDL_modf_REAL +#define SDL_modff SDL_modff_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index f4cf4b731..62bf7dd39 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -932,3 +932,5 @@ SDL_DYNAPI_PROC(int,SDL_wcsncmp,(const wchar_t *a, const wchar_t *b, size_t c),( SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),return) /* New API symbols are added at the end */ +SDL_DYNAPI_PROC(double,SDL_modf,(double a, double *b),(a,b),return) +SDL_DYNAPI_PROC(float,SDL_modff,(float a, float *b),(a,b),return) diff --git a/src/libm/math_libm.h b/src/libm/math_libm.h index f88c73bf3..5ed5f21a3 100644 --- a/src/libm/math_libm.h +++ b/src/libm/math_libm.h @@ -27,16 +27,17 @@ /* Math routines from uClibc: http://www.uclibc.org */ double SDL_uclibc_atan(double x); -double SDL_uclibc_atan2(double y, double x); -double SDL_uclibc_copysign(double x, double y); -double SDL_uclibc_cos(double x); +double SDL_uclibc_atan2(double y, double x); +double SDL_uclibc_copysign(double x, double y); +double SDL_uclibc_cos(double x); double SDL_uclibc_exp(double x); -double SDL_uclibc_fabs(double x); +double SDL_uclibc_fabs(double x); double SDL_uclibc_floor(double x); double SDL_uclibc_fmod(double x, double y); double SDL_uclibc_log(double x); double SDL_uclibc_log10(double x); -double SDL_uclibc_pow(double x, double y); +double SDL_uclibc_modf(double x, double *y); +double SDL_uclibc_pow(double x, double y); double SDL_uclibc_scalbn(double x, int n); double SDL_uclibc_sin(double x); double SDL_uclibc_sqrt(double x); diff --git a/src/libm/math_private.h b/src/libm/math_private.h index 8a468bf47..ba5d83468 100644 --- a/src/libm/math_private.h +++ b/src/libm/math_private.h @@ -40,6 +40,7 @@ typedef unsigned int u_int32_t; #define __ieee754_fmod SDL_uclibc_fmod #define __ieee754_log SDL_uclibc_log #define __ieee754_log10 SDL_uclibc_log10 +#define modf SDL_uclibc_modf #define __ieee754_pow SDL_uclibc_pow #define scalbln SDL_uclibc_scalbln #define scalbn SDL_uclibc_scalbn diff --git a/src/libm/s_modf.c b/src/libm/s_modf.c new file mode 100644 index 000000000..55f83ba8d --- /dev/null +++ b/src/libm/s_modf.c @@ -0,0 +1,68 @@ +#include "SDL_internal.h" +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * modf(double x, double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ + +#include "math_libm.h" +#include "math_private.h" + +static const double one = 1.0; + +double modf(double x, double *iptr) +{ + int32_t i0,i1,_j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + _j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */ + if(_j0<20) { /* integer part in high x */ + if(_j0<0) { /* |x|<1 */ + INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */ + return x; + } else { + i = (0x000fffff)>>_j0; + if(((i0&i)|i1)==0) { /* x is integral */ + *iptr = x; + INSERT_WORDS(x,i0&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0&(~i),0); + return x - *iptr; + } + } + } else if (_j0>51) { /* no fraction part */ + *iptr = x*one; + /* We must handle NaNs separately. */ + if (_j0 == 0x400 && ((i0 & 0xfffff) | i1)) + return x*one; + INSERT_WORDS(x,i0&0x80000000,0); /* return +-0 */ + return x; + } else { /* fraction part in low x */ + i = ((u_int32_t)(0xffffffff))>>(_j0-20); + if((i1&i)==0) { /* x is integral */ + *iptr = x; + INSERT_WORDS(x,i0&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0,i1&(~i)); + return x - *iptr; + } + } +} +libm_hidden_def(modf) diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c index 7663423fa..8c567cf5b 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -322,6 +322,28 @@ float SDL_log10f(float x) #endif } +double +SDL_modf(double x, double *y) +{ +#if defined(HAVE_MODF) + return modf(x, y); +#else + return SDL_uclibc_modf(x, y); +#endif +} + +float SDL_modff(float x, float *y) +{ +#if defined(HAVE_MODFF) + return modff(x, y); +#else + double double_result, double_y; + double_result = SDL_modf((double)x, &double_y); + *y = (float)double_y; + return (float)double_result; +#endif +} + double SDL_pow(double x, double y) { diff --git a/test/testautomation_math.c b/test/testautomation_math.c index 7103854e0..4bdc2f7e9 100644 --- a/test/testautomation_math.c +++ b/test/testautomation_math.c @@ -1272,6 +1272,24 @@ log10_regularCases(void *args) return helper_dtod_inexact("Log10", SDL_log10, regular_cases, SDL_arraysize(regular_cases)); } +/* SDL_modf tests functions */ + +static int +modf_baseCases(void *args) +{ + double fractional, integral; + + fractional = SDL_modf(1.25, &integral); + SDLTest_AssertCheck(integral == 1.0, + "modf(%f), expected integral %f, got %f", + 1.25, 1.0, integral); + SDLTest_AssertCheck(fractional == 0.25, + "modf(%f), expected fractional %f, got %f", + 1.25, 0.25, fractional); + + return TEST_COMPLETED; +} + /* SDL_pow tests functions */ /* Tests with positive and negative infinities as exponents */ @@ -3004,6 +3022,13 @@ static const SDLTest_TestCaseReference log10TestRegular = { "Checks a set of regular values", TEST_ENABLED }; +/* SDL_modf test cases */ + +static const SDLTest_TestCaseReference modfTestBase = { + (SDLTest_TestCaseFp)modf_baseCases, "modf_baseCases", + "Checks the base cases", TEST_ENABLED +}; + /* SDL_pow test cases */ static const SDLTest_TestCaseReference powTestExpInf1 = { @@ -3315,6 +3340,8 @@ static const SDLTest_TestCaseReference *mathTests[] = { &log10TestLimit, &log10TestNan, &log10TestBase, &log10TestRegular, + &modfTestBase, + &powTestExpInf1, &powTestExpInf2, &powTestExpInf3, &powTestBaseInf1, &powTestBaseInf2, &powTestNan1, &powTestNan2, &powTestNan3, &powTestNan4,