Save/load global map

actorid
scrawl 11 years ago
parent e62bf8fca9
commit e0de76a6f7

@ -33,6 +33,8 @@ namespace OEngine
namespace ESM
{
struct Class;
class ESMReader;
class ESMWriter;
}
namespace MWWorld
@ -288,6 +290,9 @@ namespace MWBase
/// Clear all savegame-specific data
virtual void clear() = 0;
virtual void write (ESM::ESMWriter& writer) = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
};
}

@ -584,4 +584,21 @@ namespace MWGui
MyGUI::Gui::getInstance().destroyWidget(mGlobalMapOverlay->getChildAt(0));
}
void MapWindow::write(ESM::ESMWriter &writer)
{
mGlobalMapRender->write(writer);
}
void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type)
{
std::vector<std::pair<int, int> > exploredCells;
mGlobalMapRender->readRecord(reader, type, exploredCells);
for (std::vector<std::pair<int, int> >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it)
{
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>().search(it->first, it->second);
if (cell && !cell->mName.empty())
addVisitedLocation(cell->mName, it->first, it->second);
}
}
}

@ -8,6 +8,12 @@ namespace MWRender
class GlobalMap;
}
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace Loading
{
class Listener;
@ -95,6 +101,9 @@ namespace MWGui
/// Clear all savegame-specific data
void clear();
void write (ESM::ESMWriter& writer);
void readRecord (ESM::ESMReader& reader, int32_t type);
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);

@ -1386,4 +1386,14 @@ namespace MWGui
mMap->clear();
}
void WindowManager::write(ESM::ESMWriter &writer)
{
mMap->write(writer);
}
void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type)
{
mMap->readRecord(reader, type);
}
}

@ -283,6 +283,9 @@ namespace MWGui
/// Clear all savegame-specific data
virtual void clear();
virtual void write (ESM::ESMWriter& writer);
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
private:
bool mConsoleOnlyScripts;

@ -12,6 +12,8 @@
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/esm/globalmap.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -60,8 +62,6 @@ namespace MWRender
loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1));
loadingListener->setProgress(0);
mExploredBuffer.resize((mMaxX-mMinX+1) * (mMaxY-mMinY+1) * 4);
//if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png"))
if (1)
{
@ -231,4 +231,99 @@ namespace MWRender
mOverlayTexture->getBuffer()->blitFromMemory(pb);
}
void GlobalMap::write(ESM::ESMWriter &writer)
{
ESM::GlobalMap map;
map.mBounds.mMinX = mMinX;
map.mBounds.mMaxX = mMaxX;
map.mBounds.mMinY = mMinY;
map.mBounds.mMaxY = mMaxY;
Ogre::Image image;
mOverlayTexture->convertToImage(image);
Ogre::DataStreamPtr encoded = image.encode("png");
map.mImageData.resize(encoded->size());
encoded->read(&map.mImageData[0], encoded->size());
writer.startRecord(ESM::REC_GMAP);
map.save(writer);
writer.endRecord(ESM::REC_GMAP);
}
void GlobalMap::readRecord(ESM::ESMReader &reader, int32_t type, std::vector<std::pair<int, int> >& exploredCells)
{
if (type == ESM::REC_GMAP)
{
ESM::GlobalMap map;
map.load(reader);
const ESM::GlobalMap::Bounds& bounds = map.mBounds;
if (bounds.mMaxX-bounds.mMinX <= 0)
return;
if (bounds.mMaxY-bounds.mMinY <= 0)
return;
Ogre::Image image;
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size()));
image.load(stream, "png");
int xLength = (bounds.mMaxX-bounds.mMinX+1);
int yLength = (bounds.mMaxY-bounds.mMinY+1);
// Size of one cell in image space
int cellImageSizeSrc = image.getWidth() / xLength;
if (int(image.getHeight() / yLength) != cellImageSizeSrc)
throw std::runtime_error("cell size must be quadratic");
// Determine which cells were explored by reading the image data
for (int x=0; x < xLength; ++x)
{
for (int y=0; y < yLength; ++y)
{
unsigned int imageX = (x) * cellImageSizeSrc;
// NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is
unsigned int imageY = (yLength - (y + 1)) * cellImageSizeSrc;
assert(imageX < image.getWidth());
assert(imageY < image.getWidth());
if (image.getColourAt(imageX, imageY, 0).a > 0)
exploredCells.push_back(std::make_pair(x+bounds.mMinX,y+bounds.mMinY));
}
}
// If cell bounds of the currently loaded content and the loaded savegame do not match,
// we need to resize source/dest boxes to accommodate
// This means nonexisting cells will be dropped silently
int cellImageSizeDst = 24;
int leftDiff = (mMinX - bounds.mMinX);
int topDiff = (bounds.mMaxY - mMaxY);
int rightDiff = (bounds.mMaxX - mMaxX);
int bottomDiff = (mMinY - bounds.mMinY);
Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc),
std::max(0, topDiff * cellImageSizeSrc),
std::min(image.getWidth(), image.getWidth() - rightDiff * cellImageSizeSrc),
std::min(image.getHeight(), image.getHeight() - bottomDiff * cellImageSizeSrc));
Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst),
std::max(0, -topDiff * cellImageSizeDst),
std::min(mOverlayTexture->getWidth(), mOverlayTexture->getWidth() + rightDiff * cellImageSizeDst),
std::min(mOverlayTexture->getHeight(), mOverlayTexture->getHeight() + bottomDiff * cellImageSizeDst));
// Looks like there is no interface for blitting from memory with src/dst boxes.
// So we create a temporary texture for blitting.
Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual("@temp",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, image.getWidth(),
image.getHeight(), 0, Ogre::PF_A8B8G8R8);
tex->loadImage(image);
mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox);
Ogre::TextureManager::getSingleton().remove("@temp");
}
}
}

@ -10,6 +10,12 @@ namespace Loading
class Listener;
}
namespace ESM
{
class ESMWriter;
class ESMReader;
}
namespace MWRender
{
@ -34,13 +40,15 @@ namespace MWRender
/// Clears the overlay
void clear();
void write (ESM::ESMWriter& writer);
void readRecord (ESM::ESMReader& reader, int32_t type, std::vector<std::pair<int, int> >& exploredCells);
private:
std::string mCacheDir;
std::vector< std::pair<int,int> > mExploredCells;
Ogre::TexturePtr mOverlayTexture;
std::vector<Ogre::uchar> mExploredBuffer;
int mWidth;
int mHeight;

@ -174,6 +174,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getJournal()->countSavedGameRecords()
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+ 1 // global map
);
writer.save (stream);
@ -185,6 +186,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
MWBase::Environment::get().getJournal()->write (writer);
MWBase::Environment::get().getWorld()->write (writer);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer);
MWBase::Environment::get().getWindowManager()->write(writer);
writer.close();
@ -243,6 +245,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
MWBase::Environment::get().getScriptManager()->getGlobalScripts().readRecord (reader, n.val);
break;
case ESM::REC_GMAP:
MWBase::Environment::get().getWindowManager()->readRecord(reader, n.val);
break;
default:
// ignore invalid records

@ -40,7 +40,7 @@ add_component_dir (esm
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap
)
add_component_dir (misc

@ -91,6 +91,7 @@ enum RecNameInts
REC_PLAY = 0x59414c50,
REC_CSTA = 0x41545343,
REC_OBJE = 0x454a424f,
REC_GMAP = 0x50414d47,
// format 1
REC_FILT = 0x544C4946

@ -0,0 +1,26 @@
#include "globalmap.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
unsigned int ESM::GlobalMap::sRecordId = ESM::REC_GMAP;
void ESM::GlobalMap::load (ESMReader &esm)
{
esm.getHNT(mBounds, "BNDS");
esm.getSubNameIs("DATA");
esm.getSubHeader();
mImageData.resize(esm.getSubSize());
esm.getExact(&mImageData[0], mImageData.size());
}
void ESM::GlobalMap::save (ESMWriter &esm) const
{
esm.writeHNT("BNDS", mBounds);
esm.startSubRecord("DATA");
esm.write(&mImageData[0], mImageData.size());
esm.endRecord("DATA");
}

@ -0,0 +1,34 @@
#ifndef OPENMW_COMPONENTS_ESM_GLOBALMAP_H
#define OPENMW_COMPONENTS_ESM_GLOBALMAP_H
#include <vector>
namespace ESM
{
class ESMReader;
class ESMWriter;
// format 0, saved games only
///< \brief An image containing the explored areas on the global map.
struct GlobalMap
{
static unsigned int sRecordId;
// The minimum and maximum cell coordinates
struct Bounds
{
int mMinX, mMaxX, mMinY, mMaxY;
};
Bounds mBounds;
std::vector<char> mImageData;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};
}
#endif
Loading…
Cancel
Save