From 7fbc38d9c2fda9bfb10eeb7ecb3db36c3daa2824 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Sun, 21 Jan 2007 16:49:24 +0000 Subject: [PATCH] - Cleanup and rewrite some mainloop code - We don't do aritifical SDL_Delay anymore to save CPU cycles, activate vsyncing in your opengl driver if you want that. SVN-Revision: 4627 --- src/mainloop.cpp | 227 +++++++++++++++++++++++++--------------------- src/mainloop.hpp | 6 ++ src/worldmap/worldmap.cpp | 2 +- 3 files changed, 131 insertions(+), 104 deletions(-) diff --git a/src/mainloop.cpp b/src/mainloop.cpp index d0b623693..2001a143a 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -41,6 +41,10 @@ // We chose 64fps here because it is a power of 2, so 1/64 gives an "even" // binary fraction... static const float LOGICAL_FPS = 64.0; +/** ticks (as returned from SDL_GetTicks) per frame */ +static const Uint32 TICKS_PER_FRAME = (Uint32) (1000.0 / LOGICAL_FPS); +/** don't skip more than every 2nd frame */ +static const int MAX_FRAME_SKIP = 2; MainLoop* main_loop = NULL; @@ -116,126 +120,143 @@ MainLoop::draw_fps(DrawingContext& context, float fps_fps) } void +MainLoop::draw(DrawingContext& context) +{ + static Uint32 fps_ticks = SDL_GetTicks(); + static int frame_count = 0; + + current_screen->draw(context); + if(Menu::current() != NULL) + Menu::current()->draw(context); + if(screen_fade.get() != NULL) + screen_fade->draw(context); + Console::instance->draw(context); + + if(config->show_fps) + draw_fps(context, fps); + + context.do_drawing(); + + /* Calculate frames per second */ + if(config->show_fps) + { + ++frame_count; + + if(SDL_GetTicks() - fps_ticks >= 500) + { + fps = (float) frame_count / .5; + frame_count = 0; + fps_ticks = SDL_GetTicks(); + } + } +} + +void +MainLoop::update_gamelogic(float elapsed_time) +{ + Scripting::update_debugger(); + Scripting::TimeScheduler::instance->update(game_time); + current_screen->update(elapsed_time); + if(screen_fade.get() != NULL) + screen_fade->update(elapsed_time); + Console::instance->update(elapsed_time); +} + +void +MainLoop::process_events() +{ + main_controller->update(); + SDL_Event event; + while(SDL_PollEvent(&event)) { + main_controller->process_event(event); + if(Menu::current() != NULL) + Menu::current()->event(event); + if(event.type == SDL_QUIT) + quit(); + } +} + +void +MainLoop::handle_screen_switch() +{ + while( (next_screen.get() != NULL || nextpop) && + (screen_fade.get() == NULL || screen_fade->done())) { + if(current_screen.get() != NULL) { + current_screen->leave(); + } + + if(nextpop) { + if(screen_stack.empty()) { + running = false; + break; + } + next_screen.reset(screen_stack.back()); + screen_stack.pop_back(); + } + if(nextpush && current_screen.get() != NULL) { + screen_stack.push_back(current_screen.release()); + } + + nextpush = false; + nextpop = false; + speed = 1.0; + if(next_screen.get() != NULL) + next_screen->setup(); + current_screen.reset(next_screen.release()); + screen_fade.reset(NULL); + + waiting_threads.wakeup(); + } +} + +void MainLoop::run() { DrawingContext context; - unsigned int frame_count = 0; - float fps_fps = 0; - Uint32 fps_ticks = SDL_GetTicks(); - Uint32 fps_nextframe_ticks = SDL_GetTicks(); - Uint32 ticks; - bool skipdraw = false; + Uint32 last_ticks; + Uint32 elapsed_ticks = 0; + int skipped_frames = 0; running = true; while(running) { - while( (next_screen.get() != NULL || nextpop) && - (screen_fade.get() == NULL || screen_fade->done())) { - if(current_screen.get() != NULL) { - current_screen->leave(); - } - if(nextpop) { - if(screen_stack.empty()) { - running = false; - break; - } - next_screen.reset(screen_stack.back()); - screen_stack.pop_back(); - } - if(nextpush && current_screen.get() != NULL) { - screen_stack.push_back(current_screen.release()); - } + handle_screen_switch(); + if(!running || current_screen.get() == NULL) + break; + + Uint32 ticks = SDL_GetTicks(); + elapsed_ticks += ticks - last_ticks; + last_ticks = ticks; - nextpush = false; - nextpop = false; - speed = 1.0; - if(next_screen.get() != NULL) - next_screen->setup(); - current_screen.reset(next_screen.release()); - screen_fade.reset(NULL); + /* time for a new logical frame? */ + if(elapsed_ticks > TICKS_PER_FRAME) { + elapsed_ticks -= TICKS_PER_FRAME; + float timestep = 1.0 / LOGICAL_FPS; + real_time += timestep; + timestep *= speed; + game_time += timestep; - waiting_threads.wakeup(); + process_events(); + update_gamelogic(timestep); } - if(!running || current_screen.get() == NULL) - break; + if(elapsed_ticks > TICKS_PER_FRAME) { + // too much time passed since last frame, the computer doesn't seem to be + // able to draw 64fps on screen, so skip 1 frame for now + skipped_frames++; - float elapsed_time = 1.0 / LOGICAL_FPS; - ticks = SDL_GetTicks(); - if(ticks > fps_nextframe_ticks) { - if(skipdraw) { - // already skipped last frame? we have to slow down the game then... - skipdraw = false; - fps_nextframe_ticks -= (Uint32) (1000.0 / LOGICAL_FPS); - } else { - // don't draw all frames when we're getting too slow - skipdraw = true; + // slow down the game if we skip too many frames + if(skipped_frames > MAX_FRAME_SKIP) { + elapsed_ticks = elapsed_ticks % TICKS_PER_FRAME; + draw(context); + skipped_frames = 0; } } else { - skipdraw = false; - while(fps_nextframe_ticks > ticks) { - /* just wait */ - // If we really have to wait long, then do an imprecise SDL_Delay() - Uint32 diff = fps_nextframe_ticks - ticks; - if(diff > 10) { - SDL_Delay(diff - 2); - } - ticks = SDL_GetTicks(); - } - } - fps_nextframe_ticks = ticks + (Uint32) (1000.0 / LOGICAL_FPS); - - if(!skipdraw) { - current_screen->draw(context); - if(Menu::current() != NULL) - Menu::current()->draw(context); - if(screen_fade.get() != NULL) - screen_fade->draw(context); - Console::instance->draw(context); - - if(config->show_fps) - draw_fps(context, fps_fps); - - context.do_drawing(); - - /* Calculate frames per second */ - if(config->show_fps) - { - ++frame_count; - - if(SDL_GetTicks() - fps_ticks >= 500) - { - fps_fps = (float) frame_count / .5; - frame_count = 0; - fps_ticks = SDL_GetTicks(); - } - } - } - - real_time += elapsed_time; - elapsed_time *= speed; - game_time += elapsed_time; - - Scripting::update_debugger(); - Scripting::TimeScheduler::instance->update(game_time); - current_screen->update(elapsed_time); - if(screen_fade.get() != NULL) - screen_fade->update(elapsed_time); - Console::instance->update(elapsed_time); - - main_controller->update(); - SDL_Event event; - while(SDL_PollEvent(&event)) { - main_controller->process_event(event); - if(Menu::current() != NULL) - Menu::current()->event(event); - if(event.type == SDL_QUIT) - quit(); + draw(context); + skipped_frames = 0; } sound_manager->update(); - - //log_info << "== periodic rand() = " << systemRandom.rand() << std::endl; } } diff --git a/src/mainloop.hpp b/src/mainloop.hpp index a69baafb2..cb5bbeda2 100644 --- a/src/mainloop.hpp +++ b/src/mainloop.hpp @@ -48,11 +48,17 @@ public: private: void draw_fps(DrawingContext& context, float fps); + void draw(DrawingContext& context); + void update_gamelogic(float elapsed_time); + void process_events(); + void handle_screen_switch(); bool running; float speed; bool nextpop; bool nextpush; + /// measured fps + float fps; std::auto_ptr next_screen; std::auto_ptr current_screen; std::auto_ptr console; diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index c3f71d143..0ee8774ba 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -989,7 +989,7 @@ WorldMap::load_state() // get table for our world sq_pushstring(vm, map_filename.c_str(), map_filename.length()); if(SQ_FAILED(sq_get(vm, -2))) - throw Scripting::SquirrelError(vm, "Couldn't get state.world.mapfilename"); + throw Scripting::SquirrelError(vm, "Couldn't get state.worlds.mapfilename"); // load tux sq_pushstring(vm, "tux", -1); -- 2.11.0