Respect the framelimit in all cases (Fixes #3531)

Affects loading screen, videos & modal dialogs. Also skips rendering if window is minimized.
pull/280/head
scrawl 7 years ago
parent dc53573de4
commit 8c6a8ca48d

@ -84,7 +84,6 @@ void OMW::Engine::frame(float frametime)
try
{
mStartTick = mViewer->getStartTick();
mEnvironment.setFrameDuration (frametime);
// update input
mEnvironment.getInputManager()->update(frametime, false);
@ -651,6 +650,8 @@ void OMW::Engine::go()
Settings::Manager::getString("screenshot format", "General")));
mViewer->addEventHandler(mScreenCaptureHandler);
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
// Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding);
mEncoder = &encoder;
@ -684,7 +685,6 @@ void OMW::Engine::go()
// Start the main rendering loop
osg::Timer frameTimer;
double simulationTime = 0.0;
float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video");
while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest())
{
double dt = frameTimer.time_s();
@ -697,6 +697,8 @@ void OMW::Engine::go()
mViewer->advance(simulationTime);
mEnvironment.setFrameDuration(dt);
frame(dt);
if (!mEnvironment.getInputManager()->isWindowVisible())
@ -714,15 +716,7 @@ void OMW::Engine::go()
mViewer->renderingTraversals();
}
if (framerateLimit > 0.f)
{
double thisFrameTime = frameTimer.time_s();
double minFrameTime = 1.0 / framerateLimit;
if (thisFrameTime < minFrameTime)
{
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime));
}
}
mEnvironment.limitFrameRate(frameTimer.time_s());
}
// Save user settings

@ -2,6 +2,8 @@
#include <cassert>
#include <OpenThreads/Thread>
#include "world.hpp"
#include "scriptmanager.hpp"
#include "dialoguemanager.hpp"
@ -17,7 +19,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0;
MWBase::Environment::Environment()
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0),
mFrameDuration (0)
mFrameDuration (0), mFrameRateLimit(0.f)
{
assert (!sThis);
sThis = this;
@ -79,6 +81,29 @@ void MWBase::Environment::setFrameDuration (float 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
{
assert (mWorld);

@ -33,6 +33,7 @@ namespace MWBase
InputManager *mInputManager;
StateManager *mStateManager;
float mFrameDuration;
float mFrameRateLimit;
Environment (const Environment&);
///< not implemented
@ -67,6 +68,10 @@ namespace MWBase
void setFrameDuration (float duration);
///< Set length of current frame in seconds.
void setFrameRateLimit(float frameRateLimit);
float getFrameRateLimit() const;
void limitFrameRate(double dt) const;
World *getWorld() const;
SoundManager *getSoundManager() const;

@ -102,6 +102,15 @@ namespace MWGui
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
{
public:
@ -141,7 +150,7 @@ namespace MWGui
if (mViewer->getIncrementalCompileOperation())
{
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
@ -210,7 +219,7 @@ namespace MWGui
void LoadingScreen::setProgress (size_t value)
{
// 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;
value = std::min(value, mProgressBar->getScrollRange()-1);
mProgress = value;
@ -231,7 +240,7 @@ namespace MWGui
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;
// the minimal delay before a loading screen shows

@ -43,6 +43,8 @@ namespace MWGui
virtual void setVisible(bool visible);
double getTargetFrameRate() const;
private:
void findSplashScreens();
bool needToDrawLoadingScreen();

@ -906,19 +906,30 @@ namespace MWGui
if (block)
{
osg::Timer frameTimer;
while (mMessageBoxManager->readPressedButton(false) == -1
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest())
{
mMessageBoxManager->onFrame(0.f);
MWBase::Environment::get().getInputManager()->update(0, true, false);
double dt = frameTimer.time_s();
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,
// 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()
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
}
}
}
@ -1838,18 +1849,28 @@ namespace MWGui
if (mVideoWidget->hasAudioStream())
MWBase::Environment::get().getSoundManager()->pauseSounds(
MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie));
osg::Timer frameTimer;
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,
// 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()
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
}
mVideoWidget->stop();

Loading…
Cancel
Save