2007-05-27 12:01:53 -04:00
|
|
|
//
|
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
2015-03-29 20:31:42 -04:00
|
|
|
// Copyright (C) 2004-2015 Ingo Ruhnke <grumbel@gmx.de>
|
|
|
|
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
2007-05-27 12:01:53 -04:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
2008-06-12 20:53:52 -04:00
|
|
|
// as published by the Free Software Foundation; either version 3
|
2007-05-27 12:01:53 -04:00
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program 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 General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
2008-09-15 00:34:46 -04:00
|
|
|
#include "main_loop.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
#include <assert.h>
|
2009-06-02 08:37:29 -04:00
|
|
|
|
2014-10-15 17:13:55 -04:00
|
|
|
#include "audio/sfx_manager.hpp"
|
2009-06-11 06:00:43 -04:00
|
|
|
#include "config/user_config.hpp"
|
2009-02-10 00:30:59 -05:00
|
|
|
#include "graphics/irr_driver.hpp"
|
2009-06-02 08:37:29 -04:00
|
|
|
#include "graphics/material_manager.hpp"
|
2009-07-18 13:48:36 -04:00
|
|
|
#include "guiengine/engine.hpp"
|
2009-06-02 08:37:29 -04:00
|
|
|
#include "input/input_manager.hpp"
|
2012-01-01 16:19:13 -05:00
|
|
|
#include "input/wiimote_manager.hpp"
|
2009-08-23 11:42:58 -04:00
|
|
|
#include "modes/profile_world.hpp"
|
2009-02-10 00:30:59 -05:00
|
|
|
#include "modes/world.hpp"
|
2015-11-11 17:53:12 -05:00
|
|
|
#include "network/network_config.hpp"
|
2013-07-31 14:03:11 -04:00
|
|
|
#include "network/protocol_manager.hpp"
|
2016-02-10 17:03:51 -05:00
|
|
|
#include "network/race_event_manager.hpp"
|
2017-06-04 18:54:52 -04:00
|
|
|
#include "network/rewind_manager.hpp"
|
2015-11-01 03:45:28 -05:00
|
|
|
#include "network/stk_host.hpp"
|
2014-01-08 23:57:58 -05:00
|
|
|
#include "online/request_manager.hpp"
|
2016-09-22 17:56:21 -04:00
|
|
|
#include "race/history.hpp"
|
2009-06-02 21:36:48 -04:00
|
|
|
#include "race/race_manager.hpp"
|
2009-08-23 11:42:58 -04:00
|
|
|
#include "states_screens/state_manager.hpp"
|
2011-07-09 15:13:17 -04:00
|
|
|
#include "utils/profiler.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-09-15 00:34:46 -04:00
|
|
|
MainLoop* main_loop = 0;
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-09-15 00:34:46 -04:00
|
|
|
MainLoop::MainLoop() :
|
2015-02-04 12:30:27 -05:00
|
|
|
m_abort(false)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2009-04-25 13:55:39 -04:00
|
|
|
m_curr_time = 0;
|
|
|
|
m_prev_time = 0;
|
2014-01-24 18:38:47 -05:00
|
|
|
m_throttle_fps = true;
|
2008-09-15 00:34:46 -04:00
|
|
|
} // MainLoop
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-09-15 00:34:46 -04:00
|
|
|
MainLoop::~MainLoop()
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2008-09-15 00:34:46 -04:00
|
|
|
} // ~MainLoop
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2009-07-12 07:54:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Returns the current dt, which guarantees a limited frame rate. If dt is
|
|
|
|
* too low (the frame rate too high), the process will sleep to reach the
|
|
|
|
* maxium frame rate.
|
|
|
|
*/
|
|
|
|
float MainLoop::getLimitedDt()
|
|
|
|
{
|
2016-09-22 17:56:21 -04:00
|
|
|
float dt = 0;
|
|
|
|
// If we are doing a replay, use the dt from the history file
|
|
|
|
if (World::getWorld() && history->replayHistory() )
|
|
|
|
{
|
|
|
|
dt = history->updateReplayAndGetDT();
|
|
|
|
return dt;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-03 07:28:11 -04:00
|
|
|
// In profile mode without graphics, run with a fixed dt of 1/60
|
2016-05-05 04:25:54 -04:00
|
|
|
if ((ProfileWorld::isProfileMode() && ProfileWorld::isNoGraphics()) ||
|
|
|
|
UserConfigParams::m_arena_ai_stats)
|
2016-05-03 07:28:11 -04:00
|
|
|
{
|
|
|
|
return 1.0f/60.0f;
|
|
|
|
}
|
|
|
|
|
2009-07-12 07:54:21 -04:00
|
|
|
IrrlichtDevice* device = irr_driver->getDevice();
|
|
|
|
m_prev_time = m_curr_time;
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2009-07-12 07:54:21 -04:00
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
m_curr_time = device->getTimer()->getRealTime();
|
|
|
|
dt = (float)(m_curr_time - m_prev_time);
|
2017-01-31 02:25:30 -05:00
|
|
|
if (dt <= 0) break; // should not really happen
|
2015-09-28 17:58:24 -04:00
|
|
|
const World* const world = World::getWorld();
|
|
|
|
if (UserConfigParams::m_fps_debug && world)
|
|
|
|
{
|
|
|
|
const LinearWorld *lw = dynamic_cast<const LinearWorld*>(world);
|
|
|
|
if (lw)
|
|
|
|
{
|
|
|
|
Log::verbose("fps", "time %f distance %f dt %f fps %f",
|
|
|
|
lw->getTime(),
|
|
|
|
lw->getDistanceDownTrackForKart(0),
|
|
|
|
dt*0.001f, 1000.0f / dt);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log::verbose("fps", "time %f dt %f fps %f",
|
|
|
|
world->getTime(), dt*0.001f, 1000.0f / dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2009-07-12 07:54:21 -04:00
|
|
|
|
2016-03-29 18:02:55 -04:00
|
|
|
// Don't allow the game to run slower than a certain amount.
|
2009-07-12 07:54:21 -04:00
|
|
|
// when the computer can't keep it up, slow down the shown time instead
|
2016-03-29 18:02:55 -04:00
|
|
|
// But this can not be done in networking, otherwise the game time on
|
|
|
|
// client and server will not be in synch anymore
|
|
|
|
if(!NetworkConfig::get()->isNetworking())
|
|
|
|
{
|
2017-01-31 02:25:30 -05:00
|
|
|
/* time 3 internal substeps take */
|
|
|
|
const float MAX_ELAPSED_TIME = 3.0f*1.0f / 60.0f*1000.0f;
|
|
|
|
if (dt > MAX_ELAPSED_TIME) dt = MAX_ELAPSED_TIME;
|
2016-03-29 18:02:55 -04:00
|
|
|
}
|
2017-01-31 02:25:30 -05:00
|
|
|
if (!m_throttle_fps || ProfileWorld::isProfileMode()) break;
|
2009-07-12 07:54:21 -04:00
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// Throttle fps if more than maximum, which can reduce
|
2009-07-12 07:54:21 -04:00
|
|
|
// the noise the fan on a graphics card makes.
|
2017-08-08 19:50:46 -04:00
|
|
|
// When in menus, reduce FPS much, it's not necessary to push to the
|
|
|
|
// maximum for plain menus
|
2017-03-21 19:43:00 -04:00
|
|
|
const int max_fps = (irr_driver->isRecording() &&
|
2017-08-08 19:50:46 -04:00
|
|
|
UserConfigParams::m_limit_game_fps )
|
|
|
|
? UserConfigParams::m_record_fps
|
|
|
|
: ( StateManager::get()->throttleFPS()
|
|
|
|
? 60
|
|
|
|
: UserConfigParams::m_max_fps );
|
2017-01-31 02:25:30 -05:00
|
|
|
const int current_fps = (int)(1000.0f / dt);
|
2017-08-08 19:50:46 -04:00
|
|
|
if (!m_throttle_fps || current_fps <= max_fps ||
|
|
|
|
ProfileWorld::isProfileMode() ) break;
|
2017-01-31 02:25:30 -05:00
|
|
|
|
|
|
|
int wait_time = 1000 / max_fps - 1000 / current_fps;
|
|
|
|
if (wait_time < 1) wait_time = 1;
|
|
|
|
|
|
|
|
PROFILER_PUSH_CPU_MARKER("Throttle framerate", 0, 0, 0);
|
|
|
|
StkTime::sleep(wait_time);
|
|
|
|
PROFILER_POP_CPU_MARKER();
|
2017-08-08 19:50:46 -04:00
|
|
|
} // while(1)
|
2009-07-12 07:54:21 -04:00
|
|
|
|
|
|
|
dt *= 0.001f;
|
2017-06-04 19:46:34 -04:00
|
|
|
|
|
|
|
// If this is a client, the server might request an
|
|
|
|
// adjustment of this client's world clock (to reduce
|
|
|
|
// number of rewinds).
|
|
|
|
if (World::getWorld() &&
|
|
|
|
NetworkConfig::get()->isClient() &&
|
|
|
|
!RewindManager::get()->isRewinding() )
|
|
|
|
{
|
|
|
|
dt = World::getWorld()->adjustDT(dt);
|
|
|
|
}
|
2009-07-12 07:54:21 -04:00
|
|
|
return dt;
|
2009-09-16 01:32:17 -04:00
|
|
|
} // getLimitedDt
|
2009-07-12 07:54:21 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Updates all race related objects.
|
|
|
|
* \param dt Time step size.
|
|
|
|
*/
|
|
|
|
void MainLoop::updateRace(float dt)
|
|
|
|
{
|
2017-01-31 02:25:30 -05:00
|
|
|
if (!World::getWorld()) return; // No race on atm - i.e. we are in menu
|
|
|
|
|
2016-02-10 17:03:51 -05:00
|
|
|
// The race event manager will update world in case of an online race
|
2016-12-16 07:26:34 -05:00
|
|
|
if ( RaceEventManager::getInstance() &&
|
|
|
|
RaceEventManager::getInstance()->isRunning() )
|
2016-12-09 00:39:59 -05:00
|
|
|
RaceEventManager::getInstance()->update(dt);
|
2013-07-31 14:03:11 -04:00
|
|
|
else
|
|
|
|
World::getWorld()->updateWorld(dt);
|
2009-07-12 07:54:21 -04:00
|
|
|
} // updateRace
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2008-09-15 00:34:46 -04:00
|
|
|
/** Run the actual main loop.
|
2013-08-15 02:20:31 -04:00
|
|
|
* The sequnce in which various parts of STK are updated is:
|
|
|
|
* - Determine next time step size (`getLimitedDt`). This takes maximum fps
|
|
|
|
* into account (i.e. sleep if the fps would be too high), and will actually
|
|
|
|
* slow down the in-game clock if the fps are too low (if more than 3/60 of
|
|
|
|
* a second have passed, more than 3 physics time steps would be needed,
|
|
|
|
* and physics do at most 3 time steps).
|
|
|
|
* - if a race is taking place (i.e. not only a menu being shown), call
|
|
|
|
* `updateRace()`, which is a thin wrapper around a call to
|
|
|
|
* `World::updateWorld()`:
|
|
|
|
* - Update history manager (which will either set the kart position and/or
|
|
|
|
* controls when replaying, or store the current info for a replay).
|
|
|
|
* This is mostly for debugging only (though available even in release
|
|
|
|
* mode).
|
|
|
|
* - Updates Replays - either storing data when not replaying, or
|
|
|
|
* updating kart positions/control when replaying).
|
|
|
|
* - Calls `WorldStatus::update()`, which updates the race state (e.g.
|
|
|
|
* go from 'ready' to 'set' etc), and clock.
|
|
|
|
* - Updates the physics (`Physics::update()`). This will simulate all
|
|
|
|
* physical objects for the specified time with bullet.
|
|
|
|
* - Updates all karts (`Kart::update()`). Obviously the update function
|
|
|
|
* does a lot more than what is described here, this is only supposed to
|
|
|
|
* be a _very_ high level overview:
|
|
|
|
* - Updates its rewinder (to store potentially changed controls
|
|
|
|
* as events) in `KartRewinder::update()`.
|
|
|
|
* - Calls `Moveable::update()`, which takes the new position from
|
|
|
|
* the physics and saves it (and computes dependent values, like
|
|
|
|
* heading, local velocity).
|
|
|
|
* - Updates its controller. This is either:
|
|
|
|
* - an AI using `SkiddingController::update()` (which then will
|
|
|
|
* compute the new controls), or
|
|
|
|
* - a player controller using `PlayerController::update()`, which will
|
|
|
|
* handle smooth steering (in case of digital input devices steering
|
|
|
|
* is adjusted a bit over time to avoid an instant change from all
|
|
|
|
* left to all right). Input events will be handled when updating
|
|
|
|
* the irrlicht driver later at the end of the main loop.
|
|
|
|
* - Updates kart animation (like rescue, ...) if one is shown atm.
|
|
|
|
* - Update attachments.
|
|
|
|
* - update physics, i.e. taking the current steering and updating
|
|
|
|
* the bullet raycast vehicle with that data. The settings are actually
|
|
|
|
* only used in the next frame when the physics are updated.
|
|
|
|
* - Updates all cameras via `Camera::update()`. The camera position and
|
|
|
|
* rotation is adjusted according to the position etc of the kart (and
|
|
|
|
* special circumstances like rescue, falling).
|
|
|
|
* - Updates all projectiles using the projectile manager. Some of the
|
|
|
|
* projectiles are mostly handled by the physics (e.g. a cake will mainly
|
|
|
|
* check if it's out of bounds), others (like basket ball) do all
|
|
|
|
* their aiming and movement here.
|
|
|
|
* - Updates the rewind manager to store rewind states.
|
|
|
|
* - Updates the music manager.
|
|
|
|
* - Updates the input manager (which only updates internal time, actual
|
|
|
|
* input handling follows late)
|
|
|
|
* - Updates the wiimote manager. This will read the data of all wiimotes
|
|
|
|
* and feed the corresponding events to the irrlicht event system.
|
|
|
|
* - Updates the STK internal gui engine. This updates all widgets, and
|
|
|
|
* e.g. takes care of the rotation of the karts in the KartSelection
|
|
|
|
* screen using the ModelViewWidget.
|
|
|
|
* - Updates STK's irrlicht driver `IrrDriver::update()`:
|
|
|
|
* - Calls Irrlicht's `beginScene()` .
|
|
|
|
* - Renders the scene (several times with different viewport if
|
|
|
|
* split screen is being used)
|
|
|
|
* - Calls `GUIEngine::render()`, which renders all widgets with the
|
|
|
|
* help of Irrlicht's GUIEnvironment (`drawAll()`). This will also
|
|
|
|
* handle all events, i.e. all input is now handled (e.g. steering,
|
|
|
|
* firing etc are all set in the corresponding karts depending on
|
|
|
|
* user input).
|
|
|
|
* - Calls Irrlicht's `endScene()`
|
2008-09-15 00:34:46 -04:00
|
|
|
*/
|
|
|
|
void MainLoop::run()
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2009-04-25 14:25:08 -04:00
|
|
|
IrrlichtDevice* device = irr_driver->getDevice();
|
2010-05-10 19:53:32 -04:00
|
|
|
|
2009-05-02 20:50:09 -04:00
|
|
|
m_curr_time = device->getTimer()->getRealTime();
|
2007-05-27 12:01:53 -04:00
|
|
|
while(!m_abort)
|
|
|
|
{
|
2011-09-05 18:55:55 -04:00
|
|
|
PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2008-02-12 20:02:02 -05:00
|
|
|
m_prev_time = m_curr_time;
|
2009-07-12 07:54:21 -04:00
|
|
|
float dt = getLimitedDt();
|
2016-08-31 02:31:59 -04:00
|
|
|
|
2017-06-04 18:54:52 -04:00
|
|
|
// Add a Time step entry to the rewind list, which can store all
|
|
|
|
// all input ecents being issued during the driver update.
|
|
|
|
if (World::getWorld() && RewindManager::get()->isEnabled())
|
|
|
|
{
|
|
|
|
RewindManager::get()
|
|
|
|
->addNextTimeStep(World::getWorld()->getTime(), dt);
|
|
|
|
}
|
|
|
|
|
2016-10-17 21:55:30 -04:00
|
|
|
if (!m_abort && !ProfileWorld::isNoGraphics())
|
|
|
|
{
|
|
|
|
// Render the previous frame, and also handle all user input.
|
|
|
|
PROFILER_PUSH_CPU_MARKER("IrrDriver update", 0x00, 0x00, 0x7F);
|
|
|
|
irr_driver->update(dt);
|
|
|
|
PROFILER_POP_CPU_MARKER();
|
|
|
|
}
|
2008-03-17 01:18:26 -04:00
|
|
|
|
2017-01-31 02:25:30 -05:00
|
|
|
PROFILER_PUSH_CPU_MARKER("Update race", 0, 255, 255);
|
|
|
|
updateRace(dt); // Doesn't do anything if race is not active
|
|
|
|
PROFILER_POP_CPU_MARKER();
|
|
|
|
|
2010-09-11 12:54:45 -04:00
|
|
|
// We need to check again because update_race may have requested
|
|
|
|
// the main loop to abort; and it's not a good idea to continue
|
|
|
|
// since the GUI engine is no more to be called then.
|
2017-01-31 02:25:30 -05:00
|
|
|
if (m_abort) break;
|
|
|
|
|
|
|
|
// Only do music, input, and graphics update if graphics are
|
2011-07-27 08:11:11 -04:00
|
|
|
// enabled.
|
2017-01-31 02:25:30 -05:00
|
|
|
if (!ProfileWorld::isNoGraphics())
|
2010-09-11 12:54:45 -04:00
|
|
|
{
|
2014-01-24 19:13:53 -05:00
|
|
|
PROFILER_PUSH_CPU_MARKER("Music/input/GUI", 0x7F, 0x00, 0x00);
|
2010-09-11 12:54:45 -04:00
|
|
|
input_manager->update(dt);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-01-01 16:19:13 -05:00
|
|
|
#ifdef ENABLE_WIIUSE
|
|
|
|
wiimote_manager->update();
|
|
|
|
#endif
|
2014-01-24 19:13:53 -05:00
|
|
|
|
2013-02-27 20:05:27 -05:00
|
|
|
GUIEngine::update(dt);
|
|
|
|
PROFILER_POP_CPU_MARKER();
|
|
|
|
|
2014-10-16 02:11:15 -04:00
|
|
|
// Update sfx and music after graphics, so that graphics code
|
|
|
|
// can use as many threads as possible without interfering
|
2016-09-19 04:24:42 -04:00
|
|
|
// with audio
|
2014-10-16 02:11:15 -04:00
|
|
|
PROFILER_PUSH_CPU_MARKER("Music/input/GUI", 0x7F, 0x00, 0x00);
|
2015-03-26 21:26:51 -04:00
|
|
|
SFXManager::get()->update();
|
2014-10-16 02:11:15 -04:00
|
|
|
PROFILER_POP_CPU_MARKER();
|
|
|
|
|
2013-07-31 14:03:11 -04:00
|
|
|
PROFILER_PUSH_CPU_MARKER("Protocol manager update", 0x7F, 0x00, 0x7F);
|
2015-11-11 17:53:12 -05:00
|
|
|
if (STKHost::existHost())
|
2015-11-27 20:33:01 -05:00
|
|
|
{
|
|
|
|
if (STKHost::get()->requestedShutdown())
|
|
|
|
STKHost::get()->shutdown();
|
|
|
|
else
|
2016-03-18 19:24:44 -04:00
|
|
|
ProtocolManager::getInstance()->update(dt);
|
2015-11-27 20:33:01 -05:00
|
|
|
}
|
2013-07-31 14:03:11 -04:00
|
|
|
PROFILER_POP_CPU_MARKER();
|
|
|
|
|
2010-09-11 12:54:45 -04:00
|
|
|
}
|
2017-01-31 02:25:30 -05:00
|
|
|
else
|
2013-07-31 14:03:11 -04:00
|
|
|
{
|
|
|
|
PROFILER_PUSH_CPU_MARKER("Protocol manager update", 0x7F, 0x00, 0x7F);
|
2015-11-11 17:53:12 -05:00
|
|
|
if(NetworkConfig::get()->isNetworking())
|
2016-03-18 19:24:44 -04:00
|
|
|
ProtocolManager::getInstance()->update(dt);
|
2013-07-31 14:03:11 -04:00
|
|
|
PROFILER_POP_CPU_MARKER();
|
2013-08-26 21:02:41 -04:00
|
|
|
|
2013-07-31 14:03:11 -04:00
|
|
|
}
|
2017-01-31 02:25:30 -05:00
|
|
|
PROFILER_PUSH_CPU_MARKER("Database polling update", 0x00, 0x7F, 0x7F);
|
|
|
|
Online::RequestManager::get()->update(dt);
|
|
|
|
PROFILER_POP_CPU_MARKER();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-10-26 17:40:45 -04:00
|
|
|
if (World::getWorld() )
|
|
|
|
{
|
2016-08-31 02:31:59 -04:00
|
|
|
World::getWorld()->updateTime(dt);
|
2016-10-26 17:40:45 -04:00
|
|
|
}
|
2016-08-31 02:31:59 -04:00
|
|
|
|
2011-09-05 18:55:55 -04:00
|
|
|
PROFILER_POP_CPU_MARKER();
|
2014-09-04 19:45:16 -04:00
|
|
|
PROFILER_SYNC_FRAME();
|
2014-06-25 16:22:14 -04:00
|
|
|
} // while !m_abort
|
2009-07-12 07:54:21 -04:00
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
} // run
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-09-15 00:34:46 -04:00
|
|
|
/** Set the abort flag, causing the mainloop to be left.
|
|
|
|
*/
|
|
|
|
void MainLoop::abort()
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
m_abort = true;
|
2008-09-15 00:34:46 -04:00
|
|
|
} // abort
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
/* EOF */
|