X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fmainloop.cpp;h=3d4ec4b51781e2e3e06ac363d3fde8136d593aa1;hb=b9a924741473410f99fee4e56aba6ebe9d181a8c;hp=7e5a01bc5647e8597d9b961e090f2de559353ed7;hpb=fc73efa7ff699fe3c9c237845b6f4fda0d999862;p=supertux.git diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 7e5a01bc5..3d4ec4b51 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -26,28 +26,43 @@ #include "control/joystickkeyboardcontroller.hpp" #include "gui/menu.hpp" #include "audio/sound_manager.hpp" +#include "scripting/time_scheduler.hpp" +#include "scripting/squirrel_util.hpp" #include "gameconfig.hpp" #include "main.hpp" #include "resources.hpp" -#include "script_manager.hpp" #include "screen.hpp" +#include "screen_fade.hpp" #include "timer.hpp" #include "player_status.hpp" +#include "random_generator.hpp" // the engine will be run with a logical framerate of 64fps. // 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; + +float game_speed = 1.0f; MainLoop* main_loop = NULL; MainLoop::MainLoop() - : speed(1.0) + : speed(1.0), nextpop(false), nextpush(false), fps(0), screenshot_requested(false) { + using namespace Scripting; + TimeScheduler::instance = new TimeScheduler(); } MainLoop::~MainLoop() { + using namespace Scripting; + delete TimeScheduler::instance; + TimeScheduler::instance = NULL; + for(std::vector::iterator i = screen_stack.begin(); i != screen_stack.end(); ++i) { delete *i; @@ -55,30 +70,39 @@ MainLoop::~MainLoop() } void -MainLoop::push_screen(Screen* screen) +MainLoop::push_screen(Screen* screen, ScreenFade* screen_fade) { this->next_screen.reset(screen); - nextpush = true; + this->screen_fade.reset(screen_fade); + nextpush = !nextpop; + nextpop = false; speed = 1.0; } void -MainLoop::exit_screen() +MainLoop::exit_screen(ScreenFade* screen_fade) { - if (screen_stack.size() < 1) { - quit(); - return; - } - next_screen.reset(screen_stack.back()); + next_screen.reset(NULL); + this->screen_fade.reset(screen_fade); + nextpop = true; nextpush = false; - screen_stack.pop_back(); - speed = 1.0; } void -MainLoop::quit() +MainLoop::set_screen_fade(ScreenFade* screen_fade) { - running = false; + this->screen_fade.reset(screen_fade); +} + +void +MainLoop::quit(ScreenFade* screen_fade) +{ + for(std::vector::iterator i = screen_stack.begin(); + i != screen_stack.end(); ++i) + delete *i; + screen_stack.clear(); + + exit_screen(screen_fade); } void @@ -87,114 +111,179 @@ MainLoop::set_speed(float speed) this->speed = speed; } +float +MainLoop::get_speed() const +{ + return speed; +} + void MainLoop::draw_fps(DrawingContext& context, float fps_fps) { char str[60]; snprintf(str, sizeof(str), "%3.1f", fps_fps); const char* fpstext = "FPS"; - context.draw_text(white_text, fpstext, Vector(SCREEN_WIDTH - white_text->get_text_width(fpstext) - gold_text->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), LEFT_ALLIGN, LAYER_FOREGROUND1); - context.draw_text(gold_text, str, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y + 20), RIGHT_ALLIGN, LAYER_FOREGROUND1); + context.draw_text(white_text, fpstext, Vector(SCREEN_WIDTH - white_text->get_text_width(fpstext) - gold_text->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), ALIGN_LEFT, LAYER_HUD); + context.draw_text(gold_text, str, Vector(SCREEN_WIDTH - BORDER_X, BORDER_Y + 20), ALIGN_RIGHT, LAYER_HUD); } void -MainLoop::run() +MainLoop::draw(DrawingContext& context) { - DrawingContext context; - - unsigned int frame_count; - float fps_fps = 0; - Uint32 fps_ticks = SDL_GetTicks(); - Uint32 fps_nextframe_ticks = SDL_GetTicks(); - Uint32 ticks; - bool skipdraw = false; - - running = true; - while(running) { - if(next_screen.get() != NULL) { - if(nextpush && current_screen.get() != NULL) { - current_screen->leave(); - screen_stack.push_back(current_screen.release()); - } - - next_screen->setup(); - ScriptManager::instance->fire_wakeup_event(ScriptManager::SCREEN_SWITCHED); - current_screen.reset(next_screen.release()); - next_screen.reset(NULL); - nextpush = false; + 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); + + // if a screenshot was requested, pass request on to drawing_context + if (screenshot_requested) { + context.take_screenshot(); + screenshot_requested = false; + } + 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(); + else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F11) { + config->use_fullscreen = !config->use_fullscreen; + init_video(); + } + else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_PRINT) { + take_screenshot(); } + } +} - if(current_screen.get() == NULL) +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; - - float elapsed_time = 1.0 / LOGICAL_FPS; - ticks = SDL_GetTicks(); - if(ticks > fps_nextframe_ticks) { - if(skipdraw == true) { - // 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; - } - } 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(); } + next_screen.reset(screen_stack.back()); + screen_stack.pop_back(); + } + if(nextpush && current_screen.get() != NULL) { + screen_stack.push_back(current_screen.release()); } - fps_nextframe_ticks = ticks + (Uint32) (1000.0 / LOGICAL_FPS); - if(!skipdraw) { - current_screen->draw(context); - if(Menu::current() != NULL) - Menu::current()->draw(context); - Console::instance->draw(context); + 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); - if(config->show_fps) - draw_fps(context, fps_fps); + waiting_threads.wakeup(); + } +} - context.do_drawing(); +void +MainLoop::run(DrawingContext &context) +{ + Uint32 last_ticks = 0; + Uint32 elapsed_ticks = 0; - /* 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(); - } - } - } + running = true; + while(running) { + + handle_screen_switch(); + if(!running || current_screen.get() == NULL) + break; - elapsed_time *= speed; - - game_time += elapsed_time; - ScriptManager::instance->update(); - current_screen->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(); + Uint32 ticks = SDL_GetTicks(); + elapsed_ticks += ticks - last_ticks; + last_ticks = ticks; + + Uint32 ticks_per_frame = TICKS_PER_FRAME * game_speed; + + if (elapsed_ticks > ticks_per_frame*4) { + // when the game loads up or levels are switched the + // elapsed_ticks grows extremly large, so we just ignore those + // large time jumps + elapsed_ticks = 0; } + int frames = 0; + + if (elapsed_ticks > ticks_per_frame) + { + while(elapsed_ticks > ticks_per_frame && frames < MAX_FRAME_SKIP) + { + elapsed_ticks -= ticks_per_frame; + float timestep = 1.0 / LOGICAL_FPS; + real_time += timestep; + timestep *= speed; + game_time += timestep; + + process_events(); + update_gamelogic(timestep); + frames += 1; + } + + draw(context); + } + sound_manager->update(); + + SDL_Delay(0); } } +void +MainLoop::take_screenshot() +{ + screenshot_requested = true; +} +