From 7a1408cfed960ded9d10baedb5b8ba126a73fb9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 May 2015 18:49:24 +0200 Subject: [PATCH] Restore display of global map overlay, no exploration yet --- apps/openmw/mwgui/mapwindow.cpp | 11 +-- apps/openmw/mwgui/mapwindow.hpp | 3 +- apps/openmw/mwrender/globalmap.cpp | 144 ++++++++++++++++++++--------- apps/openmw/mwrender/globalmap.hpp | 6 +- 4 files changed, 114 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3a56d3dfd1..46e2f29e03 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -582,7 +582,6 @@ namespace MWGui , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) - , mGlobalMapTexture(NULL) , mGlobalMapImage(NULL) , mGlobalMapOverlay(NULL) , mGlobal(false) @@ -736,17 +735,17 @@ namespace MWGui mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapTexture = new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture()); - mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture); + mGlobalMapTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getBaseTexture())); + mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get()); mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); - //mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); + mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); + mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); } MapWindow::~MapWindow() { - delete mGlobalMapTexture; - delete mGlobalMapRender; } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 40ccbda5f1..bea3d33b9f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -212,7 +212,8 @@ namespace MWGui void globalMapUpdatePlayer(); MyGUI::ScrollView* mGlobalMap; - MyGUI::ITexture* mGlobalMapTexture; + std::auto_ptr mGlobalMapTexture; + std::auto_ptr mGlobalMapOverlayTexture; MyGUI::ImageBox* mGlobalMapImage; MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index da1be00287..8ca21cbfb1 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -5,8 +5,11 @@ #include #include +#include + #include #include +#include #include @@ -134,7 +137,12 @@ namespace MWRender } mBaseTexture = new osg::Texture2D; + mBaseTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mBaseTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mBaseTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mBaseTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mBaseTexture->setImage(image); + mBaseTexture->setResizeNonPowerOfTwoHint(false); clear(); @@ -200,14 +208,25 @@ namespace MWRender void GlobalMap::clear() { - /* - Ogre::uchar* buffer = OGRE_ALLOC_T(Ogre::uchar, mWidth * mHeight * 4, Ogre::MEMCATEGORY_GENERAL); - memset(buffer, 0, mWidth * mHeight * 4); + if (!mOverlayImage) + { + mOverlayImage = new osg::Image; + mOverlayImage->allocateImage(mWidth, mHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE); + assert(mOverlayImage->isDataContiguous()); + } + memset(mOverlayImage->data(), 0, mOverlayImage->getTotalSizeInBytes()); + mOverlayImage->dirty(); - mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image - - mOverlayTexture->load(); - */ + if (!mOverlayTexture) + { + mOverlayTexture = new osg::Texture2D; + mOverlayTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + mOverlayTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + mOverlayTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mOverlayTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + mOverlayTexture->setImage(mOverlayImage); + mOverlayTexture->setResizeNonPowerOfTwoHint(false); + } } void GlobalMap::write(ESM::GlobalMap& map) @@ -217,13 +236,35 @@ namespace MWRender map.mBounds.mMinY = mMinY; map.mBounds.mMaxY = mMaxY; - /* - Ogre::DataStreamPtr encoded = mOverlayImage.encode("png"); - map.mImageData.resize(encoded->size()); - encoded->read(&map.mImageData[0], encoded->size()); - */ + std::ostringstream ostream; + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Can't write map overlay: no png readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream); + if (!result.success()) + { + std::cerr << "Can't write map overlay: " << result.message() << std::endl; + return; + } + + std::string data = ostream.str(); + map.mImageData = std::vector(data.begin(), data.end()); } + struct Box + { + int mLeft, mRight, mTop, mBottom; + + Box(int left, int right, int top, int bottom) + : mLeft(left), mRight(right), mTop(top), mBottom(bottom) + { + } + }; + void GlobalMap::read(ESM::GlobalMap& map) { const ESM::GlobalMap::Bounds& bounds = map.mBounds; @@ -237,17 +278,35 @@ namespace MWRender || 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"); + if (!map.mImageData.size()) + return; + + Files::IMemStream istream(&map.mImageData[0], map.mImageData.size()); + + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Can't read map overlay: no png readerwriter found" << std::endl; + return; + } + + osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream); + if (!result.success()) + { + std::cerr << "Can't read map overlay: " << result.message() << std::endl; + return; + } + + osg::ref_ptr image = result.getImage(); + int imageWidth = image->s(); + int imageHeight = image->t(); 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) + int cellImageSizeSrc = imageWidth / xLength; + if (int(imageHeight / 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, @@ -266,39 +325,40 @@ namespace MWRender int topDiff = (bounds.mMaxY - mMaxY); int rightDiff = (bounds.mMaxX - mMaxX); int bottomDiff = (mMinY - bounds.mMinY); - Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), + + 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)); + std::min(imageWidth, imageWidth - rightDiff * cellImageSizeSrc), + std::min(imageHeight, imageHeight - bottomDiff * cellImageSizeSrc)); - Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), + 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)); + std::min(mWidth, mWidth + rightDiff * cellImageSizeDst), + std::min(mHeight, mHeight + 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->load(); - mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox); - - if (srcBox.left == destBox.left && srcBox.right == destBox.right - && srcBox.top == destBox.top && srcBox.bottom == destBox.bottom - && int(image.getWidth()) == mWidth && int(image.getHeight()) == mHeight) - mOverlayImage = image; + if (srcBox.mLeft == destBox.mLeft && srcBox.mRight == destBox.mRight + && srcBox.mTop == destBox.mTop && srcBox.mBottom == destBox.mBottom + && imageWidth == mWidth && imageHeight == mHeight) + { + mOverlayImage->copySubImage(0, 0, 0, image); + } else - mOverlayTexture->convertToImage(mOverlayImage); - - Ogre::TextureManager::getSingleton().remove("@temp"); - */ + { + // TODO: + // Dimensions don't match. This could mean a changed map region, or a changed map resolution. + // In the latter case, we'll want to use filtering. + // Create a RTT Camera and draw the image onto mOverlayImage in the next frame? + } + mOverlayImage->dirty(); } osg::ref_ptr GlobalMap::getBaseTexture() { return mBaseTexture; } + + osg::ref_ptr GlobalMap::getOverlayTexture() + { + return mOverlayTexture; + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index d7e20a3a77..9ca7ed5b4a 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -9,6 +9,7 @@ namespace osg { class Texture2D; + class Image; } namespace Loading @@ -50,7 +51,7 @@ namespace MWRender void read (ESM::GlobalMap& map); osg::ref_ptr getBaseTexture(); - //osg::ref_ptr getOverlayTexture(); + osg::ref_ptr getOverlayTexture(); private: int mCellSize; @@ -58,6 +59,9 @@ namespace MWRender std::vector< std::pair > mExploredCells; osg::ref_ptr mBaseTexture; + osg::ref_ptr mOverlayTexture; + + osg::ref_ptr mOverlayImage; int mWidth; int mHeight;