mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-20 06:40:09 +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 forceLootMode(const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual void asyncPrepareSaveMap() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -759,7 +759,7 @@ namespace MWGui
|
||||
, mGlobal(Settings::Manager::getBool("global", "Map"))
|
||||
, mEventBoxGlobal(nullptr)
|
||||
, mEventBoxLocal(nullptr)
|
||||
, mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue))
|
||||
, mGlobalMapRender(std::make_unique<MWRender::GlobalMap>(localMapRender->getRoot(), workQueue))
|
||||
, mEditNoteDialog()
|
||||
{
|
||||
static bool registered = false;
|
||||
@ -1028,7 +1028,6 @@ namespace MWGui
|
||||
|
||||
MapWindow::~MapWindow()
|
||||
{
|
||||
delete mGlobalMapRender;
|
||||
}
|
||||
|
||||
void MapWindow::setCellName(const std::string& cellName)
|
||||
@ -1357,6 +1356,11 @@ namespace MWGui
|
||||
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
||||
}
|
||||
|
||||
void MapWindow::asyncPrepareSaveMap()
|
||||
{
|
||||
mGlobalMapRender->asyncWritePng();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
EditNoteDialog::EditNoteDialog()
|
||||
|
@ -260,6 +260,8 @@ namespace MWGui
|
||||
void write (ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||
void readRecord (ESM::ESMReader& reader, uint32_t type);
|
||||
|
||||
void asyncPrepareSaveMap();
|
||||
|
||||
private:
|
||||
void onDragStart(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;
|
||||
|
||||
float mGlobalMapZoom = 1.0f;
|
||||
MWRender::GlobalMap* mGlobalMapRender;
|
||||
std::unique_ptr<MWRender::GlobalMap> mGlobalMapRender;
|
||||
|
||||
struct MapMarkerType
|
||||
{
|
||||
|
@ -2263,4 +2263,9 @@ namespace MWGui
|
||||
for(auto* window : mWindows)
|
||||
window->onDeleteCustomData(ptr);
|
||||
}
|
||||
|
||||
void WindowManager::asyncPrepareSaveMap()
|
||||
{
|
||||
mMap->asyncPrepareSaveMap();
|
||||
}
|
||||
}
|
||||
|
@ -392,6 +392,8 @@ namespace MWGui
|
||||
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
|
||||
void forceLootMode(const MWWorld::Ptr& ptr) override;
|
||||
|
||||
void asyncPrepareSaveMap() override;
|
||||
|
||||
private:
|
||||
unsigned int mOldUpdateMask; unsigned int mOldCullMask;
|
||||
|
||||
|
@ -93,6 +93,26 @@ namespace
|
||||
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
|
||||
@ -221,6 +241,20 @@ namespace MWRender
|
||||
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)
|
||||
: mRoot(root)
|
||||
, mWorkQueue(workQueue)
|
||||
@ -400,23 +434,15 @@ namespace MWRender
|
||||
map.mBounds.mMinY = mMinY;
|
||||
map.mBounds.mMaxY = mMaxY;
|
||||
|
||||
std::ostringstream ostream;
|
||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||
if (!readerwriter)
|
||||
if (mWritePng != nullptr)
|
||||
{
|
||||
Log(Debug::Error) << "Error: Can't write map overlay: no png readerwriter found";
|
||||
mWritePng->waitTillDone();
|
||||
map.mImageData = std::move(mWritePng->mImageData);
|
||||
mWritePng = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream);
|
||||
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());
|
||||
map.mImageData = writePng(*mOverlayImage);
|
||||
}
|
||||
|
||||
struct Box
|
||||
@ -606,4 +632,11 @@ namespace MWRender
|
||||
cam->removeChildren(0, cam->getNumChildren());
|
||||
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 asyncWritePng();
|
||||
|
||||
private:
|
||||
struct WritePng;
|
||||
|
||||
/**
|
||||
* Request rendering a 2d quad onto mOverlayTexture.
|
||||
* 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<CreateMapWorkItem> mWorkItem;
|
||||
osg::ref_ptr<WritePng> mWritePng;
|
||||
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
@ -188,6 +188,10 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||
|
||||
try
|
||||
{
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->asyncPrepareSaveMap();
|
||||
|
||||
if (!character)
|
||||
{
|
||||
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().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
||||
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
|
||||
+MWBase::Environment::get().getWindowManager()->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.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().getWorld()->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().getInputManager()->write(writer, listener);
|
||||
MWBase::Environment::get().getWindowManager()->write(writer, listener);
|
||||
|
||||
// Ensure we have written the number of records that was estimated
|
||||
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",
|
||||
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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user