1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-02 00:45:32 +00:00

Basic functions in place. Still bad handling of GUI

This commit is contained in:
Mads Buvik Sandvei 2020-12-11 18:37:50 +01:00
commit d03f55bc2d
8 changed files with 215 additions and 88 deletions

View file

@ -755,19 +755,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
#ifdef USE_OPENXR
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer, mResourceSystem.get()));
//mViewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
#endif
if (!mSkipMenu)
{
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
if (!logo.empty())
window->playVideo(logo, true);
}
// VR mode will override this setting by setting mStereoOverride.
mStereoEnabled = mEnvironment.getVrMode() || Settings::Manager::getBool("stereo enabled", "Stereo");
@ -776,6 +763,23 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
if (mStereoEnabled)
{
mResourceSystem->getSceneManager()->getShaderManager().setStereoGeometryShaderEnabled(Misc::getStereoTechnique() == Misc::StereoView::Technique::GeometryShader_IndexedViewports);
// Mask in everything that does not currently use shaders.
// Remove that altogether when the sky finally uses them.
auto noShaderMask = MWRender::VisMask::Mask_Sky | MWRender::VisMask::Mask_Sun | MWRender::VisMask::Mask_WeatherParticles;
auto geometryShaderMask = mViewer->getCamera()->getCullMask() & ~noShaderMask;
mStereoView.reset(new Misc::StereoView(mViewer, Misc::getStereoTechnique(), geometryShaderMask, noShaderMask | MWRender::VisMask::Mask_Scene));
}
#ifdef USE_OPENXR
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer, mResourceSystem.get()));
mXrEnvironment.getViewer()->configureCallbacks();
#endif
if (!mSkipMenu)
{
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
if (!logo.empty())
window->playVideo(logo, true);
}
// Create the world
@ -787,11 +791,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Set up stereo
if (mStereoEnabled)
{
// Mask in everything that does not currently use shaders.
// Remove that altogether when the sky finally uses them.
auto noShaderMask = MWRender::VisMask::Mask_Sky | MWRender::VisMask::Mask_Sun | MWRender::VisMask::Mask_WeatherParticles;
auto geometryShaderMask = mViewer->getCamera()->getCullMask() & ~noShaderMask;
mStereoView = new Misc::StereoView(mViewer, Misc::getStereoTechnique(), geometryShaderMask, noShaderMask | MWRender::VisMask::Mask_Scene);
mStereoView->initializeScene();
}
window->setStore(mEnvironment.getWorld()->getStore());

View file

@ -97,7 +97,7 @@ namespace OMW
bool mStereoEnabled;
bool mStereoOverride;
osg::ref_ptr<Misc::StereoView> mStereoView;
std::unique_ptr<Misc::StereoView> mStereoView;
bool mSkipMenu;
bool mUseSound;

View file

@ -97,7 +97,6 @@ namespace MWVR {
void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc)
{
acquire();
renderBuffer()->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
}
int swapCount = 0;

View file

@ -187,22 +187,29 @@ namespace MWVR
getFrame(FramePhase::Swap) = nullptr;
}
mCondition.notify_one();
mCondition.notify_all();
}
void VRSession::beginPhase(FramePhase phase)
{
Log(Debug::Debug) << "beginPhase(" << ((int)phase) << ") " << std::this_thread::get_id();
auto& frame = getFrame(phase);
if (frame)
{
// Happens once during startup but can be ignored that time.
// TODO: This issue would be cleaned up if beginPhase(Update) was called at a more appropriate location.
Log(Debug::Warning) << "advanceFramePhase called with a frame alreay in the target phase";
return;
std::unique_lock<std::mutex> lock(mMutex);
while (getFrame(phase))
mCondition.wait(lock);
}
mCondition.notify_all();
auto& frame = getFrame(phase);
//if (frame)
//{
// // Happens once during startup but can be ignored that time.
// // TODO: This issue would be cleaned up if beginPhase(Update) was called at a more appropriate location.
// Log(Debug::Warning) << "advanceFramePhase called with a frame alreay in the target phase";
// return;
//}
if (phase == FramePhase::Update)
{
@ -216,6 +223,7 @@ namespace MWVR
throw std::logic_error("beginPhase called without a frame");
frame = std::move(getFrame(previousPhase));
}
if (phase == mXrSyncPhase && frame->mShouldSyncFrameLoop)
{
// We may reach this point before xrEndFrame of the previous frame
@ -228,6 +236,8 @@ namespace MWVR
Environment::get().getManager()->beginFrame();
}
mCondition.notify_all();
}
std::unique_ptr<VRSession::VRFrameMeta>& VRSession::getFrame(FramePhase phase)

View file

@ -14,6 +14,9 @@
#include <components/sceneutil/mwshadowtechnique.hpp>
#include <components/misc/stringops.hpp>
#include <components/misc/stereo.hpp>
#include <components/sdlutil/sdlgraphicswindow.hpp>
namespace MWVR
{
@ -39,7 +42,8 @@ namespace MWVR
: mViewer(viewer)
, mPreDraw(new PredrawCallback(this))
, mPostDraw(new PostdrawCallback(this))
, mConfigured(false)
, mOpenXRConfigured(false)
, mCallbacksConfigured(false)
, mMsaaResolveMirrorTexture{}
, mMirrorTexture{ nullptr }
{
@ -90,19 +94,6 @@ namespace MWVR
return VRViewer::MirrorTextureEye::Both;
}
void VRViewer::InitialDrawCallback::operator()(osg::RenderInfo& renderInfo) const
{
Environment::get().getSession()->beginPhase(VRSession::FramePhase::Draw);
osg::GraphicsOperation* graphicsOperation = renderInfo.getCurrentCamera()->getRenderer();
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(graphicsOperation);
if (renderer != nullptr)
{
// Disable normal OSG FBO camera setup
renderer->setCameraRequiresSetUp(false);
}
}
class CullCallback : public osg::NodeCallback
{
void operator()(osg::Node* node, osg::NodeVisitor* nv)
@ -112,19 +103,15 @@ namespace MWVR
}
};
void VRViewer::realize(osg::GraphicsContext* context)
void VRViewer::configureXR(osg::GraphicsContext* context)
{
std::unique_lock<std::mutex> lock(mMutex);
if (mConfigured)
if (mOpenXRConfigured)
{
return;
}
// Give the main camera an initial draw callback that disables camera setup (we don't want it)
auto mainCamera = mViewer->getCamera();
mainCamera->setName("Main");
mainCamera->setInitialDrawCallback(new InitialDrawCallback());
auto* xr = Environment::get().getManager();
xr->realize(context);
@ -185,16 +172,25 @@ namespace MWVR
mSubImages[0].swapchain = mSubImages[1].swapchain = mSwapchain.get();
mViewer->setReleaseContextAtEndOfFrameHint(false);
mViewer->getCamera()->getGraphicsContext()->setSwapCallback(new VRViewer::SwapBuffersCallback(this));
setupMirrorTexture();
Log(Debug::Verbose) << "XR configured";
mOpenXRConfigured = true;
}
mainCamera->getGraphicsContext()->setSwapCallback(new VRViewer::SwapBuffersCallback(this));
mainCamera->setPreDrawCallback(mPreDraw);
mainCamera->setPostDrawCallback(mPostDraw);
mainCamera->setCullCallback(new CullCallback);
mConfigured = true;
void VRViewer::configureCallbacks()
{
if (mCallbacksConfigured)
return;
Log(Debug::Verbose) << "Realized";
// Give the main camera an initial draw callback that disables camera setup (we don't want it)
Misc::StereoView::instance().setInitialDrawCallback(new InitialDrawCallback(this));
Misc::StereoView::instance().setPredrawCallback(mPreDraw);
Misc::StereoView::instance().setPostdrawCallback(mPostDraw);
Misc::StereoView::instance().setCullCallback(new CullCallback);
mCallbacksConfigured = true;
}
void VRViewer::setupMirrorTexture()
@ -254,9 +250,9 @@ namespace MWVR
if (!mMirrorTextureEnabled)
return;
auto* camera = mViewer->getCamera();
int screenWidth = camera->getGraphicsContext()->getTraits()->width;
int screenHeight = camera->getGraphicsContext()->getTraits()->height;
auto* traits = SDLUtil::GraphicsWindowSDL2::findContext(*mViewer)->getTraits();
int screenWidth = traits->width;
int screenHeight = traits->height;
if (!mMirrorTexture)
{
;
@ -307,20 +303,35 @@ namespace MWVR
RealizeOperation::operator()(
osg::GraphicsContext* gc)
{
return Environment::get().getViewer()->realize(gc);
return Environment::get().getViewer()->configureXR(gc);
}
bool
RealizeOperation::realized()
{
return Environment::get().getViewer()->realized();
return Environment::get().getViewer()->xrConfigured();
}
void VRViewer::initialDrawCallback(osg::RenderInfo& info)
{
Environment::get().getSession()->beginPhase(VRSession::FramePhase::Draw);
if (Environment::get().getSession()->getFrame(VRSession::FramePhase::Draw)->mShouldRender)
mSwapchain->beginFrame(info.getState()->getGraphicsContext());
mViewer->getCamera()->setViewport(0, 0, mSwapchainConfig.selectedWidth, mSwapchainConfig.selectedHeight);
osg::GraphicsOperation* graphicsOperation = info.getCurrentCamera()->getRenderer();
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(graphicsOperation);
if (renderer != nullptr)
{
// Disable normal OSG FBO camera setup
renderer->setCameraRequiresSetUp(false);
}
}
void VRViewer::preDrawCallback(osg::RenderInfo& info)
{
if(Environment::get().getSession()->getFrame(VRSession::FramePhase::Draw)->mShouldRender)
mSwapchain->beginFrame(info.getState()->getGraphicsContext());
mViewer->getCamera()->setViewport(0, 0, mSwapchainConfig.selectedWidth, mSwapchainConfig.selectedHeight);
if (Environment::get().getSession()->getFrame(VRSession::FramePhase::Draw)->mShouldRender)
mSwapchain->renderBuffer()->bindFramebuffer(info.getState()->getGraphicsContext(), GL_FRAMEBUFFER_EXT);
}
void VRViewer::postDrawCallback(osg::RenderInfo& info)
@ -336,4 +347,7 @@ namespace MWVR
Log(Debug::Warning) << ("osg overwrote predraw");
}
}
VRViewer::InitialDrawCallback::~InitialDrawCallback()
{
}
}

View file

@ -68,7 +68,17 @@ namespace MWVR
class InitialDrawCallback : public osg::Camera::DrawCallback
{
public:
virtual void operator()(osg::RenderInfo& renderInfo) const;
InitialDrawCallback(VRViewer* viewer)
: mViewer(viewer)
{}
~InitialDrawCallback();
void operator()(osg::RenderInfo& info) const override { mViewer->initialDrawCallback(info); };
private:
VRViewer* mViewer;
};
static const std::array<const char*, 2> sViewNames;
@ -86,19 +96,24 @@ namespace MWVR
~VRViewer(void);
void traversals();
void initialDrawCallback(osg::RenderInfo& info);
void preDrawCallback(osg::RenderInfo& info);
void postDrawCallback(osg::RenderInfo& info);
void blitEyesToMirrorTexture(osg::GraphicsContext* gc);
void realize(osg::GraphicsContext* gc);
bool realized() { return mConfigured; }
void configureXR(osg::GraphicsContext* gc);
void configureCallbacks();
void setupMirrorTexture();
void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed);
SubImage subImage(Side side);
bool xrConfigured() { return mOpenXRConfigured; };
bool callbacksConfigured() { return mCallbacksConfigured; };
private:
std::mutex mMutex{};
bool mConfigured{ false };
bool mOpenXRConfigured{ false };
bool mCallbacksConfigured{ false };
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };

View file

@ -9,6 +9,8 @@
#include <osgViewer/Viewer>
#include <iostream>
#include <map>
#include <string>
#include <components/debug/debuglog.hpp>
@ -225,11 +227,18 @@ namespace Misc
StereoView* stereoView;
};
StereoView* sInstance = nullptr;
StereoView& StereoView::instance()
{
return *sInstance;
}
StereoView::StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask geometryShaderMask, osg::Node::NodeMask noShaderMask)
: osg::Group()
, mViewer(viewer)
: mViewer(viewer)
, mMainCamera(mViewer->getCamera())
, mRoot(viewer->getSceneData()->asGroup())
, mRoot(mViewer->getSceneData()->asGroup())
, mStereoRoot(new osg::Group)
, mTechnique(technique)
, mGeometryShaderMask(geometryShaderMask)
, mNoShaderMask(noShaderMask)
@ -241,20 +250,13 @@ namespace Misc
// Do nothing
return;
mRoot->setDataVariance(osg::Object::STATIC);
mMasterConfig->_id = "STEREO";
mMasterConfig->_master = true;
mSlaveConfig->_id = "STEREO";
mSlaveConfig->_master = false;
SceneUtil::FindByNameVisitor findScene("Scene Root");
mRoot->accept(findScene);
mScene = findScene.mFoundNode;
if (!mScene)
throw std::logic_error("Couldn't find scene root");
setName("Stereo Root");
mRoot->setDataVariance(osg::Object::STATIC);
setDataVariance(osg::Object::STATIC);
mLeftCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
mLeftCamera->setProjectionResizePolicy(osg::Camera::FIXED);
mLeftCamera->setProjectionMatrix(osg::Matrix::identity());
@ -287,6 +289,10 @@ namespace Misc
{
setupBruteForceTechnique();
}
if (sInstance)
throw std::logic_error("Double instance og StereoView");
sInstance = this;
}
void StereoView::setupBruteForceTechnique()
@ -302,8 +308,8 @@ namespace Misc
if (mSharedShadowMaps)
{
mLeftCamera->setUserData(mMasterConfig);
mRightCamera->setUserData(mSlaveConfig);
mLeftCamera->setUserData(mSlaveConfig);
mRightCamera->setUserData(mMasterConfig);
}
// Slave cameras must have their viewports defined immediately
@ -313,8 +319,8 @@ namespace Misc
mRightCamera->setViewport(width / 2, 0, width / 2, height);
mViewer->stopThreading();
mViewer->addSlave(mLeftCamera, true);
mViewer->addSlave(mRightCamera, true);
mViewer->addSlave(mLeftCamera, true);
mRightCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext());
mLeftCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext());
mViewer->getCamera()->setGraphicsContext(nullptr);
@ -331,18 +337,18 @@ namespace Misc
mRightCamera->setCullMask(mNoShaderMask);
mMainCamera->setCullMask(mGeometryShaderMask);
addChild(mStereoGeometryShaderRoot);
mStereoGeometryShaderRoot->addChild(mRoot);
addChild(mStereoBruteForceRoot);
mStereoRoot->setName("Stereo Root");
mStereoRoot->setDataVariance(osg::Object::STATIC);
mStereoRoot->addChild(mStereoGeometryShaderRoot);
mStereoRoot->addChild(mStereoBruteForceRoot);
mStereoBruteForceRoot->addChild(mLeftCamera);
mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation.
mStereoBruteForceRoot->addChild(mRightCamera);
mRightCamera->addChild(mScene);
addCullCallback(new StereoStatesetUpdateCallback(this));
mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this));
// Inject self as the root of the scene graph
mViewer->setSceneData(this);
mStereoGeometryShaderRoot->addChild(mRoot);
mViewer->setSceneData(mStereoRoot);
}
void StereoView::update()
@ -494,6 +500,21 @@ namespace Misc
cb = cb_;
}
void StereoView::initializeScene()
{
SceneUtil::FindByNameVisitor findScene("Scene Root");
mRoot->accept(findScene);
mScene = findScene.mFoundNode;
if (!mScene)
throw std::logic_error("Couldn't find scene root");
if (mTechnique == Technique::GeometryShader_IndexedViewports)
{
mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation.
mRightCamera->addChild(mScene);
}
}
void disableStereoForCamera(osg::Camera* camera)
{
auto* viewport = camera->getViewport();
@ -553,4 +574,54 @@ namespace Misc
near = 1;
far = 6656;
}
void StereoView::setInitialDrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
{
if (mTechnique == Technique::GeometryShader_IndexedViewports)
{
mMainCamera->setInitialDrawCallback(cb);
}
else
{
mRightCamera->setInitialDrawCallback(cb);
}
}
void StereoView::setPredrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
{
if (mTechnique == Technique::GeometryShader_IndexedViewports)
{
mMainCamera->setPreDrawCallback(cb);
}
else
{
mLeftCamera->setPreDrawCallback(cb);
mRightCamera->setPreDrawCallback(cb);
}
}
void StereoView::setPostdrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
{
if (mTechnique == Technique::GeometryShader_IndexedViewports)
{
mMainCamera->setPostDrawCallback(cb);
}
else
{
mLeftCamera->setPostDrawCallback(cb);
mRightCamera->setPostDrawCallback(cb);
}
}
void StereoView::setCullCallback(osg::ref_ptr<osg::NodeCallback> cb)
{
if (mTechnique == Technique::GeometryShader_IndexedViewports)
{
mMainCamera->setCullCallback(cb);
}
else
{
mRightCamera->setCullCallback(cb);
}
}
}

View file

@ -68,7 +68,7 @@ namespace Misc
};
//! Represent two eyes. The eyes are in relative terms, and are assumed to lie on the horizon plane.
struct StereoView : public osg::Group
struct StereoView
{
struct UpdateViewCallback
{
@ -89,6 +89,8 @@ namespace Misc
GeometryShader_IndexedViewports, //!< Frustum camera culls and draws stereo into indexed viewports using an automatically generated geometry shader.
};
static StereoView& instance();
//! Adds two cameras in stereo to the mainCamera.
//! All nodes matching the mask are rendered in stereo using brute force via two camera transforms, the rest are rendered in stereo via a geometry shader.
//! \param geometryShaderMask should mask in all nodes that use shaders.
@ -101,9 +103,24 @@ namespace Misc
void update();
void updateStateset(osg::StateSet* stateset);
//! Initialized scene. Call when the "scene root" node has been created
void initializeScene();
//! Callback that updates stereo configuration during the update pass
void setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb);
//! Set the initial draw callback on the appropriate camera object
void setInitialDrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb);
//! Set the predraw callback on the appropriate camera object
void setPredrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb);
//! Set the postdraw callback on the appropriate camera object
void setPostdrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb);
//! Set the cull callback on the appropriate camera object
void setCullCallback(osg::ref_ptr<osg::NodeCallback> cb);
private:
void setupBruteForceTechnique();
void setupGeometryShaderIndexedViewportTechnique();
@ -112,6 +129,7 @@ namespace Misc
osg::ref_ptr<osg::Camera> mMainCamera;
osg::ref_ptr<osg::Group> mRoot;
osg::ref_ptr<osg::Group> mScene;
osg::ref_ptr<osg::Group> mStereoRoot;
Technique mTechnique;
// Keeps state relevant to doing stereo via the geometry shader