Skip to content

Commit

Permalink
Reorganized some functions, WaitTime() is common to all platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
raysan5 committed Oct 11, 2023
1 parent a2c5f01 commit da9c289
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 88 deletions.
18 changes: 9 additions & 9 deletions src/raylib.h
Original file line number Diff line number Diff line change
Expand Up @@ -986,14 +986,6 @@ RLAPI const char *GetClipboardText(void); // Get clipboa
RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling
RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling

// Custom frame control functions
// NOTE: Those functions are intended for advance users that want full control over the frame processing
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
RLAPI void PollInputEvents(void); // Register all input events
RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)

// Cursor-related functions
RLAPI void ShowCursor(void); // Shows cursor
RLAPI void HideCursor(void); // Hides cursor
Expand Down Expand Up @@ -1049,9 +1041,17 @@ RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the

// Timing-related functions
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
RLAPI int GetFPS(void); // Get current FPS
RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time)
RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow()
RLAPI int GetFPS(void); // Get current FPS

// Custom frame control functions
// NOTE: Those functions are intended for advance users that want full control over the frame processing
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
RLAPI void PollInputEvents(void); // Register all input events
RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)

// Misc. functions
RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included)
Expand Down
157 changes: 78 additions & 79 deletions src/rcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,15 +430,6 @@ bool IsCursorOnScreen(void)
return CORE.Input.Mouse.cursorOnScreen;
}

//----------------------------------------------------------------------------------
// Module Functions Definition: Custom frame control
//----------------------------------------------------------------------------------

// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//void SwapScreenBuffer(void);
//void PollInputEvents(void);
//void WaitTime(double seconds);

//----------------------------------------------------------------------------------
// Module Functions Definition: Screen Drawing
//----------------------------------------------------------------------------------
Expand Down Expand Up @@ -1236,6 +1227,60 @@ float GetFrameTime(void)
return (float)CORE.Time.frame;
}

//----------------------------------------------------------------------------------
// Module Functions Definition: Custom frame control
//----------------------------------------------------------------------------------

// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//void SwapScreenBuffer(void);
//void PollInputEvents(void);

// Wait for some time (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
void WaitTime(double seconds)
{
if (seconds < 0) return;

#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double destinationTime = GetTime() + seconds;
#endif

#if defined(SUPPORT_BUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#else
#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double sleepSeconds = seconds - seconds*0.05; // NOTE: We reserve a percentage of the time for busy waiting
#else
double sleepSeconds = seconds;
#endif

// System halt functions
#if defined(_WIN32)
Sleep((unsigned long)(sleepSeconds*1000.0));
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec req = { 0 };
time_t sec = sleepSeconds;
long nsec = (sleepSeconds - sec)*1000000000L;
req.tv_sec = sec;
req.tv_nsec = nsec;

// NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
while (nanosleep(&req, &req) == -1) continue;
#endif
#if defined(__APPLE__)
usleep(sleepSeconds*1000000.0);
#endif

#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#endif
#endif
}

//----------------------------------------------------------------------------------
// Module Functions Definition: Misc
//----------------------------------------------------------------------------------
Expand Down Expand Up @@ -2288,6 +2333,30 @@ int GetTouchPointCount(void)
// NOTE: Functions with a platform-specific implementation on rcore_<platform>.c
//static bool InitGraphicsDevice(int width, int height)

// Initialize hi-resolution timer
void InitTimer(void)
{
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
// High resolutions can also prevent the CPU power management system from entering power-saving modes.
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif

#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec now = { 0 };

if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
{
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
}
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
#endif

CORE.Time.previous = GetTime(); // Get time as double
}

// Set viewport for a provided width and height
void SetupViewport(int width, int height)
{
Expand Down Expand Up @@ -2395,76 +2464,6 @@ void SetupFramebuffer(int width, int height)
}
}

// Initialize hi-resolution timer
void InitTimer(void)
{
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
// High resolutions can also prevent the CPU power management system from entering power-saving modes.
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif

#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec now = { 0 };

if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
{
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
}
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
#endif

CORE.Time.previous = GetTime(); // Get time as double
}

// Wait for some time (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
void WaitTime(double seconds)
{
if (seconds < 0) return;

#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double destinationTime = GetTime() + seconds;
#endif

#if defined(SUPPORT_BUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#else
#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double sleepSeconds = seconds - seconds*0.05; // NOTE: We reserve a percentage of the time for busy waiting
#else
double sleepSeconds = seconds;
#endif

// System halt functions
#if defined(_WIN32)
Sleep((unsigned long)(sleepSeconds*1000.0));
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec req = { 0 };
time_t sec = sleepSeconds;
long nsec = (sleepSeconds - sec)*1000000000L;
req.tv_sec = sec;
req.tv_nsec = nsec;

// NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
while (nanosleep(&req, &req) == -1) continue;
#endif
#if defined(__APPLE__)
usleep(sleepSeconds*1000000.0);
#endif

#if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
while (GetTime() < destinationTime) { }
#endif
#endif
}

// Scan all files and directories in a base path
// WARNING: files.paths[] must be previously allocated and
// contain enough space to store all required paths
Expand Down

0 comments on commit da9c289

Please sign in to comment.