From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- apps/plugins/sdl/src/timer/SDL_timer.c | 285 +++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 apps/plugins/sdl/src/timer/SDL_timer.c (limited to 'apps/plugins/sdl/src/timer/SDL_timer.c') diff --git a/apps/plugins/sdl/src/timer/SDL_timer.c b/apps/plugins/sdl/src/timer/SDL_timer.c new file mode 100644 index 0000000000..8d137e1a70 --- /dev/null +++ b/apps/plugins/sdl/src/timer/SDL_timer.c @@ -0,0 +1,285 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_timer.h" +#include "SDL_timer_c.h" +#include "SDL_mutex.h" +#include "SDL_systimer.h" + +/* #define DEBUG_TIMERS */ + +int SDL_timer_started = 0; +int SDL_timer_running = 0; + +/* Data to handle a single periodic alarm */ +Uint32 SDL_alarm_interval = 0; +SDL_TimerCallback SDL_alarm_callback; + +/* Data used for a thread-based timer */ +static int SDL_timer_threaded = 0; + +struct _SDL_TimerID { + Uint32 interval; + SDL_NewTimerCallback cb; + void *param; + Uint32 last_alarm; + struct _SDL_TimerID *next; +}; + +static SDL_TimerID SDL_timers = NULL; +static SDL_mutex *SDL_timer_mutex; +static volatile SDL_bool list_changed = SDL_FALSE; + +/* Set whether or not the timer should use a thread. + This should not be called while the timer subsystem is running. +*/ +int SDL_SetTimerThreaded(int value) +{ + int retval; + + if ( SDL_timer_started ) { + SDL_SetError("Timer already initialized"); + retval = -1; + } else { + retval = 0; + SDL_timer_threaded = value; + } + return retval; +} + +int SDL_TimerInit(void) +{ + int retval; + + retval = 0; + if ( SDL_timer_started ) { + SDL_TimerQuit(); + } + if ( ! SDL_timer_threaded ) { + retval = SDL_SYS_TimerInit(); + } + if ( SDL_timer_threaded ) { + SDL_timer_mutex = SDL_CreateMutex(); + } + if ( retval == 0 ) { + SDL_timer_started = 1; + } + return(retval); +} + +void SDL_TimerQuit(void) +{ + SDL_SetTimer(0, NULL); + if ( SDL_timer_threaded < 2 ) { + SDL_SYS_TimerQuit(); + } + if ( SDL_timer_threaded ) { + SDL_DestroyMutex(SDL_timer_mutex); + SDL_timer_mutex = NULL; + } + SDL_timer_started = 0; + SDL_timer_threaded = 0; +} + +void SDL_ThreadedTimerCheck(void) +{ + Uint32 now, ms; + SDL_TimerID t, prev, next; + SDL_bool removed; + + SDL_mutexP(SDL_timer_mutex); + list_changed = SDL_FALSE; + now = SDL_GetTicks(); + for ( prev = NULL, t = SDL_timers; t; t = next ) { + removed = SDL_FALSE; + ms = t->interval - SDL_TIMESLICE; + next = t->next; + if ( (int)(now - t->last_alarm) > (int)ms ) { + struct _SDL_TimerID timer; + + if ( (now - t->last_alarm) < t->interval ) { + t->last_alarm += t->interval; + } else { + t->last_alarm = now; + } +#ifdef DEBUG_TIMERS + printf("Executing timer %p (thread = %d)\n", + t, SDL_ThreadID()); +#endif + timer = *t; + SDL_mutexV(SDL_timer_mutex); + ms = timer.cb(timer.interval, timer.param); + SDL_mutexP(SDL_timer_mutex); + if ( list_changed ) { + /* Abort, list of timers modified */ + /* FIXME: what if ms was changed? */ + break; + } + if ( ms != t->interval ) { + if ( ms ) { + t->interval = ROUND_RESOLUTION(ms); + } else { + /* Remove timer from the list */ +#ifdef DEBUG_TIMERS + printf("SDL: Removing timer %p\n", t); +#endif + if ( prev ) { + prev->next = next; + } else { + SDL_timers = next; + } + SDL_free(t); + --SDL_timer_running; + removed = SDL_TRUE; + } + } + } + /* Don't update prev if the timer has disappeared */ + if ( ! removed ) { + prev = t; + } + } + SDL_mutexV(SDL_timer_mutex); +} + +static SDL_TimerID SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback, void *param) +{ + SDL_TimerID t; + t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID)); + if ( t ) { + t->interval = ROUND_RESOLUTION(interval); + t->cb = callback; + t->param = param; + t->last_alarm = SDL_GetTicks(); + t->next = SDL_timers; + SDL_timers = t; + ++SDL_timer_running; + list_changed = SDL_TRUE; + } +#ifdef DEBUG_TIMERS + printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, SDL_timer_running); +#endif + return t; +} + +SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param) +{ + SDL_TimerID t; + if ( ! SDL_timer_mutex ) { + if ( SDL_timer_started ) { + SDL_SetError("This platform doesn't support multiple timers"); + } else { + SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first"); + } + return NULL; + } + if ( ! SDL_timer_threaded ) { + SDL_SetError("Multiple timers require threaded events!"); + return NULL; + } + SDL_mutexP(SDL_timer_mutex); + t = SDL_AddTimerInternal(interval, callback, param); + SDL_mutexV(SDL_timer_mutex); + return t; +} + +SDL_bool SDL_RemoveTimer(SDL_TimerID id) +{ + SDL_TimerID t, prev = NULL; + SDL_bool removed; + + removed = SDL_FALSE; + SDL_mutexP(SDL_timer_mutex); + /* Look for id in the linked list of timers */ + for (t = SDL_timers; t; prev=t, t = t->next ) { + if ( t == id ) { + if(prev) { + prev->next = t->next; + } else { + SDL_timers = t->next; + } + SDL_free(t); + --SDL_timer_running; + removed = SDL_TRUE; + list_changed = SDL_TRUE; + break; + } + } +#ifdef DEBUG_TIMERS + printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, SDL_timer_running, SDL_ThreadID()); +#endif + SDL_mutexV(SDL_timer_mutex); + return removed; +} + +/* Old style callback functions are wrapped through this */ +static Uint32 SDLCALL callback_wrapper(Uint32 ms, void *param) +{ + SDL_TimerCallback func = (SDL_TimerCallback) param; + return (*func)(ms); +} + +int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback) +{ + int retval; + +#ifdef DEBUG_TIMERS + printf("SDL_SetTimer(%d)\n", ms); +#endif + retval = 0; + + if ( SDL_timer_threaded ) { + SDL_mutexP(SDL_timer_mutex); + } + if ( SDL_timer_running ) { /* Stop any currently running timer */ + if ( SDL_timer_threaded ) { + while ( SDL_timers ) { + SDL_TimerID freeme = SDL_timers; + SDL_timers = SDL_timers->next; + SDL_free(freeme); + } + SDL_timer_running = 0; + list_changed = SDL_TRUE; + } else { + SDL_SYS_StopTimer(); + SDL_timer_running = 0; + } + } + if ( ms ) { + if ( SDL_timer_threaded ) { + if ( SDL_AddTimerInternal(ms, callback_wrapper, (void *)callback) == NULL ) { + retval = -1; + } + } else { + SDL_timer_running = 1; + SDL_alarm_interval = ms; + SDL_alarm_callback = callback; + retval = SDL_SYS_StartTimer(); + } + } + if ( SDL_timer_threaded ) { + SDL_mutexV(SDL_timer_mutex); + } + + return retval; +} -- cgit v1.2.3