mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-17 01:32:21 +02:00
FramerateManager now uses chrono instead of SDL_Ticks
This commit is contained in:
@ -16,7 +16,6 @@
|
|||||||
#include "mainmenu/CMainMenu.h"
|
#include "mainmenu/CMainMenu.h"
|
||||||
#include "mainmenu/CPrologEpilogVideo.h"
|
#include "mainmenu/CPrologEpilogVideo.h"
|
||||||
#include "gui/CursorHandler.h"
|
#include "gui/CursorHandler.h"
|
||||||
#include "gui/FramerateManager.h"
|
|
||||||
#include "CPlayerInterface.h"
|
#include "CPlayerInterface.h"
|
||||||
#include "CVideoHandler.h"
|
#include "CVideoHandler.h"
|
||||||
#include "CMusicHandler.h"
|
#include "CMusicHandler.h"
|
||||||
@ -600,7 +599,6 @@ static void mainLoop()
|
|||||||
fsChanged([](const JsonNode &newState){ CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
fsChanged([](const JsonNode &newState){ CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
||||||
|
|
||||||
inGuiThread.reset(new bool(true));
|
inGuiThread.reset(new bool(true));
|
||||||
GH.framerateManager().init(settings["video"]["targetfps"].Integer());
|
|
||||||
|
|
||||||
while(1) //main SDL events loop
|
while(1) //main SDL events loop
|
||||||
{
|
{
|
||||||
|
@ -717,11 +717,13 @@ CGuiHandler::~CGuiHandler()
|
|||||||
|
|
||||||
ShortcutHandler & CGuiHandler::shortcutsHandler()
|
ShortcutHandler & CGuiHandler::shortcutsHandler()
|
||||||
{
|
{
|
||||||
|
assert(shortcutsHandlerInstance);
|
||||||
return *shortcutsHandlerInstance;
|
return *shortcutsHandlerInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramerateManager & CGuiHandler::framerateManager()
|
FramerateManager & CGuiHandler::framerateManager()
|
||||||
{
|
{
|
||||||
|
assert(framerateManagerInstance);
|
||||||
return *framerateManagerInstance;
|
return *framerateManagerInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,13 +93,19 @@ public:
|
|||||||
public:
|
public:
|
||||||
//objs to blit
|
//objs to blit
|
||||||
std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
|
std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
|
||||||
|
|
||||||
/// returns current position of mouse cursor, relative to vcmi window
|
/// returns current position of mouse cursor, relative to vcmi window
|
||||||
const Point & getCursorPosition() const;
|
const Point & getCursorPosition() const;
|
||||||
|
|
||||||
ShortcutHandler & shortcutsHandler();
|
ShortcutHandler & shortcutsHandler();
|
||||||
FramerateManager & framerateManager();
|
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;
|
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;
|
Point screenDimensions() const;
|
||||||
|
|
||||||
/// returns true if at least one mouse button is pressed
|
/// returns true if at least one mouse button is pressed
|
||||||
|
@ -11,55 +11,47 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "FramerateManager.h"
|
#include "FramerateManager.h"
|
||||||
|
|
||||||
#include <SDL_timer.h>
|
FramerateManager::FramerateManager(int targetFrameRate)
|
||||||
|
: targetFrameTime(Duration(boost::chrono::seconds(1)) / targetFrameRate)
|
||||||
FramerateManager::FramerateManager(int newRate)
|
, lastFrameIndex(0)
|
||||||
: rate(0)
|
, lastFrameTimes({})
|
||||||
, rateticks(0)
|
, lastTimePoint (Clock::now())
|
||||||
, fps(0)
|
|
||||||
, accumulatedFrames(0)
|
|
||||||
, accumulatedTime(0)
|
|
||||||
, lastticks(0)
|
|
||||||
, timeElapsed(0)
|
|
||||||
{
|
{
|
||||||
init(newRate);
|
boost::range::fill(lastFrameTimes, targetFrameTime);
|
||||||
}
|
|
||||||
|
|
||||||
void FramerateManager::init(int newRate)
|
|
||||||
{
|
|
||||||
rate = newRate;
|
|
||||||
rateticks = 1000.0 / rate;
|
|
||||||
this->lastticks = SDL_GetTicks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramerateManager::framerateDelay()
|
void FramerateManager::framerateDelay()
|
||||||
{
|
{
|
||||||
ui32 currentTicks = SDL_GetTicks();
|
Duration timeSpentBusy = Clock::now() - lastTimePoint;
|
||||||
|
|
||||||
timeElapsed = currentTicks - lastticks;
|
|
||||||
accumulatedFrames++;
|
|
||||||
|
|
||||||
// FPS is higher than it should be, then wait some time
|
// FPS is higher than it should be, then wait some time
|
||||||
if(timeElapsed < rateticks)
|
if(timeSpentBusy < targetFrameTime)
|
||||||
{
|
boost::this_thread::sleep_for(targetFrameTime - timeSpentBusy);
|
||||||
int timeToSleep = (uint32_t)ceil(this->rateticks) - timeElapsed;
|
|
||||||
boost::this_thread::sleep(boost::posix_time::milliseconds(timeToSleep));
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTicks = SDL_GetTicks();
|
// compute actual timeElapsed taking into account actual sleep interval
|
||||||
// recalculate timeElapsed for external calls via getElapsed()
|
|
||||||
// limit it to 100 ms to avoid breaking animation in case of huge lag (e.g. triggered breakpoint)
|
// 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;
|
ui32 FramerateManager::getElapsedMilliseconds() const
|
||||||
|
|
||||||
if(accumulatedFrames >= 100)
|
|
||||||
{
|
{
|
||||||
//about 2 second should be passed
|
return lastFrameTimes[lastFrameIndex] / boost::chrono::milliseconds(1);
|
||||||
fps = static_cast<int>(ceil(1000.0 / (accumulatedTime / accumulatedFrames)));
|
|
||||||
accumulatedTime = 0;
|
|
||||||
accumulatedFrames = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#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
|
class FramerateManager
|
||||||
{
|
{
|
||||||
private:
|
using Clock = boost::chrono::high_resolution_clock;
|
||||||
double rateticks;
|
using TimePoint = Clock::time_point;
|
||||||
ui32 lastticks;
|
using Duration = Clock::duration;
|
||||||
ui32 timeElapsed;
|
|
||||||
int rate;
|
/// cyclic buffer of durations of last frames
|
||||||
int fps; // the actual fps value
|
std::array<Duration, 60> lastFrameTimes;
|
||||||
ui32 accumulatedTime;
|
|
||||||
ui32 accumulatedFrames;
|
Duration targetFrameTime;
|
||||||
|
TimePoint lastTimePoint;
|
||||||
|
|
||||||
|
/// index of last measured frome in lastFrameTimes array
|
||||||
|
ui32 lastFrameIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FramerateManager(int newRate); // initializes the manager with a given fps rate
|
FramerateManager(int targetFramerate);
|
||||||
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
|
/// must be called every frame
|
||||||
ui32 getElapsedMilliseconds() const {return this->timeElapsed;}
|
/// updates framerate calculations and executes sleep to maintain target frame rate
|
||||||
ui32 getFrameNumber() const { return accumulatedFrames; }
|
void framerateDelay();
|
||||||
ui32 getFramerate() const { return fps; };
|
|
||||||
|
/// 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)
|
void CBuildingRect::show(SDL_Surface * to)
|
||||||
{
|
{
|
||||||
uint32_t stageDelay = BUILDING_APPEAR_TIMEPOINT;
|
uint32_t stageDelay = BUILDING_APPEAR_TIMEPOINT;
|
||||||
|
Reference in New Issue
Block a user