forked from mirror/openmw-tes3mp
e8662bea31
Flip the texture coordinates instead of flipping textures. This simplifies the TextureManager (no need to worry if the caller wants flipping or not), should make it easier to generalize & multithread it.
311 lines
11 KiB
C++
311 lines
11 KiB
C++
#include "loadingscreen.hpp"
|
|
|
|
#include <osgViewer/Viewer>
|
|
|
|
#include <osg/Texture2D>
|
|
|
|
#include <MyGUI_RenderManager.h>
|
|
#include <MyGUI_ScrollBar.h>
|
|
#include <MyGUI_Gui.h>
|
|
#include <MyGUI_TextBox.h>
|
|
|
|
#include <components/misc/rng.hpp>
|
|
|
|
#include <components/myguiplatform/myguitexture.hpp>
|
|
|
|
#include <components/settings/settings.hpp>
|
|
#include <components/vfs/manager.hpp>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/statemanager.hpp"
|
|
#include "../mwbase/windowmanager.hpp"
|
|
#include "../mwbase/inputmanager.hpp"
|
|
|
|
#include "../mwrender/vismask.hpp"
|
|
|
|
#include "backgroundimage.hpp"
|
|
|
|
namespace MWGui
|
|
{
|
|
|
|
LoadingScreen::LoadingScreen(const VFS::Manager* vfs, osgViewer::Viewer* viewer)
|
|
: WindowBase("openmw_loading_screen.layout")
|
|
, mVFS(vfs)
|
|
, mViewer(viewer)
|
|
, mTargetFrameRate(120.0)
|
|
, mLastWallpaperChangeTime(0.0)
|
|
, mLastRenderTime(0.0)
|
|
, mLoadingOnTime(0.0)
|
|
, mImportantLabel(false)
|
|
, mProgress(0)
|
|
{
|
|
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
|
|
|
getWidget(mLoadingText, "LoadingText");
|
|
getWidget(mProgressBar, "ProgressBar");
|
|
getWidget(mLoadingBox, "LoadingBox");
|
|
|
|
mProgressBar->setScrollViewPage(1);
|
|
|
|
mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal<BackgroundImage>("ImageBox", 0,0,1,1,
|
|
MyGUI::Align::Stretch, "Menu");
|
|
|
|
setVisible(false);
|
|
|
|
findSplashScreens();
|
|
}
|
|
|
|
LoadingScreen::~LoadingScreen()
|
|
{
|
|
}
|
|
|
|
void LoadingScreen::findSplashScreens()
|
|
{
|
|
const std::map<std::string, VFS::File*>& index = mVFS->getIndex();
|
|
std::string pattern = "Splash/";
|
|
mVFS->normalizeFilename(pattern);
|
|
|
|
std::map<std::string, VFS::File*>::const_iterator found = index.lower_bound(pattern);
|
|
while (found != index.end())
|
|
{
|
|
const std::string& name = found->first;
|
|
if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern)
|
|
{
|
|
size_t pos = name.find_last_of('.');
|
|
if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".tga") == 0)
|
|
mSplashScreens.push_back(found->first);
|
|
}
|
|
else
|
|
break;
|
|
++found;
|
|
}
|
|
if (mSplashScreens.empty())
|
|
std::cerr << "No splash screens found!" << std::endl;
|
|
}
|
|
|
|
void LoadingScreen::setLabel(const std::string &label, bool important)
|
|
{
|
|
mImportantLabel = important;
|
|
|
|
mLoadingText->setCaptionWithReplacing(label);
|
|
int padding = mLoadingBox->getWidth() - mLoadingText->getWidth();
|
|
MyGUI::IntSize size(mLoadingText->getTextSize().width+padding, mLoadingBox->getHeight());
|
|
size.width = std::max(300, size.width);
|
|
mLoadingBox->setSize(size);
|
|
mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mLoadingBox->getTop());
|
|
}
|
|
|
|
void LoadingScreen::setVisible(bool visible)
|
|
{
|
|
WindowBase::setVisible(visible);
|
|
mBackgroundImage->setVisible(visible);
|
|
}
|
|
|
|
class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback
|
|
{
|
|
public:
|
|
CopyFramebufferToTextureCallback(osg::Texture2D* texture, int w, int h)
|
|
: mTexture(texture), mWidth(w), mHeight(h)
|
|
{
|
|
}
|
|
|
|
virtual void operator () (osg::RenderInfo& renderInfo) const
|
|
{
|
|
mTexture->copyTexImage2D(*renderInfo.getState(), 0, 0, mWidth, mHeight);
|
|
|
|
// Callback removes itself when done
|
|
if (renderInfo.getCurrentCamera())
|
|
renderInfo.getCurrentCamera()->setInitialDrawCallback(NULL);
|
|
}
|
|
|
|
private:
|
|
osg::ref_ptr<osg::Texture2D> mTexture;
|
|
int mWidth, mHeight;
|
|
};
|
|
|
|
void LoadingScreen::loadingOn()
|
|
{
|
|
mLoadingOnTime = mTimer.time_m();
|
|
// Early-out if already on
|
|
if (mMainWidget->getVisible())
|
|
return;
|
|
|
|
if (mViewer->getIncrementalCompileOperation())
|
|
{
|
|
mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100);
|
|
mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate);
|
|
}
|
|
|
|
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
|
== MWBase::StateManager::State_NoGame);
|
|
|
|
if (!showWallpaper)
|
|
{
|
|
// Copy the current framebuffer onto a texture and display that texture as the background image
|
|
// Note, we could also set the camera to disable clearing and have the background image transparent,
|
|
// but then we get shaking effects on buffer swaps.
|
|
|
|
if (!mTexture)
|
|
{
|
|
mTexture = new osg::Texture2D;
|
|
mTexture->setInternalFormat(GL_RGB);
|
|
mTexture->setResizeNonPowerOfTwoHint(false);
|
|
}
|
|
|
|
int width = mViewer->getCamera()->getViewport()->width();
|
|
int height = mViewer->getCamera()->getViewport()->height();
|
|
mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture, width, height));
|
|
|
|
if (!mGuiTexture.get())
|
|
{
|
|
mGuiTexture.reset(new osgMyGUI::OSGTexture(mTexture));
|
|
}
|
|
|
|
mBackgroundImage->setBackgroundImage("");
|
|
|
|
mBackgroundImage->setRenderItemTexture(mGuiTexture.get());
|
|
mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f));
|
|
}
|
|
|
|
setVisible(true);
|
|
|
|
if (showWallpaper)
|
|
{
|
|
changeWallpaper();
|
|
}
|
|
|
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(showWallpaper ? GM_LoadingWallpaper : GM_Loading);
|
|
}
|
|
|
|
void LoadingScreen::loadingOff()
|
|
{
|
|
if (mLastRenderTime < mLoadingOnTime)
|
|
{
|
|
// the loading was so fast that we didn't show loading screen at all
|
|
// we may still want to show the label if the caller requested it
|
|
if (mImportantLabel)
|
|
{
|
|
MWBase::Environment::get().getWindowManager()->messageBox(mLoadingText->getCaption());
|
|
mImportantLabel = false;
|
|
}
|
|
}
|
|
else
|
|
mImportantLabel = false; // label was already shown on loading screen
|
|
|
|
//std::cout << "loading took " << mTimer.time_m() - mLoadingOnTime << std::endl;
|
|
setVisible(false);
|
|
|
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading);
|
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper);
|
|
}
|
|
|
|
void LoadingScreen::changeWallpaper ()
|
|
{
|
|
if (!mSplashScreens.empty())
|
|
{
|
|
std::string const & randomSplash = mSplashScreens.at(Misc::Rng::rollDice(mSplashScreens.size()));
|
|
|
|
// TODO: add option (filename pattern?) to use image aspect ratio instead of 4:3
|
|
// we can't do this by default, because the Morrowind splash screens are 1024x1024, but should be displayed as 4:3
|
|
bool stretch = Settings::Manager::getBool("stretch menu background", "GUI");
|
|
mBackgroundImage->setBackgroundImage(randomSplash, true, stretch);
|
|
}
|
|
}
|
|
|
|
void LoadingScreen::setProgressRange (size_t range)
|
|
{
|
|
mProgressBar->setScrollRange(range+1);
|
|
mProgressBar->setScrollPosition(0);
|
|
mProgressBar->setTrackSize(0);
|
|
mProgress = 0;
|
|
}
|
|
|
|
void LoadingScreen::setProgress (size_t value)
|
|
{
|
|
// skip expensive update if there isn't enough visible progress
|
|
if (value - mProgress < mProgressBar->getScrollRange()/200.f)
|
|
return;
|
|
value = std::min(value, mProgressBar->getScrollRange()-1);
|
|
mProgress = value;
|
|
mProgressBar->setScrollPosition(0);
|
|
mProgressBar->setTrackSize(static_cast<int>(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()));
|
|
draw();
|
|
}
|
|
|
|
void LoadingScreen::increaseProgress (size_t increase)
|
|
{
|
|
mProgressBar->setScrollPosition(0);
|
|
size_t value = mProgress + increase;
|
|
value = std::min(value, mProgressBar->getScrollRange()-1);
|
|
mProgress = value;
|
|
mProgressBar->setTrackSize(static_cast<int>(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()));
|
|
draw();
|
|
}
|
|
|
|
bool LoadingScreen::needToDrawLoadingScreen()
|
|
{
|
|
if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0)
|
|
return false;
|
|
|
|
// the minimal delay before a loading screen shows
|
|
const float initialDelay = 0.05;
|
|
|
|
bool alreadyShown = (mLastRenderTime > mLoadingOnTime);
|
|
float diff = (mTimer.time_m() - mLoadingOnTime);
|
|
|
|
if (!alreadyShown)
|
|
{
|
|
// bump the delay by the current progress - i.e. if during the initial delay the loading
|
|
// has almost finished, no point showing the loading screen now
|
|
diff -= mProgress / static_cast<float>(mProgressBar->getScrollRange()) * 100.f;
|
|
}
|
|
|
|
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
|
== MWBase::StateManager::State_NoGame);
|
|
if (!showWallpaper && diff < initialDelay*1000)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void LoadingScreen::draw()
|
|
{
|
|
if (!needToDrawLoadingScreen())
|
|
return;
|
|
|
|
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
|
== MWBase::StateManager::State_NoGame);
|
|
if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1)
|
|
{
|
|
mLastWallpaperChangeTime = mTimer.time_m();
|
|
changeWallpaper();
|
|
}
|
|
|
|
// Turn off rendering except the GUI
|
|
int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
|
|
int oldCullMask = mViewer->getCamera()->getCullMask();
|
|
mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI);
|
|
mViewer->getCamera()->setCullMask(MWRender::Mask_GUI);
|
|
|
|
MWBase::Environment::get().getInputManager()->update(0, true, true);
|
|
|
|
//osg::Timer timer;
|
|
// 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());
|
|
//std::cout << "frame took " << timer.time_m() << std::endl;
|
|
|
|
//if (mViewer->getIncrementalCompileOperation())
|
|
//std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl;
|
|
|
|
// resume 3d rendering
|
|
mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask);
|
|
mViewer->getCamera()->setCullMask(oldCullMask);
|
|
|
|
mLastRenderTime = mTimer.time_m();
|
|
}
|
|
|
|
}
|