mirror of https://github.com/OpenMW/openmw.git
Merge branch 'async_screenshot' into 'master'
Write screenshots to file asynchronously (#6143) Closes #6143 See merge request OpenMW/openmw!907dont-compose-content
commit
7f3a4315aa
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
Loading…
Reference in New Issue