X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fmainloop.cpp;h=f291e2807f16ba2f214d7ebfd98212d24d76c04f;hb=c13404a6b6a97ad0d5e1c9f905d7a7e37b797c13;hp=4e7199d404135a174247cadf929ebdbc5f323e30;hpb=f056506f67cb19f8c849917342f67d5d3f34be9b;p=supertux.git diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 4e7199d40..f291e2807 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -26,29 +26,41 @@ #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 "constants.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 "video/renderer.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; @@ -60,8 +72,9 @@ MainLoop::push_screen(Screen* screen, ScreenFade* screen_fade) { this->next_screen.reset(screen); this->screen_fade.reset(screen_fade); + nextpush = !nextpop; nextpop = false; - speed = 1.0; + speed = 1.0f; } void @@ -70,6 +83,7 @@ MainLoop::exit_screen(ScreenFade* screen_fade) next_screen.reset(NULL); this->screen_fade.reset(screen_fade); nextpop = true; + nextpush = false; } void @@ -95,131 +109,215 @@ 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(small_font, fpstext, Vector(SCREEN_WIDTH - small_font->get_text_width(fpstext) - small_font->get_text_width(" 99999") - BORDER_X, BORDER_Y + 20), ALIGN_LEFT, LAYER_HUD); + context.draw_text(small_font, 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 || nextpop == true) && - (screen_fade.get() == NULL || screen_fade->done())) { - if(current_screen.get() != NULL) { - current_screen->leave(); - } + static Uint32 fps_ticks = SDL_GetTicks(); + static int frame_count = 0; - if(nextpop) { - if(screen_stack.empty()) { - running = false; - break; - } - next_screen.reset(screen_stack.back()); - screen_stack.pop_back(); - nextpop = false; - speed = 1.0; - } else if(current_screen.get() != NULL) { - 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); - screen_fade.reset(NULL); - } + 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(current_screen.get() == NULL) - 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(); - } + 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(); } - 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); +void +MainLoop::update_gamelogic(float elapsed_time) +{ + Scripting::update_debugger(); + Scripting::TimeScheduler::instance->update(game_time); + current_screen->update(elapsed_time); + if (Menu::current() != NULL) + Menu::current()->update(); + if(screen_fade.get() != NULL) + screen_fade->update(elapsed_time); + Console::instance->update(elapsed_time); +} - if(config->show_fps) - draw_fps(context, fps_fps); +void +MainLoop::process_events() +{ + main_controller->update(); + Uint8* keystate = SDL_GetKeyState(NULL); + SDL_Event event; + while(SDL_PollEvent(&event)) + { + main_controller->process_event(event); - context.do_drawing(); + if(Menu::current() != NULL) + Menu::current()->event(event); - /* Calculate frames per second */ - if(config->show_fps) - { - ++frame_count; - - if(SDL_GetTicks() - fps_ticks >= 500) + switch(event.type) { - fps_fps = (float) frame_count / .5; - frame_count = 0; - fps_ticks = SDL_GetTicks(); + case SDL_QUIT: + quit(); + break; + + case SDL_VIDEORESIZE: + Renderer::instance()->resize(event.resize.w, event.resize.h); + Menu::recalc_pos(); + break; + + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_F10) + { + config->show_fps = !config->show_fps; + } + if (event.key.keysym.sym == SDLK_F11) + { + config->use_fullscreen = !config->use_fullscreen; + init_video(); + Menu::recalc_pos(); + } + else if (event.key.keysym.sym == SDLK_PRINT || + event.key.keysym.sym == SDLK_F12) + { + take_screenshot(); + } + else if (event.key.keysym.sym == SDLK_F1 && + (keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) && + keystate[SDLK_c]) + { + Console::instance->toggle(); + config->console_enabled = true; + config->save(); + } + break; } + } +} + +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()); } - elapsed_time *= speed; - - game_time += elapsed_time; - ScriptManager::instance->update(); - 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(); + nextpush = false; + nextpop = false; + speed = 1.0; + Screen* next_screen_ptr = next_screen.release(); + next_screen.reset(0); + if(next_screen_ptr) + next_screen_ptr->setup(); + current_screen.reset(next_screen_ptr); + screen_fade.reset(NULL); + + waiting_threads.wakeup(); + } +} + +void +MainLoop::run(DrawingContext &context) +{ + Uint32 last_ticks = 0; + Uint32 elapsed_ticks = 0; + + running = true; + while(running) { + + handle_screen_switch(); + if(!running || current_screen.get() == NULL) + break; + + Uint32 ticks = SDL_GetTicks(); + elapsed_ticks += ticks - last_ticks; + last_ticks = ticks; + + Uint32 ticks_per_frame = (Uint32) (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 extremely 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; +} +