mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 22:20:33 +00:00
Merge branch 'async_screenshot' into 'master'
Write screenshots to file asynchronously (#6143) Closes #6143 See merge request OpenMW/openmw!907
This commit is contained in:
commit
7f3a4315aa
@ -17,6 +17,7 @@
|
||||
Bug #6129: Player avatar not displayed correctly for large window sizes when GUI scaling active
|
||||
Bug #6131: Item selection in the avatar window not working correctly for large window sizes
|
||||
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
||||
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
||||
Feature #2780: A way to see current OpenMW version in the console
|
||||
Feature #5489: MCP: Telekinesis fix for activators
|
||||
Feature #6017: Separate persistent and temporary cell references when saving
|
||||
|
@ -213,6 +213,8 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
|
||||
screenshotFormatComboBox->addItem(screenshotFormatString);
|
||||
screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString));
|
||||
|
||||
loadSettingBool(notifyOnSavedScreenshotCheckBox, "notify on saved screenshot", "General");
|
||||
}
|
||||
|
||||
// Testing
|
||||
@ -376,6 +378,8 @@ void Launcher::AdvancedPage::saveSettings()
|
||||
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
|
||||
if (screenshotFormatString != Settings::Manager::getString("screenshot format", "General"))
|
||||
Settings::Manager::setString("screenshot format", "General", screenshotFormatString);
|
||||
|
||||
saveSettingBool(notifyOnSavedScreenshotCheckBox, "notify on saved screenshot", "General");
|
||||
}
|
||||
|
||||
// Testing
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
#include <components/misc/frameratelimiter.hpp>
|
||||
|
||||
#include <components/sceneutil/screencapture.hpp>
|
||||
|
||||
#include "mwinput/inputmanagerimp.hpp"
|
||||
|
||||
#include "mwgui/windowmanagerimp.hpp"
|
||||
@ -216,6 +218,19 @@ namespace
|
||||
if (Settings::Manager::getInt("async num threads", "Physics") == 0)
|
||||
profiler.removeUserStatsLine(" -Async");
|
||||
}
|
||||
|
||||
struct ScheduleNonDialogMessageBox
|
||||
{
|
||||
void operator()(std::string message) const
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->scheduleMessageBox(std::move(message), MWGui::ShowInDialogueMode_Never);
|
||||
}
|
||||
};
|
||||
|
||||
struct IgnoreString
|
||||
{
|
||||
void operator()(std::string) const {}
|
||||
};
|
||||
}
|
||||
|
||||
void OMW::Engine::executeLocalScripts()
|
||||
@ -405,6 +420,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||
|
||||
OMW::Engine::~Engine()
|
||||
{
|
||||
mWorkQueue->stop();
|
||||
|
||||
mEnvironment.cleanup();
|
||||
|
||||
delete mScriptContext;
|
||||
@ -668,6 +685,21 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
throw std::runtime_error("Invalid setting: 'preload num threads' must be >0");
|
||||
mWorkQueue = new SceneUtil::WorkQueue(numThreads);
|
||||
|
||||
mScreenCaptureOperation = new SceneUtil::AsyncScreenCaptureOperation(
|
||||
mWorkQueue,
|
||||
new SceneUtil::WriteScreenshotToFileOperation(
|
||||
mCfgMgr.getScreenshotPath().string(),
|
||||
Settings::Manager::getString("screenshot format", "General"),
|
||||
Settings::Manager::getBool("notify on saved screenshot", "General")
|
||||
? std::function(ScheduleNonDialogMessageBox {})
|
||||
: std::function(IgnoreString {})
|
||||
)
|
||||
);
|
||||
|
||||
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(mScreenCaptureOperation);
|
||||
|
||||
mViewer->addEventHandler(mScreenCaptureHandler);
|
||||
|
||||
// Create input and UI first to set up a bootstrapping environment for
|
||||
// showing a loading screen and keeping the window responsive while doing so
|
||||
|
||||
@ -781,54 +813,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
}
|
||||
}
|
||||
|
||||
class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
||||
{
|
||||
public:
|
||||
WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat)
|
||||
: mScreenshotPath(screenshotPath)
|
||||
, mScreenshotFormat(screenshotFormat)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(const osg::Image& image, const unsigned int context_id) override
|
||||
{
|
||||
// Count screenshots.
|
||||
int shotCount = 0;
|
||||
|
||||
// Find the first unused filename with a do-while
|
||||
std::ostringstream stream;
|
||||
do
|
||||
{
|
||||
// Reset the stream
|
||||
stream.str("");
|
||||
stream.clear();
|
||||
|
||||
stream << mScreenshotPath << "/screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << mScreenshotFormat;
|
||||
|
||||
} while (boost::filesystem::exists(stream.str()));
|
||||
|
||||
boost::filesystem::ofstream outStream;
|
||||
outStream.open(boost::filesystem::path(stream.str()), std::ios::binary);
|
||||
|
||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat);
|
||||
if (!readerwriter)
|
||||
{
|
||||
Log(Debug::Error) << "Error: Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found";
|
||||
return;
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
|
||||
if (!result.success())
|
||||
{
|
||||
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mScreenshotPath;
|
||||
std::string mScreenshotFormat;
|
||||
};
|
||||
|
||||
// Initialise and enter main loop.
|
||||
void OMW::Engine::go()
|
||||
{
|
||||
@ -860,14 +844,6 @@ void OMW::Engine::go()
|
||||
mViewer->setUseConfigureAffinity(false);
|
||||
#endif
|
||||
|
||||
mScreenCaptureOperation = new WriteScreenshotToFileOperation(
|
||||
mCfgMgr.getScreenshotPath().string(),
|
||||
Settings::Manager::getString("screenshot format", "General"));
|
||||
|
||||
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(mScreenCaptureOperation);
|
||||
|
||||
mViewer->addEventHandler(mScreenCaptureHandler);
|
||||
|
||||
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
|
||||
|
||||
prepareEngine (settings);
|
||||
|
@ -62,7 +62,7 @@ namespace OMW
|
||||
boost::filesystem::path mResDir;
|
||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
|
||||
osgViewer::ScreenCaptureHandler::CaptureOperation *mScreenCaptureOperation;
|
||||
osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mScreenCaptureOperation;
|
||||
std::string mCellName;
|
||||
std::vector<std::string> mContentFiles;
|
||||
std::vector<std::string> mGroundcoverFiles;
|
||||
|
@ -228,6 +228,8 @@ namespace MWBase
|
||||
virtual void exitCurrentGuiMode() = 0;
|
||||
|
||||
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
||||
/// Puts message into a queue to show on the next update. Thread safe alternative for messageBox.
|
||||
virtual void scheduleMessageBox(std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
||||
virtual void staticMessageBox(const std::string& message) = 0;
|
||||
virtual void removeStaticMessageBox() = 0;
|
||||
virtual void interactiveMessageBox (const std::string& message,
|
||||
|
@ -101,6 +101,8 @@ namespace MWGui
|
||||
if(stat)
|
||||
mStaticMessageBox = box;
|
||||
|
||||
box->setVisible(mVisible);
|
||||
|
||||
mMessageBoxes.push_back(box);
|
||||
|
||||
if(mMessageBoxes.size() > 3) {
|
||||
@ -167,8 +169,12 @@ namespace MWGui
|
||||
return pressed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MessageBoxManager::setVisible(bool value)
|
||||
{
|
||||
mVisible = value;
|
||||
for (MessageBox* messageBox : mMessageBoxes)
|
||||
messageBox->setVisible(value);
|
||||
}
|
||||
|
||||
MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message)
|
||||
: Layout("openmw_messagebox.layout")
|
||||
@ -201,7 +207,10 @@ namespace MWGui
|
||||
return mMainWidget->getHeight()+mNextBoxPadding;
|
||||
}
|
||||
|
||||
|
||||
void MessageBox::setVisible(bool value)
|
||||
{
|
||||
mMainWidget->setVisible(value);
|
||||
}
|
||||
|
||||
InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector<std::string>& buttons)
|
||||
: WindowModal(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "openmw_interactive_messagebox_notransp.layout" : "openmw_interactive_messagebox.layout")
|
||||
|
@ -47,12 +47,15 @@ namespace MWGui
|
||||
|
||||
void onButtonPressed(int button) { eventButtonPressed(button); eventButtonPressed.clear(); }
|
||||
|
||||
void setVisible(bool value);
|
||||
|
||||
private:
|
||||
std::vector<MessageBox*> mMessageBoxes;
|
||||
InteractiveMessageBox* mInterMessageBoxe;
|
||||
MessageBox* mStaticMessageBox;
|
||||
float mMessageBoxSpeed;
|
||||
int mLastButtonPressed;
|
||||
bool mVisible = true;
|
||||
};
|
||||
|
||||
class MessageBox : public Layout
|
||||
@ -62,6 +65,7 @@ namespace MWGui
|
||||
void setMessage (const std::string& message);
|
||||
int getHeight ();
|
||||
void update (int height);
|
||||
void setVisible(bool value);
|
||||
|
||||
float mCurrentTime;
|
||||
float mMaxTime;
|
||||
|
@ -749,6 +749,11 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::scheduleMessageBox(std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode)
|
||||
{
|
||||
mScheduledMessageBoxes.lock()->emplace_back(std::move(message), showInDialogueMode);
|
||||
}
|
||||
|
||||
void WindowManager::staticMessageBox(const std::string& message)
|
||||
{
|
||||
mMessageBoxManager->createMessageBox(message, true);
|
||||
@ -803,6 +808,8 @@ namespace MWGui
|
||||
|
||||
void WindowManager::update (float frameDuration)
|
||||
{
|
||||
handleScheduledMessageBoxes();
|
||||
|
||||
bool gameRunning = MWBase::Environment::get().getStateManager()->getState()!=
|
||||
MWBase::StateManager::State_NoGame;
|
||||
|
||||
@ -1492,6 +1499,7 @@ namespace MWGui
|
||||
{
|
||||
mHudEnabled = !mHudEnabled;
|
||||
updateVisible();
|
||||
mMessageBoxManager->setVisible(mHudEnabled);
|
||||
return mHudEnabled;
|
||||
}
|
||||
|
||||
@ -2204,4 +2212,12 @@ namespace MWGui
|
||||
{
|
||||
return mVersionDescription;
|
||||
}
|
||||
|
||||
void WindowManager::handleScheduledMessageBoxes()
|
||||
{
|
||||
const auto scheduledMessageBoxes = mScheduledMessageBoxes.lock();
|
||||
for (const ScheduledMessageBox& v : *scheduledMessageBoxes)
|
||||
messageBox(v.mMessage, v.mShowInDialogueMode);
|
||||
scheduledMessageBoxes->clear();
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
**/
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
@ -16,6 +17,7 @@
|
||||
#include <components/sdlutil/events.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
#include <components/misc/guarded.hpp>
|
||||
|
||||
#include "mapwindow.hpp"
|
||||
#include "statswatcher.hpp"
|
||||
@ -264,6 +266,7 @@ namespace MWGui
|
||||
void exitCurrentGuiMode() override;
|
||||
|
||||
void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) override;
|
||||
void scheduleMessageBox (std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) override;
|
||||
void staticMessageBox(const std::string& message) override;
|
||||
void removeStaticMessageBox() override;
|
||||
void interactiveMessageBox (const std::string& message,
|
||||
@ -524,6 +527,17 @@ namespace MWGui
|
||||
|
||||
float mScalingFactor;
|
||||
|
||||
struct ScheduledMessageBox
|
||||
{
|
||||
std::string mMessage;
|
||||
MWGui::ShowInDialogueMode mShowInDialogueMode;
|
||||
|
||||
ScheduledMessageBox(std::string&& message, MWGui::ShowInDialogueMode showInDialogueMode)
|
||||
: mMessage(std::move(message)), mShowInDialogueMode(showInDialogueMode) {}
|
||||
};
|
||||
|
||||
Misc::ScopeGuarded<std::vector<ScheduledMessageBox>> mScheduledMessageBoxes;
|
||||
|
||||
/**
|
||||
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
||||
* Supported syntax:
|
||||
@ -555,6 +569,8 @@ namespace MWGui
|
||||
void updatePinnedWindows();
|
||||
|
||||
void enableScene(bool enable);
|
||||
|
||||
void handleScheduledMessageBoxes();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ add_component_dir (sceneutil
|
||||
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
||||
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
|
||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller
|
||||
screencapture
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
|
137
components/sceneutil/screencapture.cpp
Normal file
137
components/sceneutil/screencapture.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include "screencapture.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/sceneutil/workqueue.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Image>
|
||||
#include <osgDB/ReaderWriter>
|
||||
#include <osgDB/Registry>
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
class ScreenCaptureWorkItem : public SceneUtil::WorkItem
|
||||
{
|
||||
public:
|
||||
ScreenCaptureWorkItem(const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation>& impl,
|
||||
const osg::Image& image, unsigned int contextId)
|
||||
: mImpl(impl),
|
||||
mImage(new osg::Image(image)),
|
||||
mContextId(contextId)
|
||||
{
|
||||
assert(mImpl != nullptr);
|
||||
}
|
||||
|
||||
void doWork() override
|
||||
{
|
||||
try
|
||||
{
|
||||
(*mImpl)(*mImage, mContextId);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "ScreenCaptureWorkItem exception: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mImpl;
|
||||
const osg::ref_ptr<const osg::Image> mImage;
|
||||
const unsigned int mContextId;
|
||||
};
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
|
||||
const osg::Image& image)
|
||||
{
|
||||
// Count screenshots.
|
||||
int shotCount = 0;
|
||||
|
||||
// Find the first unused filename with a do-while
|
||||
std::ostringstream stream;
|
||||
std::string lastFileName;
|
||||
std::string lastFilePath;
|
||||
do
|
||||
{
|
||||
// Reset the stream
|
||||
stream.str("");
|
||||
stream.clear();
|
||||
|
||||
stream << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << screenshotFormat;
|
||||
|
||||
lastFileName = stream.str();
|
||||
lastFilePath = screenshotPath + "/" + lastFileName;
|
||||
|
||||
} while (boost::filesystem::exists(lastFilePath));
|
||||
|
||||
boost::filesystem::ofstream outStream;
|
||||
outStream.open(boost::filesystem::path(std::move(lastFilePath)), std::ios::binary);
|
||||
|
||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(screenshotFormat);
|
||||
if (!readerwriter)
|
||||
{
|
||||
Log(Debug::Error) << "Error: Can't write screenshot, no '" << screenshotFormat << "' readerwriter found";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
|
||||
if (!result.success())
|
||||
{
|
||||
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return lastFileName;
|
||||
}
|
||||
|
||||
WriteScreenshotToFileOperation::WriteScreenshotToFileOperation(const std::string& screenshotPath,
|
||||
const std::string& screenshotFormat,
|
||||
std::function<void (std::string)> callback)
|
||||
: mScreenshotPath(screenshotPath)
|
||||
, mScreenshotFormat(screenshotFormat)
|
||||
, mCallback(callback)
|
||||
{
|
||||
}
|
||||
|
||||
void WriteScreenshotToFileOperation::operator()(const osg::Image& image, const unsigned int /*context_id*/)
|
||||
{
|
||||
std::string fileName;
|
||||
try
|
||||
{
|
||||
fileName = writeScreenshotToFile(mScreenshotPath, mScreenshotFormat, image);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "Failed to write screenshot to file with path=\"" << mScreenshotPath
|
||||
<< "\", format=\"" << mScreenshotFormat << "\": " << e.what();
|
||||
}
|
||||
if (fileName.empty())
|
||||
mCallback("Failed to save screenshot");
|
||||
else
|
||||
mCallback(fileName + " has been saved");
|
||||
}
|
||||
|
||||
AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr<WorkQueue> queue,
|
||||
osg::ref_ptr<CaptureOperation> impl)
|
||||
: mQueue(std::move(queue)),
|
||||
mImpl(std::move(impl))
|
||||
{
|
||||
assert(mQueue != nullptr);
|
||||
assert(mImpl != nullptr);
|
||||
}
|
||||
|
||||
void AsyncScreenCaptureOperation::operator()(const osg::Image& image, const unsigned int context_id)
|
||||
{
|
||||
mQueue->addWorkItem(new ScreenCaptureWorkItem(mImpl, image, context_id));
|
||||
}
|
||||
}
|
49
components/sceneutil/screencapture.hpp
Normal file
49
components/sceneutil/screencapture.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_SCREENCAPTURE_H
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_SCREENCAPTURE_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class WorkQueue;
|
||||
|
||||
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
|
||||
const osg::Image& image);
|
||||
|
||||
class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
||||
{
|
||||
public:
|
||||
WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat,
|
||||
std::function<void (std::string)> callback);
|
||||
|
||||
void operator()(const osg::Image& image, const unsigned int context_id) override;
|
||||
|
||||
private:
|
||||
const std::string mScreenshotPath;
|
||||
const std::string mScreenshotFormat;
|
||||
const std::function<void (std::string)> mCallback;
|
||||
};
|
||||
|
||||
class AsyncScreenCaptureOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
||||
{
|
||||
public:
|
||||
AsyncScreenCaptureOperation(osg::ref_ptr<SceneUtil::WorkQueue> queue,
|
||||
osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> impl);
|
||||
|
||||
void operator()(const osg::Image& image, const unsigned int context_id) override;
|
||||
|
||||
private:
|
||||
const osg::ref_ptr<SceneUtil::WorkQueue> mQueue;
|
||||
const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mImpl;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -33,14 +33,25 @@ bool WorkItem::isDone() const
|
||||
return mDone;
|
||||
}
|
||||
|
||||
WorkQueue::WorkQueue(int workerThreads)
|
||||
WorkQueue::WorkQueue(std::size_t workerThreads)
|
||||
: mIsReleased(false)
|
||||
{
|
||||
for (int i=0; i<workerThreads; ++i)
|
||||
mThreads.emplace_back(std::make_unique<WorkThread>(*this));
|
||||
start(workerThreads);
|
||||
}
|
||||
|
||||
WorkQueue::~WorkQueue()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void WorkQueue::start(std::size_t workerThreads)
|
||||
{
|
||||
while (mThreads.size() < workerThreads)
|
||||
mThreads.emplace_back(std::make_unique<WorkThread>(*this));
|
||||
mIsReleased = false;
|
||||
}
|
||||
|
||||
void WorkQueue::stop()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
|
@ -44,9 +44,13 @@ namespace SceneUtil
|
||||
class WorkQueue : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
WorkQueue(int numWorkerThreads=1);
|
||||
WorkQueue(std::size_t workerThreads);
|
||||
~WorkQueue();
|
||||
|
||||
void start(std::size_t workerThreads);
|
||||
|
||||
void stop();
|
||||
|
||||
/// Add a new work item to the back of the queue.
|
||||
/// @par The work item's waitTillDone() method may be used by the caller to wait until the work is complete.
|
||||
/// @param front If true, add item to the front of the queue. If false (default), add to the back.
|
||||
|
@ -59,3 +59,12 @@ texture mipmap
|
||||
Set the texture mipmap type to control the method mipmaps are created.
|
||||
Mipmapping is a way of reducing the processing power needed during minification
|
||||
by pregenerating a series of smaller textures.
|
||||
|
||||
notify on saved screenshot
|
||||
--------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Show message box when screenshot is saved to a file.
|
||||
|
@ -386,6 +386,9 @@ texture min filter = linear
|
||||
# Texture mipmap type. (none, nearest, or linear).
|
||||
texture mipmap = nearest
|
||||
|
||||
# Show message box when screenshot is saved to a file.
|
||||
notify on saved screenshot = false
|
||||
|
||||
[Shaders]
|
||||
|
||||
# Force rendering with shaders. By default, only bump-mapped objects will use shaders.
|
||||
|
@ -1121,7 +1121,7 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C
|
||||
<layout class="QVBoxLayout" name="otherGroupVerticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="screenshotFormatLayout">
|
||||
<item alignment="Qt::AlignRight">
|
||||
<item>
|
||||
<widget class="QLabel" name="screenshotFormatLabel">
|
||||
<property name="text">
|
||||
<string>Screenshot Format</string>
|
||||
@ -1149,6 +1149,13 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="notifyOnSavedScreenshotCheckBox">
|
||||
<property name="text">
|
||||
<string>Notify on saved screenshot</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
Loading…
x
Reference in New Issue
Block a user