mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Implement savegame screenshots
This commit is contained in:
parent
786ed6ca5b
commit
295aed3533
9 changed files with 89 additions and 2 deletions
|
@ -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…
Reference in a new issue