mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-21 09:39:56 +00:00
Merge branch 'async_save_map' into 'master'
Write png image of the global map for save asynchronously See merge request OpenMW/openmw!1656
This commit is contained in:
commit
cc8d05bd9a
@ -358,6 +358,8 @@ namespace MWBase
|
|||||||
|
|
||||||
virtual void onDeleteCustomData(const MWWorld::Ptr& ptr) = 0;
|
virtual void onDeleteCustomData(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual void forceLootMode(const MWWorld::Ptr& ptr) = 0;
|
virtual void forceLootMode(const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
|
virtual void asyncPrepareSaveMap() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,7 +759,7 @@ namespace MWGui
|
|||||||
, mGlobal(Settings::Manager::getBool("global", "Map"))
|
, mGlobal(Settings::Manager::getBool("global", "Map"))
|
||||||
, mEventBoxGlobal(nullptr)
|
, mEventBoxGlobal(nullptr)
|
||||||
, mEventBoxLocal(nullptr)
|
, mEventBoxLocal(nullptr)
|
||||||
, mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue))
|
, mGlobalMapRender(std::make_unique<MWRender::GlobalMap>(localMapRender->getRoot(), workQueue))
|
||||||
, mEditNoteDialog()
|
, mEditNoteDialog()
|
||||||
{
|
{
|
||||||
static bool registered = false;
|
static bool registered = false;
|
||||||
@ -1028,7 +1028,6 @@ namespace MWGui
|
|||||||
|
|
||||||
MapWindow::~MapWindow()
|
MapWindow::~MapWindow()
|
||||||
{
|
{
|
||||||
delete mGlobalMapRender;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::setCellName(const std::string& cellName)
|
void MapWindow::setCellName(const std::string& cellName)
|
||||||
@ -1357,6 +1356,11 @@ namespace MWGui
|
|||||||
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapWindow::asyncPrepareSaveMap()
|
||||||
|
{
|
||||||
|
mGlobalMapRender->asyncWritePng();
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
EditNoteDialog::EditNoteDialog()
|
EditNoteDialog::EditNoteDialog()
|
||||||
|
@ -260,6 +260,8 @@ namespace MWGui
|
|||||||
void write (ESM::ESMWriter& writer, Loading::Listener& progress);
|
void write (ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
void readRecord (ESM::ESMReader& reader, uint32_t type);
|
void readRecord (ESM::ESMReader& reader, uint32_t type);
|
||||||
|
|
||||||
|
void asyncPrepareSaveMap();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||||
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||||
@ -304,7 +306,7 @@ namespace MWGui
|
|||||||
MyGUI::Button* mEventBoxLocal;
|
MyGUI::Button* mEventBoxLocal;
|
||||||
|
|
||||||
float mGlobalMapZoom = 1.0f;
|
float mGlobalMapZoom = 1.0f;
|
||||||
MWRender::GlobalMap* mGlobalMapRender;
|
std::unique_ptr<MWRender::GlobalMap> mGlobalMapRender;
|
||||||
|
|
||||||
struct MapMarkerType
|
struct MapMarkerType
|
||||||
{
|
{
|
||||||
|
@ -2263,4 +2263,9 @@ namespace MWGui
|
|||||||
for(auto* window : mWindows)
|
for(auto* window : mWindows)
|
||||||
window->onDeleteCustomData(ptr);
|
window->onDeleteCustomData(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::asyncPrepareSaveMap()
|
||||||
|
{
|
||||||
|
mMap->asyncPrepareSaveMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,6 +392,8 @@ namespace MWGui
|
|||||||
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
|
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
|
||||||
void forceLootMode(const MWWorld::Ptr& ptr) override;
|
void forceLootMode(const MWWorld::Ptr& ptr) override;
|
||||||
|
|
||||||
|
void asyncPrepareSaveMap() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int mOldUpdateMask; unsigned int mOldCullMask;
|
unsigned int mOldUpdateMask; unsigned int mOldCullMask;
|
||||||
|
|
||||||
|
@ -93,6 +93,26 @@ namespace
|
|||||||
MWRender::GlobalMap* mParent;
|
MWRender::GlobalMap* mParent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<char> writePng(const osg::Image& overlayImage)
|
||||||
|
{
|
||||||
|
std::ostringstream ostream;
|
||||||
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||||
|
if (!readerwriter)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error: Can't write map overlay: no png readerwriter found";
|
||||||
|
return std::vector<char>();
|
||||||
|
}
|
||||||
|
|
||||||
|
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(overlayImage, ostream);
|
||||||
|
if (!result.success())
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Error: Can't write map overlay: " << result.message() << " code " << result.status();
|
||||||
|
return std::vector<char>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string data = ostream.str();
|
||||||
|
return std::vector<char>(data.begin(), data.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
@ -221,6 +241,20 @@ namespace MWRender
|
|||||||
osg::ref_ptr<osg::Texture2D> mOverlayTexture;
|
osg::ref_ptr<osg::Texture2D> mOverlayTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlobalMap::WritePng final : public SceneUtil::WorkItem
|
||||||
|
{
|
||||||
|
osg::ref_ptr<const osg::Image> mOverlayImage;
|
||||||
|
std::vector<char> mImageData;
|
||||||
|
|
||||||
|
explicit WritePng(osg::ref_ptr<const osg::Image> overlayImage)
|
||||||
|
: mOverlayImage(std::move(overlayImage)) {}
|
||||||
|
|
||||||
|
void doWork() override
|
||||||
|
{
|
||||||
|
mImageData = writePng(*mOverlayImage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
GlobalMap::GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue)
|
GlobalMap::GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue)
|
||||||
: mRoot(root)
|
: mRoot(root)
|
||||||
, mWorkQueue(workQueue)
|
, mWorkQueue(workQueue)
|
||||||
@ -400,23 +434,15 @@ namespace MWRender
|
|||||||
map.mBounds.mMinY = mMinY;
|
map.mBounds.mMinY = mMinY;
|
||||||
map.mBounds.mMaxY = mMaxY;
|
map.mBounds.mMaxY = mMaxY;
|
||||||
|
|
||||||
std::ostringstream ostream;
|
if (mWritePng != nullptr)
|
||||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
|
||||||
if (!readerwriter)
|
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Error: Can't write map overlay: no png readerwriter found";
|
mWritePng->waitTillDone();
|
||||||
|
map.mImageData = std::move(mWritePng->mImageData);
|
||||||
|
mWritePng = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream);
|
map.mImageData = writePng(*mOverlayImage);
|
||||||
if (!result.success())
|
|
||||||
{
|
|
||||||
Log(Debug::Warning) << "Error: Can't write map overlay: " << result.message() << " code " << result.status();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string data = ostream.str();
|
|
||||||
map.mImageData = std::vector<char>(data.begin(), data.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Box
|
struct Box
|
||||||
@ -606,4 +632,11 @@ namespace MWRender
|
|||||||
cam->removeChildren(0, cam->getNumChildren());
|
cam->removeChildren(0, cam->getNumChildren());
|
||||||
mRoot->removeChild(cam);
|
mRoot->removeChild(cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlobalMap::asyncWritePng()
|
||||||
|
{
|
||||||
|
// Use deep copy to avoid any sychronization
|
||||||
|
mWritePng = new WritePng(new osg::Image(*mOverlayImage, osg::CopyOp::DEEP_COPY_ALL));
|
||||||
|
mWorkQueue->addWorkItem(mWritePng, /*front=*/true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,11 @@ namespace MWRender
|
|||||||
|
|
||||||
void ensureLoaded();
|
void ensureLoaded();
|
||||||
|
|
||||||
|
void asyncWritePng();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct WritePng;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request rendering a 2d quad onto mOverlayTexture.
|
* Request rendering a 2d quad onto mOverlayTexture.
|
||||||
* x, y, width and height are the destination coordinates (top-left coordinate origin)
|
* x, y, width and height are the destination coordinates (top-left coordinate origin)
|
||||||
@ -121,6 +125,7 @@ namespace MWRender
|
|||||||
|
|
||||||
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
|
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
|
||||||
osg::ref_ptr<CreateMapWorkItem> mWorkItem;
|
osg::ref_ptr<CreateMapWorkItem> mWorkItem;
|
||||||
|
osg::ref_ptr<WritePng> mWritePng;
|
||||||
|
|
||||||
int mWidth;
|
int mWidth;
|
||||||
int mHeight;
|
int mHeight;
|
||||||
|
@ -188,6 +188,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
const auto start = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->asyncPrepareSaveMap();
|
||||||
|
|
||||||
if (!character)
|
if (!character)
|
||||||
{
|
{
|
||||||
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
||||||
@ -255,9 +259,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||||||
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
|
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
|
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords()
|
|
||||||
+MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords()
|
+MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getInputManager()->countSavedGameRecords();
|
+MWBase::Environment::get().getInputManager()->countSavedGameRecords()
|
||||||
|
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords();
|
||||||
writer.setRecordCount (recordCount);
|
writer.setRecordCount (recordCount);
|
||||||
|
|
||||||
writer.save (stream);
|
writer.save (stream);
|
||||||
@ -280,9 +284,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||||||
MWBase::Environment::get().getLuaManager()->write(writer, listener);
|
MWBase::Environment::get().getLuaManager()->write(writer, listener);
|
||||||
MWBase::Environment::get().getWorld()->write (writer, listener);
|
MWBase::Environment::get().getWorld()->write (writer, listener);
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
|
||||||
MWBase::Environment::get().getWindowManager()->write(writer, listener);
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->write(writer, listener);
|
MWBase::Environment::get().getMechanicsManager()->write(writer, listener);
|
||||||
MWBase::Environment::get().getInputManager()->write(writer, listener);
|
MWBase::Environment::get().getInputManager()->write(writer, listener);
|
||||||
|
MWBase::Environment::get().getWindowManager()->write(writer, listener);
|
||||||
|
|
||||||
// Ensure we have written the number of records that was estimated
|
// Ensure we have written the number of records that was estimated
|
||||||
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
|
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
|
||||||
@ -302,6 +306,11 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||||||
|
|
||||||
Settings::Manager::setString ("character", "Saves",
|
Settings::Manager::setString ("character", "Saves",
|
||||||
slot->mPath.parent_path().filename().string());
|
slot->mPath.parent_path().filename().string());
|
||||||
|
|
||||||
|
const auto finish = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
Log(Debug::Info) << '\'' << description << "' is saved in "
|
||||||
|
<< std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(finish - start).count() << "ms";
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user