Implement savegame screenshots

actorid
scrawl 11 years ago
parent 786ed6ca5b
commit 295aed3533

@ -412,6 +412,7 @@ namespace MWBase
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
virtual void stopVideo() = 0;
virtual void frameStarted (float dt, bool paused) = 0;
virtual void screenshot (Ogre::Image& image, int w, int h) = 0;
/// Find default position inside exterior cell specified by name
/// \return false if exterior with given name not exists, true otherwise

@ -1,6 +1,9 @@
#include "savegamedialog.hpp"
#include "widgets.hpp"
#include <OgreImage.h>
#include <OgreTextureManager.h>
#include <components/misc/stringops.hpp>
#include <components/settings/settings.hpp>
@ -166,6 +169,7 @@ namespace MWGui
if (pos == MyGUI::ITEM_NONE)
{
mInfoText->setCaption("");
mScreenshot->setImageTexture("");
return;
}
@ -199,5 +203,29 @@ namespace MWGui
<< " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
mInfoText->setCaptionWithReplacing(text.str());
// Decode screenshot
std::vector<char> data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
Ogre::Image image;
image.load(stream, "jpg");
const std::string textureName = "@savegame_screenshot";
Ogre::TexturePtr texture;
texture = Ogre::TextureManager::getSingleton().getByName(textureName);
mScreenshot->setImageTexture("");
if (texture.isNull())
{
texture = Ogre::TextureManager::getSingleton().createManual(textureName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D,
image.getWidth(), image.getHeight(), 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY);
}
texture->unload();
texture->setWidth(image.getWidth());
texture->setHeight(image.getHeight());
texture->loadImage(image);
mScreenshot->setImageTexture(textureName);
}
}

@ -289,6 +289,9 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr)
void
RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
{
Ogre::Image im;
im.encode(".jpg");
Ogre::SceneNode *child =
mRendering.getScene()->getSceneNode(old.getRefData().getHandle());
@ -966,6 +969,38 @@ Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr)
return anim;
}
void RenderingManager::screenshot(Image &image, int w, int h)
{
// Create a temporary render target. We do not use the RenderWindow since we want a specific size.
// Also, the GUI should not be visible (and it is only rendered on the RenderWindow's primary viewport)
const std::string tempName = "@temp";
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(tempName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, w, h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
float oldAspect = mRendering.getCamera()->getAspectRatio();
mRendering.getCamera()->setAspectRatio(w / static_cast<float>(h));
Ogre::RenderTarget* rt = texture->getBuffer()->getRenderTarget();
Ogre::Viewport* vp = rt->addViewport(mRendering.getCamera());
vp->setBackgroundColour(mRendering.getViewport()->getBackgroundColour());
vp->setOverlaysEnabled(false);
vp->setVisibilityMask(mRendering.getViewport()->getVisibilityMask());
rt->update();
Ogre::PixelFormat pf = rt->suggestPixelFormat();
std::vector<Ogre::uchar> data;
data.resize(w * h * Ogre::PixelUtil::getNumElemBytes(pf));
Ogre::PixelBox pb(w, h, 1, pf, &data[0]);
rt->copyContentsToMemory(pb);
image.loadDynamicImage(&data[0], w, h, pf);
Ogre::TextureManager::getSingleton().remove(tempName);
mRendering.getCamera()->setAspectRatio(oldAspect);
}
void RenderingManager::playVideo(const std::string& name, bool allowSkipping)
{

@ -213,6 +213,7 @@ public:
void playVideo(const std::string& name, bool allowSkipping);
void stopVideo();
void frameStarted(float dt, bool paused);
void screenshot(Ogre::Image& image, int w, int h);
protected:
virtual void windowResized(int x, int y);

@ -8,6 +8,8 @@
#include <components/settings/settings.hpp>
#include <OgreImage.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
@ -151,6 +153,13 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
profile.mTimePlayed = mTimePlayed;
profile.mDescription = description;
int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing
Ogre::Image screenshot;
world.screenshot(screenshot, screenshotW, screenshotH);
Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
profile.mScreenshot.resize(encoded->size());
encoded->read(&profile.mScreenshot[0], encoded->size());
if (!slot)
slot = mCharacterManager.getCurrentCharacter()->createSlot (profile);
else

@ -1810,6 +1810,11 @@ namespace MWWorld
mRendering->frameStarted(dt, paused);
}
void World::screenshot(Ogre::Image &image, int w, int h)
{
mRendering->screenshot(image, w, h);
}
void World::activateDoor(const MWWorld::Ptr& door)
{
if (mDoorStates.find(door) != mDoorStates.end())

@ -504,6 +504,7 @@ namespace MWWorld
virtual void playVideo(const std::string& name, bool allowSkipping);
virtual void stopVideo();
virtual void frameStarted (float dt, bool paused);
virtual void screenshot (Ogre::Image& image, int w, int h);
/// Find center of exterior cell above land surface
/// \return false if exterior with given name not exists, true otherwise

@ -19,6 +19,11 @@ void ESM::SavedGame::load (ESMReader &esm)
while (esm.isNextSub ("DEPE"))
mContentFiles.push_back (esm.getHString());
esm.getSubNameIs("SCRN");
esm.getSubHeader();
mScreenshot.resize(esm.getSubSize());
esm.getExact(&mScreenshot[0], mScreenshot.size());
}
void ESM::SavedGame::save (ESMWriter &esm) const
@ -35,4 +40,7 @@ void ESM::SavedGame::save (ESMWriter &esm) const
iter!=mContentFiles.end(); ++iter)
esm.writeHNString ("DEPE", *iter);
esm.startSubRecord("SCRN");
esm.write(&mScreenshot[0], mScreenshot.size());
esm.endRecord("SCRN");
}

@ -31,8 +31,7 @@ namespace ESM
TimeStamp mInGameTime;
double mTimePlayed;
std::string mDescription;
/// \todo add field for screenshot
std::vector<char> mScreenshot; // raw jpg-encoded data
void load (ESMReader &esm);
void save (ESMWriter &esm) const;

Loading…
Cancel
Save