forked from teamnwah/openmw-tes3coop
Fixes #1297: Store global map markers in savegame
This commit is contained in:
parent
f921f2e7db
commit
30666f2cce
7 changed files with 104 additions and 91 deletions
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "../mwrender/globalmap.hpp"
|
||||
|
||||
#include "../components/esm/globalmap.hpp"
|
||||
|
||||
#include "widgets.hpp"
|
||||
|
||||
namespace MWGui
|
||||
|
@ -436,7 +438,6 @@ namespace MWGui
|
|||
worldY * mGlobalMapRender->getHeight()+6,
|
||||
12, 12);
|
||||
|
||||
|
||||
static int _counter=0;
|
||||
MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget<MyGUI::Button>("ButtonImage",
|
||||
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
|
||||
|
@ -452,6 +453,11 @@ namespace MWGui
|
|||
markerWidget->setUserString("ToolTipType", "Layout");
|
||||
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
||||
markerWidget->setUserString("Caption_TextOneLine", name);
|
||||
|
||||
CellId cell;
|
||||
cell.first = x;
|
||||
cell.second = y;
|
||||
mMarkers.push_back(cell);
|
||||
}
|
||||
|
||||
void MapWindow::cellExplored(int x, int y)
|
||||
|
@ -580,6 +586,7 @@ namespace MWGui
|
|||
|
||||
void MapWindow::clear()
|
||||
{
|
||||
mMarkers.clear();
|
||||
mGlobalMapRender->clear();
|
||||
|
||||
while (mEventBoxGlobal->getChildCount())
|
||||
|
@ -590,19 +597,31 @@ namespace MWGui
|
|||
|
||||
void MapWindow::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
mGlobalMapRender->write(writer);
|
||||
ESM::GlobalMap map;
|
||||
mGlobalMapRender->write(map);
|
||||
|
||||
map.mMarkers = mMarkers;
|
||||
|
||||
writer.startRecord(ESM::REC_GMAP);
|
||||
map.save(writer);
|
||||
writer.endRecord(ESM::REC_GMAP);
|
||||
}
|
||||
|
||||
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)
|
||||
if (type == ESM::REC_GMAP)
|
||||
{
|
||||
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);
|
||||
ESM::GlobalMap map;
|
||||
map.load(reader);
|
||||
|
||||
mGlobalMapRender->read(map);
|
||||
|
||||
for (std::vector<ESM::GlobalMap::CellId>::iterator it = map.mMarkers.begin(); it != map.mMarkers.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,9 @@ namespace MWGui
|
|||
bool mChanged;
|
||||
bool mFogOfWar;
|
||||
|
||||
typedef std::pair<int, int> CellId;
|
||||
std::vector<CellId> mMarkers;
|
||||
|
||||
std::vector<MyGUI::ImageBox*> mMapWidgets;
|
||||
std::vector<MyGUI::ImageBox*> mFogWidgets;
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace MWGui
|
|||
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
|
||||
|
||||
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
|
||||
SDL_ShowCursor(false);
|
||||
//SDL_ShowCursor(false);
|
||||
|
||||
mCursorManager->setEnabled(true);
|
||||
|
||||
|
|
|
@ -231,9 +231,8 @@ namespace MWRender
|
|||
mOverlayTexture->getBuffer()->blitFromMemory(pb);
|
||||
}
|
||||
|
||||
void GlobalMap::write(ESM::ESMWriter &writer)
|
||||
void GlobalMap::write(ESM::GlobalMap& map)
|
||||
{
|
||||
ESM::GlobalMap map;
|
||||
map.mBounds.mMinX = mMinX;
|
||||
map.mBounds.mMaxX = mMaxX;
|
||||
map.mBounds.mMinY = mMinY;
|
||||
|
@ -244,95 +243,68 @@ namespace MWRender
|
|||
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)
|
||||
void GlobalMap::read(ESM::GlobalMap& map)
|
||||
{
|
||||
if (type == ESM::REC_GMAP)
|
||||
{
|
||||
ESM::GlobalMap map;
|
||||
map.load(reader);
|
||||
const ESM::GlobalMap::Bounds& bounds = map.mBounds;
|
||||
|
||||
const ESM::GlobalMap::Bounds& bounds = map.mBounds;
|
||||
if (bounds.mMaxX-bounds.mMinX <= 0)
|
||||
return;
|
||||
if (bounds.mMaxY-bounds.mMinY <= 0)
|
||||
return;
|
||||
|
||||
if (bounds.mMaxX-bounds.mMinX <= 0)
|
||||
return;
|
||||
if (bounds.mMaxY-bounds.mMinY <= 0)
|
||||
return;
|
||||
if (bounds.mMinX > bounds.mMaxX
|
||||
|| bounds.mMinY > bounds.mMaxY)
|
||||
throw std::runtime_error("invalid map bounds");
|
||||
|
||||
if (bounds.mMinX > bounds.mMaxX
|
||||
|| bounds.mMinY > bounds.mMaxY)
|
||||
throw std::runtime_error("invalid map bounds");
|
||||
Ogre::Image image;
|
||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size()));
|
||||
image.load(stream, "png");
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
|
||||
// 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");
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
// Completely off-screen? -> no need to blit anything
|
||||
if (bounds.mMaxX < mMinX
|
||||
|| bounds.mMaxY < mMinY
|
||||
|| bounds.mMinX > mMaxX
|
||||
|| bounds.mMinY > mMaxY)
|
||||
return;
|
||||
|
||||
assert(imageX < image.getWidth());
|
||||
assert(imageY < image.getHeight());
|
||||
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));
|
||||
|
||||
if (image.getColourAt(imageX, imageY, 0).a > 0)
|
||||
exploredCells.push_back(std::make_pair(x+bounds.mMinX,y+bounds.mMinY));
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
|
||||
// Completely off-screen? -> no need to blit anything
|
||||
if (bounds.mMaxX < mMinX
|
||||
|| bounds.mMaxY < mMinY
|
||||
|| bounds.mMinX > mMaxX
|
||||
|| bounds.mMinY > mMaxY)
|
||||
return;
|
||||
mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox);
|
||||
|
||||
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");
|
||||
}
|
||||
Ogre::TextureManager::getSingleton().remove("@temp");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@ namespace Loading
|
|||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMWriter;
|
||||
class ESMReader;
|
||||
class GlobalMap;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -40,8 +39,8 @@ 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);
|
||||
void write (ESM::GlobalMap& map);
|
||||
void read (ESM::GlobalMap& map);
|
||||
|
||||
private:
|
||||
std::string mCacheDir;
|
||||
|
|
|
@ -14,6 +14,15 @@ void ESM::GlobalMap::load (ESMReader &esm)
|
|||
esm.getSubHeader();
|
||||
mImageData.resize(esm.getSubSize());
|
||||
esm.getExact(&mImageData[0], mImageData.size());
|
||||
|
||||
while (esm.isNextSub("MRK_"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
CellId cell;
|
||||
esm.getT(cell.first);
|
||||
esm.getT(cell.second);
|
||||
mMarkers.push_back(cell);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::GlobalMap::save (ESMWriter &esm) const
|
||||
|
@ -23,4 +32,12 @@ void ESM::GlobalMap::save (ESMWriter &esm) const
|
|||
esm.startSubRecord("DATA");
|
||||
esm.write(&mImageData[0], mImageData.size());
|
||||
esm.endRecord("DATA");
|
||||
|
||||
for (std::vector<CellId>::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it)
|
||||
{
|
||||
esm.startSubRecord("MRK_");
|
||||
esm.writeT(it->first);
|
||||
esm.writeT(it->second);
|
||||
esm.endRecord("MRK_");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ namespace ESM
|
|||
|
||||
std::vector<char> mImageData;
|
||||
|
||||
typedef std::pair<int, int> CellId;
|
||||
std::vector<CellId> mMarkers;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue