Merge pull request #1548 from drummyfish/screenshot360

360° screenshots
0.6.3
Bret Curtis 7 years ago committed by GitHub
commit ccfc07e7e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,6 +31,7 @@
Bug #4453: Quick keys behaviour is invalid for equipment Bug #4453: Quick keys behaviour is invalid for equipment
Bug #4454: AI opens doors too slow Bug #4454: AI opens doors too slow
Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results
Feature #4222: 360° screenshots
Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts
Feature #4345: Add equivalents for the command line commands to Launcher Feature #4345: Add equivalents for the command line commands to Launcher
Feature #4444: Per-group KF-animation files support Feature #4444: Per-group KF-animation files support

@ -499,7 +499,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
else else
gameControllerdb = ""; //if it doesn't exist, pass in an empty string gameControllerdb = ""; //if it doesn't exist, pass in an empty string
MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, gameControllerdb, mGrab);
mEnvironment.setInputManager (input); mEnvironment.setInputManager (input);
std::string myguiResources = (mResDir / "mygui").string(); std::string myguiResources = (mResDir / "mygui").string();
@ -656,8 +656,11 @@ void OMW::Engine::go()
settingspath = loadSettings (settings); settingspath = loadSettings (settings);
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(), mScreenCaptureOperation = new WriteScreenshotToFileOperation(mCfgMgr.getUserDataPath().string(),
Settings::Manager::getString("screenshot format", "General"))); Settings::Manager::getString("screenshot format", "General"));
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(mScreenCaptureOperation);
mViewer->addEventHandler(mScreenCaptureHandler); mViewer->addEventHandler(mScreenCaptureHandler);
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video")); mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));

@ -7,7 +7,7 @@
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include "mwbase/environment.hpp" #include "mwbase/environment.hpp"
@ -82,6 +82,7 @@ namespace OMW
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
osg::ref_ptr<osgViewer::Viewer> mViewer; osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler; osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
osgViewer::ScreenCaptureHandler::CaptureOperation *mScreenCaptureOperation;
std::string mCellName; std::string mCellName;
std::vector<std::string> mContentFiles; std::vector<std::string> mContentFiles;
bool mSkipMenu; bool mSkipMenu;

@ -450,6 +450,7 @@ namespace MWBase
/// \todo this does not belong here /// \todo this does not belong here
virtual void screenshot (osg::Image* image, int w, int h) = 0; virtual void screenshot (osg::Image* image, int w, int h) = 0;
virtual bool screenshot360 (osg::Image* image, std::string settingStr) = 0;
/// Find default position inside exterior cell specified by name /// Find default position inside exterior cell specified by name
/// \return false if exterior with given name not exists, true otherwise /// \return false if exterior with given name not exists, true otherwise

@ -153,7 +153,7 @@ namespace MWGui
virtual osg::BoundingSphere computeBound(const osg::Node&) const { return osg::BoundingSphere(); } virtual osg::BoundingSphere computeBound(const osg::Node&) const { return osg::BoundingSphere(); }
}; };
void LoadingScreen::loadingOn() void LoadingScreen::loadingOn(bool visible)
{ {
mLoadingOnTime = mTimer.time_m(); mLoadingOnTime = mTimer.time_m();
// Early-out if already on // Early-out if already on
@ -169,7 +169,10 @@ namespace MWGui
// We are already using node masks to avoid the scene from being updated/rendered, but node masks don't work for computeBound() // We are already using node masks to avoid the scene from being updated/rendered, but node masks don't work for computeBound()
mViewer->getSceneData()->setComputeBoundingSphereCallback(new DontComputeBoundCallback); mViewer->getSceneData()->setComputeBoundingSphereCallback(new DontComputeBoundCallback);
mShowWallpaper = (MWBase::Environment::get().getStateManager()->getState() mVisible = visible;
mLoadingBox->setVisible(mVisible);
mShowWallpaper = mVisible && (MWBase::Environment::get().getStateManager()->getState()
== MWBase::StateManager::State_NoGame); == MWBase::StateManager::State_NoGame);
setVisible(true); setVisible(true);
@ -180,10 +183,15 @@ namespace MWGui
} }
MWBase::Environment::get().getWindowManager()->pushGuiMode(mShowWallpaper ? GM_LoadingWallpaper : GM_Loading); MWBase::Environment::get().getWindowManager()->pushGuiMode(mShowWallpaper ? GM_LoadingWallpaper : GM_Loading);
if (!mVisible)
draw();
} }
void LoadingScreen::loadingOff() void LoadingScreen::loadingOff()
{ {
mLoadingBox->setVisible(true); // restore
if (mLastRenderTime < mLoadingOnTime) if (mLastRenderTime < mLoadingOnTime)
{ {
// the loading was so fast that we didn't show loading screen at all // the loading was so fast that we didn't show loading screen at all
@ -306,7 +314,7 @@ namespace MWGui
void LoadingScreen::draw() void LoadingScreen::draw()
{ {
if (!needToDrawLoadingScreen()) if (mVisible && !needToDrawLoadingScreen())
return; return;
if (mShowWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1) if (mShowWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1)

@ -35,7 +35,7 @@ namespace MWGui
/// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details /// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details
virtual void setLabel (const std::string& label, bool important); virtual void setLabel (const std::string& label, bool important);
virtual void loadingOn(); virtual void loadingOn(bool visible=true);
virtual void loadingOff(); virtual void loadingOff();
virtual void setProgressRange (size_t range); virtual void setProgressRange (size_t range);
virtual void setProgress (size_t value); virtual void setProgress (size_t value);
@ -63,6 +63,8 @@ namespace MWGui
bool mImportantLabel; bool mImportantLabel;
bool mVisible;
size_t mProgress; size_t mProgress;
bool mShowWallpaper; bool mShowWallpaper;

@ -36,12 +36,14 @@ namespace MWInput
SDL_Window* window, SDL_Window* window,
osg::ref_ptr<osgViewer::Viewer> viewer, osg::ref_ptr<osgViewer::Viewer> viewer,
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler, osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler,
osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation,
const std::string& userFile, bool userFileExists, const std::string& userFile, bool userFileExists,
const std::string& controllerBindingsFile, bool grab) const std::string& controllerBindingsFile, bool grab)
: mWindow(window) : mWindow(window)
, mWindowVisible(true) , mWindowVisible(true)
, mViewer(viewer) , mViewer(viewer)
, mScreenCaptureHandler(screenCaptureHandler) , mScreenCaptureHandler(screenCaptureHandler)
, mScreenCaptureOperation(screenCaptureOperation)
, mJoystickLastUsed(false) , mJoystickLastUsed(false)
, mPlayer(NULL) , mPlayer(NULL)
, mInputManager(NULL) , mInputManager(NULL)
@ -1033,8 +1035,34 @@ namespace MWInput
void InputManager::screenshot() void InputManager::screenshot()
{ {
mScreenCaptureHandler->setFramesToCapture(1); bool regularScreenshot = true;
mScreenCaptureHandler->captureNextFrame(*mViewer); bool screenshotTaken = false;
std::string settingStr;
settingStr = Settings::Manager::getString("screenshot type","Video");
regularScreenshot = settingStr.size() == 0 || settingStr.compare("regular") == 0;
if (regularScreenshot)
{
mScreenCaptureHandler->setFramesToCapture(1);
mScreenCaptureHandler->captureNextFrame(*mViewer);
screenshotTaken = true;
}
else
{
osg::ref_ptr<osg::Image> screenshot (new osg::Image);
if (MWBase::Environment::get().getWorld()->screenshot360(screenshot.get(),settingStr))
{
(*mScreenCaptureOperation) (*(screenshot.get()),0);
// FIXME: mScreenCaptureHandler->getCaptureOperation() causes crash for some reason
screenshotTaken = true;
}
}
if (screenshotTaken)
MWBase::Environment::get().getWindowManager()->messageBox("Screenshot saved");
} }
void InputManager::toggleInventory() void InputManager::toggleInventory()

@ -4,6 +4,7 @@
#include "../mwgui/mode.hpp" #include "../mwgui/mode.hpp"
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osgViewer/ViewerEventHandlers>
#include <extern/oics/ICSChannelListener.h> #include <extern/oics/ICSChannelListener.h>
#include <extern/oics/ICSInputControlSystem.h> #include <extern/oics/ICSInputControlSystem.h>
@ -14,7 +15,6 @@
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
namespace MWWorld namespace MWWorld
{ {
class Player; class Player;
@ -74,6 +74,7 @@ namespace MWInput
SDL_Window* window, SDL_Window* window,
osg::ref_ptr<osgViewer::Viewer> viewer, osg::ref_ptr<osgViewer::Viewer> viewer,
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler, osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler,
osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation,
const std::string& userFile, bool userFileExists, const std::string& userFile, bool userFileExists,
const std::string& controllerBindingsFile, bool grab); const std::string& controllerBindingsFile, bool grab);
@ -158,6 +159,7 @@ namespace MWInput
bool mWindowVisible; bool mWindowVisible;
osg::ref_ptr<osgViewer::Viewer> mViewer; osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler; osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
osgViewer::ScreenCaptureHandler::CaptureOperation *mScreenCaptureOperation;
bool mJoystickLastUsed; bool mJoystickLastUsed;
MWWorld::Player* mPlayer; MWWorld::Player* mPlayer;

@ -12,16 +12,21 @@
#include <osg/Group> #include <osg/Group>
#include <osg/UserDataContainer> #include <osg/UserDataContainer>
#include <osg/ComputeBoundsVisitor> #include <osg/ComputeBoundsVisitor>
#include <osg/ShapeDrawable>
#include <osg/TextureCubeMap>
#include <osgUtil/LineSegmentIntersector> #include <osgUtil/LineSegmentIntersector>
#include <osgUtil/IncrementalCompileOperation> #include <osgUtil/IncrementalCompileOperation>
#include <osg/ImageUtils>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/resource/keyframemanager.hpp> #include <components/resource/keyframemanager.hpp>
#include <components/shader/shadermanager.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -39,7 +44,12 @@
#include <components/esm/loadcell.hpp> #include <components/esm/loadcell.hpp>
#include <components/fallback/fallback.hpp> #include <components/fallback/fallback.hpp>
#include <boost/algorithm/string.hpp>
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwgui/loadingscreen.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "sky.hpp" #include "sky.hpp"
#include "effectmanager.hpp" #include "effectmanager.hpp"
@ -212,7 +222,7 @@ namespace MWRender
mSceneRoot = sceneRoot; mSceneRoot = sceneRoot;
sceneRoot->setStartLight(1); sceneRoot->setStartLight(1);
mRootNode->addChild(sceneRoot); mRootNode->addChild(mSceneRoot);
mPathgrid.reset(new Pathgrid(mRootNode)); mPathgrid.reset(new Pathgrid(mRootNode));
@ -668,7 +678,203 @@ namespace MWRender
mutable bool mDone; mutable bool mDone;
}; };
void RenderingManager::screenshot(osg::Image *image, int w, int h) bool RenderingManager::screenshot360(osg::Image* image, std::string settingStr)
{
int screenshotW = mViewer->getCamera()->getViewport()->width();
int screenshotH = mViewer->getCamera()->getViewport()->height();
int screenshotMapping = 0;
int cubeSize = screenshotMapping == 2 ?
screenshotW: // planet mapping needs higher resolution
screenshotW / 2;
std::vector<std::string> settingArgs;
boost::algorithm::split(settingArgs,settingStr,boost::is_any_of(" "));
if (settingArgs.size() > 0)
{
std::string typeStrings[4] = {"spherical","cylindrical","planet","cubemap"};
bool found = false;
for (int i = 0; i < 4; ++i)
if (settingArgs[0].compare(typeStrings[i]) == 0)
{
screenshotMapping = i;
found = true;
break;
}
if (!found)
{
std::cerr << "Wrong screenshot type: " << settingArgs[0] << "." << std::endl;
return false;
}
}
if (settingArgs.size() > 1)
screenshotW = std::min(10000,std::atoi(settingArgs[1].c_str()));
if (settingArgs.size() > 2)
screenshotH = std::min(10000,std::atoi(settingArgs[2].c_str()));
if (settingArgs.size() > 3)
cubeSize = std::min(5000,std::atoi(settingArgs[3].c_str()));
if (mCamera->isVanityOrPreviewModeEnabled())
{
std::cerr << "Spherical screenshots are not allowed in preview mode." << std::endl;
return false;
}
bool rawCubemap = screenshotMapping == 3;
if (rawCubemap)
screenshotW = cubeSize * 6; // the image will consist of 6 cube sides in a row
else if (screenshotMapping == 2)
screenshotH = screenshotW; // use square resolution for planet mapping
std::vector<osg::ref_ptr<osg::Image>> images;
for (int i = 0; i < 6; ++i)
images.push_back(new osg::Image);
osg::Vec3 directions[6] = {
rawCubemap ? osg::Vec3(1,0,0) : osg::Vec3(0,0,1),
osg::Vec3(0,0,-1),
osg::Vec3(-1,0,0),
rawCubemap ? osg::Vec3(0,0,1) : osg::Vec3(1,0,0),
osg::Vec3(0,1,0),
osg::Vec3(0,-1,0)};
double rotations[] = {
-osg::PI / 2.0,
osg::PI / 2.0,
osg::PI,
0,
osg::PI / 2.0,
osg::PI / 2.0};
double fovBackup = mFieldOfView;
mFieldOfView = 90.0; // each cubemap side sees 90 degrees
int maskBackup = mPlayerAnimation->getObjectRoot()->getNodeMask();
if (mCamera->isFirstPerson())
mPlayerAnimation->getObjectRoot()->setNodeMask(0);
for (int i = 0; i < 6; ++i) // for each cubemap side
{
osg::Matrixd transform = osg::Matrixd::rotate(osg::Vec3(0,0,-1),directions[i]);
if (!rawCubemap)
transform *= osg::Matrixd::rotate(rotations[i],osg::Vec3(0,0,-1));
osg::Image *sideImage = images[i].get();
screenshot(sideImage,cubeSize,cubeSize,transform);
if (!rawCubemap)
sideImage->flipHorizontal();
}
mPlayerAnimation->getObjectRoot()->setNodeMask(maskBackup);
mFieldOfView = fovBackup;
if (rawCubemap) // for raw cubemap don't run on GPU, just merge the images
{
image->allocateImage(cubeSize * 6,cubeSize,images[0]->r(),images[0]->getPixelFormat(),images[0]->getDataType());
for (int i = 0; i < 6; ++i)
osg::copyImage(images[i].get(),0,0,0,images[i]->s(),images[i]->t(),images[i]->r(),image,i * cubeSize,0,0);
return true;
}
// run on GPU now:
osg::ref_ptr<osg::TextureCubeMap> cubeTexture (new osg::TextureCubeMap);
cubeTexture->setResizeNonPowerOfTwoHint(false);
cubeTexture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::NEAREST);
cubeTexture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::NEAREST);
cubeTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
cubeTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
for (int i = 0; i < 6; ++i)
cubeTexture->setImage(i,images[i].get());
osg::ref_ptr<osg::Camera> screenshotCamera (new osg::Camera);
osg::ref_ptr<osg::ShapeDrawable> quad (new osg::ShapeDrawable(new osg::Box(osg::Vec3(0,0,0),2.0)));
std::map<std::string, std::string> defineMap;
Shader::ShaderManager& shaderMgr = mResourceSystem->getSceneManager()->getShaderManager();
osg::ref_ptr<osg::Shader> fragmentShader (shaderMgr.getShader("s360_fragment.glsl",defineMap,osg::Shader::FRAGMENT));
osg::ref_ptr<osg::Shader> vertexShader (shaderMgr.getShader("s360_vertex.glsl", defineMap, osg::Shader::VERTEX));
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
osg::ref_ptr<osg::Program> program (new osg::Program);
program->addShader(fragmentShader);
program->addShader(vertexShader);
stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("cubeMap",0));
stateset->addUniform(new osg::Uniform("mapping",screenshotMapping));
stateset->setTextureAttributeAndModes(0,cubeTexture,osg::StateAttribute::ON);
quad->setStateSet(stateset);
quad->setUpdateCallback(NULL);
screenshotCamera->addChild(quad);
mRootNode->addChild(screenshotCamera);
renderCameraToImage(screenshotCamera,image,screenshotW,screenshotH);
screenshotCamera->removeChildren(0,screenshotCamera->getNumChildren());
mRootNode->removeChild(screenshotCamera);
return true;
}
void RenderingManager::renderCameraToImage(osg::Camera *camera, osg::Image *image, int w, int h)
{
camera->setNodeMask(Mask_RenderToTexture);
camera->attach(osg::Camera::COLOR_BUFFER, image);
camera->setRenderOrder(osg::Camera::PRE_RENDER);
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT,osg::Camera::PIXEL_BUFFER_RTT);
camera->setViewport(0, 0, w, h);
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
texture->setInternalFormat(GL_RGB);
texture->setTextureSize(w,h);
texture->setResizeNonPowerOfTwoHint(false);
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
camera->attach(osg::Camera::COLOR_BUFFER,texture);
image->setDataType(GL_UNSIGNED_BYTE);
image->setPixelFormat(texture->getInternalFormat());
// The draw needs to complete before we can copy back our image.
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback);
camera->setFinalDrawCallback(callback);
MWBase::Environment::get().getWindowManager()->getLoadingScreen()->loadingOn(false);
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
callback->waitTillDone();
MWBase::Environment::get().getWindowManager()->getLoadingScreen()->loadingOff();
// now that we've "used up" the current frame, get a fresh framenumber for the next frame() following after the screenshot is completed
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
}
void RenderingManager::screenshot(osg::Image *image, int w, int h, osg::Matrixd cameraTransform)
{ {
osg::ref_ptr<osg::Camera> rttCamera (new osg::Camera); osg::ref_ptr<osg::Camera> rttCamera (new osg::Camera);
rttCamera->setNodeMask(Mask_RenderToTexture); rttCamera->setNodeMask(Mask_RenderToTexture);
@ -677,7 +883,8 @@ namespace MWRender
rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); rttCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); rttCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT);
rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance); rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance);
rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix()); rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix() * cameraTransform);
rttCamera->setViewport(0, 0, w, h); rttCamera->setViewport(0, 0, w, h);
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D); osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
@ -693,25 +900,17 @@ namespace MWRender
rttCamera->setUpdateCallback(new NoTraverseCallback); rttCamera->setUpdateCallback(new NoTraverseCallback);
rttCamera->addChild(mSceneRoot); rttCamera->addChild(mSceneRoot);
rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI));
mRootNode->addChild(rttCamera); rttCamera->addChild(mWater->getReflectionCamera());
rttCamera->addChild(mWater->getRefractionCamera());
// The draw needs to complete before we can copy back our image. rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI));
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback);
rttCamera->setFinalDrawCallback(callback);
// at the time this function is called we are in the middle of a frame, mRootNode->addChild(rttCamera);
// so out of order calls are necessary to get a correct frameNumber for the next frame.
// refer to the advance() and frame() order in Engine::go()
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
callback->waitTillDone(); rttCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// now that we've "used up" the current frame, get a fresh framenumber for the next frame() following after the screenshot is completed renderCameraToImage(rttCamera.get(),image,w,h);
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->removeChildren(0, rttCamera->getNumChildren());
mRootNode->removeChild(rttCamera); mRootNode->removeChild(rttCamera);

@ -3,6 +3,7 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Light> #include <osg/Light>
#include <osg/Camera>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -125,7 +126,8 @@ namespace MWRender
void setWaterHeight(float level); void setWaterHeight(float level);
/// Take a screenshot of w*h onto the given image, not including the GUI. /// Take a screenshot of w*h onto the given image, not including the GUI.
void screenshot(osg::Image* image, int w, int h); void screenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd());
bool screenshot360(osg::Image* image, std::string settingStr);
struct RayResult struct RayResult
{ {
@ -213,6 +215,8 @@ namespace MWRender
void reportStats() const; void reportStats() const;
void renderCameraToImage(osg::Camera *camera, osg::Image *image, int w, int h);
osg::ref_ptr<osgUtil::IntersectionVisitor> getIntersectionVisitor(osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors); osg::ref_ptr<osgUtil::IntersectionVisitor> getIntersectionVisitor(osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors);
osg::ref_ptr<osgUtil::IntersectionVisitor> mIntersectionVisitor; osg::ref_ptr<osgUtil::IntersectionVisitor> mIntersectionVisitor;

@ -470,6 +470,16 @@ void Water::updateWaterMaterial()
updateVisible(); updateVisible();
} }
osg::Camera *Water::getReflectionCamera()
{
return mReflection;
}
osg::Camera *Water::getRefractionCamera()
{
return mRefraction;
}
void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
{ {
osg::ref_ptr<osg::StateSet> stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water); osg::ref_ptr<osg::StateSet> stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water);

@ -7,6 +7,7 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Vec3f> #include <osg/Vec3f>
#include <osg/Uniform> #include <osg/Uniform>
#include <osg/Camera>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -112,6 +113,9 @@ namespace MWRender
void update(float dt); void update(float dt);
osg::Camera *getReflectionCamera();
osg::Camera *getRefractionCamera();
void processChangedSettings(const Settings::CategorySettingVector& settings); void processChangedSettings(const Settings::CategorySettingVector& settings);
osg::Uniform *getRainIntensityUniform(); osg::Uniform *getRainIntensityUniform();

@ -2300,6 +2300,11 @@ namespace MWWorld
{ {
mRendering->screenshot(image, w, h); mRendering->screenshot(image, w, h);
} }
bool World::screenshot360(osg::Image* image, std::string settingStr)
{
return mRendering->screenshot360(image,settingStr);
}
void World::activateDoor(const MWWorld::Ptr& door) void World::activateDoor(const MWWorld::Ptr& door)
{ {

@ -561,6 +561,7 @@ namespace MWWorld
/// \todo this does not belong here /// \todo this does not belong here
void screenshot (osg::Image* image, int w, int h) override; void screenshot (osg::Image* image, int w, int h) override;
bool screenshot360 (osg::Image* image, std::string settingStr) override;
/// Find center of exterior cell above land surface /// Find center of exterior cell above land surface
/// \return false if exterior with given name not exists, true otherwise /// \return false if exterior with given name not exists, true otherwise

@ -20,7 +20,7 @@ namespace Loading
/// @note To get the loading screen to actually update, you must call setProgress / increaseProgress periodically. /// @note To get the loading screen to actually update, you must call setProgress / increaseProgress periodically.
/// @note It is best to use the ScopedLoad object instead of using loadingOn()/loadingOff() directly, /// @note It is best to use the ScopedLoad object instead of using loadingOn()/loadingOff() directly,
/// so that the loading is exception safe. /// so that the loading is exception safe.
virtual void loadingOn() {} virtual void loadingOn(bool visible=true) {}
virtual void loadingOff() {} virtual void loadingOff() {}
/// Set the total range of progress (e.g. the number of objects to load). /// Set the total range of progress (e.g. the number of objects to load).

@ -402,6 +402,10 @@ contrast = 1.0
# Video gamma setting. (>0.0). No effect in Linux. # Video gamma setting. (>0.0). No effect in Linux.
gamma = 1.0 gamma = 1.0
# Type of screenshot to take (regular, cylindrical, spherical or planet), optionally followed by
# screenshot width, height and cubemap resolution in pixels. (e.g. spherical 1600 1000 1200)
screenshot type = regular
[Water] [Water]
# Enable water shader with reflections and optionally refraction. # Enable water shader with reflections and optionally refraction.

@ -16,6 +16,8 @@ set(SHADER_FILES
terrain_fragment.glsl terrain_fragment.glsl
lighting.glsl lighting.glsl
parallax.glsl parallax.glsl
s360_fragment.glsl
s360_vertex.glsl
) )
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}")

@ -0,0 +1,52 @@
#version 120
varying vec2 uv;
uniform samplerCube cubeMap;
uniform int mapping;
#define PI 3.1415926535
vec3 sphericalCoords(vec2 coords)
{
coords.x = -1 * coords.x * 2 * PI;
coords.y = (coords.y - 0.5) * PI;
vec3 result = vec3(0.0,cos(coords.y),sin(coords.y));
result = vec3(cos(coords.x) * result.y,sin(coords.x) * result.y,result.z);
return result;
}
vec3 cylindricalCoords(vec2 coords)
{
return normalize(vec3(cos(-1 * coords.x * 2 * PI),sin(-1 * coords.x * 2 * PI),coords.y * 2.0 - 1.0));
}
vec3 planetCoords(vec2 coords)
{
vec2 fromCenter = coords - vec2(0.5,0.5);
float magnitude = length(fromCenter);
fromCenter = normalize(fromCenter);
float dotProduct = dot(fromCenter,vec2(0.0,1.0));
coords.x = coords.x > 0.5 ? 0.5 - (dotProduct + 1.0) / 4.0 : 0.5 + (dotProduct + 1.0) / 4.0;
coords.y = max(0.0,1.0 - pow(magnitude / 0.5,0.5));
return sphericalCoords(coords);
}
void main(void)
{
vec3 c;
if (mapping == 0)
c = sphericalCoords(uv);
else if (mapping == 1)
c = cylindricalCoords(uv);
else
c = planetCoords(uv);
gl_FragData[0] = textureCube(cubeMap,c);
}

@ -0,0 +1,9 @@
#version 120
varying vec2 uv;
void main(void)
{
gl_Position = gl_Vertex;
uv = (gl_Vertex.xy * vec2(1.0,-1.0) + vec2(1.0)) / 2;
}
Loading…
Cancel
Save