forked from mirror/openmw-tes3mp
Respect the framelimit in all cases (Fixes #3531)
Affects loading screen, videos & modal dialogs. Also skips rendering if window is minimized.
This commit is contained in:
parent
dc53573de4
commit
8c6a8ca48d
6 changed files with 81 additions and 25 deletions
|
@ -84,7 +84,6 @@ void OMW::Engine::frame(float frametime)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mStartTick = mViewer->getStartTick();
|
mStartTick = mViewer->getStartTick();
|
||||||
mEnvironment.setFrameDuration (frametime);
|
|
||||||
|
|
||||||
// update input
|
// update input
|
||||||
mEnvironment.getInputManager()->update(frametime, false);
|
mEnvironment.getInputManager()->update(frametime, false);
|
||||||
|
@ -651,6 +650,8 @@ void OMW::Engine::go()
|
||||||
Settings::Manager::getString("screenshot format", "General")));
|
Settings::Manager::getString("screenshot format", "General")));
|
||||||
mViewer->addEventHandler(mScreenCaptureHandler);
|
mViewer->addEventHandler(mScreenCaptureHandler);
|
||||||
|
|
||||||
|
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
|
||||||
|
|
||||||
// Create encoder
|
// Create encoder
|
||||||
ToUTF8::Utf8Encoder encoder (mEncoding);
|
ToUTF8::Utf8Encoder encoder (mEncoding);
|
||||||
mEncoder = &encoder;
|
mEncoder = &encoder;
|
||||||
|
@ -684,7 +685,6 @@ void OMW::Engine::go()
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
osg::Timer frameTimer;
|
osg::Timer frameTimer;
|
||||||
double simulationTime = 0.0;
|
double simulationTime = 0.0;
|
||||||
float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video");
|
|
||||||
while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest())
|
while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
double dt = frameTimer.time_s();
|
double dt = frameTimer.time_s();
|
||||||
|
@ -697,6 +697,8 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
mViewer->advance(simulationTime);
|
mViewer->advance(simulationTime);
|
||||||
|
|
||||||
|
mEnvironment.setFrameDuration(dt);
|
||||||
|
|
||||||
frame(dt);
|
frame(dt);
|
||||||
|
|
||||||
if (!mEnvironment.getInputManager()->isWindowVisible())
|
if (!mEnvironment.getInputManager()->isWindowVisible())
|
||||||
|
@ -714,15 +716,7 @@ void OMW::Engine::go()
|
||||||
mViewer->renderingTraversals();
|
mViewer->renderingTraversals();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (framerateLimit > 0.f)
|
mEnvironment.limitFrameRate(frameTimer.time_s());
|
||||||
{
|
|
||||||
double thisFrameTime = frameTimer.time_s();
|
|
||||||
double minFrameTime = 1.0 / framerateLimit;
|
|
||||||
if (thisFrameTime < minFrameTime)
|
|
||||||
{
|
|
||||||
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save user settings
|
// Save user settings
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <OpenThreads/Thread>
|
||||||
|
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
#include "scriptmanager.hpp"
|
#include "scriptmanager.hpp"
|
||||||
#include "dialoguemanager.hpp"
|
#include "dialoguemanager.hpp"
|
||||||
|
@ -17,7 +19,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0;
|
||||||
MWBase::Environment::Environment()
|
MWBase::Environment::Environment()
|
||||||
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
|
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
|
||||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0),
|
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0),
|
||||||
mFrameDuration (0)
|
mFrameDuration (0), mFrameRateLimit(0.f)
|
||||||
{
|
{
|
||||||
assert (!sThis);
|
assert (!sThis);
|
||||||
sThis = this;
|
sThis = this;
|
||||||
|
@ -79,6 +81,29 @@ void MWBase::Environment::setFrameDuration (float duration)
|
||||||
mFrameDuration = duration;
|
mFrameDuration = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWBase::Environment::setFrameRateLimit(float limit)
|
||||||
|
{
|
||||||
|
mFrameRateLimit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
float MWBase::Environment::getFrameRateLimit() const
|
||||||
|
{
|
||||||
|
return mFrameRateLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWBase::Environment::limitFrameRate(double dt) const
|
||||||
|
{
|
||||||
|
if (mFrameRateLimit > 0.f)
|
||||||
|
{
|
||||||
|
double thisFrameTime = dt;
|
||||||
|
double minFrameTime = 1.0 / static_cast<double>(mFrameRateLimit);
|
||||||
|
if (thisFrameTime < minFrameTime)
|
||||||
|
{
|
||||||
|
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWBase::World *MWBase::Environment::getWorld() const
|
MWBase::World *MWBase::Environment::getWorld() const
|
||||||
{
|
{
|
||||||
assert (mWorld);
|
assert (mWorld);
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace MWBase
|
||||||
InputManager *mInputManager;
|
InputManager *mInputManager;
|
||||||
StateManager *mStateManager;
|
StateManager *mStateManager;
|
||||||
float mFrameDuration;
|
float mFrameDuration;
|
||||||
|
float mFrameRateLimit;
|
||||||
|
|
||||||
Environment (const Environment&);
|
Environment (const Environment&);
|
||||||
///< not implemented
|
///< not implemented
|
||||||
|
@ -67,6 +68,10 @@ namespace MWBase
|
||||||
void setFrameDuration (float duration);
|
void setFrameDuration (float duration);
|
||||||
///< Set length of current frame in seconds.
|
///< Set length of current frame in seconds.
|
||||||
|
|
||||||
|
void setFrameRateLimit(float frameRateLimit);
|
||||||
|
float getFrameRateLimit() const;
|
||||||
|
void limitFrameRate(double dt) const;
|
||||||
|
|
||||||
World *getWorld() const;
|
World *getWorld() const;
|
||||||
|
|
||||||
SoundManager *getSoundManager() const;
|
SoundManager *getSoundManager() const;
|
||||||
|
|
|
@ -102,6 +102,15 @@ namespace MWGui
|
||||||
mBackgroundImage->setVisible(visible);
|
mBackgroundImage->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double LoadingScreen::getTargetFrameRate() const
|
||||||
|
{
|
||||||
|
double frameRateLimit = MWBase::Environment::get().getFrameRateLimit();
|
||||||
|
if (frameRateLimit > 0)
|
||||||
|
return std::min(frameRateLimit, mTargetFrameRate);
|
||||||
|
else
|
||||||
|
return mTargetFrameRate;
|
||||||
|
}
|
||||||
|
|
||||||
class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback
|
class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -141,7 +150,7 @@ namespace MWGui
|
||||||
if (mViewer->getIncrementalCompileOperation())
|
if (mViewer->getIncrementalCompileOperation())
|
||||||
{
|
{
|
||||||
mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100);
|
mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100);
|
||||||
mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate);
|
mViewer->getIncrementalCompileOperation()->setTargetFrameRate(getTargetFrameRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign dummy bounding sphere callback to avoid the bounding sphere of the entire scene being recomputed after each frame of loading
|
// Assign dummy bounding sphere callback to avoid the bounding sphere of the entire scene being recomputed after each frame of loading
|
||||||
|
@ -210,7 +219,7 @@ namespace MWGui
|
||||||
void LoadingScreen::setProgress (size_t value)
|
void LoadingScreen::setProgress (size_t value)
|
||||||
{
|
{
|
||||||
// skip expensive update if there isn't enough visible progress
|
// skip expensive update if there isn't enough visible progress
|
||||||
if (value - mProgress < mProgressBar->getScrollRange()/200.f)
|
if (mProgressBar->getWidth() <= 0 || value - mProgress < mProgressBar->getScrollRange()/mProgressBar->getWidth())
|
||||||
return;
|
return;
|
||||||
value = std::min(value, mProgressBar->getScrollRange()-1);
|
value = std::min(value, mProgressBar->getScrollRange()-1);
|
||||||
mProgress = value;
|
mProgress = value;
|
||||||
|
@ -231,7 +240,7 @@ namespace MWGui
|
||||||
|
|
||||||
bool LoadingScreen::needToDrawLoadingScreen()
|
bool LoadingScreen::needToDrawLoadingScreen()
|
||||||
{
|
{
|
||||||
if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0)
|
if ( mTimer.time_m() <= mLastRenderTime + (1.0/getTargetFrameRate()) * 1000.0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// the minimal delay before a loading screen shows
|
// the minimal delay before a loading screen shows
|
||||||
|
|
|
@ -43,6 +43,8 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
|
double getTargetFrameRate() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void findSplashScreens();
|
void findSplashScreens();
|
||||||
bool needToDrawLoadingScreen();
|
bool needToDrawLoadingScreen();
|
||||||
|
|
|
@ -906,19 +906,30 @@ namespace MWGui
|
||||||
|
|
||||||
if (block)
|
if (block)
|
||||||
{
|
{
|
||||||
|
osg::Timer frameTimer;
|
||||||
while (mMessageBoxManager->readPressedButton(false) == -1
|
while (mMessageBoxManager->readPressedButton(false) == -1
|
||||||
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
mMessageBoxManager->onFrame(0.f);
|
double dt = frameTimer.time_s();
|
||||||
MWBase::Environment::get().getInputManager()->update(0, true, false);
|
frameTimer.setStartTick();
|
||||||
|
|
||||||
|
mMessageBoxManager->onFrame(dt);
|
||||||
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
|
||||||
|
OpenThreads::Thread::microSleep(5000);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mViewer->eventTraversal();
|
||||||
|
mViewer->updateTraversal();
|
||||||
|
mViewer->renderingTraversals();
|
||||||
|
}
|
||||||
// at the time this function is called we are in the middle of a frame,
|
// at the time this function is called we are in the middle of a frame,
|
||||||
// so out of order calls are necessary to get a correct frameNumber for the next frame.
|
// so out of order calls are necessary to get a correct frameNumber for the next frame.
|
||||||
// refer to the advance() and frame() order in Engine::go()
|
// refer to the advance() and frame() order in Engine::go()
|
||||||
mViewer->eventTraversal();
|
|
||||||
mViewer->updateTraversal();
|
|
||||||
mViewer->renderingTraversals();
|
|
||||||
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
||||||
|
|
||||||
|
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1838,18 +1849,28 @@ namespace MWGui
|
||||||
if (mVideoWidget->hasAudioStream())
|
if (mVideoWidget->hasAudioStream())
|
||||||
MWBase::Environment::get().getSoundManager()->pauseSounds(
|
MWBase::Environment::get().getSoundManager()->pauseSounds(
|
||||||
MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie));
|
MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie));
|
||||||
|
osg::Timer frameTimer;
|
||||||
while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getInputManager()->update(0, true, false);
|
double dt = frameTimer.time_s();
|
||||||
|
frameTimer.setStartTick();
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
|
||||||
|
OpenThreads::Thread::microSleep(5000);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mViewer->eventTraversal();
|
||||||
|
mViewer->updateTraversal();
|
||||||
|
mViewer->renderingTraversals();
|
||||||
|
}
|
||||||
// at the time this function is called we are in the middle of a frame,
|
// at the time this function is called we are in the middle of a frame,
|
||||||
// so out of order calls are necessary to get a correct frameNumber for the next frame.
|
// so out of order calls are necessary to get a correct frameNumber for the next frame.
|
||||||
// refer to the advance() and frame() order in Engine::go()
|
// refer to the advance() and frame() order in Engine::go()
|
||||||
mViewer->eventTraversal();
|
|
||||||
mViewer->updateTraversal();
|
|
||||||
mViewer->renderingTraversals();
|
|
||||||
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
||||||
|
|
||||||
|
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
|
||||||
}
|
}
|
||||||
mVideoWidget->stop();
|
mVideoWidget->stop();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue