mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
FramerateManager now uses chrono instead of SDL_Ticks
This commit is contained in:
parent
03df274450
commit
3ecdff2a21
@ -16,7 +16,6 @@
|
||||
#include "mainmenu/CMainMenu.h"
|
||||
#include "mainmenu/CPrologEpilogVideo.h"
|
||||
#include "gui/CursorHandler.h"
|
||||
#include "gui/FramerateManager.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CVideoHandler.h"
|
||||
#include "CMusicHandler.h"
|
||||
@ -600,7 +599,6 @@ static void mainLoop()
|
||||
fsChanged([](const JsonNode &newState){ CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
||||
|
||||
inGuiThread.reset(new bool(true));
|
||||
GH.framerateManager().init(settings["video"]["targetfps"].Integer());
|
||||
|
||||
while(1) //main SDL events loop
|
||||
{
|
||||
|
@ -717,11 +717,13 @@ CGuiHandler::~CGuiHandler()
|
||||
|
||||
ShortcutHandler & CGuiHandler::shortcutsHandler()
|
||||
{
|
||||
assert(shortcutsHandlerInstance);
|
||||
return *shortcutsHandlerInstance;
|
||||
}
|
||||
|
||||
FramerateManager & CGuiHandler::framerateManager()
|
||||
{
|
||||
assert(framerateManagerInstance);
|
||||
return *framerateManagerInstance;
|
||||
}
|
||||
|
||||
|
@ -93,13 +93,19 @@ public:
|
||||
public:
|
||||
//objs to blit
|
||||
std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
|
||||
|
||||
/// returns current position of mouse cursor, relative to vcmi window
|
||||
const Point & getCursorPosition() const;
|
||||
|
||||
ShortcutHandler & shortcutsHandler();
|
||||
FramerateManager & framerateManager();
|
||||
|
||||
/// returns duration of last frame in milliseconds
|
||||
/// NOTE: avoid to use, preferred method is to overload CIntObject::tick(uint32_t)
|
||||
uint32_t getFrameDeltaMilliseconds() const;
|
||||
|
||||
/// Returns current logical screen dimensions
|
||||
/// May not match size of window if user has UI scaling different from 100%
|
||||
Point screenDimensions() const;
|
||||
|
||||
/// returns true if at least one mouse button is pressed
|
||||
|
@ -11,55 +11,47 @@
|
||||
#include "StdInc.h"
|
||||
#include "FramerateManager.h"
|
||||
|
||||
#include <SDL_timer.h>
|
||||
|
||||
FramerateManager::FramerateManager(int newRate)
|
||||
: rate(0)
|
||||
, rateticks(0)
|
||||
, fps(0)
|
||||
, accumulatedFrames(0)
|
||||
, accumulatedTime(0)
|
||||
, lastticks(0)
|
||||
, timeElapsed(0)
|
||||
FramerateManager::FramerateManager(int targetFrameRate)
|
||||
: targetFrameTime(Duration(boost::chrono::seconds(1)) / targetFrameRate)
|
||||
, lastFrameIndex(0)
|
||||
, lastFrameTimes({})
|
||||
, lastTimePoint (Clock::now())
|
||||
{
|
||||
init(newRate);
|
||||
}
|
||||
|
||||
void FramerateManager::init(int newRate)
|
||||
{
|
||||
rate = newRate;
|
||||
rateticks = 1000.0 / rate;
|
||||
this->lastticks = SDL_GetTicks();
|
||||
boost::range::fill(lastFrameTimes, targetFrameTime);
|
||||
}
|
||||
|
||||
void FramerateManager::framerateDelay()
|
||||
{
|
||||
ui32 currentTicks = SDL_GetTicks();
|
||||
|
||||
timeElapsed = currentTicks - lastticks;
|
||||
accumulatedFrames++;
|
||||
Duration timeSpentBusy = Clock::now() - lastTimePoint;
|
||||
|
||||
// FPS is higher than it should be, then wait some time
|
||||
if(timeElapsed < rateticks)
|
||||
{
|
||||
int timeToSleep = (uint32_t)ceil(this->rateticks) - timeElapsed;
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(timeToSleep));
|
||||
}
|
||||
if(timeSpentBusy < targetFrameTime)
|
||||
boost::this_thread::sleep_for(targetFrameTime - timeSpentBusy);
|
||||
|
||||
currentTicks = SDL_GetTicks();
|
||||
// recalculate timeElapsed for external calls via getElapsed()
|
||||
// compute actual timeElapsed taking into account actual sleep interval
|
||||
// limit it to 100 ms to avoid breaking animation in case of huge lag (e.g. triggered breakpoint)
|
||||
timeElapsed = std::min<ui32>(currentTicks - lastticks, 100);
|
||||
TimePoint currentTicks = Clock::now();
|
||||
Duration timeElapsed = currentTicks - lastTimePoint;
|
||||
if(timeElapsed > boost::chrono::milliseconds(100))
|
||||
timeElapsed = boost::chrono::milliseconds(100);
|
||||
|
||||
lastticks = SDL_GetTicks();
|
||||
lastTimePoint = currentTicks;
|
||||
lastFrameIndex = (lastFrameIndex + 1) % lastFrameTimes.size();
|
||||
lastFrameTimes[lastFrameIndex] = timeElapsed;
|
||||
}
|
||||
|
||||
accumulatedTime += timeElapsed;
|
||||
|
||||
if(accumulatedFrames >= 100)
|
||||
ui32 FramerateManager::getElapsedMilliseconds() const
|
||||
{
|
||||
//about 2 second should be passed
|
||||
fps = static_cast<int>(ceil(1000.0 / (accumulatedTime / accumulatedFrames)));
|
||||
accumulatedTime = 0;
|
||||
accumulatedFrames = 0;
|
||||
}
|
||||
return lastFrameTimes[lastFrameIndex] / boost::chrono::milliseconds(1);
|
||||
}
|
||||
|
||||
ui32 FramerateManager::getFramerate() const
|
||||
{
|
||||
Duration accumulatedTime = std::accumulate(lastFrameTimes.begin(), lastFrameTimes.end(), Duration());
|
||||
|
||||
auto actualFrameTime = accumulatedTime / lastFrameTimes.size();
|
||||
if(actualFrameTime == actualFrameTime.zero())
|
||||
return 0;
|
||||
|
||||
return std::round(boost::chrono::duration<double>(1) / actualFrameTime);
|
||||
};
|
||||
|
@ -9,23 +9,32 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// A fps manager which holds game updates at a constant rate
|
||||
/// Framerate manager controls current game frame rate by constantly trying to reach targeted frame rate
|
||||
class FramerateManager
|
||||
{
|
||||
private:
|
||||
double rateticks;
|
||||
ui32 lastticks;
|
||||
ui32 timeElapsed;
|
||||
int rate;
|
||||
int fps; // the actual fps value
|
||||
ui32 accumulatedTime;
|
||||
ui32 accumulatedFrames;
|
||||
using Clock = boost::chrono::high_resolution_clock;
|
||||
using TimePoint = Clock::time_point;
|
||||
using Duration = Clock::duration;
|
||||
|
||||
/// cyclic buffer of durations of last frames
|
||||
std::array<Duration, 60> lastFrameTimes;
|
||||
|
||||
Duration targetFrameTime;
|
||||
TimePoint lastTimePoint;
|
||||
|
||||
/// index of last measured frome in lastFrameTimes array
|
||||
ui32 lastFrameIndex;
|
||||
|
||||
public:
|
||||
FramerateManager(int newRate); // initializes the manager with a given fps rate
|
||||
void init(int newRate); // needs to be called directly before the main game loop to reset the internal timer
|
||||
void framerateDelay(); // needs to be called every game update cycle
|
||||
ui32 getElapsedMilliseconds() const {return this->timeElapsed;}
|
||||
ui32 getFrameNumber() const { return accumulatedFrames; }
|
||||
ui32 getFramerate() const { return fps; };
|
||||
FramerateManager(int targetFramerate);
|
||||
|
||||
/// must be called every frame
|
||||
/// updates framerate calculations and executes sleep to maintain target frame rate
|
||||
void framerateDelay();
|
||||
|
||||
/// returns duration of last frame in seconds
|
||||
ui32 getElapsedMilliseconds() const;
|
||||
|
||||
/// returns current estimation of frame rate
|
||||
ui32 getFramerate() const;
|
||||
};
|
||||
|
@ -163,16 +163,6 @@ void CBuildingRect::clickRight(tribool down, bool previousState)
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Color multiplyColors(const SDL_Color & b, const SDL_Color & a, double f)
|
||||
{
|
||||
SDL_Color ret;
|
||||
ret.r = static_cast<uint8_t>(a.r * f + b.r * (1 - f));
|
||||
ret.g = static_cast<uint8_t>(a.g * f + b.g * (1 - f));
|
||||
ret.b = static_cast<uint8_t>(a.b * f + b.b * (1 - f));
|
||||
ret.a = static_cast<uint8_t>(a.a * f + b.b * (1 - f));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CBuildingRect::show(SDL_Surface * to)
|
||||
{
|
||||
uint32_t stageDelay = BUILDING_APPEAR_TIMEPOINT;
|
||||
|
Loading…
Reference in New Issue
Block a user