Merge pull request #3039 from akortunov/screenshotmanager

Move screenshots handling to the separate class
cherry-pick-c431f31c
Bret Curtis 4 years ago committed by GitHub
commit b3f3b29bbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,7 +19,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging
)

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

@ -333,12 +333,8 @@ namespace MWInput
void ActionManager::screenshot()
{
bool regularScreenshot = true;
std::string settingStr;
settingStr = Settings::Manager::getString("screenshot type","Video");
regularScreenshot = settingStr.size() == 0 || settingStr.compare("regular") == 0;
const std::string& settingStr = Settings::Manager::getString("screenshot type", "Video");
bool regularScreenshot = settingStr.size() == 0 || settingStr.compare("regular") == 0;
if (regularScreenshot)
{
@ -349,7 +345,7 @@ namespace MWInput
{
osg::ref_ptr<osg::Image> screenshot (new osg::Image);
if (MWBase::Environment::get().getWorld()->screenshot360(screenshot.get(), settingStr))
if (MWBase::Environment::get().getWorld()->screenshot360(screenshot.get()))
{
(*mScreenCaptureOperation) (*(screenshot.get()), 0);
// FIXME: mScreenCaptureHandler->getCaptureOperation() causes crash for some reason

@ -2,8 +2,6 @@
#include <limits>
#include <cstdlib>
#include <condition_variable>
#include <mutex>
#include <osg/Light>
#include <osg/LightModel>
@ -13,25 +11,20 @@
#include <osg/Group>
#include <osg/UserDataContainer>
#include <osg/ComputeBoundsVisitor>
#include <osg/ShapeDrawable>
#include <osg/TextureCubeMap>
#include <osgUtil/LineSegmentIntersector>
#include <osg/ImageUtils>
#include <osgViewer/Viewer>
#include <components/nifosg/nifloader.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/keyframemanager.hpp>
#include <components/shader/shadermanager.hpp>
#include <components/settings/settings.hpp>
@ -74,7 +67,7 @@
#include "recastmesh.hpp"
#include "fogmanager.hpp"
#include "objectpaging.hpp"
#include "screenshotmanager.hpp"
namespace MWRender
{
@ -311,6 +304,8 @@ namespace MWRender
if (Settings::Manager::getBool("view over shoulder", "Camera"))
mViewOverShoulderController.reset(new ViewOverShoulderController(mCamera.get()));
mScreenshotManager.reset(new ScreenshotManager(viewer, mRootNode, sceneRoot, mResourceSystem, mWater.get()));
mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
osg::ref_ptr<osg::LightSource> source = new osg::LightSource;
@ -695,298 +690,31 @@ namespace MWRender
mSky->setWaterHeight(height);
}
class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback
void RenderingManager::screenshot(osg::Image* image, int w, int h)
{
public:
NotifyDrawCompletedCallback(unsigned int frame)
: mDone(false), mFrame(frame)
{
}
void operator () (osg::RenderInfo& renderInfo) const override
{
std::lock_guard<std::mutex> lock(mMutex);
if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame)
{
mDone = true;
mCondition.notify_one();
}
}
void waitTillDone()
{
std::unique_lock<std::mutex> lock(mMutex);
if (mDone)
return;
mCondition.wait(lock);
}
mutable std::condition_variable mCondition;
mutable std::mutex mMutex;
mutable bool mDone;
unsigned int mFrame;
};
mScreenshotManager->screenshot(image, w, h);
}
bool RenderingManager::screenshot360(osg::Image* image, std::string settingStr)
bool RenderingManager::screenshot360(osg::Image* image)
{
int screenshotW = mViewer->getCamera()->getViewport()->width();
int screenshotH = mViewer->getCamera()->getViewport()->height();
int screenshotMapping = 0;
std::vector<std::string> settingArgs;
Misc::StringUtils::split(settingStr, settingArgs);
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)
{
Log(Debug::Warning) << "Wrong screenshot type: " << settingArgs[0] << ".";
return false;
}
}
// planet mapping needs higher resolution
int cubeSize = screenshotMapping == 2 ? screenshotW : screenshotW / 2;
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())
{
Log(Debug::Warning) << "Spherical screenshots are not allowed in preview mode.";
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();
}
mScreenshotManager->screenshot360(image);
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(nullptr);
screenshotCamera->addChild(quad);
renderCameraToImage(screenshotCamera,image,screenshotW,screenshotH);
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());
mRootNode->addChild(camera);
// The draw needs to complete before we can copy back our image.
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback(0));
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());
camera->removeChildren(0, camera->getNumChildren());
mRootNode->removeChild(camera);
}
class ReadImageFromFramebufferCallback : public osg::Drawable::DrawCallback
{
public:
ReadImageFromFramebufferCallback(osg::Image* image, int width, int height)
: mWidth(width), mHeight(height), mImage(image)
{
}
void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* /*drawable*/) const override
{
int screenW = renderInfo.getCurrentCamera()->getViewport()->width();
int screenH = renderInfo.getCurrentCamera()->getViewport()->height();
double imageaspect = (double)mWidth/(double)mHeight;
int leftPadding = std::max(0, static_cast<int>(screenW - screenH * imageaspect) / 2);
int topPadding = std::max(0, static_cast<int>(screenH - screenW / imageaspect) / 2);
int width = screenW - leftPadding*2;
int height = screenH - topPadding*2;
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
mImage->scaleImage(mWidth, mHeight, 1);
}
private:
int mWidth;
int mHeight;
osg::ref_ptr<osg::Image> mImage;
};
void RenderingManager::screenshotFramebuffer(osg::Image* image, int w, int h)
{
osg::Camera* camera = mViewer->getCamera();
osg::ref_ptr<osg::Drawable> tempDrw = new osg::Drawable;
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
tempDrw->setCullingActive(false);
tempDrw->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin", osg::StateSet::USE_RENDERBIN_DETAILS); // so its after all scene bins but before POST_RENDER gui camera
camera->addChild(tempDrw);
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback(mViewer->getFrameStamp()->getFrameNumber()));
camera->setFinalDrawCallback(callback);
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
callback->waitTillDone();
// now that we've "used up" the current frame, get a fresh frame number for the next frame() following after the screenshot is completed
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
camera->removeChild(tempDrw);
camera->setFinalDrawCallback(nullptr);
}
void RenderingManager::screenshot(osg::Image *image, int w, int h, osg::Matrixd cameraTransform)
{
osg::ref_ptr<osg::Camera> rttCamera (new osg::Camera);
rttCamera->setProjectionMatrixAsPerspective(mFieldOfView, w/float(h), mNearClip, mViewDistance);
rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix() * cameraTransform);
rttCamera->setUpdateCallback(new NoTraverseCallback);
rttCamera->addChild(mSceneRoot);
rttCamera->addChild(mWater->getReflectionCamera());
rttCamera->addChild(mWater->getRefractionCamera());
rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI));
rttCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderCameraToImage(rttCamera.get(),image,w,h);
}
osg::Vec4f RenderingManager::getScreenBounds(const osg::BoundingBox &worldbb)
{
if (!worldbb.valid()) return osg::Vec4f();

@ -74,6 +74,7 @@ namespace MWRender
class StateUpdater;
class EffectManager;
class ScreenshotManager;
class FogManager;
class SkyManager;
class NpcAnimation;
@ -148,9 +149,8 @@ namespace MWRender
void setWaterHeight(float level);
/// Take a screenshot of w*h onto the given image, not including the GUI.
void screenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd()); // make a new render at given size
void screenshotFramebuffer(osg::Image* image, int w, int h); // copy directly from framebuffer and scale to given size
bool screenshot360(osg::Image* image, std::string settingStr);
void screenshot(osg::Image* image, int w, int h);
bool screenshot360(osg::Image* image);
struct RayResult
{
@ -248,8 +248,6 @@ namespace MWRender
void reportStats() const;
void renderCameraToImage(osg::Camera *camera, osg::Image *image, int w, int h);
void updateNavMesh();
void updateRecastMesh();
@ -281,6 +279,7 @@ namespace MWRender
std::unique_ptr<ObjectPaging> mObjectPaging;
std::unique_ptr<SkyManager> mSky;
std::unique_ptr<FogManager> mFog;
std::unique_ptr<ScreenshotManager> mScreenshotManager;
std::unique_ptr<EffectManager> mEffectManager;
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
osg::ref_ptr<NpcAnimation> mPlayerAnimation;

@ -0,0 +1,324 @@
#include "screenshotmanager.hpp"
#include <condition_variable>
#include <mutex>
#include <osg/ImageUtils>
#include <osg/ShapeDrawable>
#include <osg/Texture2D>
#include <osg/TextureCubeMap>
#include <components/misc/stringops.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/shader/shadermanager.hpp>
#include <components/settings/settings.hpp>
#include "../mwgui/loadingscreen.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "util.hpp"
#include "vismask.hpp"
#include "water.hpp"
namespace MWRender
{
enum Screenshot360Type
{
Spherical,
Cylindrical,
Planet,
RawCubemap
};
class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback
{
public:
NotifyDrawCompletedCallback(unsigned int frame)
: mDone(false), mFrame(frame)
{
}
void operator () (osg::RenderInfo& renderInfo) const override
{
std::lock_guard<std::mutex> lock(mMutex);
if (renderInfo.getState()->getFrameStamp()->getFrameNumber() >= mFrame)
{
mDone = true;
mCondition.notify_one();
}
}
void waitTillDone()
{
std::unique_lock<std::mutex> lock(mMutex);
if (mDone)
return;
mCondition.wait(lock);
}
mutable std::condition_variable mCondition;
mutable std::mutex mMutex;
mutable bool mDone;
unsigned int mFrame;
};
class ReadImageFromFramebufferCallback : public osg::Drawable::DrawCallback
{
public:
ReadImageFromFramebufferCallback(osg::Image* image, int width, int height)
: mWidth(width), mHeight(height), mImage(image)
{
}
void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* /*drawable*/) const override
{
int screenW = renderInfo.getCurrentCamera()->getViewport()->width();
int screenH = renderInfo.getCurrentCamera()->getViewport()->height();
double imageaspect = (double)mWidth/(double)mHeight;
int leftPadding = std::max(0, static_cast<int>(screenW - screenH * imageaspect) / 2);
int topPadding = std::max(0, static_cast<int>(screenH - screenW / imageaspect) / 2);
int width = screenW - leftPadding*2;
int height = screenH - topPadding*2;
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
mImage->scaleImage(mWidth, mHeight, 1);
}
private:
int mWidth;
int mHeight;
osg::ref_ptr<osg::Image> mImage;
};
ScreenshotManager::ScreenshotManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, osg::ref_ptr<osg::Group> sceneRoot, Resource::ResourceSystem* resourceSystem, Water* water)
: mViewer(viewer)
, mRootNode(rootNode)
, mSceneRoot(sceneRoot)
, mResourceSystem(resourceSystem)
, mWater(water)
{
}
void ScreenshotManager::screenshot(osg::Image* image, int w, int h)
{
osg::Camera* camera = mViewer->getCamera();
osg::ref_ptr<osg::Drawable> tempDrw = new osg::Drawable;
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
tempDrw->setCullingActive(false);
tempDrw->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin", osg::StateSet::USE_RENDERBIN_DETAILS); // so its after all scene bins but before POST_RENDER gui camera
camera->addChild(tempDrw);
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback(mViewer->getFrameStamp()->getFrameNumber()));
camera->setFinalDrawCallback(callback);
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
callback->waitTillDone();
// now that we've "used up" the current frame, get a fresh frame number for the next frame() following after the screenshot is completed
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
camera->removeChild(tempDrw);
camera->setFinalDrawCallback(nullptr);
}
bool ScreenshotManager::screenshot360(osg::Image* image)
{
int screenshotW = mViewer->getCamera()->getViewport()->width();
int screenshotH = mViewer->getCamera()->getViewport()->height();
Screenshot360Type screenshotMapping = Spherical;
const std::string& settingStr = Settings::Manager::getString("screenshot type", "Video");
std::vector<std::string> settingArgs;
Misc::StringUtils::split(settingStr, settingArgs);
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 = static_cast<Screenshot360Type>(i);
found = true;
break;
}
}
if (!found)
{
Log(Debug::Warning) << "Wrong screenshot type: " << settingArgs[0] << ".";
return false;
}
}
// planet mapping needs higher resolution
int cubeSize = screenshotMapping == Planet ? screenshotW : screenshotW / 2;
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()));
bool rawCubemap = screenshotMapping == RawCubemap;
if (rawCubemap)
screenshotW = cubeSize * 6; // the image will consist of 6 cube sides in a row
else if (screenshotMapping == Planet)
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 };
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();
makeCubemapScreenshot(sideImage, cubeSize, cubeSize, transform);
if (!rawCubemap)
sideImage->flipHorizontal();
}
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(nullptr);
screenshotCamera->addChild(quad);
renderCameraToImage(screenshotCamera, image, screenshotW, screenshotH);
return true;
}
void ScreenshotManager::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());
mRootNode->addChild(camera);
// The draw needs to complete before we can copy back our image.
osg::ref_ptr<NotifyDrawCompletedCallback> callback (new NotifyDrawCompletedCallback(0));
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());
camera->removeChildren(0, camera->getNumChildren());
mRootNode->removeChild(camera);
}
void ScreenshotManager::makeCubemapScreenshot(osg::Image *image, int w, int h, osg::Matrixd cameraTransform)
{
osg::ref_ptr<osg::Camera> rttCamera (new osg::Camera);
float nearClip = Settings::Manager::getFloat("near clip", "Camera");
float viewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
// each cubemap side sees 90 degrees
rttCamera->setProjectionMatrixAsPerspective(90.0, w/float(h), nearClip, viewDistance);
rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix() * cameraTransform);
rttCamera->setUpdateCallback(new NoTraverseCallback);
rttCamera->addChild(mSceneRoot);
rttCamera->addChild(mWater->getReflectionCamera());
rttCamera->addChild(mWater->getRefractionCamera());
rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI));
rttCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderCameraToImage(rttCamera.get(),image,w,h);
}
}

@ -0,0 +1,40 @@
#ifndef MWRENDER_SCREENSHOTMANAGER_H
#define MWRENDER_SCREENSHOTMANAGER_H
#include <memory>
#include <osg/Group>
#include <osg/ref_ptr>
#include <osgViewer/Viewer>
namespace Resource
{
class ResourceSystem;
}
namespace MWRender
{
class Water;
class ScreenshotManager
{
public:
ScreenshotManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, osg::ref_ptr<osg::Group> sceneRoot, Resource::ResourceSystem* resourceSystem, Water* water);
void screenshot(osg::Image* image, int w, int h);
bool screenshot360(osg::Image* image);
private:
osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osg::Group> mRootNode;
osg::ref_ptr<osg::Group> mSceneRoot;
Resource::ResourceSystem* mResourceSystem;
Water* mWater;
void renderCameraToImage(osg::Camera *camera, osg::Image *image, int w, int h);
void makeCubemapScreenshot(osg::Image* image, int w, int h, osg::Matrixd cameraTransform=osg::Matrixd());
};
}
#endif

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

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

Loading…
Cancel
Save