mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 05:19:55 +00:00
More refactoring/cleanup
This commit is contained in:
parent
1cf97fd7ad
commit
df45ee1690
19 changed files with 253 additions and 230 deletions
|
@ -32,7 +32,7 @@ bool OpenXRAction::getFloat(XrPath subactionPath, float& value)
|
||||||
getInfo.subactionPath = subactionPath;
|
getInfo.subactionPath = subactionPath;
|
||||||
|
|
||||||
XrActionStateFloat xrValue{ XR_TYPE_ACTION_STATE_FLOAT };
|
XrActionStateFloat xrValue{ XR_TYPE_ACTION_STATE_FLOAT };
|
||||||
CHECK_XRCMD(xrGetActionStateFloat(xr->impl().mSession, &getInfo, &xrValue));
|
CHECK_XRCMD(xrGetActionStateFloat(xr->impl().xrSession(), &getInfo, &xrValue));
|
||||||
|
|
||||||
if (xrValue.isActive)
|
if (xrValue.isActive)
|
||||||
value = xrValue.currentState;
|
value = xrValue.currentState;
|
||||||
|
@ -47,7 +47,7 @@ bool OpenXRAction::getBool(XrPath subactionPath, bool& value)
|
||||||
getInfo.subactionPath = subactionPath;
|
getInfo.subactionPath = subactionPath;
|
||||||
|
|
||||||
XrActionStateBoolean xrValue{ XR_TYPE_ACTION_STATE_BOOLEAN };
|
XrActionStateBoolean xrValue{ XR_TYPE_ACTION_STATE_BOOLEAN };
|
||||||
CHECK_XRCMD(xrGetActionStateBoolean(xr->impl().mSession, &getInfo, &xrValue));
|
CHECK_XRCMD(xrGetActionStateBoolean(xr->impl().xrSession(), &getInfo, &xrValue));
|
||||||
|
|
||||||
if (xrValue.isActive)
|
if (xrValue.isActive)
|
||||||
value = xrValue.currentState;
|
value = xrValue.currentState;
|
||||||
|
@ -63,7 +63,7 @@ bool OpenXRAction::getPoseIsActive(XrPath subactionPath)
|
||||||
getInfo.subactionPath = subactionPath;
|
getInfo.subactionPath = subactionPath;
|
||||||
|
|
||||||
XrActionStatePose xrValue{ XR_TYPE_ACTION_STATE_POSE };
|
XrActionStatePose xrValue{ XR_TYPE_ACTION_STATE_POSE };
|
||||||
CHECK_XRCMD(xrGetActionStatePose(xr->impl().mSession, &getInfo, &xrValue));
|
CHECK_XRCMD(xrGetActionStatePose(xr->impl().xrSession(), &getInfo, &xrValue));
|
||||||
|
|
||||||
return xrValue.isActive;
|
return xrValue.isActive;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ bool OpenXRAction::applyHaptics(XrPath subactionPath, float amplitude)
|
||||||
XrHapticActionInfo hapticActionInfo{ XR_TYPE_HAPTIC_ACTION_INFO };
|
XrHapticActionInfo hapticActionInfo{ XR_TYPE_HAPTIC_ACTION_INFO };
|
||||||
hapticActionInfo.action = mAction;
|
hapticActionInfo.action = mAction;
|
||||||
hapticActionInfo.subactionPath = subactionPath;
|
hapticActionInfo.subactionPath = subactionPath;
|
||||||
CHECK_XRCMD(xrApplyHapticFeedback(xr->impl().mSession, &hapticActionInfo, (XrHapticBaseHeader*)&vibration));
|
CHECK_XRCMD(xrApplyHapticFeedback(xr->impl().xrSession(), &hapticActionInfo, (XrHapticBaseHeader*)&vibration));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ OpenXRInput::OpenXRInput(const std::vector<SuggestedBindings>& suggestedBindings
|
||||||
XrSessionActionSetsAttachInfo attachInfo{ XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO };
|
XrSessionActionSetsAttachInfo attachInfo{ XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO };
|
||||||
attachInfo.countActionSets = 1;
|
attachInfo.countActionSets = 1;
|
||||||
attachInfo.actionSets = &mActionSet;
|
attachInfo.actionSets = &mActionSet;
|
||||||
CHECK_XRCMD(xrAttachSessionActionSets(xr->impl().mSession, &attachInfo));
|
CHECK_XRCMD(xrAttachSessionActionSets(xr->impl().xrSession(), &attachInfo));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ OpenXRInput::createActionSet()
|
||||||
strcpy_s(createInfo.actionSetName, "gameplay");
|
strcpy_s(createInfo.actionSetName, "gameplay");
|
||||||
strcpy_s(createInfo.localizedActionSetName, "Gameplay");
|
strcpy_s(createInfo.localizedActionSetName, "Gameplay");
|
||||||
createInfo.priority = 0;
|
createInfo.priority = 0;
|
||||||
CHECK_XRCMD(xrCreateActionSet(xr->impl().mInstance, &createInfo, &actionSet));
|
CHECK_XRCMD(xrCreateActionSet(xr->impl().xrInstance(), &createInfo, &actionSet));
|
||||||
return actionSet;
|
return actionSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ void OpenXRInput::suggestBindings(const SuggestedBindings& mwSuggestedBindings)
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
XrPath oculusTouchInteractionProfilePath;
|
XrPath oculusTouchInteractionProfilePath;
|
||||||
CHECK_XRCMD(
|
CHECK_XRCMD(
|
||||||
xrStringToPath(xr->impl().mInstance, mwSuggestedBindings.controllerPath.c_str(), &oculusTouchInteractionProfilePath));
|
xrStringToPath(xr->impl().xrInstance(), mwSuggestedBindings.controllerPath.c_str(), &oculusTouchInteractionProfilePath));
|
||||||
|
|
||||||
std::vector<XrActionSuggestedBinding> suggestedBindings =
|
std::vector<XrActionSuggestedBinding> suggestedBindings =
|
||||||
{
|
{
|
||||||
|
@ -178,7 +178,7 @@ void OpenXRInput::suggestBindings(const SuggestedBindings& mwSuggestedBindings)
|
||||||
xrSuggestedBindings.interactionProfile = oculusTouchInteractionProfilePath;
|
xrSuggestedBindings.interactionProfile = oculusTouchInteractionProfilePath;
|
||||||
xrSuggestedBindings.suggestedBindings = suggestedBindings.data();
|
xrSuggestedBindings.suggestedBindings = suggestedBindings.data();
|
||||||
xrSuggestedBindings.countSuggestedBindings = (uint32_t)suggestedBindings.size();
|
xrSuggestedBindings.countSuggestedBindings = (uint32_t)suggestedBindings.size();
|
||||||
CHECK_XRCMD(xrSuggestInteractionProfileBindings(xr->impl().mInstance, &xrSuggestedBindings));
|
CHECK_XRCMD(xrSuggestInteractionProfileBindings(xr->impl().xrInstance(), &xrSuggestedBindings));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -192,8 +192,8 @@ OpenXRInput::generateControllerActionPaths(
|
||||||
std::string left = std::string("/user/hand/left") + controllerAction;
|
std::string left = std::string("/user/hand/left") + controllerAction;
|
||||||
std::string right = std::string("/user/hand/right") + controllerAction;
|
std::string right = std::string("/user/hand/right") + controllerAction;
|
||||||
|
|
||||||
CHECK_XRCMD(xrStringToPath(xr->impl().mInstance, left.c_str(), &actionPaths[(int)Side::LEFT_SIDE]));
|
CHECK_XRCMD(xrStringToPath(xr->impl().xrInstance(), left.c_str(), &actionPaths[(int)Side::LEFT_SIDE]));
|
||||||
CHECK_XRCMD(xrStringToPath(xr->impl().mInstance, right.c_str(), &actionPaths[(int)Side::RIGHT_SIDE]));
|
CHECK_XRCMD(xrStringToPath(xr->impl().xrInstance(), right.c_str(), &actionPaths[(int)Side::RIGHT_SIDE]));
|
||||||
|
|
||||||
mPathMap[actionPath] = actionPaths;
|
mPathMap[actionPath] = actionPaths;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ void
|
||||||
OpenXRInput::updateControls()
|
OpenXRInput::updateControls()
|
||||||
{
|
{
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
if (!xr->impl().mSessionRunning)
|
if (!xr->impl().xrSessionRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ OpenXRInput::updateControls()
|
||||||
XrActionsSyncInfo syncInfo{ XR_TYPE_ACTIONS_SYNC_INFO };
|
XrActionsSyncInfo syncInfo{ XR_TYPE_ACTIONS_SYNC_INFO };
|
||||||
syncInfo.countActiveActionSets = 1;
|
syncInfo.countActiveActionSets = 1;
|
||||||
syncInfo.activeActionSets = &activeActionSet;
|
syncInfo.activeActionSets = &activeActionSet;
|
||||||
CHECK_XRCMD(xrSyncActions(xr->impl().mSession, &syncInfo));
|
CHECK_XRCMD(xrSyncActions(xr->impl().xrSession(), &syncInfo));
|
||||||
|
|
||||||
|
|
||||||
// Note on update order:
|
// Note on update order:
|
||||||
|
@ -246,7 +246,7 @@ XrPath OpenXRInput::generateXrPath(const std::string& path)
|
||||||
{
|
{
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
XrPath xrpath = 0;
|
XrPath xrpath = 0;
|
||||||
CHECK_XRCMD(xrStringToPath(xr->impl().mInstance, path.c_str(), &xrpath));
|
CHECK_XRCMD(xrStringToPath(xr->impl().xrInstance(), path.c_str(), &xrpath));
|
||||||
return xrpath;
|
return xrpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,10 @@ namespace MWVR
|
||||||
return !!mPrivate;
|
return !!mPrivate;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenXRManager::sessionRunning()
|
bool OpenXRManager::xrSessionRunning()
|
||||||
{
|
{
|
||||||
if (realized())
|
if (realized())
|
||||||
return impl().mSessionRunning;
|
return impl().xrSessionRunning();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,12 +71,6 @@ namespace MWVR
|
||||||
return impl().endFrame(displayTime, layerCount, layerStack);
|
return impl().endFrame(displayTime, layerCount, layerStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenXRManager::updateControls()
|
|
||||||
{
|
|
||||||
if (realized())
|
|
||||||
return impl().updateControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenXRManager::realize(
|
OpenXRManager::realize(
|
||||||
osg::GraphicsContext* gc)
|
osg::GraphicsContext* gc)
|
||||||
|
@ -97,13 +91,6 @@ namespace MWVR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int OpenXRManager::eyes()
|
|
||||||
{
|
|
||||||
if (realized())
|
|
||||||
return impl().eyes();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenXRManager::enablePredictions()
|
void OpenXRManager::enablePredictions()
|
||||||
{
|
{
|
||||||
return impl().enablePredictions();
|
return impl().enablePredictions();
|
||||||
|
@ -114,21 +101,31 @@ namespace MWVR
|
||||||
return impl().disablePredictions();
|
return impl().disablePredictions();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<View, 2> OpenXRManager::getPredictedViews(int64_t predictedDisplayTime, TrackedSpace space)
|
std::array<View, 2> OpenXRManager::getPredictedViews(int64_t predictedDisplayTime, ReferenceSpace space)
|
||||||
{
|
{
|
||||||
return impl().getPredictedViews(predictedDisplayTime, space);
|
return impl().getPredictedViews(predictedDisplayTime, space);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWVR::Pose OpenXRManager::getPredictedHeadPose(int64_t predictedDisplayTime, TrackedSpace space)
|
MWVR::Pose OpenXRManager::getPredictedHeadPose(int64_t predictedDisplayTime, ReferenceSpace space)
|
||||||
{
|
{
|
||||||
return impl().getPredictedHeadPose(predictedDisplayTime, space);
|
return impl().getPredictedHeadPose(predictedDisplayTime, space);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long OpenXRManager::getLastPredictedDisplayTime()
|
||||||
|
{
|
||||||
|
return impl().getLastPredictedDisplayTime();
|
||||||
|
}
|
||||||
|
|
||||||
long long OpenXRManager::getLastPredictedDisplayPeriod()
|
long long OpenXRManager::getLastPredictedDisplayPeriod()
|
||||||
{
|
{
|
||||||
return impl().getLastPredictedDisplayPeriod();
|
return impl().getLastPredictedDisplayPeriod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<SwapchainConfig, 2> OpenXRManager::getRecommendedSwapchainConfig() const
|
||||||
|
{
|
||||||
|
return impl().getRecommendedSwapchainConfig();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenXRManager::RealizeOperation::operator()(
|
OpenXRManager::RealizeOperation::operator()(
|
||||||
osg::GraphicsContext* gc)
|
osg::GraphicsContext* gc)
|
||||||
|
|
|
@ -53,26 +53,47 @@ namespace MWVR
|
||||||
|
|
||||||
bool realized();
|
bool realized();
|
||||||
|
|
||||||
long long frameIndex();
|
//! Forward call to xrWaitFrame()
|
||||||
bool sessionRunning();
|
|
||||||
|
|
||||||
void handleEvents();
|
|
||||||
void waitFrame();
|
void waitFrame();
|
||||||
void beginFrame();
|
|
||||||
void endFrame(int64_t displayTime, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack);
|
|
||||||
void updateControls();
|
|
||||||
|
|
||||||
|
//! Forward call to xrBeginFrame()
|
||||||
|
void beginFrame();
|
||||||
|
|
||||||
|
//! Forward call to xrEndFrame()
|
||||||
|
void endFrame(int64_t displayTime, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack);
|
||||||
|
|
||||||
|
//! Whether the openxr session is currently in a running state
|
||||||
|
bool xrSessionRunning();
|
||||||
|
|
||||||
|
//! Process all openxr events
|
||||||
|
void handleEvents();
|
||||||
|
|
||||||
|
//! Instantiate implementation
|
||||||
void realize(osg::GraphicsContext* gc);
|
void realize(osg::GraphicsContext* gc);
|
||||||
|
|
||||||
int eyes();
|
//! Enable pose predictions. Exist to police that predictions are never made out of turn.
|
||||||
|
|
||||||
void enablePredictions();
|
void enablePredictions();
|
||||||
|
|
||||||
|
//! Disable pose predictions.
|
||||||
void disablePredictions();
|
void disablePredictions();
|
||||||
std::array<View, 2> getPredictedViews(int64_t predictedDisplayTime, TrackedSpace space);
|
|
||||||
MWVR::Pose getPredictedHeadPose(int64_t predictedDisplayTime, TrackedSpace space);
|
//! Get poses and fov of both eyes at the predicted time, relative to the given reference space. \note Will throw if predictions are disabled.
|
||||||
|
std::array<View, 2> getPredictedViews(int64_t predictedDisplayTime, ReferenceSpace space);
|
||||||
|
|
||||||
|
//! Get the pose of the player's head at the predicted time, relative to the given reference space. \note Will throw if predictions are disabled.
|
||||||
|
MWVR::Pose getPredictedHeadPose(int64_t predictedDisplayTime, ReferenceSpace space);
|
||||||
|
|
||||||
|
//! Last predicted display time returned from xrWaitFrame();
|
||||||
|
long long getLastPredictedDisplayTime();
|
||||||
|
|
||||||
|
//! Last predicted display period returned from xrWaitFrame();
|
||||||
long long getLastPredictedDisplayPeriod();
|
long long getLastPredictedDisplayPeriod();
|
||||||
|
|
||||||
|
//! Configuration hints for instantiating swapchains, queried from openxr.
|
||||||
|
std::array<SwapchainConfig, 2> getRecommendedSwapchainConfig() const;
|
||||||
|
|
||||||
OpenXRManagerImpl& impl() { return *mPrivate; }
|
OpenXRManagerImpl& impl() { return *mPrivate; }
|
||||||
|
const OpenXRManagerImpl& impl() const { return *mPrivate; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<OpenXRManagerImpl> mPrivate;
|
std::shared_ptr<OpenXRManagerImpl> mPrivate;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "openxrmanagerimpl.hpp"
|
#include "openxrmanagerimpl.hpp"
|
||||||
#include "openxrswapchain.hpp"
|
#include "openxrswapchainimpl.hpp"
|
||||||
#include "vrtexture.hpp"
|
#include "vrtexture.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
@ -173,6 +173,11 @@ namespace MWVR
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string XrResultString(XrResult res)
|
||||||
|
{
|
||||||
|
return to_string(res);
|
||||||
|
}
|
||||||
|
|
||||||
OpenXRManagerImpl::~OpenXRManagerImpl()
|
OpenXRManagerImpl::~OpenXRManagerImpl()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -259,12 +264,6 @@ namespace MWVR
|
||||||
Log(Debug::Verbose) << ss.str();
|
Log(Debug::Verbose) << ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
XrFrameState OpenXRManagerImpl::frameState()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mFrameStateMutex);
|
|
||||||
return mFrameState;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenXRManagerImpl::waitFrame()
|
OpenXRManagerImpl::waitFrame()
|
||||||
{
|
{
|
||||||
|
@ -294,7 +293,7 @@ namespace MWVR
|
||||||
{
|
{
|
||||||
XrCompositionLayerProjectionView xrLayer;
|
XrCompositionLayerProjectionView xrLayer;
|
||||||
xrLayer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
xrLayer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
||||||
xrLayer.subImage = layer.swapchain->subImage();
|
xrLayer.subImage = layer.swapchain->impl().xrSubImage();
|
||||||
xrLayer.pose = toXR(layer.pose);
|
xrLayer.pose = toXR(layer.pose);
|
||||||
xrLayer.fov = toXR(layer.fov);
|
xrLayer.fov = toXR(layer.fov);
|
||||||
xrLayer.next = nullptr;
|
xrLayer.next = nullptr;
|
||||||
|
@ -316,7 +315,7 @@ namespace MWVR
|
||||||
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR(layerStack[(int)Side::RIGHT_SIDE]);
|
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR(layerStack[(int)Side::RIGHT_SIDE]);
|
||||||
XrCompositionLayerProjection layer{};
|
XrCompositionLayerProjection layer{};
|
||||||
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
||||||
layer.space = getReferenceSpace(TrackedSpace::STAGE);
|
layer.space = getReferenceSpace(ReferenceSpace::STAGE);
|
||||||
layer.viewCount = 2;
|
layer.viewCount = 2;
|
||||||
layer.views = compositionLayerProjectionViews.data();
|
layer.views = compositionLayerProjectionViews.data();
|
||||||
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
|
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
|
||||||
|
@ -334,7 +333,7 @@ namespace MWVR
|
||||||
std::array<View, 2>
|
std::array<View, 2>
|
||||||
OpenXRManagerImpl::getPredictedViews(
|
OpenXRManagerImpl::getPredictedViews(
|
||||||
int64_t predictedDisplayTime,
|
int64_t predictedDisplayTime,
|
||||||
TrackedSpace space)
|
ReferenceSpace space)
|
||||||
{
|
{
|
||||||
if (!mPredictionsEnabled)
|
if (!mPredictionsEnabled)
|
||||||
{
|
{
|
||||||
|
@ -350,10 +349,10 @@ namespace MWVR
|
||||||
viewLocateInfo.displayTime = predictedDisplayTime;
|
viewLocateInfo.displayTime = predictedDisplayTime;
|
||||||
switch (space)
|
switch (space)
|
||||||
{
|
{
|
||||||
case TrackedSpace::STAGE:
|
case ReferenceSpace::STAGE:
|
||||||
viewLocateInfo.space = mReferenceSpaceStage;
|
viewLocateInfo.space = mReferenceSpaceStage;
|
||||||
break;
|
break;
|
||||||
case TrackedSpace::VIEW:
|
case ReferenceSpace::VIEW:
|
||||||
viewLocateInfo.space = mReferenceSpaceView;
|
viewLocateInfo.space = mReferenceSpaceView;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +368,7 @@ namespace MWVR
|
||||||
|
|
||||||
MWVR::Pose OpenXRManagerImpl::getPredictedHeadPose(
|
MWVR::Pose OpenXRManagerImpl::getPredictedHeadPose(
|
||||||
int64_t predictedDisplayTime,
|
int64_t predictedDisplayTime,
|
||||||
TrackedSpace space)
|
ReferenceSpace space)
|
||||||
{
|
{
|
||||||
if (!mPredictionsEnabled)
|
if (!mPredictionsEnabled)
|
||||||
{
|
{
|
||||||
|
@ -382,10 +381,10 @@ namespace MWVR
|
||||||
|
|
||||||
switch (space)
|
switch (space)
|
||||||
{
|
{
|
||||||
case TrackedSpace::STAGE:
|
case ReferenceSpace::STAGE:
|
||||||
referenceSpace = mReferenceSpaceStage;
|
referenceSpace = mReferenceSpaceStage;
|
||||||
break;
|
break;
|
||||||
case TrackedSpace::VIEW:
|
case ReferenceSpace::VIEW:
|
||||||
referenceSpace = mReferenceSpaceView;
|
referenceSpace = mReferenceSpaceView;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -398,16 +397,11 @@ namespace MWVR
|
||||||
location.pose.orientation.w = 1;
|
location.pose.orientation.w = 1;
|
||||||
}
|
}
|
||||||
return MWVR::Pose{
|
return MWVR::Pose{
|
||||||
osg::fromXR(location.pose.position),
|
fromXR(location.pose.position),
|
||||||
osg::fromXR(location.pose.orientation)
|
fromXR(location.pose.orientation)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
int OpenXRManagerImpl::eyes()
|
|
||||||
{
|
|
||||||
return mConfigViews.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenXRManagerImpl::handleEvents()
|
void OpenXRManagerImpl::handleEvents()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mEventMutex);
|
std::unique_lock<std::mutex> lock(mEventMutex);
|
||||||
|
@ -435,9 +429,6 @@ namespace MWVR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenXRManagerImpl::updateControls()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void
|
void
|
||||||
OpenXRManagerImpl::HandleSessionStateChanged(
|
OpenXRManagerImpl::HandleSessionStateChanged(
|
||||||
const XrEventDataSessionStateChanged& stateChangedEvent)
|
const XrEventDataSessionStateChanged& stateChangedEvent)
|
||||||
|
@ -495,12 +486,12 @@ namespace MWVR
|
||||||
|
|
||||||
MWVR::Pose fromXR(XrPosef pose)
|
MWVR::Pose fromXR(XrPosef pose)
|
||||||
{
|
{
|
||||||
return MWVR::Pose{ osg::fromXR(pose.position), osg::fromXR(pose.orientation) };
|
return MWVR::Pose{ fromXR(pose.position), fromXR(pose.orientation) };
|
||||||
}
|
}
|
||||||
|
|
||||||
XrPosef toXR(MWVR::Pose pose)
|
XrPosef toXR(MWVR::Pose pose)
|
||||||
{
|
{
|
||||||
return XrPosef{ osg::toXR(pose.orientation), osg::toXR(pose.position) };
|
return XrPosef{ toXR(pose.orientation), toXR(pose.position) };
|
||||||
}
|
}
|
||||||
|
|
||||||
MWVR::FieldOfView fromXR(XrFovf fov)
|
MWVR::FieldOfView fromXR(XrFovf fov)
|
||||||
|
@ -513,12 +504,12 @@ namespace MWVR
|
||||||
return XrFovf{ fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown };
|
return XrFovf{ fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown };
|
||||||
}
|
}
|
||||||
|
|
||||||
XrSpace OpenXRManagerImpl::getReferenceSpace(TrackedSpace space)
|
XrSpace OpenXRManagerImpl::getReferenceSpace(ReferenceSpace space)
|
||||||
{
|
{
|
||||||
XrSpace referenceSpace = XR_NULL_HANDLE;
|
XrSpace referenceSpace = XR_NULL_HANDLE;
|
||||||
if (space == TrackedSpace::STAGE)
|
if (space == ReferenceSpace::STAGE)
|
||||||
referenceSpace = mReferenceSpaceStage;
|
referenceSpace = mReferenceSpaceStage;
|
||||||
if (space == TrackedSpace::VIEW)
|
if (space == ReferenceSpace::VIEW)
|
||||||
referenceSpace = mReferenceSpaceView;
|
referenceSpace = mReferenceSpaceView;
|
||||||
return referenceSpace;
|
return referenceSpace;
|
||||||
}
|
}
|
||||||
|
@ -533,32 +524,48 @@ namespace MWVR
|
||||||
mPredictionsEnabled = false;
|
mPredictionsEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long OpenXRManagerImpl::getLastPredictedDisplayTime()
|
||||||
|
{
|
||||||
|
return mFrameState.predictedDisplayTime;
|
||||||
|
}
|
||||||
|
|
||||||
long long OpenXRManagerImpl::getLastPredictedDisplayPeriod()
|
long long OpenXRManagerImpl::getLastPredictedDisplayPeriod()
|
||||||
{
|
{
|
||||||
return mFrameState.predictedDisplayPeriod;
|
return mFrameState.predictedDisplayPeriod;
|
||||||
}
|
}
|
||||||
}
|
std::array<SwapchainConfig, 2> OpenXRManagerImpl::getRecommendedSwapchainConfig() const
|
||||||
|
|
||||||
namespace osg
|
|
||||||
{
|
|
||||||
|
|
||||||
Vec3 fromXR(XrVector3f v)
|
|
||||||
{
|
{
|
||||||
return Vec3{ v.x, -v.z, v.y };
|
std::array<SwapchainConfig, 2> config{};
|
||||||
|
for (uint32_t i = 0; i < 2; i++)
|
||||||
|
config[i] = SwapchainConfig{
|
||||||
|
mConfigViews[i].recommendedImageRectWidth,
|
||||||
|
mConfigViews[i].maxImageRectWidth,
|
||||||
|
mConfigViews[i].recommendedImageRectHeight,
|
||||||
|
mConfigViews[i].maxImageRectHeight,
|
||||||
|
mConfigViews[i].recommendedSwapchainSampleCount,
|
||||||
|
mConfigViews[i].recommendedSwapchainSampleCount,
|
||||||
|
};
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
Quat fromXR(XrQuaternionf quat)
|
osg::Vec3 fromXR(XrVector3f v)
|
||||||
{
|
{
|
||||||
return Quat{ quat.x, -quat.z, quat.y, quat.w };
|
return osg::Vec3{ v.x, -v.z, v.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
XrVector3f toXR(Vec3 v)
|
osg::Quat fromXR(XrQuaternionf quat)
|
||||||
|
{
|
||||||
|
return osg::Quat{ quat.x, -quat.z, quat.y, quat.w };
|
||||||
|
}
|
||||||
|
|
||||||
|
XrVector3f toXR(osg::Vec3 v)
|
||||||
{
|
{
|
||||||
return XrVector3f{ v.x(), v.z(), -v.y() };
|
return XrVector3f{ v.x(), v.z(), -v.y() };
|
||||||
}
|
}
|
||||||
|
|
||||||
XrQuaternionf toXR(Quat quat)
|
XrQuaternionf toXR(osg::Quat quat)
|
||||||
{
|
{
|
||||||
return XrQuaternionf{ quat.x(), quat.z(), -quat.y(), quat.w() };
|
return XrQuaternionf{ quat.x(), quat.z(), -quat.y(), quat.w() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,82 +22,82 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
namespace osg {
|
|
||||||
Vec3 fromXR(XrVector3f);
|
|
||||||
Quat fromXR(XrQuaternionf quat);
|
|
||||||
XrVector3f toXR(Vec3 v);
|
|
||||||
XrQuaternionf toXR(Quat quat);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Error management macros and functions. Should be used on every openxr call.
|
||||||
#define CHK_STRINGIFY(x) #x
|
#define CHK_STRINGIFY(x) #x
|
||||||
#define TOSTRING(x) CHK_STRINGIFY(x)
|
#define TOSTRING(x) CHK_STRINGIFY(x)
|
||||||
#define FILE_AND_LINE __FILE__ ":" TOSTRING(__LINE__)
|
#define FILE_AND_LINE __FILE__ ":" TOSTRING(__LINE__)
|
||||||
#define CHECK_XRCMD(cmd) CheckXrResult(cmd, #cmd, FILE_AND_LINE);
|
#define CHECK_XRCMD(cmd) CheckXrResult(cmd, #cmd, FILE_AND_LINE);
|
||||||
#define CHECK_XRRESULT(res, cmdStr) CheckXrResult(res, cmdStr, FILE_AND_LINE);
|
#define CHECK_XRRESULT(res, cmdStr) CheckXrResult(res, cmdStr, FILE_AND_LINE);
|
||||||
|
XrResult CheckXrResult(XrResult res, const char* originator = nullptr, const char* sourceLocation = nullptr);
|
||||||
|
std::string XrResultString(XrResult res);
|
||||||
|
|
||||||
XrResult CheckXrResult(XrResult res, const char* originator = nullptr, const char* sourceLocation = nullptr);
|
/// Conversion methods from openxr types to osg/mwvr types. Includes managing the differing conventions.
|
||||||
MWVR::Pose fromXR(XrPosef pose);
|
MWVR::Pose fromXR(XrPosef pose);
|
||||||
XrPosef toXR(MWVR::Pose pose);
|
MWVR::FieldOfView fromXR(XrFovf fov);
|
||||||
MWVR::FieldOfView fromXR(XrFovf fov);
|
osg::Vec3 fromXR(XrVector3f);
|
||||||
XrFovf toXR(MWVR::FieldOfView fov);
|
osg::Quat fromXR(XrQuaternionf quat);
|
||||||
|
|
||||||
XrCompositionLayerProjectionView toXR(MWVR::CompositionLayerProjectionView layer);
|
/// Conversion methods from osg/mwvr types to openxr types. Includes managing the differing conventions.
|
||||||
|
XrPosef toXR(MWVR::Pose pose);
|
||||||
|
XrFovf toXR(MWVR::FieldOfView fov);
|
||||||
|
XrVector3f toXR(osg::Vec3 v);
|
||||||
|
XrQuaternionf toXR(osg::Quat quat);
|
||||||
|
|
||||||
struct OpenXRManagerImpl
|
XrCompositionLayerProjectionView toXR(MWVR::CompositionLayerProjectionView layer);
|
||||||
{
|
|
||||||
OpenXRManagerImpl(void);
|
|
||||||
~OpenXRManagerImpl(void);
|
|
||||||
|
|
||||||
void LogLayersAndExtensions();
|
struct OpenXRManagerImpl
|
||||||
void LogInstanceInfo();
|
{
|
||||||
void LogReferenceSpaces();
|
OpenXRManagerImpl(void);
|
||||||
|
~OpenXRManagerImpl(void);
|
||||||
|
|
||||||
const XrEventDataBaseHeader* nextEvent();
|
void waitFrame();
|
||||||
void waitFrame();
|
void beginFrame();
|
||||||
void beginFrame();
|
void endFrame(int64_t displayTime, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack);
|
||||||
void endFrame(int64_t displayTime, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack);
|
bool xrSessionRunning() const { return mSessionRunning; }
|
||||||
std::array<View, 2> getPredictedViews(int64_t predictedDisplayTime, TrackedSpace space);
|
std::array<View, 2> getPredictedViews(int64_t predictedDisplayTime, ReferenceSpace space);
|
||||||
MWVR::Pose getPredictedHeadPose(int64_t predictedDisplayTime, TrackedSpace space);
|
MWVR::Pose getPredictedHeadPose(int64_t predictedDisplayTime, ReferenceSpace space);
|
||||||
int eyes();
|
void handleEvents();
|
||||||
void handleEvents();
|
void enablePredictions();
|
||||||
void updateControls();
|
void disablePredictions();
|
||||||
void HandleSessionStateChanged(const XrEventDataSessionStateChanged& stateChangedEvent);
|
long long getLastPredictedDisplayTime();
|
||||||
XrFrameState frameState();
|
long long getLastPredictedDisplayPeriod();
|
||||||
XrSpace getReferenceSpace(TrackedSpace space);
|
std::array<SwapchainConfig, 2> getRecommendedSwapchainConfig() const;
|
||||||
void enablePredictions();
|
XrSpace getReferenceSpace(ReferenceSpace space);
|
||||||
void disablePredictions();
|
XrSession xrSession() const { return mSession; };
|
||||||
long long getLastPredictedDisplayPeriod();
|
XrInstance xrInstance() const { return mInstance; };
|
||||||
|
|
||||||
bool initialized = false;
|
protected:
|
||||||
bool mPredictionsEnabled = false;
|
void LogLayersAndExtensions();
|
||||||
XrInstance mInstance = XR_NULL_HANDLE;
|
void LogInstanceInfo();
|
||||||
XrSession mSession = XR_NULL_HANDLE;
|
void LogReferenceSpaces();
|
||||||
XrSpace mSpace = XR_NULL_HANDLE;
|
const XrEventDataBaseHeader* nextEvent();
|
||||||
XrFormFactor mFormFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
void HandleSessionStateChanged(const XrEventDataSessionStateChanged& stateChangedEvent);
|
||||||
XrViewConfigurationType mViewConfigType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
|
||||||
XrEnvironmentBlendMode mEnvironmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
|
||||||
XrSystemId mSystemId = XR_NULL_SYSTEM_ID;
|
|
||||||
XrGraphicsBindingOpenGLWin32KHR mGraphicsBinding{ XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR };
|
|
||||||
XrSystemProperties mSystemProperties{ XR_TYPE_SYSTEM_PROPERTIES };
|
|
||||||
std::array<XrViewConfigurationView, 2> mConfigViews{ { {XR_TYPE_VIEW_CONFIGURATION_VIEW}, {XR_TYPE_VIEW_CONFIGURATION_VIEW} } };
|
|
||||||
XrSpace mReferenceSpaceView = XR_NULL_HANDLE;
|
|
||||||
XrSpace mReferenceSpaceStage = XR_NULL_HANDLE;
|
|
||||||
XrEventDataBuffer mEventDataBuffer{ XR_TYPE_EVENT_DATA_BUFFER };
|
|
||||||
XrFrameState mFrameState{};
|
|
||||||
XrSessionState mSessionState = XR_SESSION_STATE_UNKNOWN;
|
|
||||||
bool mSessionRunning = false;
|
|
||||||
std::mutex mFrameStateMutex{};
|
|
||||||
std::mutex mEventMutex{};
|
|
||||||
|
|
||||||
XrActionSet mActionSet = nullptr;
|
private:
|
||||||
XrAction mHandPoseAction = nullptr;
|
bool initialized = false;
|
||||||
XrSpace mHandSpaces[2]{ nullptr, nullptr };
|
bool mPredictionsEnabled = false;
|
||||||
XrPath mSubactionPaths[2]{ 0, 0 };
|
XrInstance mInstance = XR_NULL_HANDLE;
|
||||||
XrPath mPosePath[2]{ 0, 0 };
|
XrSession mSession = XR_NULL_HANDLE;
|
||||||
};
|
XrSpace mSpace = XR_NULL_HANDLE;
|
||||||
|
XrFormFactor mFormFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||||
|
XrViewConfigurationType mViewConfigType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
||||||
|
XrEnvironmentBlendMode mEnvironmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
||||||
|
XrSystemId mSystemId = XR_NULL_SYSTEM_ID;
|
||||||
|
XrGraphicsBindingOpenGLWin32KHR mGraphicsBinding{ XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR };
|
||||||
|
XrSystemProperties mSystemProperties{ XR_TYPE_SYSTEM_PROPERTIES };
|
||||||
|
std::array<XrViewConfigurationView, 2> mConfigViews{ { {XR_TYPE_VIEW_CONFIGURATION_VIEW}, {XR_TYPE_VIEW_CONFIGURATION_VIEW} } };
|
||||||
|
XrSpace mReferenceSpaceView = XR_NULL_HANDLE;
|
||||||
|
XrSpace mReferenceSpaceStage = XR_NULL_HANDLE;
|
||||||
|
XrEventDataBuffer mEventDataBuffer{ XR_TYPE_EVENT_DATA_BUFFER };
|
||||||
|
XrFrameState mFrameState{};
|
||||||
|
XrSessionState mSessionState = XR_SESSION_STATE_UNKNOWN;
|
||||||
|
bool mSessionRunning = false;
|
||||||
|
std::mutex mFrameStateMutex{};
|
||||||
|
std::mutex mEventMutex{};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace MWVR {
|
||||||
SUBVIEW_MAX = RIGHT_VIEW, //!< Used to size subview arrays. Not a valid input.
|
SUBVIEW_MAX = RIGHT_VIEW, //!< Used to size subview arrays. Not a valid input.
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenXRSwapchainImpl(osg::ref_ptr<osg::State> state, OpenXRSwapchain::Config config);
|
OpenXRSwapchainImpl(osg::ref_ptr<osg::State> state, SwapchainConfig config);
|
||||||
~OpenXRSwapchainImpl();
|
~OpenXRSwapchainImpl();
|
||||||
|
|
||||||
void beginFrame(osg::GraphicsContext* gc);
|
void beginFrame(osg::GraphicsContext* gc);
|
||||||
|
@ -53,10 +53,10 @@ namespace MWVR {
|
||||||
bool mIsAcquired{ false };
|
bool mIsAcquired{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr<osg::State> state, OpenXRSwapchain::Config config)
|
OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr<osg::State> state, SwapchainConfig config)
|
||||||
: mWidth(config.width)
|
: mWidth(config.recommendedWidth)
|
||||||
, mHeight(config.height)
|
, mHeight(config.recommendedHeight)
|
||||||
, mSamples(config.samples)
|
, mSamples(config.recommendedSamples)
|
||||||
{
|
{
|
||||||
if (mWidth <= 0)
|
if (mWidth <= 0)
|
||||||
throw std::invalid_argument("Width must be a positive integer");
|
throw std::invalid_argument("Width must be a positive integer");
|
||||||
|
@ -69,9 +69,9 @@ namespace MWVR {
|
||||||
|
|
||||||
// Select a swapchain format.
|
// Select a swapchain format.
|
||||||
uint32_t swapchainFormatCount;
|
uint32_t swapchainFormatCount;
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().mSession, 0, &swapchainFormatCount, nullptr));
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), 0, &swapchainFormatCount, nullptr));
|
||||||
std::vector<int64_t> swapchainFormats(swapchainFormatCount);
|
std::vector<int64_t> swapchainFormats(swapchainFormatCount);
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().mSession, (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data()));
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(xr->impl().xrSession(), (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data()));
|
||||||
|
|
||||||
// List of supported color swapchain formats.
|
// List of supported color swapchain formats.
|
||||||
constexpr int64_t SupportedColorSwapchainFormats[] = {
|
constexpr int64_t SupportedColorSwapchainFormats[] = {
|
||||||
|
@ -100,7 +100,7 @@ namespace MWVR {
|
||||||
swapchainCreateInfo.faceCount = 1;
|
swapchainCreateInfo.faceCount = 1;
|
||||||
swapchainCreateInfo.sampleCount = mSamples;
|
swapchainCreateInfo.sampleCount = mSamples;
|
||||||
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
CHECK_XRCMD(xrCreateSwapchain(xr->impl().mSession, &swapchainCreateInfo, &mSwapchain));
|
CHECK_XRCMD(xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain));
|
||||||
|
|
||||||
uint32_t imageCount = 0;
|
uint32_t imageCount = 0;
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr));
|
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr));
|
||||||
|
@ -176,7 +176,7 @@ namespace MWVR {
|
||||||
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenXRSwapchain::OpenXRSwapchain(osg::ref_ptr<osg::State> state, OpenXRSwapchain::Config config)
|
OpenXRSwapchain::OpenXRSwapchain(osg::ref_ptr<osg::State> state, SwapchainConfig config)
|
||||||
: mPrivate(new OpenXRSwapchainImpl(state, config))
|
: mPrivate(new OpenXRSwapchainImpl(state, config))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace MWVR
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpenXRSwapchain(osg::ref_ptr<osg::State> state, Config config);
|
OpenXRSwapchain(osg::ref_ptr<osg::State> state, SwapchainConfig config);
|
||||||
~OpenXRSwapchain();
|
~OpenXRSwapchain();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -31,7 +31,7 @@ PoseAction::PoseAction(std::unique_ptr<OpenXRAction> xrAction)
|
||||||
createInfo.action = *mXRAction;
|
createInfo.action = *mXRAction;
|
||||||
createInfo.poseInActionSpace.orientation.w = 1.f;
|
createInfo.poseInActionSpace.orientation.w = 1.f;
|
||||||
createInfo.subactionPath = XR_NULL_PATH;
|
createInfo.subactionPath = XR_NULL_PATH;
|
||||||
CHECK_XRCMD(xrCreateActionSpace(xr->impl().mSession, &createInfo, &mXRSpace));
|
CHECK_XRCMD(xrCreateActionSpace(xr->impl().xrSession(), &createInfo, &mXRSpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseAction::update(long long time)
|
void PoseAction::update(long long time)
|
||||||
|
@ -39,7 +39,7 @@ void PoseAction::update(long long time)
|
||||||
mPrevious = mValue;
|
mPrevious = mValue;
|
||||||
|
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
XrSpace referenceSpace = xr->impl().getReferenceSpace(TrackedSpace::STAGE);
|
XrSpace referenceSpace = xr->impl().getReferenceSpace(ReferenceSpace::STAGE);
|
||||||
|
|
||||||
XrSpaceLocation location{ XR_TYPE_SPACE_LOCATION };
|
XrSpaceLocation location{ XR_TYPE_SPACE_LOCATION };
|
||||||
XrSpaceVelocity velocity{ XR_TYPE_SPACE_VELOCITY };
|
XrSpaceVelocity velocity{ XR_TYPE_SPACE_VELOCITY };
|
||||||
|
@ -51,8 +51,8 @@ void PoseAction::update(long long time)
|
||||||
location.pose.orientation.w = 1;
|
location.pose.orientation.w = 1;
|
||||||
|
|
||||||
mValue = Pose{
|
mValue = Pose{
|
||||||
osg::fromXR(location.pose.position),
|
fromXR(location.pose.position),
|
||||||
osg::fromXR(location.pose.orientation)
|
fromXR(location.pose.orientation)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ osg::Matrix VRSession::viewMatrix(FramePhase phase, Side side)
|
||||||
|
|
||||||
bool VRSession::isRunning() const {
|
bool VRSession::isRunning() const {
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
return xr->sessionRunning();
|
return xr->xrSessionRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
|
void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
|
||||||
|
@ -254,13 +254,13 @@ void VRSession::prepareFrame()
|
||||||
PoseSet predictedPoses{};
|
PoseSet predictedPoses{};
|
||||||
|
|
||||||
xr->enablePredictions();
|
xr->enablePredictions();
|
||||||
predictedPoses.head = xr->getPredictedHeadPose(predictedDisplayTime, TrackedSpace::STAGE) * mPlayerScale;
|
predictedPoses.head = xr->getPredictedHeadPose(predictedDisplayTime, ReferenceSpace::STAGE) * mPlayerScale;
|
||||||
auto hmdViews = xr->getPredictedViews(predictedDisplayTime, TrackedSpace::VIEW);
|
auto hmdViews = xr->getPredictedViews(predictedDisplayTime, ReferenceSpace::VIEW);
|
||||||
predictedPoses.view[(int)Side::LEFT_SIDE].pose = hmdViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
|
predictedPoses.view[(int)Side::LEFT_SIDE].pose = hmdViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
|
||||||
predictedPoses.view[(int)Side::RIGHT_SIDE].pose = hmdViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
|
predictedPoses.view[(int)Side::RIGHT_SIDE].pose = hmdViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
|
||||||
predictedPoses.view[(int)Side::LEFT_SIDE].fov = hmdViews[(int)Side::LEFT_SIDE].fov;
|
predictedPoses.view[(int)Side::LEFT_SIDE].fov = hmdViews[(int)Side::LEFT_SIDE].fov;
|
||||||
predictedPoses.view[(int)Side::RIGHT_SIDE].fov = hmdViews[(int)Side::RIGHT_SIDE].fov;
|
predictedPoses.view[(int)Side::RIGHT_SIDE].fov = hmdViews[(int)Side::RIGHT_SIDE].fov;
|
||||||
auto stageViews = xr->getPredictedViews(predictedDisplayTime, TrackedSpace::STAGE);
|
auto stageViews = xr->getPredictedViews(predictedDisplayTime, ReferenceSpace::STAGE);
|
||||||
predictedPoses.eye[(int)Side::LEFT_SIDE] = stageViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
|
predictedPoses.eye[(int)Side::LEFT_SIDE] = stageViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
|
||||||
predictedPoses.eye[(int)Side::RIGHT_SIDE] = stageViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
|
predictedPoses.eye[(int)Side::RIGHT_SIDE] = stageViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ namespace MWVR
|
||||||
|
|
||||||
extern void getEulerAngles(const osg::Quat& quat, float& yaw, float& pitch, float& roll);
|
extern void getEulerAngles(const osg::Quat& quat, float& yaw, float& pitch, float& roll);
|
||||||
|
|
||||||
|
//! Manages VR logic, such as managing frames, predicting their poses, and handling frame synchronization.
|
||||||
|
//! Should not be confused with the openxr session object.
|
||||||
class VRSession
|
class VRSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -13,52 +13,56 @@
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
VRTexture::VRTexture(
|
|
||||||
osg::ref_ptr<osg::State> state,
|
VRTexture::VRTexture(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer, uint32_t depthBuffer)
|
||||||
std::size_t width,
|
|
||||||
std::size_t height,
|
|
||||||
uint32_t msaaSamples)
|
|
||||||
: mState(state)
|
: mState(state)
|
||||||
, mWidth(width)
|
, mWidth(width)
|
||||||
, mHeight(height)
|
, mHeight(height)
|
||||||
, mSamples(msaaSamples)
|
, mSamples(msaaSamples)
|
||||||
|
, mColorBuffer(colorBuffer)
|
||||||
|
, mDepthBuffer(depthBuffer)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||||
|
|
||||||
gl->glGenFramebuffers(1, &mBlitFBO);
|
gl->glGenFramebuffers(1, &mBlitFBO);
|
||||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mBlitFBO);
|
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mBlitFBO);
|
||||||
|
|
||||||
gl->glGenFramebuffers(1, &mFBO);
|
gl->glGenFramebuffers(1, &mFBO);
|
||||||
glGenTextures(1, &mDepthBuffer);
|
|
||||||
glGenTextures(1, &mColorBuffer);
|
|
||||||
|
|
||||||
if (mSamples == 0)
|
if (mSamples <= 1)
|
||||||
mTextureTarget = GL_TEXTURE_2D;
|
mTextureTarget = GL_TEXTURE_2D;
|
||||||
else
|
else
|
||||||
mTextureTarget = GL_TEXTURE_2D_MULTISAMPLE;
|
mTextureTarget = GL_TEXTURE_2D_MULTISAMPLE;
|
||||||
|
|
||||||
glBindTexture(mTextureTarget, mColorBuffer);
|
if (mColorBuffer == 0)
|
||||||
if (mSamples == 0)
|
{
|
||||||
glTexImage2D(mTextureTarget, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_INT, nullptr);
|
glGenTextures(1, &mColorBuffer);
|
||||||
else
|
glBindTexture(mTextureTarget, mColorBuffer);
|
||||||
gl->glTexImage2DMultisample(mTextureTarget, mSamples, GL_RGBA, mWidth, mHeight, false);
|
if (mSamples <= 1)
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
|
glTexImage2D(mTextureTarget, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_INT, nullptr);
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_ARB);
|
else
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
gl->glTexImage2DMultisample(mTextureTarget, mSamples, GL_RGBA, mWidth, mHeight, false);
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_ARB);
|
||||||
|
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(mTextureTarget, mDepthBuffer);
|
if (mDepthBuffer == 0)
|
||||||
if (mSamples == 0)
|
{
|
||||||
glTexImage2D(mTextureTarget, 0, GL_DEPTH_COMPONENT24, mWidth, mHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
glGenTextures(1, &mDepthBuffer);
|
||||||
else
|
glBindTexture(mTextureTarget, mDepthBuffer);
|
||||||
gl->glTexImage2DMultisample(mTextureTarget, mSamples, GL_DEPTH_COMPONENT, mWidth, mHeight, false);
|
if (mSamples <= 1)
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexImage2D(mTextureTarget, 0, GL_DEPTH_COMPONENT24, mWidth, mHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
else
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
gl->glTexImage2DMultisample(mTextureTarget, mSamples, GL_DEPTH_COMPONENT, mWidth, mHeight, false);
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFBO);
|
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFBO);
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MWVR
|
||||||
class VRTexture : public osg::Referenced
|
class VRTexture : public osg::Referenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VRTexture(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples);
|
VRTexture(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer = 0, uint32_t depthBuffer = 0);
|
||||||
~VRTexture();
|
~VRTexture();
|
||||||
|
|
||||||
void destroy(osg::State* state);
|
void destroy(osg::State* state);
|
||||||
|
|
|
@ -172,13 +172,13 @@ std::ostream& operator <<(
|
||||||
|
|
||||||
std::ostream& operator <<(
|
std::ostream& operator <<(
|
||||||
std::ostream& os,
|
std::ostream& os,
|
||||||
TrackedSpace limb)
|
ReferenceSpace limb)
|
||||||
{
|
{
|
||||||
switch (limb)
|
switch (limb)
|
||||||
{
|
{
|
||||||
case TrackedSpace::STAGE:
|
case ReferenceSpace::STAGE:
|
||||||
os << "STAGE"; break;
|
os << "STAGE"; break;
|
||||||
case TrackedSpace::VIEW:
|
case ReferenceSpace::VIEW:
|
||||||
os << "VIEW"; break;
|
os << "VIEW"; break;
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
|
|
|
@ -24,7 +24,7 @@ enum class TrackedLimb
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Describes what space to track the limb in
|
//! Describes what space to track the limb in
|
||||||
enum class TrackedSpace
|
enum class ReferenceSpace
|
||||||
{
|
{
|
||||||
STAGE = 0, //!< Track limb in the VR stage space. Meaning a space with a floor level origin and fixed horizontal orientation.
|
STAGE = 0, //!< Track limb in the VR stage space. Meaning a space with a floor level origin and fixed horizontal orientation.
|
||||||
VIEW = 1 //!< Track limb in the VR view space. Meaning a space with the head as origin and orientation.
|
VIEW = 1 //!< Track limb in the VR view space. Meaning a space with the head as origin and orientation.
|
||||||
|
@ -58,7 +58,7 @@ struct Pose
|
||||||
bool operator==(const Pose& rhs) const;
|
bool operator==(const Pose& rhs) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Represents the field of view of an eye
|
//! Fov of a single eye
|
||||||
struct FieldOfView {
|
struct FieldOfView {
|
||||||
float angleLeft;
|
float angleLeft;
|
||||||
float angleRight;
|
float angleRight;
|
||||||
|
@ -97,13 +97,23 @@ struct CompositionLayerProjectionView
|
||||||
FieldOfView fov;
|
FieldOfView fov;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SwapchainConfig
|
||||||
|
{
|
||||||
|
uint32_t recommendedWidth = -1;
|
||||||
|
uint32_t maxWidth = -1;
|
||||||
|
uint32_t recommendedHeight = -1;
|
||||||
|
uint32_t maxHeight = -1;
|
||||||
|
uint32_t recommendedSamples = -1;
|
||||||
|
uint32_t maxSamples = -1;
|
||||||
|
};
|
||||||
|
|
||||||
// Serialization methods for VR types.
|
// Serialization methods for VR types.
|
||||||
std::ostream& operator <<(std::ostream& os, const Pose& pose);
|
std::ostream& operator <<(std::ostream& os, const Pose& pose);
|
||||||
std::ostream& operator <<(std::ostream& os, const FieldOfView& fov);
|
std::ostream& operator <<(std::ostream& os, const FieldOfView& fov);
|
||||||
std::ostream& operator <<(std::ostream& os, const View& view);
|
std::ostream& operator <<(std::ostream& os, const View& view);
|
||||||
std::ostream& operator <<(std::ostream& os, const PoseSet& poseSet);
|
std::ostream& operator <<(std::ostream& os, const PoseSet& poseSet);
|
||||||
std::ostream& operator <<(std::ostream& os, TrackedLimb limb);
|
std::ostream& operator <<(std::ostream& os, TrackedLimb limb);
|
||||||
std::ostream& operator <<(std::ostream& os, TrackedSpace space);
|
std::ostream& operator <<(std::ostream& os, ReferenceSpace space);
|
||||||
std::ostream& operator <<(std::ostream& os, Side side);
|
std::ostream& operator <<(std::ostream& os, Side side);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace MWVR {
|
||||||
|
|
||||||
VRView::VRView(
|
VRView::VRView(
|
||||||
std::string name,
|
std::string name,
|
||||||
OpenXRSwapchain::Config config,
|
SwapchainConfig config,
|
||||||
osg::ref_ptr<osg::State> state)
|
osg::ref_ptr<osg::State> state)
|
||||||
: mSwapchainConfig{ config }
|
: mSwapchainConfig{ config }
|
||||||
, mSwapchain(new OpenXRSwapchain(state, mSwapchainConfig))
|
, mSwapchain(new OpenXRSwapchain(state, mSwapchainConfig))
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace MWVR
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VRView(std::string name, OpenXRSwapchain::Config config, osg::ref_ptr<osg::State> state);
|
VRView(std::string name, SwapchainConfig config, osg::ref_ptr<osg::State> state);
|
||||||
virtual ~VRView();
|
virtual ~VRView();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -52,7 +52,7 @@ namespace MWVR
|
||||||
void swapBuffers(osg::GraphicsContext* gc);
|
void swapBuffers(osg::GraphicsContext* gc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpenXRSwapchain::Config mSwapchainConfig;
|
SwapchainConfig mSwapchainConfig;
|
||||||
std::unique_ptr<OpenXRSwapchain> mSwapchain;
|
std::unique_ptr<OpenXRSwapchain> mSwapchain;
|
||||||
std::string mName{};
|
std::string mName{};
|
||||||
bool mRendering{ false };
|
bool mRendering{ false };
|
||||||
|
|
|
@ -67,17 +67,10 @@ namespace MWVR
|
||||||
|
|
||||||
xr->handleEvents();
|
xr->handleEvents();
|
||||||
|
|
||||||
OpenXRSwapchain::Config leftConfig;
|
auto config = xr->getRecommendedSwapchainConfig();
|
||||||
leftConfig.width = xr->impl().mConfigViews[(int)Side::LEFT_SIDE].recommendedImageRectWidth;
|
|
||||||
leftConfig.height = xr->impl().mConfigViews[(int)Side::LEFT_SIDE].recommendedImageRectHeight;
|
|
||||||
leftConfig.samples = xr->impl().mConfigViews[(int)Side::LEFT_SIDE].recommendedSwapchainSampleCount;
|
|
||||||
OpenXRSwapchain::Config rightConfig;
|
|
||||||
rightConfig.width = xr->impl().mConfigViews[(int)Side::RIGHT_SIDE].recommendedImageRectWidth;
|
|
||||||
rightConfig.height = xr->impl().mConfigViews[(int)Side::RIGHT_SIDE].recommendedImageRectHeight;
|
|
||||||
rightConfig.samples = xr->impl().mConfigViews[(int)Side::RIGHT_SIDE].recommendedSwapchainSampleCount;
|
|
||||||
|
|
||||||
auto leftView = new VRView("LeftEye", leftConfig, context->getState());
|
auto leftView = new VRView("LeftEye", config[(int)Side::LEFT_SIDE], context->getState());
|
||||||
auto rightView = new VRView("RightEye", rightConfig, context->getState());
|
auto rightView = new VRView("RightEye", config[(int)Side::RIGHT_SIDE], context->getState());
|
||||||
|
|
||||||
mViews["LeftEye"] = leftView;
|
mViews["LeftEye"] = leftView;
|
||||||
mViews["RightEye"] = rightView;
|
mViews["RightEye"] = rightView;
|
||||||
|
@ -118,15 +111,7 @@ namespace MWVR
|
||||||
|
|
||||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||||
|
|
||||||
|
mMirrorTexture.reset(new VRTexture(context->getState(), mainCamera->getViewport()->width(), mainCamera->getViewport()->height(), 0));
|
||||||
OpenXRSwapchain::Config config;
|
|
||||||
config.width = mainCamera->getViewport()->width();
|
|
||||||
config.height = mainCamera->getViewport()->height();
|
|
||||||
config.samples = 1;
|
|
||||||
|
|
||||||
// Mirror texture doesn't have to be an OpenXR swapchain.
|
|
||||||
// It was just convenient at the time.
|
|
||||||
mMirrorTextureSwapchain.reset(new OpenXRSwapchain(context->getState(), config));
|
|
||||||
|
|
||||||
mViewer->getSlave(0)._updateSlaveCallback = new VRView::UpdateSlaveCallback(leftView, context);
|
mViewer->getSlave(0)._updateSlaveCallback = new VRView::UpdateSlaveCallback(leftView, context);
|
||||||
mViewer->getSlave(1)._updateSlaveCallback = new VRView::UpdateSlaveCallback(rightView, context);
|
mViewer->getSlave(1)._updateSlaveCallback = new VRView::UpdateSlaveCallback(rightView, context);
|
||||||
|
@ -151,18 +136,16 @@ namespace MWVR
|
||||||
|
|
||||||
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
||||||
{
|
{
|
||||||
int mirror_width = mMirrorTextureSwapchain->width() / 2;
|
|
||||||
mMirrorTextureSwapchain->beginFrame(gc);
|
|
||||||
|
|
||||||
mViews["RightEye"]->swapchain().renderBuffer()->blit(gc, 0, 0, mirror_width, mMirrorTextureSwapchain->height());
|
|
||||||
mViews["LeftEye"]->swapchain().renderBuffer()->blit(gc, mirror_width, 0, 2 * mirror_width, mMirrorTextureSwapchain->height());
|
|
||||||
|
|
||||||
mMirrorTextureSwapchain->endFrame(gc);
|
|
||||||
|
|
||||||
auto* state = gc->getState();
|
auto* state = gc->getState();
|
||||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||||
|
int mirror_width = mMirrorTexture->width() / 2;
|
||||||
|
mMirrorTexture->beginFrame(gc);
|
||||||
|
|
||||||
|
mViews["RightEye"]->swapchain().renderBuffer()->blit(gc, 0, 0, mirror_width, mMirrorTexture->height());
|
||||||
|
mViews["LeftEye"]->swapchain().renderBuffer()->blit(gc, mirror_width, 0, 2 * mirror_width, mMirrorTexture->height());
|
||||||
|
|
||||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||||
mMirrorTextureSwapchain->renderBuffer()->blit(gc, 0, 0, mMirrorTextureSwapchain->width(), mMirrorTextureSwapchain->height());
|
mMirrorTexture->blit(gc, 0, 0, mMirrorTexture->width(), mMirrorTexture->height());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,8 +91,7 @@ namespace MWVR
|
||||||
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
||||||
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
||||||
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
osg::GraphicsContext* mMainCameraGC{ nullptr };
|
||||||
|
std::unique_ptr<VRTexture> mMirrorTexture{ nullptr };
|
||||||
std::unique_ptr<OpenXRSwapchain> mMirrorTextureSwapchain{ nullptr };
|
|
||||||
|
|
||||||
std::mutex mMutex;
|
std::mutex mMutex;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue