diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 06f180310e..990db6ac38 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -595,7 +595,63 @@ void OMW::Engine::createWindow() realizeOperations->add(mSelectColorFormatOperation); if (Stereo::getStereo()) - realizeOperations->add(new Stereo::InitializeStereoOperation()); + { + Stereo::Settings settings; + + settings.mMultiview = Settings::stereo().mMultiview; + settings.mAllowDisplayListsForMultiview = Settings::stereo().mAllowDisplayListsForMultiview; + settings.mSharedShadowMaps = Settings::stereo().mSharedShadowMaps; + + if (Settings::stereo().mUseCustomView) + { + const osg::Vec3 leftEyeOffset(Settings::stereoView().mLeftEyeOffsetX, + Settings::stereoView().mLeftEyeOffsetY, Settings::stereoView().mLeftEyeOffsetZ); + + const osg::Quat leftEyeOrientation(Settings::stereoView().mLeftEyeOrientationX, + Settings::stereoView().mLeftEyeOrientationY, Settings::stereoView().mLeftEyeOrientationZ, + Settings::stereoView().mLeftEyeOrientationW); + + const osg::Vec3 rightEyeOffset(Settings::stereoView().mRightEyeOffsetX, + Settings::stereoView().mRightEyeOffsetY, Settings::stereoView().mRightEyeOffsetZ); + + const osg::Quat rightEyeOrientation(Settings::stereoView().mRightEyeOrientationX, + Settings::stereoView().mRightEyeOrientationY, Settings::stereoView().mRightEyeOrientationZ, + Settings::stereoView().mRightEyeOrientationW); + + settings.mCustomView = Stereo::CustomView{ + .mLeft = Stereo::View{ + .pose = Stereo::Pose{ + .position = leftEyeOffset, + .orientation = leftEyeOrientation, + }, + .fov = Stereo::FieldOfView{ + .angleLeft = Settings::stereoView().mLeftEyeFovLeft, + .angleRight = Settings::stereoView().mLeftEyeFovRight, + .angleUp = Settings::stereoView().mLeftEyeFovUp, + .angleDown = Settings::stereoView().mLeftEyeFovDown, + }, + }, + .mRight = Stereo::View{ + .pose = Stereo::Pose{ + .position = rightEyeOffset, + .orientation = rightEyeOrientation, + }, + .fov = Stereo::FieldOfView{ + .angleLeft = Settings::stereoView().mRightEyeFovLeft, + .angleRight = Settings::stereoView().mRightEyeFovRight, + .angleUp = Settings::stereoView().mRightEyeFovUp, + .angleDown = Settings::stereoView().mRightEyeFovDown, + }, + }, + }; + } + + if (Settings::stereo().mUseCustomEyeResolution) + settings.mEyeResolution + = osg::Vec2i(Settings::stereoView().mEyeResolutionX, Settings::stereoView().mEyeResolutionY); + + realizeOperations->add(new Stereo::InitializeStereoOperation(settings)); + } mViewer->realize(); mGlMaxTextureImageUnits = identifyOp->getMaxTextureImageUnits(); @@ -634,8 +690,7 @@ void OMW::Engine::prepareEngine() mStateManager = std::make_unique(mCfgMgr.getUserDataPath() / "saves", mContentFiles); mEnvironment.setStateManager(*mStateManager); - bool stereoEnabled - = Settings::Manager::getBool("stereo enabled", "Stereo") || osg::DisplaySettings::instance().get()->getStereo(); + const bool stereoEnabled = Settings::stereo().mStereoEnabled || osg::DisplaySettings::instance().get()->getStereo(); mStereoManager = std::make_unique( mViewer, stereoEnabled, Settings::camera().mNearClip, Settings::camera().mViewingDistance); diff --git a/components/settings/categories/stereoview.hpp b/components/settings/categories/stereoview.hpp index 1e9d35ace8..bcd0f57abc 100644 --- a/components/settings/categories/stereoview.hpp +++ b/components/settings/categories/stereoview.hpp @@ -31,14 +31,14 @@ namespace Settings makeClampSanitizerDouble(-1, 1) }; SettingValue mLeftEyeOrientationW{ mIndex, "Stereo View", "left eye orientation w", makeClampSanitizerDouble(-1, 1) }; - SettingValue mLeftEyeFovLeft{ mIndex, "Stereo View", "left eye fov left", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; - SettingValue mLeftEyeFovRight{ mIndex, "Stereo View", "left eye fov right", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; - SettingValue mLeftEyeFovUp{ mIndex, "Stereo View", "left eye fov up", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; - SettingValue mLeftEyeFovDown{ mIndex, "Stereo View", "left eye fov down", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; + SettingValue mLeftEyeFovLeft{ mIndex, "Stereo View", "left eye fov left", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; + SettingValue mLeftEyeFovRight{ mIndex, "Stereo View", "left eye fov right", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; + SettingValue mLeftEyeFovUp{ mIndex, "Stereo View", "left eye fov up", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; + SettingValue mLeftEyeFovDown{ mIndex, "Stereo View", "left eye fov down", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; SettingValue mRightEyeOffsetX{ mIndex, "Stereo View", "right eye offset x" }; SettingValue mRightEyeOffsetY{ mIndex, "Stereo View", "right eye offset y" }; SettingValue mRightEyeOffsetZ{ mIndex, "Stereo View", "right eye offset z" }; @@ -50,14 +50,14 @@ namespace Settings makeClampSanitizerDouble(-1, 1) }; SettingValue mRightEyeOrientationW{ mIndex, "Stereo View", "right eye orientation w", makeClampSanitizerDouble(-1, 1) }; - SettingValue mRightEyeFovLeft{ mIndex, "Stereo View", "right eye fov left", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; - SettingValue mRightEyeFovRight{ mIndex, "Stereo View", "right eye fov right", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; - SettingValue mRightEyeFovUp{ mIndex, "Stereo View", "right eye fov up", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; - SettingValue mRightEyeFovDown{ mIndex, "Stereo View", "right eye fov down", - makeClampSanitizerDouble(-osg::PI, osg::PI) }; + SettingValue mRightEyeFovLeft{ mIndex, "Stereo View", "right eye fov left", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; + SettingValue mRightEyeFovRight{ mIndex, "Stereo View", "right eye fov right", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; + SettingValue mRightEyeFovUp{ mIndex, "Stereo View", "right eye fov up", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; + SettingValue mRightEyeFovDown{ mIndex, "Stereo View", "right eye fov down", + makeClampSanitizerFloat(-osg::PIf, osg::PIf) }; }; } diff --git a/components/stereo/frustum.cpp b/components/stereo/frustum.cpp index cf8a7e8c30..a35beba7dd 100644 --- a/components/stereo/frustum.cpp +++ b/components/stereo/frustum.cpp @@ -85,7 +85,7 @@ namespace Stereo } } - StereoFrustumManager::StereoFrustumManager(osg::Camera* camera) + StereoFrustumManager::StereoFrustumManager(bool sharedShadowMaps, osg::Camera* camera) : mCamera(camera) , mShadowTechnique(nullptr) , mShadowFrustumCallback(nullptr) @@ -95,7 +95,7 @@ namespace Stereo mMultiviewFrustumCallback = std::make_unique(this, camera); } - if (Settings::Manager::getBool("shared shadow maps", "Stereo")) + if (sharedShadowMaps) { mShadowFrustumCallback = new ShadowFrustumCallback(this); auto* renderer = static_cast(mCamera->getRenderer()); diff --git a/components/stereo/frustum.hpp b/components/stereo/frustum.hpp index c3abdd87d2..35e3adf95a 100644 --- a/components/stereo/frustum.hpp +++ b/components/stereo/frustum.hpp @@ -45,7 +45,7 @@ namespace Stereo class StereoFrustumManager { public: - StereoFrustumManager(osg::Camera* camera); + StereoFrustumManager(bool sharedShadowMaps, osg::Camera* camera); ~StereoFrustumManager(); void update(std::array projections); diff --git a/components/stereo/multiview.cpp b/components/stereo/multiview.cpp index 047a52747b..a2f6cfd626 100644 --- a/components/stereo/multiview.cpp +++ b/components/stereo/multiview.cpp @@ -124,12 +124,12 @@ namespace Stereo } } - void setVertexBufferHint(bool enableMultiview) + void setVertexBufferHint(bool enableMultiview, bool allowDisplayListsForMultiview) { if (getStereo() && enableMultiview) { auto* ds = osg::DisplaySettings::instance().get(); - if (!Settings::Manager::getBool("allow display lists for multiview", "Stereo") + if (!allowDisplayListsForMultiview && ds->getVertexBufferHint() == osg::DisplaySettings::VertexBufferHint::NO_PREFERENCE) { // Note that this only works if this code is executed before realize() is called on the viewer. diff --git a/components/stereo/multiview.hpp b/components/stereo/multiview.hpp index fa69afc7a1..a9d84eae85 100644 --- a/components/stereo/multiview.hpp +++ b/components/stereo/multiview.hpp @@ -37,7 +37,7 @@ namespace Stereo void configureExtensions(unsigned int contextID, bool enableMultiview); //! Sets the appropriate vertex buffer hint on OSG's display settings if needed - void setVertexBufferHint(bool enableMultiview); + void setVertexBufferHint(bool enableMultiview, bool allowDisplayListsForMultiview); //! Creates a Texture2D as a texture view into a Texture2DArray osg::ref_ptr createTextureView_Texture2DFromTexture2DArray( diff --git a/components/stereo/stereomanager.cpp b/components/stereo/stereomanager.cpp index b7023095d2..29de9d0bb0 100644 --- a/components/stereo/stereomanager.cpp +++ b/components/stereo/stereomanager.cpp @@ -134,13 +134,13 @@ namespace Stereo Manager::~Manager() {} - void Manager::initializeStereo(osg::GraphicsContext* gc, bool enableMultiview) + void Manager::initializeStereo(osg::GraphicsContext* gc, bool enableMultiview, bool sharedShadowMaps) { auto ci = gc->getState()->getContextID(); configureExtensions(ci, enableMultiview); mMainCamera->addUpdateCallback(mUpdateCallback); - mFrustumManager = std::make_unique(mViewer->getCamera()); + mFrustumManager = std::make_unique(sharedShadowMaps, mViewer->getCamera()); if (getMultiview()) setupOVRMultiView2Technique(); @@ -393,60 +393,30 @@ namespace Stereo right = mRight; } - InitializeStereoOperation::InitializeStereoOperation() + InitializeStereoOperation::InitializeStereoOperation(const Settings& settings) : GraphicsOperation("InitializeStereoOperation", false) + , mMultiview(settings.mMultiview) + , mSharedShadowMaps(settings.mSharedShadowMaps) + , mCustomView(settings.mCustomView) + , mEyeResolution(settings.mEyeResolution) { // Ideally, this would have belonged to the operator(). But the vertex buffer // hint has to be set before realize is called on the osg viewer, and so has to // be done here instead. - Stereo::setVertexBufferHint(Settings::Manager::getBool("multiview", "Stereo")); + Stereo::setVertexBufferHint(settings.mMultiview, settings.mAllowDisplayListsForMultiview); } void InitializeStereoOperation::operator()(osg::GraphicsContext* graphicsContext) { auto& sm = Stereo::Manager::instance(); - if (Settings::Manager::getBool("use custom view", "Stereo")) - { - Stereo::View left; - Stereo::View right; - - left.pose.position.x() = Settings::Manager::getDouble("left eye offset x", "Stereo View"); - left.pose.position.y() = Settings::Manager::getDouble("left eye offset y", "Stereo View"); - left.pose.position.z() = Settings::Manager::getDouble("left eye offset z", "Stereo View"); - left.pose.orientation.x() = Settings::Manager::getDouble("left eye orientation x", "Stereo View"); - left.pose.orientation.y() = Settings::Manager::getDouble("left eye orientation y", "Stereo View"); - left.pose.orientation.z() = Settings::Manager::getDouble("left eye orientation z", "Stereo View"); - left.pose.orientation.w() = Settings::Manager::getDouble("left eye orientation w", "Stereo View"); - left.fov.angleLeft = Settings::Manager::getDouble("left eye fov left", "Stereo View"); - left.fov.angleRight = Settings::Manager::getDouble("left eye fov right", "Stereo View"); - left.fov.angleUp = Settings::Manager::getDouble("left eye fov up", "Stereo View"); - left.fov.angleDown = Settings::Manager::getDouble("left eye fov down", "Stereo View"); - - right.pose.position.x() = Settings::Manager::getDouble("right eye offset x", "Stereo View"); - right.pose.position.y() = Settings::Manager::getDouble("right eye offset y", "Stereo View"); - right.pose.position.z() = Settings::Manager::getDouble("right eye offset z", "Stereo View"); - right.pose.orientation.x() = Settings::Manager::getDouble("right eye orientation x", "Stereo View"); - right.pose.orientation.y() = Settings::Manager::getDouble("right eye orientation y", "Stereo View"); - right.pose.orientation.z() = Settings::Manager::getDouble("right eye orientation z", "Stereo View"); - right.pose.orientation.w() = Settings::Manager::getDouble("right eye orientation w", "Stereo View"); - right.fov.angleLeft = Settings::Manager::getDouble("right eye fov left", "Stereo View"); - right.fov.angleRight = Settings::Manager::getDouble("right eye fov right", "Stereo View"); - right.fov.angleUp = Settings::Manager::getDouble("right eye fov up", "Stereo View"); - right.fov.angleDown = Settings::Manager::getDouble("right eye fov down", "Stereo View"); - - auto customViewCallback = std::make_shared(left, right); - sm.setUpdateViewCallback(customViewCallback); - } + if (mCustomView.has_value()) + sm.setUpdateViewCallback( + std::make_shared(mCustomView->mLeft, mCustomView->mRight)); - if (Settings::Manager::getBool("use custom eye resolution", "Stereo")) - { - osg::Vec2i eyeResolution = osg::Vec2i(); - eyeResolution.x() = Settings::Manager::getInt("eye resolution x", "Stereo View"); - eyeResolution.y() = Settings::Manager::getInt("eye resolution y", "Stereo View"); - sm.overrideEyeResolution(eyeResolution); - } + if (mEyeResolution.has_value()) + sm.overrideEyeResolution(*mEyeResolution); - sm.initializeStereo(graphicsContext, Settings::Manager::getBool("multiview", "Stereo")); + sm.initializeStereo(graphicsContext, mMultiview, mSharedShadowMaps); } } diff --git a/components/stereo/stereomanager.hpp b/components/stereo/stereomanager.hpp index 40bb9fd10c..8ed88da550 100644 --- a/components/stereo/stereomanager.hpp +++ b/components/stereo/stereomanager.hpp @@ -92,7 +92,7 @@ namespace Stereo //! Initializes all details of stereo if applicable. If the constructor was called with enableMultiview=true, //! and the GL_OVR_Multiview extension is supported, Stereo::getMultiview() will return true after this call. - void initializeStereo(osg::GraphicsContext* gc, bool enableMultiview); + void initializeStereo(osg::GraphicsContext* gc, bool enableMultiview, bool sharedShadowMaps); //! Callback that updates stereo configuration during the update pass void setUpdateViewCallback(std::shared_ptr cb); @@ -163,13 +163,34 @@ namespace Stereo osg::ref_ptr mIdentifierRight = new Identifier(); }; + struct CustomView + { + Stereo::View mLeft; + Stereo::View mRight; + }; + + struct Settings + { + bool mMultiview; + bool mAllowDisplayListsForMultiview; + bool mSharedShadowMaps; + std::optional mCustomView; + std::optional mEyeResolution; + }; + //! Performs stereo-specific initialization operations. class InitializeStereoOperation final : public osg::GraphicsOperation { public: - InitializeStereoOperation(); + explicit InitializeStereoOperation(const Settings& settings); void operator()(osg::GraphicsContext* graphicsContext) override; + + private: + bool mMultiview; + bool mSharedShadowMaps; + std::optional mCustomView; + std::optional mEyeResolution; }; }