#include "Video.h" #include "anaglym.h" #include "Engine.h" #include "SDL.h" #include /* exit() */ #include #include #include using namespace std; enum EventType { EVENT_UPDATE }; typedef struct { EventType type; } Event; static void usage(); static void mainloop(); static void update(); static void addEvent(const Event & event); static Uint32 updateCallback(Uint32 interval, void * param); static bool lastUpdateCompleted; static bool engine_running; static SDL_Event userEvent; static SDL_cond * event_condition; static SDL_mutex * event_mutex; static SDL_mutex * event_queue_mutex; static queue event_queue; Uint32 g_ticks; static void usage() { cerr << "Usage: anaglym [options] program.lua[c]" << endl; exit(42); } static int engine_thread(void * param) { const char * program = (const char *) param; if (g_engine->load(program)) { for (;;) { SDL_mutexP(event_mutex); SDL_CondWait(event_condition, event_mutex); bool moreEvents = true; while (moreEvents) { Event event; SDL_mutexP(event_queue_mutex); if (event_queue.size() < 1) moreEvents = false; else { event = event_queue.front(); event_queue.pop(); } SDL_mutexV(event_queue_mutex); if (moreEvents) { /* process the event */ switch (event.type) { case EVENT_UPDATE: g_engine->update(); lastUpdateCompleted = true; break; } } } } } engine_running = false; return 0; } int main(int argc, char * argv[]) { const char * program = NULL; for (int i = 1; i < argc; i++) { if (argv[i][0] != '-') { if (program == NULL) { program = argv[i]; } else { cerr << "Warning: argument " << argv[i] << " ignored!" << endl; usage(); } } else { cerr << "Warning: Unrecognized option '" << argv[i]+1 << "'" << endl; usage(); } } if (program == NULL) { usage(); } lastUpdateCompleted = true; engine_running = true; /* setup SDL update event */ userEvent.type = SDL_USEREVENT; userEvent.user.code = 0; event_condition = SDL_CreateCond(); event_mutex = SDL_CreateMutex(); event_queue_mutex = SDL_CreateMutex(); Video video; #if 0 /* start in windowed mode for debugging */ video.start(0, 0, false, false); #else video.start(); #endif g_engine = new Engine(argv[0]); SDL_CreateThread(engine_thread, (void *) program); mainloop(); SDL_DestroyCond(event_condition); delete g_engine; video.stop(); return 0; } /* called by SDL when the update timer expires */ static Uint32 updateCallback(Uint32 interval, void * param) { if (lastUpdateCompleted) SDL_PushEvent(&userEvent); return interval; } static void mainloop() { SDL_Event event; /* register a screen redrawing SDL event */ SDL_AddTimer(25, &updateCallback, NULL); while (SDL_WaitEvent(&event)) { if (!engine_running) goto RET; switch (event.type) { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { goto RET; } break; case SDL_QUIT: goto RET; break; case SDL_USEREVENT: if (event.user.code == 0) { update(); } break; } } RET: ; } static void update() { Event update_event; update_event.type = EVENT_UPDATE; lastUpdateCompleted = false; addEvent(update_event); } static void addEvent(const Event & event) { SDL_mutexP(event_queue_mutex); event_queue.push(event); SDL_mutexV(event_queue_mutex); SDL_CondSignal(event_condition); }