mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 07:53:51 +00:00
Tentatively completed VR GUI
This commit is contained in:
parent
57e48cfc03
commit
6f9c405afd
25 changed files with 883 additions and 388 deletions
|
@ -30,7 +30,11 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop)
|
ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop)
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
: WindowBase("openmw_container_window_vr.layout")
|
||||||
|
#else
|
||||||
: WindowBase("openmw_container_window.layout")
|
: WindowBase("openmw_container_window.layout")
|
||||||
|
#endif
|
||||||
, mDragAndDrop(dragAndDrop)
|
, mDragAndDrop(dragAndDrop)
|
||||||
, mSortModel(nullptr)
|
, mSortModel(nullptr)
|
||||||
, mModel(nullptr)
|
, mModel(nullptr)
|
||||||
|
|
|
@ -266,7 +266,11 @@ namespace MWGui
|
||||||
// --------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
DialogueWindow::DialogueWindow()
|
DialogueWindow::DialogueWindow()
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
: WindowBase("openmw_dialogue_window_vr.layout")
|
||||||
|
#else
|
||||||
: WindowBase("openmw_dialogue_window.layout")
|
: WindowBase("openmw_dialogue_window.layout")
|
||||||
|
#endif
|
||||||
, mIsCompanion(false)
|
, mIsCompanion(false)
|
||||||
, mGoodbye(false)
|
, mGoodbye(false)
|
||||||
, mPersuasionDialog(new ResponseCallback(this))
|
, mPersuasionDialog(new ResponseCallback(this))
|
||||||
|
|
|
@ -103,10 +103,13 @@ namespace MWGui
|
||||||
, mIsDrowning(false)
|
, mIsDrowning(false)
|
||||||
, mDrowningFlashTheta(0.f)
|
, mDrowningFlashTheta(0.f)
|
||||||
{
|
{
|
||||||
#ifndef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
|
||||||
#endif
|
|
||||||
mMainWidgetBaseSize = mMainWidget->getSize();
|
mMainWidgetBaseSize = mMainWidget->getSize();
|
||||||
|
mMainWidget->setSize(mMainWidgetBaseSize);
|
||||||
|
#else
|
||||||
|
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
||||||
|
mMainWidgetBaseSize = mMainWidget->getSize();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Energy bars
|
// Energy bars
|
||||||
getWidget(mHealthFrame, "HealthFrame");
|
getWidget(mHealthFrame, "HealthFrame");
|
||||||
|
@ -381,9 +384,6 @@ namespace MWGui
|
||||||
mDrowningFlashTheta += dt * osg::PI*2;
|
mDrowningFlashTheta += dt * osg::PI*2;
|
||||||
|
|
||||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||||
Log(Debug::Verbose) << "Size: " << mMainWidget->getSize();
|
|
||||||
Log(Debug::Verbose) << "width: " << mMainWidget->getWidth();
|
|
||||||
Log(Debug::Verbose) << "height: " << mMainWidget->getHeight();
|
|
||||||
|
|
||||||
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
|
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
|
||||||
{
|
{
|
||||||
|
|
|
@ -117,6 +117,8 @@ namespace MWGui
|
||||||
messageBox->update(height);
|
messageBox->update(height);
|
||||||
height += messageBox->getHeight();
|
height += messageBox->getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
box->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBoxManager::removeStaticMessageBox ()
|
void MessageBoxManager::removeStaticMessageBox ()
|
||||||
|
@ -189,6 +191,11 @@ namespace MWGui
|
||||||
mMessageWidget->setCaptionWithReplacing(mMessage);
|
mMessageWidget->setCaptionWithReplacing(mMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageBox::~MessageBox()
|
||||||
|
{
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
void MessageBox::update (int height)
|
void MessageBox::update (int height)
|
||||||
{
|
{
|
||||||
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
|
|
@ -59,6 +59,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message);
|
MessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message);
|
||||||
|
~MessageBox();
|
||||||
void setMessage (const std::string& message);
|
void setMessage (const std::string& message);
|
||||||
int getHeight ();
|
int getHeight ();
|
||||||
void update (int height);
|
void update (int height);
|
||||||
|
|
|
@ -46,7 +46,11 @@ namespace
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
TradeWindow::TradeWindow()
|
TradeWindow::TradeWindow()
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
: WindowBase("openmw_trade_window_vr.layout")
|
||||||
|
#else
|
||||||
: WindowBase("openmw_trade_window.layout")
|
: WindowBase("openmw_trade_window.layout")
|
||||||
|
#endif
|
||||||
, mSortModel(nullptr)
|
, mSortModel(nullptr)
|
||||||
, mTradeModel(nullptr)
|
, mTradeModel(nullptr)
|
||||||
, mItemToSell(-1)
|
, mItemToSell(-1)
|
||||||
|
|
|
@ -53,7 +53,6 @@ void WindowBase::onDoubleClick(MyGUI::Widget *_sender)
|
||||||
|
|
||||||
void WindowBase::setVisible(bool visible)
|
void WindowBase::setVisible(bool visible)
|
||||||
{
|
{
|
||||||
Log(Debug::Verbose) << mLayoutName << ".setVisible: " << visible;
|
|
||||||
bool wasVisible = mMainWidget->getVisible();
|
bool wasVisible = mMainWidget->getVisible();
|
||||||
mMainWidget->setVisible(visible);
|
mMainWidget->setVisible(visible);
|
||||||
|
|
||||||
|
@ -123,26 +122,42 @@ void NoDrop::onFrame(float dt)
|
||||||
|
|
||||||
MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance().getMousePosition();
|
MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance().getMousePosition();
|
||||||
|
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
// Since VR mode stretches some windows to full screen, the usual outside condition
|
||||||
|
// won't work
|
||||||
|
mTransparent = false;
|
||||||
|
#endif
|
||||||
if (mDrag->mIsOnDragAndDrop)
|
if (mDrag->mIsOnDragAndDrop)
|
||||||
{
|
{
|
||||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
|
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
|
||||||
while (focus && focus != mWidget)
|
while (focus && focus != mWidget)
|
||||||
|
{
|
||||||
focus = focus->getParent();
|
focus = focus->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
if (focus == mWidget)
|
if (focus == mWidget)
|
||||||
|
{
|
||||||
mTransparent = true;
|
mTransparent = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!mWidget->getAbsoluteCoord().inside(mousePos))
|
if (!mWidget->getAbsoluteCoord().inside(mousePos))
|
||||||
mTransparent = false;
|
mTransparent = false;
|
||||||
|
|
||||||
if (mTransparent)
|
if (mTransparent)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_OPENXR
|
||||||
|
// These makes focus null, which messes up the logic for VR
|
||||||
|
// since i reset mTransparent to false every update.
|
||||||
|
// TODO: Is there a cleaner way?
|
||||||
mWidget->setNeedMouseFocus(false); // Allow click-through
|
mWidget->setNeedMouseFocus(false); // Allow click-through
|
||||||
|
#endif
|
||||||
setAlpha(std::max(0.13f, mWidget->getAlpha() - dt*5));
|
setAlpha(std::max(0.13f, mWidget->getAlpha() - dt*5));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mWidget->setNeedMouseFocus(true);
|
#ifndef USE_OPENXR
|
||||||
|
mWidget->setNeedMouseFocus(true); // Allow click-through
|
||||||
|
#endif
|
||||||
setAlpha(std::min(1.0f, mWidget->getAlpha() + dt*5));
|
setAlpha(std::min(1.0f, mWidget->getAlpha() + dt*5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,6 +204,10 @@ namespace MWGui
|
||||||
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
|
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
|
||||||
mGuiPlatform->initialise(resourcePath, logpath);
|
mGuiPlatform->initialise(resourcePath, logpath);
|
||||||
|
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
mGuiPlatform->getRenderManagerPtr()->setViewSize(1024, 1024);
|
||||||
|
#endif
|
||||||
|
|
||||||
mGui = new MyGUI::Gui;
|
mGui = new MyGUI::Gui;
|
||||||
mGui->initialise("");
|
mGui->initialise("");
|
||||||
|
|
||||||
|
@ -1246,6 +1250,9 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::windowResized(int x, int y)
|
void WindowManager::windowResized(int x, int y)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
|
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
|
||||||
|
|
||||||
// scaled size
|
// scaled size
|
||||||
|
|
|
@ -297,7 +297,10 @@ namespace MWPhysics
|
||||||
auto* session = MWVR::Environment::get().getSession();
|
auto* session = MWVR::Environment::get().getSession();
|
||||||
if (session)
|
if (session)
|
||||||
{
|
{
|
||||||
float yaw = session->movementYaw();
|
float pitch = 0.f;
|
||||||
|
float yaw = 0.f;
|
||||||
|
session->movementAngles(yaw, pitch);
|
||||||
|
refpos.rot[0] += pitch;
|
||||||
refpos.rot[2] += yaw;
|
refpos.rot[2] += yaw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -898,6 +898,7 @@ namespace MWRender
|
||||||
|
|
||||||
|
|
||||||
const bool isPlayer = (mPtr == MWMechanics::getPlayer());
|
const bool isPlayer = (mPtr == MWMechanics::getPlayer());
|
||||||
|
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
{
|
{
|
||||||
Log(Debug::Verbose) << "groupname=" << groupname << ", start=" << start << ", stop=" << stop << ", accumRoot=" << mAccumRoot->getName();
|
Log(Debug::Verbose) << "groupname=" << groupname << ", start=" << start << ", stop=" << stop << ", accumRoot=" << mAccumRoot->getName();
|
||||||
|
@ -1068,7 +1069,8 @@ namespace MWRender
|
||||||
if (groupname.compare(0, 4, "jump"))
|
if (groupname.compare(0, 4, "jump"))
|
||||||
if (groupname.compare(0, 4, "walk"))
|
if (groupname.compare(0, 4, "walk"))
|
||||||
if (groupname.compare(0, 3, "run"))
|
if (groupname.compare(0, 3, "run"))
|
||||||
return false;
|
if (groupname.compare(0, 4, "swim"))
|
||||||
|
return false;
|
||||||
#else
|
#else
|
||||||
(void)groupname;
|
(void)groupname;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -361,10 +361,12 @@ namespace MWRender
|
||||||
if(mPreviewMode)
|
if(mPreviewMode)
|
||||||
limit /= 2;
|
limit /= 2;
|
||||||
|
|
||||||
|
#ifndef USE_OPENXR
|
||||||
if(angle > limit)
|
if(angle > limit)
|
||||||
angle = limit;
|
angle = limit;
|
||||||
else if(angle < -limit)
|
else if(angle < -limit)
|
||||||
angle = -limit;
|
angle = -limit;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mVanity.enabled || mPreviewMode) {
|
if (mVanity.enabled || mPreviewMode) {
|
||||||
mPreviewCam.pitch = angle;
|
mPreviewCam.pitch = angle;
|
||||||
|
|
|
@ -828,16 +828,7 @@ private:
|
||||||
|
|
||||||
if (node && node->getName() == "VRGUILayer")
|
if (node && node->getName() == "VRGUILayer")
|
||||||
{
|
{
|
||||||
// Intersected with a GUI layer
|
|
||||||
// Inject mouse press
|
|
||||||
//VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
|
|
||||||
//userData->mLayer->injectMouseClick(SDL_BUTTON_LEFT, onPress);
|
|
||||||
injectMousePress(SDL_BUTTON_LEFT, onPress);
|
injectMousePress(SDL_BUTTON_LEFT, onPress);
|
||||||
//SDL_MouseButtonEvent arg;
|
|
||||||
//if (onPress)
|
|
||||||
// mousePressed(arg, SDL_BUTTON_LEFT);
|
|
||||||
//else
|
|
||||||
// mouseReleased(arg, SDL_BUTTON_LEFT);
|
|
||||||
}
|
}
|
||||||
else if (onPress)
|
else if (onPress)
|
||||||
{
|
{
|
||||||
|
@ -919,35 +910,11 @@ private:
|
||||||
{
|
{
|
||||||
mXRInput->updateControls();
|
mXRInput->updateControls();
|
||||||
|
|
||||||
auto* world = MWBase::Environment::get().getWorld();
|
auto* vrGuiManager = Environment::get().getGUIManager();
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
vrGuiManager->updateFocus();
|
||||||
if (world && anim && anim->mPointerTarget.mHit)
|
auto guiCursor = vrGuiManager->guiCursor();
|
||||||
{
|
mGuiCursorX = guiCursor.x();
|
||||||
auto* node = anim->mPointerTarget.mHitNode;
|
mGuiCursorY = guiCursor.y();
|
||||||
auto* vrGuiManager = Environment::get().getGUIManager();
|
|
||||||
if (node && node->getName() == "VRGUILayer")
|
|
||||||
{
|
|
||||||
int w, h;
|
|
||||||
SDL_GetWindowSize(mWindow, &w, &h);
|
|
||||||
|
|
||||||
osg::Vec3 local = anim->mPointerTarget.mHitPointLocal;
|
|
||||||
local.x() = (local.x() + 1.f) / 2.f;
|
|
||||||
local.z() = 1.f - (local.z() + 1.f) / 2.f;
|
|
||||||
|
|
||||||
mGuiCursorX = mInvUiScalingFactor * (local.x() * w);
|
|
||||||
mGuiCursorY = mInvUiScalingFactor * (local.z() * h);
|
|
||||||
|
|
||||||
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
|
|
||||||
vrGuiManager->setFocusLayer(userData->mLayer);
|
|
||||||
MyGUI::InputManager::getInstance().injectMouseMove((int)mGuiCursorX, (int)mGuiCursorY, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vrGuiManager->setFocusLayer(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OpenXRActionEvent event{};
|
OpenXRActionEvent event{};
|
||||||
while (mXRInput->nextActionEvent(event))
|
while (mXRInput->nextActionEvent(event))
|
||||||
|
@ -988,7 +955,8 @@ private:
|
||||||
toggleMainMenu();
|
toggleMainMenu();
|
||||||
// Explicitly request position update here so that the player can move the menu
|
// Explicitly request position update here so that the player can move the menu
|
||||||
// using the menu key when the menu can't be toggled.
|
// using the menu key when the menu can't be toggled.
|
||||||
xrGUIManager->updatePose();
|
// TODO: This should respond to a menu HODL instead
|
||||||
|
// xrGUIManager->updateTracking();
|
||||||
break;
|
break;
|
||||||
case A_Screenshot:
|
case A_Screenshot:
|
||||||
screenshot();
|
screenshot();
|
||||||
|
|
|
@ -131,14 +131,12 @@ namespace MWVR
|
||||||
roll = angle_y;
|
roll = angle_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
float OpenXRSession::movementYaw(void)
|
void OpenXRSession::movementAngles(float& yaw, float& pitch)
|
||||||
{
|
{
|
||||||
auto lhandquat = predictedPoses(PredictionSlice::Predraw).hands[(int)TrackedSpace::VIEW][(int)MWVR::Side::LEFT_HAND].orientation;
|
auto lhandquat = predictedPoses(PredictionSlice::Predraw).hands[(int)TrackedSpace::VIEW][(int)MWVR::Side::LEFT_HAND].orientation;
|
||||||
float yaw = 0.f;
|
|
||||||
float pitch = 0.f;
|
|
||||||
float roll = 0.f;
|
float roll = 0.f;
|
||||||
getEulerAngles(lhandquat, yaw, pitch, roll);
|
getEulerAngles(lhandquat, yaw, pitch, roll);
|
||||||
return yaw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenXRSession::advanceFrame(void)
|
void OpenXRSession::advanceFrame(void)
|
||||||
|
|
|
@ -47,8 +47,8 @@ public:
|
||||||
//! Update predictions
|
//! Update predictions
|
||||||
void predictNext(int extraPeriods);
|
void predictNext(int extraPeriods);
|
||||||
|
|
||||||
//! Yaw angle to be used for offsetting movement direction
|
//! Angles to be used for overriding movement direction
|
||||||
float movementYaw(void);
|
void movementAngles(float& yaw, float& pitch);
|
||||||
|
|
||||||
void advanceFrame(void);
|
void advanceFrame(void);
|
||||||
|
|
||||||
|
|
|
@ -465,7 +465,7 @@ VRAnimation::VRAnimation(
|
||||||
);
|
);
|
||||||
mWeaponPointerTransform->setName("Weapon Pointer");
|
mWeaponPointerTransform->setName("Weapon Pointer");
|
||||||
mWeaponPointerTransform->setUpdateCallback(new WeaponPointerController);
|
mWeaponPointerTransform->setUpdateCallback(new WeaponPointerController);
|
||||||
mWeaponDirectionTransform->addChild(mWeaponPointerTransform);
|
//mWeaponDirectionTransform->addChild(mWeaponPointerTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
VRAnimation::~VRAnimation() {};
|
VRAnimation::~VRAnimation() {};
|
||||||
|
@ -538,7 +538,13 @@ void VRAnimation::setPointForward(bool enabled)
|
||||||
|
|
||||||
mPointerTransform->removeChild(mPointerRescale);
|
mPointerTransform->removeChild(mPointerRescale);
|
||||||
if (enabled)
|
if (enabled)
|
||||||
|
{
|
||||||
mPointerTransform->addChild(mPointerRescale);
|
mPointerTransform->addChild(mPointerRescale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPointerTarget = MWRender::RayResult{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geometry> VRAnimation::createPointerGeometry(void)
|
osg::ref_ptr<osg::Geometry> VRAnimation::createPointerGeometry(void)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../mwrender/camera.hpp"
|
#include "../mwrender/camera.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwgui/windowbase.hpp"
|
#include "../mwgui/windowbase.hpp"
|
||||||
|
|
||||||
#include <MyGUI_Widget.h>
|
#include <MyGUI_Widget.h>
|
||||||
|
@ -28,9 +29,22 @@
|
||||||
#include <MyGUI_WidgetManager.h>
|
#include <MyGUI_WidgetManager.h>
|
||||||
#include <MyGUI_Window.h>
|
#include <MyGUI_Window.h>
|
||||||
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
// Convenience
|
||||||
|
const double PI_8 = osg::PI_4 / 2.;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// When making a circle of a given radius of equally wide planes separated by a given angle, what is the width
|
||||||
|
static osg::Vec2 radiusAngleWidth(float radius, float angleRadian)
|
||||||
|
{
|
||||||
|
const float width = std::fabs( 2.f * radius * std::tanf(angleRadian / 2.f) );
|
||||||
|
return osg::Vec2(width, width);
|
||||||
|
}
|
||||||
|
|
||||||
/// RTT camera used to draw the osg GUI to a texture
|
/// RTT camera used to draw the osg GUI to a texture
|
||||||
class GUICamera : public osg::Camera
|
class GUICamera : public osg::Camera
|
||||||
{
|
{
|
||||||
|
@ -120,18 +134,11 @@ private:
|
||||||
VRGUILayer::VRGUILayer(
|
VRGUILayer::VRGUILayer(
|
||||||
osg::ref_ptr<osg::Group> geometryRoot,
|
osg::ref_ptr<osg::Group> geometryRoot,
|
||||||
osg::ref_ptr<osg::Group> cameraRoot,
|
osg::ref_ptr<osg::Group> cameraRoot,
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
std::string filter,
|
std::string filter,
|
||||||
LayerConfig config,
|
LayerConfig config,
|
||||||
MWGui::Layout* widget,
|
|
||||||
VRGUIManager* parent)
|
VRGUIManager* parent)
|
||||||
: mConfig(config)
|
: mConfig(config)
|
||||||
, mFilter(filter)
|
, mFilter(filter)
|
||||||
, mWidget(widget)
|
|
||||||
, mWindow(dynamic_cast<MWGui::WindowBase*>(mWidget))
|
|
||||||
, mMyGUIWindow(dynamic_cast<MyGUI::Window*>(mWidget->mMainWidget))
|
|
||||||
, mParent(parent)
|
|
||||||
, mGeometryRoot(geometryRoot)
|
, mGeometryRoot(geometryRoot)
|
||||||
, mCameraRoot(cameraRoot)
|
, mCameraRoot(cameraRoot)
|
||||||
{
|
{
|
||||||
|
@ -139,14 +146,18 @@ VRGUILayer::VRGUILayer(
|
||||||
osg::ref_ptr<osg::Vec2Array> texCoords{ new osg::Vec2Array(4) };
|
osg::ref_ptr<osg::Vec2Array> texCoords{ new osg::Vec2Array(4) };
|
||||||
osg::ref_ptr<osg::Vec3Array> normals{ new osg::Vec3Array(1) };
|
osg::ref_ptr<osg::Vec3Array> normals{ new osg::Vec3Array(1) };
|
||||||
|
|
||||||
// Units are divided by 2 because geometry has an extent of 2 (-1 to 1)
|
auto extent_units = config.extent * Environment::get().unitsPerMeter();
|
||||||
auto extent_units = config.extent * Environment::get().unitsPerMeter() / 2.f;
|
|
||||||
|
float left = mConfig.center.x() - 0.5;
|
||||||
|
float right = left + 1.f;
|
||||||
|
float top = 0.5f + mConfig.center.y();
|
||||||
|
float bottom = top - 1.f;
|
||||||
|
|
||||||
// Define the menu quad
|
// Define the menu quad
|
||||||
osg::Vec3 top_left (-1, 1, 1);
|
osg::Vec3 top_left (left, 1, top);
|
||||||
osg::Vec3 bottom_left(-1, 1, -1);
|
osg::Vec3 bottom_left(left, 1, bottom);
|
||||||
osg::Vec3 bottom_right(1, 1, -1);
|
osg::Vec3 bottom_right(right , 1, bottom);
|
||||||
osg::Vec3 top_right (1, 1, 1);
|
osg::Vec3 top_right (right, 1, top);
|
||||||
(*vertices)[0] = top_left;
|
(*vertices)[0] = top_left;
|
||||||
(*vertices)[1] = bottom_left;
|
(*vertices)[1] = bottom_left;
|
||||||
(*vertices)[2] = bottom_right;
|
(*vertices)[2] = bottom_right;
|
||||||
|
@ -163,20 +174,23 @@ VRGUILayer::VRGUILayer(
|
||||||
mGeometry->setDataVariance(osg::Object::DYNAMIC);
|
mGeometry->setDataVariance(osg::Object::DYNAMIC);
|
||||||
mGeometry->setSupportsDisplayList(false);
|
mGeometry->setSupportsDisplayList(false);
|
||||||
mGeometry->setName("VRGUILayer");
|
mGeometry->setName("VRGUILayer");
|
||||||
mGeometry->setUserData(new VRGUILayerUserData(this));
|
|
||||||
|
|
||||||
// Create the camera that will render the menu texture
|
// Create the camera that will render the menu texture
|
||||||
mGUICamera = new GUICamera(width, height, config.backgroundColor);
|
mGUICamera = new GUICamera(config.pixelResolution.x(), config.pixelResolution.y(), config.backgroundColor);
|
||||||
osgMyGUI::RenderManager& renderManager = static_cast<osgMyGUI::RenderManager&>(MyGUI::RenderManager::getInstance());
|
osgMyGUI::RenderManager& renderManager = static_cast<osgMyGUI::RenderManager&>(MyGUI::RenderManager::getInstance());
|
||||||
mGUICamera->setScene(renderManager.createGUICamera(osg::Camera::NESTED_RENDER, filter));
|
mMyGUICamera = renderManager.createGUICamera(osg::Camera::NESTED_RENDER, filter);
|
||||||
|
//myGUICamera->setViewport(0, 0, 256, 256);
|
||||||
|
//mMyGUICamera->setProjectionMatrixAsOrtho2D(-1, 1, -1, 1);
|
||||||
|
mGUICamera->setScene(mMyGUICamera);
|
||||||
|
|
||||||
// Define state set that allows rendering with transparency
|
// Define state set that allows rendering with transparency
|
||||||
mStateSet->setTextureAttributeAndModes(0, menuTexture(), osg::StateAttribute::ON);
|
osg::StateSet* stateSet = mGeometry->getOrCreateStateSet();
|
||||||
mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
stateSet->setTextureAttributeAndModes(0, menuTexture(), osg::StateAttribute::ON);
|
||||||
mStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
mStateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
mStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
mGeometry->setStateSet(mStateSet);
|
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
|
mGeometry->setStateSet(stateSet);
|
||||||
|
|
||||||
// Position in the game world
|
// Position in the game world
|
||||||
mTransform->setScale(osg::Vec3(extent_units.x(), 1.f, extent_units.y()));
|
mTransform->setScale(osg::Vec3(extent_units.x(), 1.f, extent_units.y()));
|
||||||
|
@ -186,6 +200,10 @@ VRGUILayer::VRGUILayer(
|
||||||
mGeometryRoot->addChild(mTransform);
|
mGeometryRoot->addChild(mTransform);
|
||||||
mCameraRoot->addChild(mGUICamera);
|
mCameraRoot->addChild(mGUICamera);
|
||||||
|
|
||||||
|
// Edit offset to account for priority
|
||||||
|
if(!mConfig.sideBySide)
|
||||||
|
mConfig.offset.y() -= 0.001f * mConfig.priority;
|
||||||
|
|
||||||
mTransform->addUpdateCallback(new LayerUpdateCallback(this));
|
mTransform->addUpdateCallback(new LayerUpdateCallback(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,68 +224,174 @@ osg::ref_ptr<osg::Texture2D> VRGUILayer::menuTexture()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUILayer::updatePose()
|
void VRGUILayer::setAngle(float angle)
|
||||||
{
|
{
|
||||||
osg::Vec3 eye{};
|
mRotation = osg::Quat{ angle, osg::Z_AXIS };
|
||||||
osg::Vec3 center{};
|
updatePose();
|
||||||
osg::Vec3 up{};
|
}
|
||||||
|
|
||||||
// Get head pose by reading the camera view matrix to place the GUI in the world.
|
void VRGUILayer::updateTracking(const Pose& headPose)
|
||||||
Pose headPose{};
|
{
|
||||||
auto* world = MWBase::Environment::get().getWorld();
|
if (mConfig.trackingMode == TrackingMode::Menu)
|
||||||
if (!world)
|
|
||||||
return;
|
|
||||||
auto* camera = world->getRenderingManager().getCamera()->getOsgCamera();
|
|
||||||
if (!camera)
|
|
||||||
return;
|
|
||||||
camera->getViewMatrixAsLookAt(eye, center, up);
|
|
||||||
headPose.position = eye;
|
|
||||||
headPose.orientation = camera->getViewMatrix().getRotate();
|
|
||||||
|
|
||||||
if (mConfig.trackedLimb == TrackedLimb::HEAD)
|
|
||||||
{
|
{
|
||||||
mTrackedPose = headPose;
|
mTrackedPose = headPose;
|
||||||
mTrackedPose.orientation = mTrackedPose.orientation.inverse();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If it's not head, it's one of the hands, so i don't bother checking
|
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||||
auto* session = MWVR::Environment::get().getSession();
|
if (anim)
|
||||||
auto& poses = session->predictedPoses(OpenXRSession::PredictionSlice::Predraw);
|
{
|
||||||
mTrackedPose = poses.hands[(int)TrackedSpace::STAGE][(int)mConfig.trackedLimb];
|
const osg::Node* hand = nullptr;
|
||||||
// World position is the head, so must add difference between head and hand in tracking space to world pose
|
if (mConfig.trackingMode == TrackingMode::HudLeftHand)
|
||||||
mTrackedPose.position = mTrackedPose.position * MWVR::Environment::get().unitsPerMeter() - poses.head[(int)TrackedSpace::STAGE].position * MWVR::Environment::get().unitsPerMeter() + headPose.position;
|
hand = anim->getNode("bip01 l hand");
|
||||||
|
else
|
||||||
|
hand = anim->getNode("bip01 r hand");
|
||||||
|
if (hand)
|
||||||
|
{
|
||||||
|
auto world = osg::computeLocalToWorld(hand->getParentalNodePaths()[0]);
|
||||||
|
mTrackedPose.position = world.getTrans();
|
||||||
|
mTrackedPose.orientation = world.getRotate();
|
||||||
|
if (mConfig.trackingMode == TrackingMode::HudRightHand)
|
||||||
|
mTrackedPose.orientation = osg::Quat(osg::PI, osg::Vec3(1, 0, 0)) * mTrackedPose.orientation;
|
||||||
|
mTrackedPose.orientation = osg::Quat(osg::PI_2, osg::Vec3(0, 0, 1)) * mTrackedPose.orientation;
|
||||||
|
mTrackedPose.orientation = osg::Quat(osg::PI, osg::Vec3(1, 0, 0)) * mTrackedPose.orientation;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLayerPose.orientation = mConfig.rotation * mTrackedPose.orientation;
|
updatePose();
|
||||||
|
}
|
||||||
|
|
||||||
if (mConfig.vertical)
|
void VRGUILayer::updatePose()
|
||||||
|
{
|
||||||
|
|
||||||
|
auto orientation = mRotation * mTrackedPose.orientation;
|
||||||
|
|
||||||
|
if (mConfig.trackingMode == TrackingMode::Menu)
|
||||||
{
|
{
|
||||||
// Force layer to be vertical
|
// Force menu layers to be vertical
|
||||||
auto axis = osg::Z_AXIS;
|
auto axis = osg::Z_AXIS;
|
||||||
osg::Quat vertical;
|
osg::Quat vertical;
|
||||||
auto local = mLayerPose.orientation * axis;
|
auto local = orientation * axis;
|
||||||
vertical.makeRotate(local, axis);
|
vertical.makeRotate(local, axis);
|
||||||
mLayerPose.orientation = mLayerPose.orientation * vertical;
|
orientation = orientation * vertical;
|
||||||
}
|
}
|
||||||
// Orient the offset and move the layer
|
// Orient the offset and move the layer
|
||||||
mLayerPose.position = mTrackedPose.position + mLayerPose.orientation * mConfig.offset * MWVR::Environment::get().unitsPerMeter();
|
auto position = mTrackedPose.position + orientation * mConfig.offset * MWVR::Environment::get().unitsPerMeter();
|
||||||
|
|
||||||
mTransform->setAttitude(mLayerPose.orientation);
|
mTransform->setAttitude(orientation);
|
||||||
mTransform->setPosition(mLayerPose.position);
|
mTransform->setPosition(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUILayer::updateRect()
|
||||||
|
{
|
||||||
|
auto viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
mRealRect.left = 1.f;
|
||||||
|
mRealRect.top = 1.f;
|
||||||
|
mRealRect.right = 0.f;
|
||||||
|
mRealRect.bottom = 0.f;
|
||||||
|
float realWidth = static_cast<float>(viewSize.width);
|
||||||
|
float realHeight = static_cast<float>(viewSize.height);
|
||||||
|
for (auto* widget : mWidgets)
|
||||||
|
{
|
||||||
|
auto rect = widget->mMainWidget->getAbsoluteRect();
|
||||||
|
mRealRect.left = std::min(static_cast<float>(rect.left) / realWidth, mRealRect.left);
|
||||||
|
mRealRect.top = std::min(static_cast<float>(rect.top) / realHeight, mRealRect.top);
|
||||||
|
mRealRect.right = std::max(static_cast<float>(rect.right) / realWidth, mRealRect.right);
|
||||||
|
mRealRect.bottom = std::max(static_cast<float>(rect.bottom) / realHeight, mRealRect.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some widgets don't capture the full visual
|
||||||
|
if (mFilter == "JournalBooks" || mFilter == "MessageBox" )
|
||||||
|
{
|
||||||
|
mRealRect.left = 0.f;
|
||||||
|
mRealRect.top = 0.f;
|
||||||
|
mRealRect.right = 1.f;
|
||||||
|
mRealRect.bottom = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFilter == "Notification")
|
||||||
|
{
|
||||||
|
// The latest widget for notification is always the top one
|
||||||
|
// So we just have to stretch the rectangle to the bottom
|
||||||
|
// TODO: This might get deprecated with this new system?
|
||||||
|
mRealRect.bottom = 1.f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUILayer::update()
|
void VRGUILayer::update()
|
||||||
{
|
{
|
||||||
if (mConfig.trackingMode == TrackingMode::Auto)
|
if (mConfig.trackingMode != TrackingMode::Menu)
|
||||||
updatePose();
|
updateTracking();
|
||||||
|
|
||||||
if (mConfig.stretch)
|
if (mConfig.sideBySide)
|
||||||
{
|
{
|
||||||
if (mWindow && mMyGUIWindow)
|
// The side-by-side windows are also the resizable windows.
|
||||||
|
// Stretch according to config
|
||||||
|
// This genre of layer should only ever have 1 widget as it will cover the full layer
|
||||||
|
auto* widget = mWidgets.front();
|
||||||
|
auto* myGUIWindow = dynamic_cast<MyGUI::Window*>(widget->mMainWidget);
|
||||||
|
auto* windowBase = dynamic_cast<MWGui::WindowBase*>(widget);
|
||||||
|
if (windowBase && myGUIWindow)
|
||||||
{
|
{
|
||||||
mWindow->setCoordf(0.f, 0.f, 1.f, 1.f);
|
auto w = mConfig.myGUIViewSize.x();
|
||||||
mWindow->onWindowResize(mMyGUIWindow);
|
auto h = mConfig.myGUIViewSize.y();
|
||||||
|
windowBase->setCoordf(0.f, 0.f, w, h);
|
||||||
|
windowBase->onWindowResize(myGUIWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateRect();
|
||||||
|
|
||||||
|
float w = 0.f;
|
||||||
|
float h = 0.f;
|
||||||
|
for (auto* widget : mWidgets)
|
||||||
|
{
|
||||||
|
w = std::max(w, (float)widget->mMainWidget->getWidth());
|
||||||
|
h = std::max(h, (float)widget->mMainWidget->getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pixels per unit
|
||||||
|
float res = static_cast<float>(mConfig.spatialResolution) / Environment::get().unitsPerMeter();
|
||||||
|
|
||||||
|
if (mConfig.sizingMode == SizingMode::Auto)
|
||||||
|
{
|
||||||
|
mTransform->setScale(osg::Vec3(w / res, 1.f, h / res));
|
||||||
|
}
|
||||||
|
if (mFilter == "Notification")
|
||||||
|
{
|
||||||
|
auto viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
h = (1.f - mRealRect.top) * viewSize.height;
|
||||||
|
mTransform->setScale(osg::Vec3(w / res, 1.f, h / res));
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Vec2Array> texCoords{ new osg::Vec2Array(4) };
|
||||||
|
(*texCoords)[0].set(mRealRect.left, 1.f - mRealRect.top);
|
||||||
|
(*texCoords)[1].set(mRealRect.left, 1.f - mRealRect.bottom);
|
||||||
|
(*texCoords)[2].set(mRealRect.right, 1.f - mRealRect.bottom);
|
||||||
|
(*texCoords)[3].set(mRealRect.right, 1.f - mRealRect.top);
|
||||||
|
mGeometry->setTexCoordArray(0, texCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRGUILayer::insertWidget(
|
||||||
|
MWGui::Layout* widget)
|
||||||
|
{
|
||||||
|
for (auto* w : mWidgets)
|
||||||
|
if (w == widget)
|
||||||
|
return;
|
||||||
|
mWidgets.push_back(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VRGUILayer::removeWidget(
|
||||||
|
MWGui::Layout* widget)
|
||||||
|
{
|
||||||
|
for (auto it = mWidgets.begin(); it != mWidgets.end(); it++)
|
||||||
|
{
|
||||||
|
if (*it == widget)
|
||||||
|
{
|
||||||
|
mWidgets.erase(it);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,148 +425,255 @@ void VRGUIManager::showGUIs(bool show)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LayerConfig gDefaultConfig = LayerConfig
|
static const LayerConfig createDefaultConfig(int priority)
|
||||||
{
|
{
|
||||||
true, // stretch
|
return LayerConfig{
|
||||||
osg::Vec4{0.f,0.f,0.f,.75f}, // background
|
1,
|
||||||
osg::Quat{}, // rotation
|
false, // side-by-side
|
||||||
osg::Vec3(0.f,1.f,0.f), // offset
|
osg::Vec4{0.f,0.f,0.f,.75f}, // background
|
||||||
osg::Vec2(1.f, 1.f), // extent (meters)
|
osg::Vec3(0.f,0.66f,-.25f), // offset
|
||||||
osg::Vec2i(2024,2024), // resolution (pixels)
|
osg::Vec2(0.f,0.f), // center (model space)
|
||||||
TrackedLimb::HEAD,
|
osg::Vec2(1.f, 1.f), // extent (meters)
|
||||||
TrackingMode::Manual,
|
1024, // Spatial resolution (pixels per meter)
|
||||||
true // vertical
|
osg::Vec2i(2048,2048), // Texture resolution
|
||||||
|
osg::Vec2(1,1),
|
||||||
|
SizingMode::Auto,
|
||||||
|
TrackingMode::Menu
|
||||||
|
};
|
||||||
|
}
|
||||||
|
LayerConfig gDefaultConfig = createDefaultConfig(1);
|
||||||
|
LayerConfig gJournalBooksConfig = LayerConfig
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
gDefaultConfig.sideBySide,
|
||||||
|
osg::Vec4{}, // background
|
||||||
|
gDefaultConfig.offset,
|
||||||
|
gDefaultConfig.center,
|
||||||
|
gDefaultConfig.extent,
|
||||||
|
gDefaultConfig.spatialResolution,
|
||||||
|
gDefaultConfig.pixelResolution,
|
||||||
|
gDefaultConfig.myGUIViewSize,
|
||||||
|
SizingMode::Fixed,
|
||||||
|
gDefaultConfig.trackingMode
|
||||||
};
|
};
|
||||||
|
LayerConfig gDefaultWindowsConfig = createDefaultConfig(3);
|
||||||
|
LayerConfig gMessageBoxConfig = gJournalBooksConfig;
|
||||||
|
LayerConfig gNotificationConfig = gJournalBooksConfig;
|
||||||
|
|
||||||
|
static const float sSideBySideRadius = 1.f;
|
||||||
|
static const float sSideBySideAzimuthInterval = -osg::PI_4;
|
||||||
|
static const LayerConfig createSideBySideConfig(int priority)
|
||||||
|
{
|
||||||
|
return LayerConfig{
|
||||||
|
priority,
|
||||||
|
true, // side-by-side
|
||||||
|
gDefaultConfig.backgroundColor,
|
||||||
|
osg::Vec3(0.f,sSideBySideRadius,-.25f), // offset
|
||||||
|
gDefaultConfig.center,
|
||||||
|
radiusAngleWidth(sSideBySideRadius, sSideBySideAzimuthInterval), // extent (meters)
|
||||||
|
gDefaultConfig.spatialResolution,
|
||||||
|
gDefaultConfig.pixelResolution,
|
||||||
|
osg::Vec2(0.70f, 0.70f),
|
||||||
|
SizingMode::Fixed,
|
||||||
|
gDefaultConfig.trackingMode
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
LayerConfig gStatsWindowConfig = createSideBySideConfig(0);
|
||||||
|
LayerConfig gInventoryWindowConfig = createSideBySideConfig(1);
|
||||||
|
LayerConfig gSpellWindowConfig = createSideBySideConfig(2);
|
||||||
|
LayerConfig gMapWindowConfig = createSideBySideConfig(3);
|
||||||
|
LayerConfig gInventoryCompanionWindowConfig = createSideBySideConfig(4);
|
||||||
|
LayerConfig gDialogueWindowConfig = createSideBySideConfig(5);
|
||||||
|
|
||||||
LayerConfig gStatusHUDConfig = LayerConfig
|
LayerConfig gStatusHUDConfig = LayerConfig
|
||||||
{
|
{
|
||||||
false, // stretch
|
0,
|
||||||
osg::Vec4{0.f,0.f,0.f,0.f}, // background
|
false, // side-by-side
|
||||||
osg::Quat{}, // rotation
|
osg::Vec4{}, // background
|
||||||
osg::Vec3(0.f,.0f,.2f), // offset (meters)
|
osg::Vec3(0.025f,.025f,.066f), // offset (meters)
|
||||||
osg::Vec2(.2f, .2f), // extent (meters)
|
osg::Vec2(0.f,0.5f), // center (model space)
|
||||||
osg::Vec2i(1024,512), // resolution (pixels)
|
osg::Vec2(.1f, .1f), // extent (meters)
|
||||||
TrackedLimb::RIGHT_HAND,
|
1024, // resolution (pixels per meter)
|
||||||
TrackingMode::Auto,
|
osg::Vec2i(1024,1024),
|
||||||
false // vertical
|
gDefaultConfig.myGUIViewSize,
|
||||||
};
|
SizingMode::Auto,
|
||||||
|
TrackingMode::HudLeftHand,
|
||||||
LayerConfig gMinimapHUDConfig = LayerConfig
|
|
||||||
{
|
|
||||||
false, // stretch
|
|
||||||
osg::Vec4{0.f,0.f,0.f,0.f}, // background
|
|
||||||
osg::Quat{}, // rotation
|
|
||||||
osg::Vec3(0.f,.0f,.2f), // offset (meters)
|
|
||||||
osg::Vec2(.2f, .2f), // extent (meters)
|
|
||||||
osg::Vec2i(1024,512), // resolution (pixels)
|
|
||||||
TrackedLimb::RIGHT_HAND,
|
|
||||||
TrackingMode::Auto,
|
|
||||||
false // vertical
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LayerConfig gPopupConfig = LayerConfig
|
LayerConfig gPopupConfig = LayerConfig
|
||||||
{
|
{
|
||||||
false, // stretch
|
0,
|
||||||
|
false, // side-by-side
|
||||||
osg::Vec4{0.f,0.f,0.f,0.f}, // background
|
osg::Vec4{0.f,0.f,0.f,0.f}, // background
|
||||||
osg::Quat{}, // rotation
|
osg::Vec3(-0.025f,.025f,.066f), // offset (meters)
|
||||||
osg::Vec3(0.f,0.f,.2f), // offset
|
osg::Vec2(0.f,0.5f), // center (model space)
|
||||||
osg::Vec2(.2f, .2f), // extent (meters)
|
osg::Vec2(.1f, .1f), // extent (meters)
|
||||||
osg::Vec2i(1024,1024),
|
1024, // resolution (pixels per meter)
|
||||||
TrackedLimb::RIGHT_HAND,
|
osg::Vec2i(2048,2048),
|
||||||
TrackingMode::Auto,
|
gDefaultConfig.myGUIViewSize,
|
||||||
false // vertical
|
SizingMode::Auto,
|
||||||
|
TrackingMode::HudRightHand,
|
||||||
};
|
};
|
||||||
|
|
||||||
LayerConfig gWindowsConfig = gDefaultConfig;
|
|
||||||
LayerConfig gJournalBooksConfig = LayerConfig
|
|
||||||
{
|
|
||||||
true, // stretch
|
|
||||||
gDefaultConfig.backgroundColor,
|
|
||||||
osg::Quat{}, // rotation
|
|
||||||
gDefaultConfig.offset,
|
|
||||||
gDefaultConfig.extent,
|
|
||||||
gDefaultConfig.resolution,
|
|
||||||
TrackedLimb::HEAD,
|
|
||||||
TrackingMode::Manual,
|
|
||||||
true // vertical
|
|
||||||
};
|
|
||||||
LayerConfig gSpellWindowConfig = LayerConfig
|
|
||||||
{
|
|
||||||
true, // stretch
|
|
||||||
gDefaultConfig.backgroundColor,
|
|
||||||
osg::Quat{-osg::PI_2, osg::Z_AXIS}, // rotation
|
|
||||||
gDefaultConfig.offset,
|
|
||||||
gDefaultConfig.extent,
|
|
||||||
gDefaultConfig.resolution,
|
|
||||||
TrackedLimb::HEAD,
|
|
||||||
TrackingMode::Manual,
|
|
||||||
true // vertical
|
|
||||||
};
|
|
||||||
LayerConfig gInventoryWindowConfig = LayerConfig
|
|
||||||
{
|
|
||||||
true, // stretch
|
|
||||||
gDefaultConfig.backgroundColor,
|
|
||||||
osg::Quat{}, // rotation
|
|
||||||
gDefaultConfig.offset,
|
|
||||||
gDefaultConfig.extent,
|
|
||||||
gDefaultConfig.resolution,
|
|
||||||
TrackedLimb::HEAD,
|
|
||||||
TrackingMode::Manual,
|
|
||||||
true // vertical
|
|
||||||
};
|
|
||||||
LayerConfig gMapWindowConfig = LayerConfig
|
|
||||||
{
|
|
||||||
true, // stretch
|
|
||||||
gDefaultConfig.backgroundColor,
|
|
||||||
osg::Quat{osg::PI, osg::Z_AXIS}, // rotation
|
|
||||||
gDefaultConfig.offset,
|
|
||||||
gDefaultConfig.extent,
|
|
||||||
gDefaultConfig.resolution,
|
|
||||||
TrackedLimb::HEAD,
|
|
||||||
TrackingMode::Manual,
|
|
||||||
true // vertical
|
|
||||||
};
|
|
||||||
LayerConfig gStatsWindowConfig = LayerConfig
|
|
||||||
{
|
|
||||||
true, // stretch
|
|
||||||
gDefaultConfig.backgroundColor,
|
|
||||||
osg::Quat{osg::PI_2, osg::Z_AXIS}, // rotation
|
|
||||||
gDefaultConfig.offset,
|
|
||||||
gDefaultConfig.extent,
|
|
||||||
gDefaultConfig.resolution,
|
|
||||||
TrackedLimb::HEAD,
|
|
||||||
TrackingMode::Manual,
|
|
||||||
true // vertical
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static std::map<std::string, LayerConfig&> gLayerConfigs =
|
static std::map<std::string, LayerConfig&> gLayerConfigs =
|
||||||
{
|
{
|
||||||
{"StatusHUD", gStatusHUDConfig},
|
{"StatusHUD", gStatusHUDConfig},
|
||||||
{"MinimapHUD", gMinimapHUDConfig},
|
//{"MinimapHUD", gMinimapHUDConfig},
|
||||||
{"Popup", gPopupConfig},
|
{"Popup", gPopupConfig},
|
||||||
{"Windows", gWindowsConfig},
|
|
||||||
{"JournalBooks", gJournalBooksConfig},
|
{"JournalBooks", gJournalBooksConfig},
|
||||||
{"SpellWindow", gSpellWindowConfig},
|
{"InventoryCompanionWindow", gInventoryCompanionWindowConfig},
|
||||||
{"InventoryWindow", gInventoryWindowConfig},
|
{"InventoryWindow", gInventoryWindowConfig},
|
||||||
|
{"SpellWindow", gSpellWindowConfig},
|
||||||
{"MapWindow", gMapWindowConfig},
|
{"MapWindow", gMapWindowConfig},
|
||||||
{"StatsWindow", gStatsWindowConfig},
|
{"StatsWindow", gStatsWindowConfig},
|
||||||
{"Default", gDefaultConfig},
|
{"DialogueWindow", gDialogueWindowConfig},
|
||||||
|
{"MessageBox", gMessageBoxConfig},
|
||||||
|
{"Windows", gDefaultWindowsConfig},
|
||||||
|
{"Notification", gNotificationConfig}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::set<std::string> layerBlacklist =
|
static std::set<std::string> layerBlacklist =
|
||||||
{
|
{
|
||||||
"Overlay"
|
"Overlay",
|
||||||
|
"AdditiveOverlay"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void VRGUIManager::updateSideBySideLayers()
|
||||||
|
{
|
||||||
|
// Nothing to update
|
||||||
|
if (mSideBySideLayers.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::sort(mSideBySideLayers.begin(), mSideBySideLayers.end(), [](const auto& lhs, const auto& rhs) { return *lhs < *rhs; });
|
||||||
|
|
||||||
|
int n = mSideBySideLayers.size();
|
||||||
|
|
||||||
|
float span = sSideBySideAzimuthInterval * (n - 1); // zero index, places lone layers straight ahead
|
||||||
|
float low = -span / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < mSideBySideLayers.size(); i++)
|
||||||
|
mSideBySideLayers[i]->setAngle(low + static_cast<float>(i) * sSideBySideAzimuthInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUIManager::insertLayer(const std::string& name)
|
||||||
|
{
|
||||||
|
LayerConfig config = gDefaultConfig;
|
||||||
|
auto configIt = gLayerConfigs.find(name);
|
||||||
|
if (configIt != gLayerConfigs.end())
|
||||||
|
{
|
||||||
|
config = configIt->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Layer " << name << " has no configuration, using default";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto layer = std::shared_ptr<VRGUILayer>(new VRGUILayer(
|
||||||
|
mGUIGeometriesRoot,
|
||||||
|
mGUICamerasRoot,
|
||||||
|
name,
|
||||||
|
config,
|
||||||
|
this
|
||||||
|
));
|
||||||
|
mLayers[name] = layer;
|
||||||
|
|
||||||
|
layer->mGeometry->setUserData(new VRGUILayerUserData(mLayers[name]));
|
||||||
|
|
||||||
|
// Default new layer's pick to false
|
||||||
|
// TODO: re-add widget->setLayerPick(false) somewhere;
|
||||||
|
|
||||||
|
if (config.sideBySide)
|
||||||
|
{
|
||||||
|
mSideBySideLayers.push_back(layer);
|
||||||
|
updateSideBySideLayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.trackingMode == TrackingMode::Menu)
|
||||||
|
{
|
||||||
|
// Update tracking when a menu is opened
|
||||||
|
// But don't automatically update it again until all menus have been closed
|
||||||
|
if (mVisibleMenus == 0)
|
||||||
|
updateTracking();
|
||||||
|
else
|
||||||
|
layer->updateTracking(mHeadPose);
|
||||||
|
mVisibleMenus++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUIManager::insertWidget(MWGui::Layout* widget)
|
||||||
|
{
|
||||||
|
auto* layer = widget->mMainWidget->getLayer();
|
||||||
|
auto name = layer->getName();
|
||||||
|
|
||||||
|
auto it = mLayers.find(name);
|
||||||
|
if (it == mLayers.end())
|
||||||
|
{
|
||||||
|
insertLayer(name);
|
||||||
|
it = mLayers.find(name);
|
||||||
|
if (it == mLayers.end())
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Failed to insert layer " << name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it->second->insertWidget(widget);
|
||||||
|
|
||||||
|
if (it->second.get() != mFocusLayer)
|
||||||
|
widget->setLayerPick(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUIManager::removeLayer(const std::string& name)
|
||||||
|
{
|
||||||
|
auto it = mLayers.find(name);
|
||||||
|
if (it == mLayers.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto layer = it->second;
|
||||||
|
|
||||||
|
for (auto it2 = mSideBySideLayers.begin(); it2 < mSideBySideLayers.end(); it2++)
|
||||||
|
{
|
||||||
|
if (*it2 == layer)
|
||||||
|
{
|
||||||
|
mSideBySideLayers.erase(it2);
|
||||||
|
updateSideBySideLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->second.get() == mFocusLayer)
|
||||||
|
setFocusLayer(nullptr);
|
||||||
|
|
||||||
|
if (it->second->mConfig.trackingMode == TrackingMode::Menu)
|
||||||
|
mVisibleMenus--;
|
||||||
|
|
||||||
|
mLayers.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUIManager::removeWidget(MWGui::Layout* widget)
|
||||||
|
{
|
||||||
|
auto* layer = widget->mMainWidget->getLayer();
|
||||||
|
auto name = layer->getName();
|
||||||
|
|
||||||
|
auto it = mLayers.find(name);
|
||||||
|
if (it == mLayers.end())
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Tried to remove widget from nonexistent layer " << name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->second->removeWidget(widget);
|
||||||
|
if (it->second->widgetCount() == 0)
|
||||||
|
{
|
||||||
|
removeLayer(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VRGUIManager::setVisible(MWGui::Layout* widget, bool visible)
|
void VRGUIManager::setVisible(MWGui::Layout* widget, bool visible)
|
||||||
{
|
{
|
||||||
auto* layer = widget->mMainWidget->getLayer();
|
auto* layer = widget->mMainWidget->getLayer();
|
||||||
//if (!layer)
|
|
||||||
//{
|
|
||||||
// Log(Debug::Warning) << "Hark! MyGUI has betrayed us. The widget " << widget->mMainWidget->getName() << " has no layer";
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
auto name = layer->getName();
|
auto name = layer->getName();
|
||||||
|
|
||||||
Log(Debug::Verbose) << "setVisible (" << name << "): " << visible;
|
Log(Debug::Verbose) << "setVisible (" << name << "): " << visible;
|
||||||
|
@ -453,60 +684,103 @@ void VRGUIManager::setVisible(MWGui::Layout* widget, bool visible)
|
||||||
widget->setLayerPick(false);
|
widget->setLayerPick(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visible)
|
if (visible)
|
||||||
{
|
insertWidget(widget);
|
||||||
if (mLayers.find(name) == mLayers.end())
|
|
||||||
{
|
|
||||||
LayerConfig config = gDefaultConfig;
|
|
||||||
auto configIt = gLayerConfigs.find(name);
|
|
||||||
if (configIt != gLayerConfigs.end())
|
|
||||||
config = configIt->second;
|
|
||||||
|
|
||||||
mLayers[name] = std::unique_ptr<VRGUILayer>(new VRGUILayer(
|
|
||||||
mGUIGeometriesRoot,
|
|
||||||
mGUICamerasRoot,
|
|
||||||
2048,
|
|
||||||
2048,
|
|
||||||
name,
|
|
||||||
config,
|
|
||||||
widget,
|
|
||||||
this
|
|
||||||
));
|
|
||||||
|
|
||||||
// Default new layer's pick to false
|
|
||||||
widget->setLayerPick(false);
|
|
||||||
|
|
||||||
Log(Debug::Verbose) << "Created GUI layer " << name;
|
|
||||||
}
|
|
||||||
updatePose();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
removeWidget(widget);
|
||||||
auto it = mLayers.find(name);
|
|
||||||
if (it != mLayers.end())
|
|
||||||
{
|
|
||||||
if (it->second.get() == mFocusLayer)
|
|
||||||
setFocusLayer(nullptr);
|
|
||||||
mLayers.erase(it);
|
|
||||||
Log(Debug::Verbose) << "Erased GUI layer " << name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUIManager::updatePose(void)
|
void VRGUIManager::updateTracking(void)
|
||||||
{
|
{
|
||||||
|
// Get head pose by reading the camera view matrix to place the GUI in the world.
|
||||||
|
osg::Vec3 eye{};
|
||||||
|
osg::Vec3 center{};
|
||||||
|
osg::Vec3 up{};
|
||||||
|
Pose headPose{};
|
||||||
|
auto* world = MWBase::Environment::get().getWorld();
|
||||||
|
if (!world)
|
||||||
|
return;
|
||||||
|
auto* camera = world->getRenderingManager().getCamera()->getOsgCamera();
|
||||||
|
if (!camera)
|
||||||
|
return;
|
||||||
|
camera->getViewMatrixAsLookAt(eye, center, up);
|
||||||
|
headPose.position = eye;
|
||||||
|
headPose.orientation = camera->getViewMatrix().getRotate();
|
||||||
|
headPose.orientation = headPose.orientation.inverse();
|
||||||
|
|
||||||
|
mHeadPose = headPose;
|
||||||
|
|
||||||
for (auto& layer : mLayers)
|
for (auto& layer : mLayers)
|
||||||
layer.second->updatePose();
|
layer.second->updateTracking(mHeadPose);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUIManager::updateFocus()
|
||||||
|
{
|
||||||
|
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||||
|
if (anim && anim->mPointerTarget.mHit)
|
||||||
|
{
|
||||||
|
std::shared_ptr<VRGUILayer> newFocusLayer = nullptr;
|
||||||
|
auto* node = anim->mPointerTarget.mHitNode;
|
||||||
|
if (node->getName() == "VRGUILayer")
|
||||||
|
{
|
||||||
|
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
|
||||||
|
newFocusLayer = userData->mLayer.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFocusLayer && newFocusLayer->mFilter != "Notification")
|
||||||
|
{
|
||||||
|
setFocusLayer(newFocusLayer.get());
|
||||||
|
computeGuiCursor(anim->mPointerTarget.mHitPointLocal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUIManager::setFocusLayer(VRGUILayer* layer)
|
void VRGUIManager::setFocusLayer(VRGUILayer* layer)
|
||||||
{
|
{
|
||||||
|
if (layer == mFocusLayer)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mFocusLayer)
|
if (mFocusLayer)
|
||||||
mFocusLayer->mWidget->setLayerPick(false);
|
{
|
||||||
|
mFocusLayer->mWidgets.front()->setLayerPick(false);
|
||||||
|
}
|
||||||
mFocusLayer = layer;
|
mFocusLayer = layer;
|
||||||
if (mFocusLayer)
|
if (mFocusLayer)
|
||||||
mFocusLayer->mWidget->setLayerPick(true);
|
{
|
||||||
|
Log(Debug::Verbose) << "Set focus layer to " << mFocusLayer->mWidgets.front()->mMainWidget->getLayer()->getName();
|
||||||
|
mFocusLayer->mWidgets.front()->setLayerPick(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << "Set focus layer to null";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VRGUIManager::computeGuiCursor(osg::Vec3 hitPoint)
|
||||||
|
{
|
||||||
|
float x = 0;
|
||||||
|
float y = 0;
|
||||||
|
if (mFocusLayer)
|
||||||
|
{
|
||||||
|
osg::Vec2 bottomLeft = mFocusLayer->mConfig.center - osg::Vec2(0.5f, 0.5f);
|
||||||
|
x = hitPoint.x() - bottomLeft.x();
|
||||||
|
y = hitPoint.z() - bottomLeft.y();
|
||||||
|
auto rect = mFocusLayer->mRealRect;
|
||||||
|
auto viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
auto width = viewSize.width * rect.width();
|
||||||
|
auto height = viewSize.height * rect.height();
|
||||||
|
auto left = viewSize.width * rect.left;
|
||||||
|
auto bottom = viewSize.height * rect.bottom;
|
||||||
|
x = width * x + left;
|
||||||
|
y = bottom - height * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGuiCursor.x() = (int)x;
|
||||||
|
mGuiCursor.y() = (int)y;
|
||||||
|
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove((int)x, (int)y, 0);
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
#include <osg/TexMat>
|
#include <osg/TexMat>
|
||||||
|
@ -34,21 +35,34 @@ namespace MWVR
|
||||||
|
|
||||||
enum class TrackingMode
|
enum class TrackingMode
|
||||||
{
|
{
|
||||||
Auto, //!< Update tracking every frame
|
Menu, //!< Menu quads with fixed position based on head tracking.
|
||||||
Manual //!< Update tracking only on user request or when GUI visibility changes.
|
HudLeftHand, //!< Hud quads tracking the left hand every frame
|
||||||
|
HudRightHand, //!< Hud quads tracking the right hand every frame
|
||||||
|
};
|
||||||
|
|
||||||
|
// Some UI elements should occupy predefined geometries
|
||||||
|
// Others should grow/shrink freely
|
||||||
|
enum class SizingMode
|
||||||
|
{
|
||||||
|
Auto,
|
||||||
|
Fixed
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LayerConfig
|
struct LayerConfig
|
||||||
{
|
{
|
||||||
bool stretch; //!< Resize layer window to occupy full quad
|
int priority; //!< Higher priority shows over lower priority windows.
|
||||||
|
bool sideBySide; //!< Resize layer window to occupy full quad
|
||||||
osg::Vec4 backgroundColor; //!< Background color of layer
|
osg::Vec4 backgroundColor; //!< Background color of layer
|
||||||
osg::Quat rotation; //!< Rotation relative to the tracking node
|
|
||||||
osg::Vec3 offset; //!< Offset from tracked node in meters
|
osg::Vec3 offset; //!< Offset from tracked node in meters
|
||||||
osg::Vec2 extent; //!< Spatial extent of the layer in meters
|
osg::Vec2 center; //!< Model space centerpoint of menu geometry. All menu geometries have model space lengths of 1 in each dimension. Use this to affect how geometries grow with changing size.
|
||||||
osg::Vec2i resolution; //!< Pixel resolution of the texture
|
osg::Vec2 extent; //!< Spatial extent of the layer in meters when using Fixed sizing mode
|
||||||
TrackedLimb trackedLimb; //!< Which limb to track
|
int spatialResolution; //!< Pixels when using the Auto sizing mode. \note Meters per pixel of the GUI viewport, not the RTT texture.
|
||||||
|
osg::Vec2i pixelResolution; //!< Pixel resolution of the RTT texture
|
||||||
|
osg::Vec2 myGUIViewSize; //!< Resizable elements are resized to this (fraction of full view)
|
||||||
|
SizingMode sizingMode; //!< How to size the layer
|
||||||
TrackingMode trackingMode; //!< Tracking mode
|
TrackingMode trackingMode; //!< Tracking mode
|
||||||
bool vertical; //!< Make layer vertical regardless of tracking orientation
|
|
||||||
|
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VRGUILayer
|
class VRGUILayer
|
||||||
|
@ -57,11 +71,8 @@ namespace MWVR
|
||||||
VRGUILayer(
|
VRGUILayer(
|
||||||
osg::ref_ptr<osg::Group> geometryRoot,
|
osg::ref_ptr<osg::Group> geometryRoot,
|
||||||
osg::ref_ptr<osg::Group> cameraRoot,
|
osg::ref_ptr<osg::Group> cameraRoot,
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
std::string filter,
|
std::string filter,
|
||||||
LayerConfig config,
|
LayerConfig config,
|
||||||
MWGui::Layout* widget,
|
|
||||||
VRGUIManager* parent);
|
VRGUIManager* parent);
|
||||||
~VRGUILayer();
|
~VRGUILayer();
|
||||||
|
|
||||||
|
@ -69,33 +80,39 @@ namespace MWVR
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> menuTexture();
|
osg::ref_ptr<osg::Texture2D> menuTexture();
|
||||||
|
|
||||||
|
void setAngle(float angle);
|
||||||
|
void updateTracking(const Pose& headPose = {});
|
||||||
void updatePose();
|
void updatePose();
|
||||||
|
void updateRect();
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
void insertWidget(MWGui::Layout* widget);
|
||||||
|
void removeWidget(MWGui::Layout* widget);
|
||||||
|
int widgetCount() { return mWidgets.size(); }
|
||||||
|
|
||||||
|
bool operator<(const VRGUILayer& rhs) const { return mConfig.priority < rhs.mConfig.priority; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Pose mTrackedPose{};
|
Pose mTrackedPose{};
|
||||||
Pose mLayerPose{};
|
|
||||||
LayerConfig mConfig;
|
LayerConfig mConfig;
|
||||||
std::string mFilter;
|
std::string mFilter;
|
||||||
MWGui::Layout* mWidget;
|
std::vector<MWGui::Layout*> mWidgets;
|
||||||
MWGui::WindowBase* mWindow;
|
|
||||||
MyGUI::Window* mMyGUIWindow;
|
|
||||||
VRGUIManager* mParent;
|
|
||||||
osg::ref_ptr<osg::Group> mGeometryRoot;
|
osg::ref_ptr<osg::Group> mGeometryRoot;
|
||||||
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
|
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
|
||||||
osg::ref_ptr<osg::PositionAttitudeTransform> mTransform{ new osg::PositionAttitudeTransform };
|
osg::ref_ptr<osg::PositionAttitudeTransform> mTransform{ new osg::PositionAttitudeTransform };
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> mCameraRoot;
|
osg::ref_ptr<osg::Group> mCameraRoot;
|
||||||
osg::ref_ptr<osg::StateSet> mStateSet{ new osg::StateSet };
|
|
||||||
osg::ref_ptr<GUICamera> mGUICamera;
|
osg::ref_ptr<GUICamera> mGUICamera;
|
||||||
|
osg::ref_ptr<osg::Camera> mMyGUICamera{ nullptr };
|
||||||
|
MyGUI::FloatRect mRealRect{};
|
||||||
|
osg::Quat mRotation{ 0,0,0,1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class VRGUILayerUserData : public osg::Referenced
|
class VRGUILayerUserData : public osg::Referenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VRGUILayerUserData(VRGUILayer* layer) : mLayer(layer) {};
|
VRGUILayerUserData(std::shared_ptr<VRGUILayer> layer) : mLayer(layer) {};
|
||||||
|
|
||||||
VRGUILayer* mLayer;
|
std::weak_ptr<VRGUILayer> mLayer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VRGUIManager
|
class VRGUIManager
|
||||||
|
@ -110,18 +127,38 @@ namespace MWVR
|
||||||
|
|
||||||
void setVisible(MWGui::Layout*, bool visible);
|
void setVisible(MWGui::Layout*, bool visible);
|
||||||
|
|
||||||
void updatePose(void);
|
void updateSideBySideLayers();
|
||||||
|
|
||||||
|
void insertLayer(const std::string& name);
|
||||||
|
|
||||||
|
void insertWidget(MWGui::Layout* widget);
|
||||||
|
|
||||||
|
void removeLayer(const std::string& name);
|
||||||
|
|
||||||
|
void removeWidget(MWGui::Layout* widget);
|
||||||
|
|
||||||
|
void updateTracking(void);
|
||||||
|
|
||||||
|
void updateFocus();
|
||||||
|
|
||||||
void setFocusLayer(VRGUILayer* layer);
|
void setFocusLayer(VRGUILayer* layer);
|
||||||
|
|
||||||
|
osg::Vec2i guiCursor() { return mGuiCursor; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void computeGuiCursor(osg::Vec3 hitPoint);
|
||||||
|
|
||||||
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
|
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> mGUIGeometriesRoot{ new osg::Group };
|
osg::ref_ptr<osg::Group> mGUIGeometriesRoot{ new osg::Group };
|
||||||
osg::ref_ptr<osg::Group> mGUICamerasRoot{ new osg::Group };
|
osg::ref_ptr<osg::Group> mGUICamerasRoot{ new osg::Group };
|
||||||
|
|
||||||
std::map<std::string, std::unique_ptr<VRGUILayer>> mLayers;
|
std::map<std::string, std::shared_ptr<VRGUILayer>> mLayers;
|
||||||
|
std::vector<std::shared_ptr<VRGUILayer> > mSideBySideLayers;
|
||||||
|
|
||||||
|
int mVisibleMenus{ 0 };
|
||||||
|
Pose mHeadPose{};
|
||||||
|
osg::Vec2i mGuiCursor{};
|
||||||
VRGUILayer* mFocusLayer{ nullptr };
|
VRGUILayer* mFocusLayer{ nullptr };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1100,6 +1100,15 @@ namespace MWWorld
|
||||||
|
|
||||||
MWWorld::Ptr World::getFacedObject()
|
MWWorld::Ptr World::getFacedObject()
|
||||||
{
|
{
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
|
||||||
|
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||||
|
if (anim && anim->mPointerTarget.mHit)
|
||||||
|
return anim->mPointerTarget.mHitObject;
|
||||||
|
else
|
||||||
|
return MWWorld::Ptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
MWWorld::Ptr facedObject;
|
MWWorld::Ptr facedObject;
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode() &&
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode() &&
|
||||||
|
|
|
@ -364,6 +364,7 @@ public:
|
||||||
GUICamera(osg::Camera::RenderOrder order, RenderManager* parent, std::string filter)
|
GUICamera(osg::Camera::RenderOrder order, RenderManager* parent, std::string filter)
|
||||||
: mParent(parent)
|
: mParent(parent)
|
||||||
, mUpdate(false)
|
, mUpdate(false)
|
||||||
|
, mFilter(filter)
|
||||||
{
|
{
|
||||||
setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||||
setProjectionResizePolicy(osg::Camera::FIXED);
|
setProjectionResizePolicy(osg::Camera::FIXED);
|
||||||
|
@ -405,6 +406,7 @@ public:
|
||||||
osg::ref_ptr<Drawable> mDrawable;
|
osg::ref_ptr<Drawable> mDrawable;
|
||||||
MyGUI::RenderTargetInfo mInfo;
|
MyGUI::RenderTargetInfo mInfo;
|
||||||
bool mUpdate;
|
bool mUpdate;
|
||||||
|
std::string mFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -436,6 +438,10 @@ RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, R
|
||||||
{
|
{
|
||||||
if (scalingFactor != 0.f)
|
if (scalingFactor != 0.f)
|
||||||
mInvScalingFactor = 1.f / scalingFactor;
|
mInvScalingFactor = 1.f / scalingFactor;
|
||||||
|
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Viewport> vp = mViewer->getCamera()->getViewport();
|
||||||
|
setViewSize(vp->width(), vp->height());
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderManager::~RenderManager()
|
RenderManager::~RenderManager()
|
||||||
|
@ -552,21 +558,13 @@ void GUICamera::collectDrawCalls(std::string filter)
|
||||||
MyGUI::LayerManager* myGUILayers = MyGUI::LayerManager::getInstancePtr();
|
MyGUI::LayerManager* myGUILayers = MyGUI::LayerManager::getInstancePtr();
|
||||||
if (myGUILayers != nullptr)
|
if (myGUILayers != nullptr)
|
||||||
{
|
{
|
||||||
std::regex layerRegex{ filter, std::regex_constants::icase };
|
|
||||||
for (unsigned i = 0; i < myGUILayers->getLayerCount(); i++)
|
for (unsigned i = 0; i < myGUILayers->getLayerCount(); i++)
|
||||||
{
|
{
|
||||||
auto layer = myGUILayers->getLayer(i);
|
auto layer = myGUILayers->getLayer(i);
|
||||||
|
|
||||||
auto name = layer->getName();
|
auto name = layer->getName();
|
||||||
|
|
||||||
if (std::regex_search(name, layerRegex))
|
if (name == filter)
|
||||||
{
|
|
||||||
//std::cout << "Including Layer: " << layer->getName() << std::endl;
|
|
||||||
layer->renderToTarget(this, mUpdate);
|
layer->renderToTarget(this, mUpdate);
|
||||||
}
|
|
||||||
else {
|
|
||||||
//std::cout << "Excluding Layer: " << layer->getName() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end();
|
end();
|
||||||
|
@ -590,6 +588,11 @@ void RenderManager::setViewSize(int width, int height)
|
||||||
if(width < 1) width = 1;
|
if(width < 1) width = 1;
|
||||||
if(height < 1) height = 1;
|
if(height < 1) height = 1;
|
||||||
|
|
||||||
|
////#ifdef USE_OPENXR
|
||||||
|
// width = 1024;
|
||||||
|
// height = 1024;
|
||||||
|
////#endif
|
||||||
|
|
||||||
mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor);
|
mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor);
|
||||||
|
|
||||||
for (auto* camera : mGuiCameras)
|
for (auto* camera : mGuiCameras)
|
||||||
|
@ -605,8 +608,8 @@ osg::ref_ptr<osg::Camera> RenderManager::createGUICamera(int order, std::string
|
||||||
{
|
{
|
||||||
osg::ref_ptr<GUICamera> camera = new GUICamera(static_cast<osg::Camera::RenderOrder>(order), this, layerFilter);
|
osg::ref_ptr<GUICamera> camera = new GUICamera(static_cast<osg::Camera::RenderOrder>(order), this, layerFilter);
|
||||||
mGuiCameras.insert(camera);
|
mGuiCameras.insert(camera);
|
||||||
osg::ref_ptr<osg::Viewport> vp = mViewer->getCamera()->getViewport();
|
camera->setViewport(0, 0, mViewSize.width, mViewSize.height);
|
||||||
setViewSize(vp->width(), vp->height());
|
camera->setViewSize(mViewSize);
|
||||||
return camera;
|
return camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ set(MYGUI_FILES
|
||||||
openmw_box.skin.xml
|
openmw_box.skin.xml
|
||||||
openmw_button.skin.xml
|
openmw_button.skin.xml
|
||||||
openmw_chargen_birth.layout
|
openmw_chargen_birth.layout
|
||||||
openmw_chargen_class_description.layout
|
|
||||||
openmw_chargen_class.layout
|
openmw_chargen_class.layout
|
||||||
|
openmw_chargen_class_description.layout
|
||||||
openmw_chargen_create_class.layout
|
openmw_chargen_create_class.layout
|
||||||
openmw_chargen_generate_class_result.layout
|
openmw_chargen_generate_class_result.layout
|
||||||
openmw_chargen_race.layout
|
openmw_chargen_race.layout
|
||||||
|
@ -25,78 +25,80 @@ set(MYGUI_FILES
|
||||||
openmw_chargen_select_attribute.layout
|
openmw_chargen_select_attribute.layout
|
||||||
openmw_chargen_select_skill.layout
|
openmw_chargen_select_skill.layout
|
||||||
openmw_chargen_select_specialization.layout
|
openmw_chargen_select_specialization.layout
|
||||||
|
openmw_companion_window.layout
|
||||||
openmw_confirmation_dialog.layout
|
openmw_confirmation_dialog.layout
|
||||||
openmw_console.layout
|
openmw_console.layout
|
||||||
openmw_console.skin.xml
|
openmw_console.skin.xml
|
||||||
openmw_container_window.layout
|
openmw_container_window.layout
|
||||||
|
openmw_container_window_vr.layout
|
||||||
openmw_count_window.layout
|
openmw_count_window.layout
|
||||||
|
openmw_debug_window.layout
|
||||||
|
openmw_debug_window.skin.xml
|
||||||
openmw_dialogue_window.layout
|
openmw_dialogue_window.layout
|
||||||
|
openmw_dialogue_window_vr.layout
|
||||||
openmw_dialogue_window.skin.xml
|
openmw_dialogue_window.skin.xml
|
||||||
openmw_edit.skin.xml
|
openmw_edit.skin.xml
|
||||||
|
openmw_edit_effect.layout
|
||||||
|
openmw_edit_note.layout
|
||||||
|
openmw_enchanting_dialog.layout
|
||||||
openmw_font.xml
|
openmw_font.xml
|
||||||
|
openmw_hud.layout
|
||||||
openmw_hud_box.skin.xml
|
openmw_hud_box.skin.xml
|
||||||
openmw_hud_energybar.skin.xml
|
openmw_hud_energybar.skin.xml
|
||||||
openmw_hud.layout
|
|
||||||
openmw_hud_vr.layout
|
openmw_hud_vr.layout
|
||||||
openmw_infobox.layout
|
openmw_infobox.layout
|
||||||
openmw_interactive_messagebox.layout
|
openmw_interactive_messagebox.layout
|
||||||
openmw_interactive_messagebox_notransp.layout
|
openmw_interactive_messagebox_notransp.layout
|
||||||
openmw_inventory_window.layout
|
openmw_inventory_window.layout
|
||||||
openmw_inventory_window_vr.layout
|
openmw_inventory_window_vr.layout
|
||||||
|
openmw_itemselection_dialog.layout
|
||||||
|
openmw_jail_screen.layout
|
||||||
openmw_journal.layout
|
openmw_journal.layout
|
||||||
openmw_journal.skin.xml
|
openmw_journal.skin.xml
|
||||||
openmw_layers.xml
|
openmw_layers.xml
|
||||||
openmw_layers_vr.xml
|
openmw_layers_vr.xml
|
||||||
|
openmw_levelup_dialog.layout
|
||||||
openmw_list.skin.xml
|
openmw_list.skin.xml
|
||||||
|
openmw_loading_screen.layout
|
||||||
|
openmw_magicselection_dialog.layout
|
||||||
openmw_mainmenu.layout
|
openmw_mainmenu.layout
|
||||||
openmw_mainmenu.skin.xml
|
openmw_mainmenu.skin.xml
|
||||||
openmw_map_window.layout
|
openmw_map_window.layout
|
||||||
openmw_map_window_vr.layout
|
|
||||||
openmw_map_window.skin.xml
|
openmw_map_window.skin.xml
|
||||||
|
openmw_map_window_vr.layout
|
||||||
|
openmw_merchantrepair.layout
|
||||||
openmw_messagebox.layout
|
openmw_messagebox.layout
|
||||||
|
openmw_persuasion_dialog.layout
|
||||||
openmw_pointer.xml
|
openmw_pointer.xml
|
||||||
openmw_progress.skin.xml
|
openmw_progress.skin.xml
|
||||||
openmw_resources.xml
|
|
||||||
openmw_scroll.layout
|
|
||||||
openmw_scroll.skin.xml
|
|
||||||
openmw_settings_window.layout
|
|
||||||
openmw_settings.xml
|
|
||||||
openmw_spell_window.layout
|
|
||||||
openmw_spell_window_vr.layout
|
|
||||||
openmw_stats_window.layout
|
|
||||||
openmw_stats_window_vr.layout
|
|
||||||
openmw_text_input.layout
|
|
||||||
openmw_text.skin.xml
|
|
||||||
openmw_tooltips.layout
|
|
||||||
openmw_trade_window.layout
|
|
||||||
openmw_spell_buying_window.layout
|
|
||||||
openmw_windows.skin.xml
|
|
||||||
openmw_quickkeys_menu.layout
|
openmw_quickkeys_menu.layout
|
||||||
openmw_quickkeys_menu_assign.layout
|
openmw_quickkeys_menu_assign.layout
|
||||||
openmw_itemselection_dialog.layout
|
|
||||||
openmw_magicselection_dialog.layout
|
|
||||||
openmw_spell_buying_window.layout
|
|
||||||
openmw_loading_screen.layout
|
|
||||||
openmw_levelup_dialog.layout
|
|
||||||
openmw_wait_dialog.layout
|
|
||||||
openmw_wait_dialog_progressbar.layout
|
|
||||||
openmw_spellcreation_dialog.layout
|
|
||||||
openmw_edit_effect.layout
|
|
||||||
openmw_enchanting_dialog.layout
|
|
||||||
openmw_trainingwindow.layout
|
|
||||||
openmw_travel_window.layout
|
|
||||||
openmw_persuasion_dialog.layout
|
|
||||||
openmw_merchantrepair.layout
|
|
||||||
openmw_repair.layout
|
|
||||||
openmw_companion_window.layout
|
|
||||||
openmw_savegame_dialog.layout
|
|
||||||
openmw_recharge_dialog.layout
|
openmw_recharge_dialog.layout
|
||||||
|
openmw_repair.layout
|
||||||
|
openmw_resources.xml
|
||||||
|
openmw_savegame_dialog.layout
|
||||||
openmw_screen_fader.layout
|
openmw_screen_fader.layout
|
||||||
openmw_screen_fader_hit.layout
|
openmw_screen_fader_hit.layout
|
||||||
openmw_edit_note.layout
|
openmw_scroll.layout
|
||||||
openmw_debug_window.layout
|
openmw_scroll.skin.xml
|
||||||
openmw_debug_window.skin.xml
|
openmw_settings.xml
|
||||||
openmw_jail_screen.layout
|
openmw_settings_window.layout
|
||||||
|
openmw_spell_buying_window.layout
|
||||||
|
openmw_spell_window.layout
|
||||||
|
openmw_spell_window_vr.layout
|
||||||
|
openmw_spellcreation_dialog.layout
|
||||||
|
openmw_stats_window.layout
|
||||||
|
openmw_stats_window_vr.layout
|
||||||
|
openmw_text.skin.xml
|
||||||
|
openmw_text_input.layout
|
||||||
|
openmw_tooltips.layout
|
||||||
|
openmw_trade_window.layout
|
||||||
|
openmw_trade_window_vr.layout
|
||||||
|
openmw_trainingwindow.layout
|
||||||
|
openmw_travel_window.layout
|
||||||
|
openmw_wait_dialog.layout
|
||||||
|
openmw_wait_dialog_progressbar.layout
|
||||||
|
openmw_windows.skin.xml
|
||||||
DejaVuLGCSansMono.ttf
|
DejaVuLGCSansMono.ttf
|
||||||
../launcher/images/openmw.png
|
../launcher/images/openmw.png
|
||||||
OpenMWResourcePlugin.xml
|
OpenMWResourcePlugin.xml
|
||||||
|
|
27
files/mygui/openmw_container_window_vr.layout
Normal file
27
files/mygui/openmw_container_window_vr.layout
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<MyGUI type="Layout">
|
||||||
|
<Widget type="Window" skin="MW_Window" layer="InventoryCompanionWindow" position="0 0 600 300" name="_Main">
|
||||||
|
<Property key="MinSize" value="245 145"/>
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
|
||||||
|
<!-- Items -->
|
||||||
|
<Widget type="ItemView" skin="MW_ItemView" position="5 5 575 225" name="ItemView" align="Left Top Stretch">
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="HBox" position="0 235 580 28" align="Right Bottom">
|
||||||
|
<Widget type="Spacer"/>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="DisposeCorpseButton" align="Right Bottom">
|
||||||
|
<Property key="Caption" value="#{sDisposeofCorpse}"/>
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="TakeButton" align="Right Bottom">
|
||||||
|
<Property key="Caption" value="#{sTakeAll}"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="CloseButton" align="Right Bottom">
|
||||||
|
<Property key="Caption" value="#{sClose}"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</Widget>
|
||||||
|
</MyGUI>
|
34
files/mygui/openmw_dialogue_window_vr.layout
Normal file
34
files/mygui/openmw_dialogue_window_vr.layout
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<MyGUI type="Layout">
|
||||||
|
<Widget type="Window" skin="MW_Window" layer="DialogueWindow" position="0 0 588 433" name="_Main">
|
||||||
|
<Property key="MinSize" value="380 230"/>
|
||||||
|
|
||||||
|
<Widget type="Widget" skin="MW_Box" position="8 8 381 381" align="Stretch"/>
|
||||||
|
|
||||||
|
<Widget type="Widget" position="15 15 364 370" align="Left Top Stretch">
|
||||||
|
<Widget type="BookPage" skin="MW_BookPage" position="0 0 364 370" name="History" align="Left Top Stretch">
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="ScrollBar" skin="MW_VScroll" position="370 13 14 371" align="Right VStretch" name="VScroll">
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- The disposition bar-->
|
||||||
|
<Widget type="ProgressBar" skin="MW_Progress_Blue" position="398 8 166 18"
|
||||||
|
align="Right Top" name="Disposition">
|
||||||
|
<Widget type="TextBox" skin="ProgressText" position="0 0 166 14" name="DispositionText" align="Right VCenter">
|
||||||
|
<Property key="NeedMouse" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
<!-- The list of topics -->
|
||||||
|
<Widget type="MWList" skin="MW_SimpleList" position="398 31 166 328" name="TopicsList" align="Right VStretch">
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- The Goodbye button -->
|
||||||
|
<Widget type="Button" skin="MW_Button" position="398 366 166 23" name="ByeButton" align="Right Bottom">
|
||||||
|
<Property key="Caption" value="#{sGoodbye}"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
</MyGUI>
|
|
@ -1,15 +1,12 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<MyGUI type="Layout">
|
<MyGUI type="Layout">
|
||||||
<Widget type="Widget" layer="StatusHUD" position="0 0 185 80" name="_Main" align="Default">
|
<Widget type="Widget" layer="StatusHUD" position="0 0 255 91" name="_Main" align="Default">
|
||||||
<!-- Spell effects box -->
|
|
||||||
<Widget type="Widget" skin="HUD_Box_Transparent" position="0 15 20 20" align="Left Bottom" name="EffectBox">
|
|
||||||
</Widget>
|
|
||||||
<!-- Energy bars -->
|
<!-- Energy bars -->
|
||||||
<Widget type="ProgressBar" skin="MW_EnergyBar_Yellow" position="0 0 65 12" align="Left Bottom" name="EnemyHealth">
|
<Widget type="ProgressBar" skin="MW_EnergyBar_Yellow" position="0 34 65 12" align="Left Bottom" name="EnemyHealth">
|
||||||
<Property key="Visible" value="false"/>
|
<Property key="Visible" value="false"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="Button" skin="" position="0 38 65 12" align="Left Bottom" name="HealthFrame">
|
<Widget type="Button" skin="" position="0 49 65 12" align="Left Bottom" name="HealthFrame">
|
||||||
<UserString key="ToolTipType" value="Layout"/>
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
<UserString key="ToolTipLayout" value="HealthToolTip"/>
|
<UserString key="ToolTipLayout" value="HealthToolTip"/>
|
||||||
<UserString key="ImageTexture_HealthImage" value="icons\k\health.dds"/>
|
<UserString key="ImageTexture_HealthImage" value="icons\k\health.dds"/>
|
||||||
|
@ -17,7 +14,7 @@
|
||||||
<Property key="NeedMouse" value="false"/>
|
<Property key="NeedMouse" value="false"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="Button" skin="" position="0 53 65 12" align="Left Bottom" name="MagickaFrame">
|
<Widget type="Button" skin="" position="0 64 65 12" align="Left Bottom" name="MagickaFrame">
|
||||||
<UserString key="ToolTipType" value="Layout"/>
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
<UserString key="ToolTipLayout" value="HealthToolTip"/>
|
<UserString key="ToolTipLayout" value="HealthToolTip"/>
|
||||||
<UserString key="ImageTexture_HealthImage" value="icons\k\magicka.dds"/>
|
<UserString key="ImageTexture_HealthImage" value="icons\k\magicka.dds"/>
|
||||||
|
@ -25,7 +22,7 @@
|
||||||
<Property key="NeedMouse" value="false"/>
|
<Property key="NeedMouse" value="false"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="Button" skin="" position="0 68 65 12" align="Left Bottom" name="FatigueFrame">
|
<Widget type="Button" skin="" position="0 79 65 12" align="Left Bottom" name="FatigueFrame">
|
||||||
<UserString key="ToolTipType" value="Layout"/>
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
<UserString key="ToolTipLayout" value="HealthToolTip"/>
|
<UserString key="ToolTipLayout" value="HealthToolTip"/>
|
||||||
<UserString key="ImageTexture_HealthImage" value="icons\k\fatigue.dds"/>
|
<UserString key="ImageTexture_HealthImage" value="icons\k\fatigue.dds"/>
|
||||||
|
@ -35,7 +32,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<!-- Equipped weapon box -->
|
<!-- Equipped weapon box -->
|
||||||
<Widget type="Button" skin="" position="69 38 36 41" align="Left Bottom" name="WeapBox">
|
<Widget type="Button" skin="" position="69 49 36 41" align="Left Bottom" name="WeapBox">
|
||||||
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
||||||
<Property key="NeedMouse" value="false"/>
|
<Property key="NeedMouse" value="false"/>
|
||||||
<Widget type="ItemWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="WeapImage">
|
<Widget type="ItemWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="WeapImage">
|
||||||
|
@ -48,7 +45,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<!-- Selected spell box -->
|
<!-- Selected spell box -->
|
||||||
<Widget type="Button" position="109 38 36 41" align="Left Bottom" name="SpellBox">
|
<Widget type="Button" position="109 49 36 41" align="Left Bottom" name="SpellBox">
|
||||||
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
||||||
<Widget type="SpellWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="SpellImage"/>
|
<Widget type="SpellWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="SpellImage"/>
|
||||||
<Property key="NeedMouse" value="false"/>
|
<Property key="NeedMouse" value="false"/>
|
||||||
|
@ -59,7 +56,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<!-- Sneak indicator box -->
|
<!-- Sneak indicator box -->
|
||||||
<Widget type="Button" skin="" position="149 38 36 36" align="Left Bottom" name="SneakBox">
|
<Widget type="Button" skin="" position="149 49 36 36" align="Left Bottom" name="SneakBox">
|
||||||
<Property key="Visible" value="false"/>
|
<Property key="Visible" value="false"/>
|
||||||
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
||||||
<Property key="NeedMouse" value="false"/>
|
<Property key="NeedMouse" value="false"/>
|
||||||
|
@ -70,44 +67,12 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
</Widget>
|
<!-- Spell effects box -->
|
||||||
<Widget type="Widget" layer="MiniMapHUD" position="0 0 300 92" name="_Main2" align="Stretch">
|
<Widget type="Widget" skin="HUD_Box_Transparent" position="0 0 20 20" align="Left Bottom" name="EffectBox">
|
||||||
<!-- Drowning bar -->
|
|
||||||
<Widget type="Window" skin="MW_Dialog" position="0 36 230 58" align="Center Top" name="DrowningFrame">
|
|
||||||
<Property key="Visible" value="false"/>
|
|
||||||
<Widget type="TextBox" skin="SandText" position="0 3 222 24" name="DrowningTitle" align="Center Top HStretch">
|
|
||||||
<Property key="Caption" value="#{sBreath}"/>
|
|
||||||
<Property key="TextAlign" value="Center"/>
|
|
||||||
<Property key="TextShadow" value="true"/>
|
|
||||||
<Property key="TextShadowColour" value="0 0 0"/>
|
|
||||||
</Widget>
|
|
||||||
<Widget type="Widget" skin="MW_Box" position="11 29 200 10" align="Stretch" name="BoundingBox"/>
|
|
||||||
<Widget type="ProgressBar" skin="MW_Progress_Drowning_Full" position="13 31 196 6" align="Center Top" name="Drowning">
|
|
||||||
<Property key="NeedMouse" value="false"/>
|
|
||||||
</Widget>
|
|
||||||
<Widget type="Widget" skin="MW_Progress_Drowning_Small" position="15 33 192 2" align="Center Top" name="Flash"/>
|
|
||||||
</Widget>
|
|
||||||
|
|
||||||
<!-- Equipped weapon/selected spell name display for a few seconds after it changes -->
|
|
||||||
<Widget type="TextBox" skin="SandText" position="13 118 270 24" name="WeaponSpellName" align="Left Bottom HStretch">
|
|
||||||
<Property key="Visible" value="false"/>
|
|
||||||
<Property key="TextAlign" value="Left"/>
|
|
||||||
<Property key="TextShadow" value="true"/>
|
|
||||||
<Property key="TextShadowColour" value="0 0 0"/>
|
|
||||||
<Property key="NeedMouse" value="false"/>
|
|
||||||
</Widget>
|
|
||||||
|
|
||||||
<!-- Cell name display when cell changes -->
|
|
||||||
<Widget type="TextBox" skin="SandText" position="0 89 288 24" name="CellName" align="Left Bottom HStretch">
|
|
||||||
<Property key="Visible" value="false"/>
|
|
||||||
<Property key="TextAlign" value="Right"/>
|
|
||||||
<Property key="TextShadow" value="true"/>
|
|
||||||
<Property key="TextShadowColour" value="0 0 0"/>
|
|
||||||
<Property key="NeedMouse" value="false"/>
|
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<!-- Map box -->
|
<!-- Map box -->
|
||||||
<Widget type="Widget" skin="" position="223 15 65 65" name="MiniMapBox" align="Right Bottom">
|
<Widget type="Widget" skin="" position="189 20 65 65" name="MiniMapBox" align="Right Bottom">
|
||||||
<Widget type="Widget" skin="HUD_Box" position="0 0 65 65" align="Center">
|
<Widget type="Widget" skin="HUD_Box" position="0 0 65 65" align="Center">
|
||||||
|
|
||||||
<Widget type="ScrollView" skin="MW_MapView" position="2 2 61 61" align="Left Bottom" name="MiniMap">
|
<Widget type="ScrollView" skin="MW_MapView" position="2 2 61 61" align="Left Bottom" name="MiniMap">
|
||||||
|
@ -124,6 +89,40 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Drowning bar -->
|
||||||
|
<Widget type="Window" skin="MW_Dialog" position="0 27 230 58" align="Center Top" name="DrowningFrame">
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
<Widget type="TextBox" skin="SandText" position="0 3 222 24" name="DrowningTitle" align="Center Top HStretch">
|
||||||
|
<Property key="Caption" value="#{sBreath}"/>
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
<Property key="TextShadow" value="true"/>
|
||||||
|
<Property key="TextShadowColour" value="0 0 0"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="Widget" skin="MW_Box" position="11 29 200 10" align="Stretch" name="BoundingBox"/>
|
||||||
|
<Widget type="ProgressBar" skin="MW_Progress_Drowning_Full" position="13 31 196 6" align="Center Top" name="Drowning">
|
||||||
|
<Property key="NeedMouse" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="Widget" skin="MW_Progress_Drowning_Small" position="15 33 192 2" align="Center Top" name="Flash"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Equipped weapon/selected spell name display for a few seconds after it changes -->
|
||||||
|
<Widget type="TextBox" skin="SandText" position="0 20 255 24" name="WeaponSpellName" align="Left Bottom HStretch">
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<Property key="TextShadow" value="true"/>
|
||||||
|
<Property key="TextShadowColour" value="0 0 0"/>
|
||||||
|
<Property key="NeedMouse" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Cell name display when cell changes -->
|
||||||
|
<Widget type="TextBox" skin="SandText" position="0 20 255 24" name="CellName" align="Left Bottom HStretch">
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<Property key="TextShadow" value="true"/>
|
||||||
|
<Property key="TextShadowColour" value="0 0 0"/>
|
||||||
|
<Property key="NeedMouse" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
<!-- Crosshair -->
|
<!-- Crosshair -->
|
||||||
<Widget type="ImageBox" skin="HUD_Crosshair" position="0 0 32 32" align="Center Center" name="Crosshair">
|
<Widget type="ImageBox" skin="HUD_Crosshair" position="0 0 32 32" align="Center Center" name="Crosshair">
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
<Layer name="Overlay" overlapped="false" pick="false"/>
|
<Layer name="Overlay" overlapped="false" pick="false"/>
|
||||||
<Layer name="AdditiveOverlay" type="AdditiveLayer" pick="false"/>
|
<Layer name="AdditiveOverlay" type="AdditiveLayer" pick="false"/>
|
||||||
<Layer name="StatusHUD" overlapped="false" pick="true"/>
|
<Layer name="StatusHUD" overlapped="false" pick="true"/>
|
||||||
<Layer name="MiniMapHUD" overlapped="false" pick="true"/>
|
|
||||||
<Layer name="Menu" overlapped="false" pick="true"/>
|
<Layer name="Menu" overlapped="false" pick="true"/>
|
||||||
|
<Layer name="InventoryCompanionWindow" overlapped="true" pick="true"/>
|
||||||
<Layer name="InventoryWindow" overlapped="true" pick="true"/>
|
<Layer name="InventoryWindow" overlapped="true" pick="true"/>
|
||||||
<Layer name="SpellWindow" overlapped="true" pick="true"/>
|
<Layer name="SpellWindow" overlapped="true" pick="true"/>
|
||||||
<Layer name="MapWindow" overlapped="true" pick="true"/>
|
<Layer name="MapWindow" overlapped="true" pick="true"/>
|
||||||
<Layer name="StatsWindow" overlapped="true" pick="true"/>
|
<Layer name="StatsWindow" overlapped="true" pick="true"/>
|
||||||
|
<Layer name="DialogueWindow" overlapped="true" pick="true"/>
|
||||||
|
<Layer name="ServiceWindow" overlapped="true" pick="true"/>
|
||||||
<Layer name="Windows" overlapped="true" pick="true"/>
|
<Layer name="Windows" overlapped="true" pick="true"/>
|
||||||
<Layer name="JournalBooks" type="ScalingLayer" pick="true">
|
<Layer name="JournalBooks" type="ScalingLayer" pick="true">
|
||||||
<Property key="Size" value="600 520"/>
|
<Property key="Size" value="600 520"/>
|
||||||
|
|
87
files/mygui/openmw_trade_window_vr.layout
Normal file
87
files/mygui/openmw_trade_window_vr.layout
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<MyGUI type="Layout">
|
||||||
|
<Widget type="Window" skin="MW_Window" layer="InventoryCompanionWindow" position="0 0 600 360" name="_Main">
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
<Property key="MinSize" value="428 245"/>
|
||||||
|
|
||||||
|
<!-- Categories -->
|
||||||
|
<Widget type="HBox" position="8 8 566 24" align="Left Top HStretch" name="Categories">
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="AllButton">
|
||||||
|
<Property key="Caption" value="#{sAllTab}"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="WeaponButton">
|
||||||
|
<Property key="Caption" value="#{sWeaponTab}"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="ApparelButton">
|
||||||
|
<Property key="Caption" value="#{sApparelTab}"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="MagicButton">
|
||||||
|
<Property key="Caption" value="#{sMagicTab}"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="MiscButton">
|
||||||
|
<Property key="Caption" value="#{sMiscTab}"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<!-- Search box-->
|
||||||
|
<Widget type="EditBox" skin="MW_TextBoxEditWithBorder" position="0 0 0 23" name="FilterEdit">
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
<UserString key="AcceptTab" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Items -->
|
||||||
|
<Widget type="ItemView" skin="MW_ItemView" position="8 38 566 185" name="ItemView" align="Left Top Stretch">
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="Widget" skin="" position="8 231 566 92" name="BottomPane" align="Left Bottom HStretch">
|
||||||
|
<Widget type="HBox" position="0 0 566 24" align="Left Top HStretch">
|
||||||
|
<Widget type="Button" skin="MW_Button" position="0 0 40 24" name="IncreaseButton" align="Left Top">
|
||||||
|
<Property key="Caption" value="+"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="48 0 140 24" name="TotalBalanceLabel" align="Left Top">
|
||||||
|
<Property key="TextAlign" value="Left VCenter"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="Spacer" />
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="0 0 374 24" name="PlayerGold" align="Right Top">
|
||||||
|
<Property key="TextAlign" value="Right"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="HBox" position="0 28 566 28" align="Left Top HStretch">
|
||||||
|
<Widget type="Button" skin="MW_Button" position="0 0 40 24" name="DecreaseButton" align="Left Top">
|
||||||
|
<Property key="Caption" value="-"/>
|
||||||
|
<Property key="NeedKey" value="false"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="NumericEditBox" skin="MW_TextEdit" position="48 0 140 24" name="TotalBalance" align="Left Top">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="Spacer" />
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="0 0 374 24" name="MerchantGold" align="Right Top">
|
||||||
|
<Property key="TextAlign" value="Right"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="HBox" position="0 60 566 28" align="Left Bottom HStretch">
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="MaxSaleButton">
|
||||||
|
<Property key="Caption" value="#{sMaxSale}"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="Spacer" />
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="OfferButton">
|
||||||
|
<Property key="Caption" value="#{sBarterDialog8}"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton">
|
||||||
|
<Property key="Caption" value="#{sCancel}"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</MyGUI>
|
Loading…
Reference in a new issue