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) {
    ...
}
This commit is contained in:
Sam Lantinga 2022-12-29 21:39:08 -08:00
parent ead4f122e4
commit 7f23d71b6a
20 changed files with 149 additions and 7 deletions

View File

@ -962,8 +962,8 @@ if(SDL_LIBC)
_stricmp _strnicmp sscanf _stricmp _strnicmp sscanf
acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf
copysign copysignf cos cosf exp expf fabs fabsf floor floorf fmod fmodf copysign copysignf cos cosf exp expf fabs fabsf floor floorf fmod fmodf
log logf log10 log10f lround lroundf pow powf round roundf scalbn scalbnf log logf log10 log10f lround lroundf modf modff pow powf round roundf
sin sinf sqrt sqrtf tan tanf trunc truncf) scalbn scalbnf sin sinf sqrt sqrtf tan tanf trunc truncf)
string(TOUPPER ${_FN} _UPPER) string(TOUPPER ${_FN} _UPPER)
set(HAVE_${_UPPER} 1) set(HAVE_${_UPPER} 1)
endforeach() endforeach()

View File

@ -666,6 +666,7 @@
<ClCompile Include="..\..\src\libm\s_cos.c" /> <ClCompile Include="..\..\src\libm\s_cos.c" />
<ClCompile Include="..\..\src\libm\s_fabs.c" /> <ClCompile Include="..\..\src\libm\s_fabs.c" />
<ClCompile Include="..\..\src\libm\s_floor.c" /> <ClCompile Include="..\..\src\libm\s_floor.c" />
<ClCompile Include="..\..\src\libm\s_modf.c" />
<ClCompile Include="..\..\src\libm\s_scalbn.c" /> <ClCompile Include="..\..\src\libm\s_scalbn.c" />
<ClCompile Include="..\..\src\libm\s_sin.c" /> <ClCompile Include="..\..\src\libm\s_sin.c" />
<ClCompile Include="..\..\src\libm\s_tan.c" /> <ClCompile Include="..\..\src\libm\s_tan.c" />

View File

@ -976,6 +976,9 @@
<ClCompile Include="..\..\src\libm\s_floor.c"> <ClCompile Include="..\..\src\libm\s_floor.c">
<Filter>libm</Filter> <Filter>libm</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\libm\s_modf.c">
<Filter>libm</Filter>
</ClCompile>
<ClCompile Include="..\..\src\libm\s_scalbn.c"> <ClCompile Include="..\..\src\libm\s_scalbn.c">
<Filter>libm</Filter> <Filter>libm</Filter>
</ClCompile> </ClCompile>

View File

@ -546,6 +546,7 @@
<ClCompile Include="..\..\src\libm\s_cos.c" /> <ClCompile Include="..\..\src\libm\s_cos.c" />
<ClCompile Include="..\..\src\libm\s_fabs.c" /> <ClCompile Include="..\..\src\libm\s_fabs.c" />
<ClCompile Include="..\..\src\libm\s_floor.c" /> <ClCompile Include="..\..\src\libm\s_floor.c" />
<ClCompile Include="..\..\src\libm\s_modf.c" />
<ClCompile Include="..\..\src\libm\s_scalbn.c" /> <ClCompile Include="..\..\src\libm\s_scalbn.c" />
<ClCompile Include="..\..\src\libm\s_sin.c" /> <ClCompile Include="..\..\src\libm\s_sin.c" />
<ClCompile Include="..\..\src\libm\s_tan.c" /> <ClCompile Include="..\..\src\libm\s_tan.c" />

View File

@ -964,6 +964,9 @@
<ClCompile Include="..\..\src\libm\s_floor.c"> <ClCompile Include="..\..\src\libm\s_floor.c">
<Filter>libm</Filter> <Filter>libm</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\libm\s_modf.c">
<Filter>libm</Filter>
</ClCompile>
<ClCompile Include="..\..\src\libm\s_scalbn.c"> <ClCompile Include="..\..\src\libm\s_scalbn.c">
<Filter>libm</Filter> <Filter>libm</Filter>
</ClCompile> </ClCompile>

View File

@ -19,3 +19,4 @@ General:
* Added SDL_GetTicksNS() to return the number of nanoseconds since the SDL library initialized * 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 * 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 * 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

View File

@ -580,6 +580,8 @@ extern DECLSPEC double SDLCALL SDL_log(double x);
extern DECLSPEC float SDLCALL SDL_logf(float x); extern DECLSPEC float SDLCALL SDL_logf(float x);
extern DECLSPEC double SDLCALL SDL_log10(double x); extern DECLSPEC double SDLCALL SDL_log10(double x);
extern DECLSPEC float SDLCALL SDL_log10f(float 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 double SDLCALL SDL_pow(double x, double y);
extern DECLSPEC float SDLCALL SDL_powf(float x, float y); extern DECLSPEC float SDLCALL SDL_powf(float x, float y);
extern DECLSPEC double SDLCALL SDL_round(double x); extern DECLSPEC double SDLCALL SDL_round(double x);

View File

@ -171,6 +171,8 @@
#cmakedefine HAVE_LOG10F 1 #cmakedefine HAVE_LOG10F 1
#cmakedefine HAVE_LROUND 1 #cmakedefine HAVE_LROUND 1
#cmakedefine HAVE_LROUNDF 1 #cmakedefine HAVE_LROUNDF 1
#cmakedefine HAVE_MODF 1
#cmakedefine HAVE_MODFF 1
#cmakedefine HAVE_POW 1 #cmakedefine HAVE_POW 1
#cmakedefine HAVE_POWF 1 #cmakedefine HAVE_POWF 1
#cmakedefine HAVE_ROUND 1 #cmakedefine HAVE_ROUND 1

View File

@ -120,6 +120,7 @@
#define HAVE_LOG10F 1 #define HAVE_LOG10F 1
#define HAVE_LROUND 1 #define HAVE_LROUND 1
#define HAVE_LROUNDF 1 #define HAVE_LROUNDF 1
#define HAVE_MODF 1
#define HAVE_POW 1 #define HAVE_POW 1
#define HAVE_POWF 1 #define HAVE_POWF 1
#define HAVE_ROUND 1 #define HAVE_ROUND 1

View File

@ -114,6 +114,7 @@
#define HAVE_LOG10F 1 #define HAVE_LOG10F 1
#define HAVE_LROUND 1 #define HAVE_LROUND 1
#define HAVE_LROUNDF 1 #define HAVE_LROUNDF 1
#define HAVE_MODF 1
#define HAVE_POW 1 #define HAVE_POW 1
#define HAVE_POWF 1 #define HAVE_POWF 1
#define HAVE_ROUND 1 #define HAVE_ROUND 1

View File

@ -116,6 +116,7 @@
#define HAVE_LOG10F 1 #define HAVE_LOG10F 1
#define HAVE_LROUND 1 #define HAVE_LROUND 1
#define HAVE_LROUNDF 1 #define HAVE_LROUNDF 1
#define HAVE_MODF 1
#define HAVE_POW 1 #define HAVE_POW 1
#define HAVE_POWF 1 #define HAVE_POWF 1
#define HAVE_ROUND 1 #define HAVE_ROUND 1

View File

@ -134,6 +134,7 @@
#define HAVE_LOG10F 1 #define HAVE_LOG10F 1
#define HAVE_LROUND 1 #define HAVE_LROUND 1
#define HAVE_LROUNDF 1 #define HAVE_LROUNDF 1
#define HAVE_MODF 1
#define HAVE_POW 1 #define HAVE_POW 1
#define HAVE_POWF 1 #define HAVE_POWF 1
#define HAVE_ROUND 1 #define HAVE_ROUND 1

View File

@ -859,6 +859,8 @@ SDL3_0.0.0 {
SDL_wcsncasecmp; SDL_wcsncasecmp;
SDL_wcsncmp; SDL_wcsncmp;
SDL_wcsstr; SDL_wcsstr;
SDL_modf;
SDL_modff;
# extra symbols go here (don't modify this line) # extra symbols go here (don't modify this line)
local: *; local: *;
}; };

View File

@ -887,3 +887,5 @@
#define SDL_wcsstr SDL_wcsstr_REAL #define SDL_wcsstr SDL_wcsstr_REAL
/* New API symbols are added at the end */ /* New API symbols are added at the end */
#define SDL_modf SDL_modf_REAL
#define SDL_modff SDL_modff_REAL

View File

@ -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) 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 */ /* 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)

View File

@ -27,16 +27,17 @@
/* Math routines from uClibc: http://www.uclibc.org */ /* Math routines from uClibc: http://www.uclibc.org */
double SDL_uclibc_atan(double x); double SDL_uclibc_atan(double x);
double SDL_uclibc_atan2(double y, double x); double SDL_uclibc_atan2(double y, double x);
double SDL_uclibc_copysign(double x, double y); double SDL_uclibc_copysign(double x, double y);
double SDL_uclibc_cos(double x); double SDL_uclibc_cos(double x);
double SDL_uclibc_exp(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_floor(double x);
double SDL_uclibc_fmod(double x, double y); double SDL_uclibc_fmod(double x, double y);
double SDL_uclibc_log(double x); double SDL_uclibc_log(double x);
double SDL_uclibc_log10(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_scalbn(double x, int n);
double SDL_uclibc_sin(double x); double SDL_uclibc_sin(double x);
double SDL_uclibc_sqrt(double x); double SDL_uclibc_sqrt(double x);

View File

@ -40,6 +40,7 @@ typedef unsigned int u_int32_t;
#define __ieee754_fmod SDL_uclibc_fmod #define __ieee754_fmod SDL_uclibc_fmod
#define __ieee754_log SDL_uclibc_log #define __ieee754_log SDL_uclibc_log
#define __ieee754_log10 SDL_uclibc_log10 #define __ieee754_log10 SDL_uclibc_log10
#define modf SDL_uclibc_modf
#define __ieee754_pow SDL_uclibc_pow #define __ieee754_pow SDL_uclibc_pow
#define scalbln SDL_uclibc_scalbln #define scalbln SDL_uclibc_scalbln
#define scalbn SDL_uclibc_scalbn #define scalbn SDL_uclibc_scalbn

68
src/libm/s_modf.c Normal file
View File

@ -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)

View File

@ -322,6 +322,28 @@ float SDL_log10f(float x)
#endif #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 double
SDL_pow(double x, double y) SDL_pow(double x, double y)
{ {

View File

@ -1272,6 +1272,24 @@ log10_regularCases(void *args)
return helper_dtod_inexact("Log10", SDL_log10, regular_cases, SDL_arraysize(regular_cases)); 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 */ /* SDL_pow tests functions */
/* Tests with positive and negative infinities as exponents */ /* 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 "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 */ /* SDL_pow test cases */
static const SDLTest_TestCaseReference powTestExpInf1 = { static const SDLTest_TestCaseReference powTestExpInf1 = {
@ -3315,6 +3340,8 @@ static const SDLTest_TestCaseReference *mathTests[] = {
&log10TestLimit, &log10TestNan, &log10TestLimit, &log10TestNan,
&log10TestBase, &log10TestRegular, &log10TestBase, &log10TestRegular,
&modfTestBase,
&powTestExpInf1, &powTestExpInf2, &powTestExpInf3, &powTestExpInf1, &powTestExpInf2, &powTestExpInf3,
&powTestBaseInf1, &powTestBaseInf2, &powTestBaseInf1, &powTestBaseInf2,
&powTestNan1, &powTestNan2, &powTestNan3, &powTestNan4, &powTestNan1, &powTestNan2, &powTestNan3, &powTestNan4,