mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-06 17:45:33 +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)
|
||||
#ifdef USE_OPENXR
|
||||
: WindowBase("openmw_container_window_vr.layout")
|
||||
#else
|
||||
: WindowBase("openmw_container_window.layout")
|
||||
#endif
|
||||
, mDragAndDrop(dragAndDrop)
|
||||
, mSortModel(nullptr)
|
||||
, mModel(nullptr)
|
||||
|
|
|
@ -266,7 +266,11 @@ namespace MWGui
|
|||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
DialogueWindow::DialogueWindow()
|
||||
#ifdef USE_OPENXR
|
||||
: WindowBase("openmw_dialogue_window_vr.layout")
|
||||
#else
|
||||
: WindowBase("openmw_dialogue_window.layout")
|
||||
#endif
|
||||
, mIsCompanion(false)
|
||||
, mGoodbye(false)
|
||||
, mPersuasionDialog(new ResponseCallback(this))
|
||||
|
|
|
@ -103,10 +103,13 @@ namespace MWGui
|
|||
, mIsDrowning(false)
|
||||
, mDrowningFlashTheta(0.f)
|
||||
{
|
||||
#ifndef USE_OPENXR
|
||||
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
||||
#endif
|
||||
#ifdef USE_OPENXR
|
||||
mMainWidgetBaseSize = mMainWidget->getSize();
|
||||
mMainWidget->setSize(mMainWidgetBaseSize);
|
||||
#else
|
||||
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
||||
mMainWidgetBaseSize = mMainWidget->getSize();
|
||||
#endif
|
||||
|
||||
// Energy bars
|
||||
getWidget(mHealthFrame, "HealthFrame");
|
||||
|
@ -381,9 +384,6 @@ namespace MWGui
|
|||
mDrowningFlashTheta += dt * osg::PI*2;
|
||||
|
||||
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())
|
||||
{
|
||||
|
|
|
@ -117,6 +117,8 @@ namespace MWGui
|
|||
messageBox->update(height);
|
||||
height += messageBox->getHeight();
|
||||
}
|
||||
|
||||
box->setVisible(true);
|
||||
}
|
||||
|
||||
void MessageBoxManager::removeStaticMessageBox ()
|
||||
|
@ -189,6 +191,11 @@ namespace MWGui
|
|||
mMessageWidget->setCaptionWithReplacing(mMessage);
|
||||
}
|
||||
|
||||
MessageBox::~MessageBox()
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void MessageBox::update (int height)
|
||||
{
|
||||
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||
|
|
|
@ -59,6 +59,7 @@ namespace MWGui
|
|||
{
|
||||
public:
|
||||
MessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message);
|
||||
~MessageBox();
|
||||
void setMessage (const std::string& message);
|
||||
int getHeight ();
|
||||
void update (int height);
|
||||
|
|
|
@ -46,7 +46,11 @@ namespace
|
|||
namespace MWGui
|
||||
{
|
||||
TradeWindow::TradeWindow()
|
||||
#ifdef USE_OPENXR
|
||||
: WindowBase("openmw_trade_window_vr.layout")
|
||||
#else
|
||||
: WindowBase("openmw_trade_window.layout")
|
||||
#endif
|
||||
, mSortModel(nullptr)
|
||||
, mTradeModel(nullptr)
|
||||
, mItemToSell(-1)
|
||||
|
|
|
@ -53,7 +53,6 @@ void WindowBase::onDoubleClick(MyGUI::Widget *_sender)
|
|||
|
||||
void WindowBase::setVisible(bool visible)
|
||||
{
|
||||
Log(Debug::Verbose) << mLayoutName << ".setVisible: " << visible;
|
||||
bool wasVisible = mMainWidget->getVisible();
|
||||
mMainWidget->setVisible(visible);
|
||||
|
||||
|
@ -123,26 +122,42 @@ void NoDrop::onFrame(float dt)
|
|||
|
||||
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)
|
||||
{
|
||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
|
||||
while (focus && focus != mWidget)
|
||||
{
|
||||
focus = focus->getParent();
|
||||
}
|
||||
|
||||
if (focus == mWidget)
|
||||
{
|
||||
mTransparent = true;
|
||||
}
|
||||
}
|
||||
if (!mWidget->getAbsoluteCoord().inside(mousePos))
|
||||
mTransparent = false;
|
||||
|
||||
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
|
||||
#endif
|
||||
setAlpha(std::max(0.13f, mWidget->getAlpha() - dt*5));
|
||||
}
|
||||
else
|
||||
{
|
||||
mWidget->setNeedMouseFocus(true);
|
||||
#ifndef USE_OPENXR
|
||||
mWidget->setNeedMouseFocus(true); // Allow click-through
|
||||
#endif
|
||||
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->initialise(resourcePath, logpath);
|
||||
|
||||
#ifdef USE_OPENXR
|
||||
mGuiPlatform->getRenderManagerPtr()->setViewSize(1024, 1024);
|
||||
#endif
|
||||
|
||||
mGui = new MyGUI::Gui;
|
||||
mGui->initialise("");
|
||||
|
||||
|
@ -1246,6 +1250,9 @@ namespace MWGui
|
|||
|
||||
void WindowManager::windowResized(int x, int y)
|
||||
{
|
||||
#ifdef USE_OPENXR
|
||||
return;
|
||||
#endif
|
||||
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
|
||||
|
||||
// scaled size
|
||||
|
|
|
@ -297,7 +297,10 @@ namespace MWPhysics
|
|||
auto* session = MWVR::Environment::get().getSession();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -898,6 +898,7 @@ namespace MWRender
|
|||
|
||||
|
||||
const bool isPlayer = (mPtr == MWMechanics::getPlayer());
|
||||
|
||||
if (isPlayer)
|
||||
{
|
||||
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, "walk"))
|
||||
if (groupname.compare(0, 3, "run"))
|
||||
return false;
|
||||
if (groupname.compare(0, 4, "swim"))
|
||||
return false;
|
||||
#else
|
||||
(void)groupname;
|
||||
#endif
|
||||
|
|
|
@ -361,10 +361,12 @@ namespace MWRender
|
|||
if(mPreviewMode)
|
||||
limit /= 2;
|
||||
|
||||
#ifndef USE_OPENXR
|
||||
if(angle > limit)
|
||||
angle = limit;
|
||||
else if(angle < -limit)
|
||||
angle = -limit;
|
||||
#endif
|
||||
|
||||
if (mVanity.enabled || mPreviewMode) {
|
||||
mPreviewCam.pitch = angle;
|
||||
|
|
|
@ -828,16 +828,7 @@ private:
|
|||
|
||||
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);
|
||||
//SDL_MouseButtonEvent arg;
|
||||
//if (onPress)
|
||||
// mousePressed(arg, SDL_BUTTON_LEFT);
|
||||
//else
|
||||
// mouseReleased(arg, SDL_BUTTON_LEFT);
|
||||
}
|
||||
else if (onPress)
|
||||
{
|
||||
|
@ -919,35 +910,11 @@ private:
|
|||
{
|
||||
mXRInput->updateControls();
|
||||
|
||||
auto* world = MWBase::Environment::get().getWorld();
|
||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||
if (world && anim && anim->mPointerTarget.mHit)
|
||||
{
|
||||
auto* node = anim->mPointerTarget.mHitNode;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto* vrGuiManager = Environment::get().getGUIManager();
|
||||
vrGuiManager->updateFocus();
|
||||
auto guiCursor = vrGuiManager->guiCursor();
|
||||
mGuiCursorX = guiCursor.x();
|
||||
mGuiCursorY = guiCursor.y();
|
||||
|
||||
OpenXRActionEvent event{};
|
||||
while (mXRInput->nextActionEvent(event))
|
||||
|
@ -988,7 +955,8 @@ private:
|
|||
toggleMainMenu();
|
||||
// Explicitly request position update here so that the player can move the menu
|
||||
// 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;
|
||||
case A_Screenshot:
|
||||
screenshot();
|
||||
|
|
|
@ -131,14 +131,12 @@ namespace MWVR
|
|||
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;
|
||||
float yaw = 0.f;
|
||||
float pitch = 0.f;
|
||||
float roll = 0.f;
|
||||
getEulerAngles(lhandquat, yaw, pitch, roll);
|
||||
return yaw;
|
||||
|
||||
}
|
||||
|
||||
void OpenXRSession::advanceFrame(void)
|
||||
|
|
|
@ -47,8 +47,8 @@ public:
|
|||
//! Update predictions
|
||||
void predictNext(int extraPeriods);
|
||||
|
||||
//! Yaw angle to be used for offsetting movement direction
|
||||
float movementYaw(void);
|
||||
//! Angles to be used for overriding movement direction
|
||||
void movementAngles(float& yaw, float& pitch);
|
||||
|
||||
void advanceFrame(void);
|
||||
|
||||
|
|
|
@ -465,7 +465,7 @@ VRAnimation::VRAnimation(
|
|||
);
|
||||
mWeaponPointerTransform->setName("Weapon Pointer");
|
||||
mWeaponPointerTransform->setUpdateCallback(new WeaponPointerController);
|
||||
mWeaponDirectionTransform->addChild(mWeaponPointerTransform);
|
||||
//mWeaponDirectionTransform->addChild(mWeaponPointerTransform);
|
||||
}
|
||||
|
||||
VRAnimation::~VRAnimation() {};
|
||||
|
@ -538,7 +538,13 @@ void VRAnimation::setPointForward(bool enabled)
|
|||
|
||||
mPointerTransform->removeChild(mPointerRescale);
|
||||
if (enabled)
|
||||
{
|
||||
mPointerTransform->addChild(mPointerRescale);
|
||||
}
|
||||
else
|
||||
{
|
||||
mPointerTarget = MWRender::RayResult{};
|
||||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> VRAnimation::createPointerGeometry(void)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../mwrender/camera.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwgui/windowbase.hpp"
|
||||
|
||||
#include <MyGUI_Widget.h>
|
||||
|
@ -28,9 +29,22 @@
|
|||
#include <MyGUI_WidgetManager.h>
|
||||
#include <MyGUI_Window.h>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
// Convenience
|
||||
const double PI_8 = osg::PI_4 / 2.;
|
||||
}
|
||||
|
||||
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
|
||||
class GUICamera : public osg::Camera
|
||||
{
|
||||
|
@ -120,18 +134,11 @@ private:
|
|||
VRGUILayer::VRGUILayer(
|
||||
osg::ref_ptr<osg::Group> geometryRoot,
|
||||
osg::ref_ptr<osg::Group> cameraRoot,
|
||||
int width,
|
||||
int height,
|
||||
std::string filter,
|
||||
LayerConfig config,
|
||||
MWGui::Layout* widget,
|
||||
VRGUIManager* parent)
|
||||
: mConfig(config)
|
||||
, mFilter(filter)
|
||||
, mWidget(widget)
|
||||
, mWindow(dynamic_cast<MWGui::WindowBase*>(mWidget))
|
||||
, mMyGUIWindow(dynamic_cast<MyGUI::Window*>(mWidget->mMainWidget))
|
||||
, mParent(parent)
|
||||
, mGeometryRoot(geometryRoot)
|
||||
, mCameraRoot(cameraRoot)
|
||||
{
|
||||
|
@ -139,14 +146,18 @@ VRGUILayer::VRGUILayer(
|
|||
osg::ref_ptr<osg::Vec2Array> texCoords{ new osg::Vec2Array(4) };
|
||||
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() / 2.f;
|
||||
auto extent_units = config.extent * Environment::get().unitsPerMeter();
|
||||
|
||||
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
|
||||
osg::Vec3 top_left (-1, 1, 1);
|
||||
osg::Vec3 bottom_left(-1, 1, -1);
|
||||
osg::Vec3 bottom_right(1, 1, -1);
|
||||
osg::Vec3 top_right (1, 1, 1);
|
||||
osg::Vec3 top_left (left, 1, top);
|
||||
osg::Vec3 bottom_left(left, 1, bottom);
|
||||
osg::Vec3 bottom_right(right , 1, bottom);
|
||||
osg::Vec3 top_right (right, 1, top);
|
||||
(*vertices)[0] = top_left;
|
||||
(*vertices)[1] = bottom_left;
|
||||
(*vertices)[2] = bottom_right;
|
||||
|
@ -163,20 +174,23 @@ VRGUILayer::VRGUILayer(
|
|||
mGeometry->setDataVariance(osg::Object::DYNAMIC);
|
||||
mGeometry->setSupportsDisplayList(false);
|
||||
mGeometry->setName("VRGUILayer");
|
||||
mGeometry->setUserData(new VRGUILayerUserData(this));
|
||||
|
||||
// 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());
|
||||
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
|
||||
mStateSet->setTextureAttributeAndModes(0, menuTexture(), osg::StateAttribute::ON);
|
||||
mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
mStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
mStateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
mStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
mGeometry->setStateSet(mStateSet);
|
||||
osg::StateSet* stateSet = mGeometry->getOrCreateStateSet();
|
||||
stateSet->setTextureAttributeAndModes(0, menuTexture(), osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
mGeometry->setStateSet(stateSet);
|
||||
|
||||
// Position in the game world
|
||||
mTransform->setScale(osg::Vec3(extent_units.x(), 1.f, extent_units.y()));
|
||||
|
@ -186,6 +200,10 @@ VRGUILayer::VRGUILayer(
|
|||
mGeometryRoot->addChild(mTransform);
|
||||
mCameraRoot->addChild(mGUICamera);
|
||||
|
||||
// Edit offset to account for priority
|
||||
if(!mConfig.sideBySide)
|
||||
mConfig.offset.y() -= 0.001f * mConfig.priority;
|
||||
|
||||
mTransform->addUpdateCallback(new LayerUpdateCallback(this));
|
||||
}
|
||||
|
||||
|
@ -206,68 +224,174 @@ osg::ref_ptr<osg::Texture2D> VRGUILayer::menuTexture()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void VRGUILayer::updatePose()
|
||||
void VRGUILayer::setAngle(float angle)
|
||||
{
|
||||
osg::Vec3 eye{};
|
||||
osg::Vec3 center{};
|
||||
osg::Vec3 up{};
|
||||
mRotation = osg::Quat{ angle, osg::Z_AXIS };
|
||||
updatePose();
|
||||
}
|
||||
|
||||
// Get head pose by reading the camera view matrix to place the GUI in the world.
|
||||
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();
|
||||
|
||||
if (mConfig.trackedLimb == TrackedLimb::HEAD)
|
||||
void VRGUILayer::updateTracking(const Pose& headPose)
|
||||
{
|
||||
if (mConfig.trackingMode == TrackingMode::Menu)
|
||||
{
|
||||
mTrackedPose = headPose;
|
||||
mTrackedPose.orientation = mTrackedPose.orientation.inverse();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's not head, it's one of the hands, so i don't bother checking
|
||||
auto* session = MWVR::Environment::get().getSession();
|
||||
auto& poses = session->predictedPoses(OpenXRSession::PredictionSlice::Predraw);
|
||||
mTrackedPose = poses.hands[(int)TrackedSpace::STAGE][(int)mConfig.trackedLimb];
|
||||
// World position is the head, so must add difference between head and hand in tracking space to world pose
|
||||
mTrackedPose.position = mTrackedPose.position * MWVR::Environment::get().unitsPerMeter() - poses.head[(int)TrackedSpace::STAGE].position * MWVR::Environment::get().unitsPerMeter() + headPose.position;
|
||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||
if (anim)
|
||||
{
|
||||
const osg::Node* hand = nullptr;
|
||||
if (mConfig.trackingMode == TrackingMode::HudLeftHand)
|
||||
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;
|
||||
osg::Quat vertical;
|
||||
auto local = mLayerPose.orientation * axis;
|
||||
auto local = orientation * axis;
|
||||
vertical.makeRotate(local, axis);
|
||||
mLayerPose.orientation = mLayerPose.orientation * vertical;
|
||||
orientation = orientation * vertical;
|
||||
}
|
||||
// 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->setPosition(mLayerPose.position);
|
||||
mTransform->setAttitude(orientation);
|
||||
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()
|
||||
{
|
||||
if (mConfig.trackingMode == TrackingMode::Auto)
|
||||
updatePose();
|
||||
if (mConfig.trackingMode != TrackingMode::Menu)
|
||||
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);
|
||||
mWindow->onWindowResize(mMyGUIWindow);
|
||||
auto w = mConfig.myGUIViewSize.x();
|
||||
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
|
||||
osg::Vec4{0.f,0.f,0.f,.75f}, // background
|
||||
osg::Quat{}, // rotation
|
||||
osg::Vec3(0.f,1.f,0.f), // offset
|
||||
osg::Vec2(1.f, 1.f), // extent (meters)
|
||||
osg::Vec2i(2024,2024), // resolution (pixels)
|
||||
TrackedLimb::HEAD,
|
||||
TrackingMode::Manual,
|
||||
true // vertical
|
||||
return LayerConfig{
|
||||
1,
|
||||
false, // side-by-side
|
||||
osg::Vec4{0.f,0.f,0.f,.75f}, // background
|
||||
osg::Vec3(0.f,0.66f,-.25f), // offset
|
||||
osg::Vec2(0.f,0.f), // center (model space)
|
||||
osg::Vec2(1.f, 1.f), // extent (meters)
|
||||
1024, // Spatial resolution (pixels per meter)
|
||||
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
|
||||
{
|
||||
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 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
|
||||
0,
|
||||
false, // side-by-side
|
||||
osg::Vec4{}, // background
|
||||
osg::Vec3(0.025f,.025f,.066f), // offset (meters)
|
||||
osg::Vec2(0.f,0.5f), // center (model space)
|
||||
osg::Vec2(.1f, .1f), // extent (meters)
|
||||
1024, // resolution (pixels per meter)
|
||||
osg::Vec2i(1024,1024),
|
||||
gDefaultConfig.myGUIViewSize,
|
||||
SizingMode::Auto,
|
||||
TrackingMode::HudLeftHand,
|
||||
};
|
||||
|
||||
LayerConfig gPopupConfig = LayerConfig
|
||||
{
|
||||
false, // stretch
|
||||
0,
|
||||
false, // side-by-side
|
||||
osg::Vec4{0.f,0.f,0.f,0.f}, // background
|
||||
osg::Quat{}, // rotation
|
||||
osg::Vec3(0.f,0.f,.2f), // offset
|
||||
osg::Vec2(.2f, .2f), // extent (meters)
|
||||
osg::Vec2i(1024,1024),
|
||||
TrackedLimb::RIGHT_HAND,
|
||||
TrackingMode::Auto,
|
||||
false // vertical
|
||||
osg::Vec3(-0.025f,.025f,.066f), // offset (meters)
|
||||
osg::Vec2(0.f,0.5f), // center (model space)
|
||||
osg::Vec2(.1f, .1f), // extent (meters)
|
||||
1024, // resolution (pixels per meter)
|
||||
osg::Vec2i(2048,2048),
|
||||
gDefaultConfig.myGUIViewSize,
|
||||
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 =
|
||||
{
|
||||
{"StatusHUD", gStatusHUDConfig},
|
||||
{"MinimapHUD", gMinimapHUDConfig},
|
||||
//{"MinimapHUD", gMinimapHUDConfig},
|
||||
{"Popup", gPopupConfig},
|
||||
{"Windows", gWindowsConfig},
|
||||
{"JournalBooks", gJournalBooksConfig},
|
||||
{"SpellWindow", gSpellWindowConfig},
|
||||
{"InventoryCompanionWindow", gInventoryCompanionWindowConfig},
|
||||
{"InventoryWindow", gInventoryWindowConfig},
|
||||
{"SpellWindow", gSpellWindowConfig},
|
||||
{"MapWindow", gMapWindowConfig},
|
||||
{"StatsWindow", gStatsWindowConfig},
|
||||
{"Default", gDefaultConfig},
|
||||
{"DialogueWindow", gDialogueWindowConfig},
|
||||
{"MessageBox", gMessageBoxConfig},
|
||||
{"Windows", gDefaultWindowsConfig},
|
||||
{"Notification", gNotificationConfig}
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
Log(Debug::Verbose) << "setVisible (" << name << "): " << visible;
|
||||
|
@ -453,60 +684,103 @@ void VRGUIManager::setVisible(MWGui::Layout* widget, bool visible)
|
|||
widget->setLayerPick(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible)
|
||||
{
|
||||
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();
|
||||
}
|
||||
insertWidget(widget);
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
removeWidget(widget);
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
if (layer == mFocusLayer)
|
||||
return;
|
||||
|
||||
if (mFocusLayer)
|
||||
mFocusLayer->mWidget->setLayerPick(false);
|
||||
{
|
||||
mFocusLayer->mWidgets.front()->setLayerPick(false);
|
||||
}
|
||||
mFocusLayer = layer;
|
||||
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 <set>
|
||||
#include <regex>
|
||||
#include <MyGUI_Widget.h>
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/TexMat>
|
||||
|
@ -34,21 +35,34 @@ namespace MWVR
|
|||
|
||||
enum class TrackingMode
|
||||
{
|
||||
Auto, //!< Update tracking every frame
|
||||
Manual //!< Update tracking only on user request or when GUI visibility changes.
|
||||
Menu, //!< Menu quads with fixed position based on head tracking.
|
||||
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
|
||||
{
|
||||
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::Quat rotation; //!< Rotation relative to the tracking node
|
||||
osg::Vec3 offset; //!< Offset from tracked node in meters
|
||||
osg::Vec2 extent; //!< Spatial extent of the layer in meters
|
||||
osg::Vec2i resolution; //!< Pixel resolution of the texture
|
||||
TrackedLimb trackedLimb; //!< Which limb to track
|
||||
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::Vec2 extent; //!< Spatial extent of the layer in meters when using Fixed sizing mode
|
||||
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
|
||||
bool vertical; //!< Make layer vertical regardless of tracking orientation
|
||||
|
||||
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
|
||||
};
|
||||
|
||||
class VRGUILayer
|
||||
|
@ -57,11 +71,8 @@ namespace MWVR
|
|||
VRGUILayer(
|
||||
osg::ref_ptr<osg::Group> geometryRoot,
|
||||
osg::ref_ptr<osg::Group> cameraRoot,
|
||||
int width,
|
||||
int height,
|
||||
std::string filter,
|
||||
LayerConfig config,
|
||||
MWGui::Layout* widget,
|
||||
VRGUIManager* parent);
|
||||
~VRGUILayer();
|
||||
|
||||
|
@ -69,33 +80,39 @@ namespace MWVR
|
|||
|
||||
osg::ref_ptr<osg::Texture2D> menuTexture();
|
||||
|
||||
void setAngle(float angle);
|
||||
void updateTracking(const Pose& headPose = {});
|
||||
void updatePose();
|
||||
void updateRect();
|
||||
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:
|
||||
Pose mTrackedPose{};
|
||||
Pose mLayerPose{};
|
||||
LayerConfig mConfig;
|
||||
std::string mFilter;
|
||||
MWGui::Layout* mWidget;
|
||||
MWGui::WindowBase* mWindow;
|
||||
MyGUI::Window* mMyGUIWindow;
|
||||
VRGUIManager* mParent;
|
||||
std::vector<MWGui::Layout*> mWidgets;
|
||||
osg::ref_ptr<osg::Group> mGeometryRoot;
|
||||
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mTransform{ new osg::PositionAttitudeTransform };
|
||||
|
||||
osg::ref_ptr<osg::Group> mCameraRoot;
|
||||
osg::ref_ptr<osg::StateSet> mStateSet{ new osg::StateSet };
|
||||
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
|
||||
{
|
||||
public:
|
||||
VRGUILayerUserData(VRGUILayer* layer) : mLayer(layer) {};
|
||||
VRGUILayerUserData(std::shared_ptr<VRGUILayer> layer) : mLayer(layer) {};
|
||||
|
||||
VRGUILayer* mLayer;
|
||||
std::weak_ptr<VRGUILayer> mLayer;
|
||||
};
|
||||
|
||||
class VRGUIManager
|
||||
|
@ -110,18 +127,38 @@ namespace MWVR
|
|||
|
||||
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);
|
||||
|
||||
osg::Vec2i guiCursor() { return mGuiCursor; };
|
||||
|
||||
private:
|
||||
void computeGuiCursor(osg::Vec3 hitPoint);
|
||||
|
||||
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
|
||||
|
||||
osg::ref_ptr<osg::Group> mGUIGeometriesRoot{ 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 };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1100,6 +1100,15 @@ namespace MWWorld
|
|||
|
||||
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;
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode() &&
|
||||
|
|
|
@ -364,6 +364,7 @@ public:
|
|||
GUICamera(osg::Camera::RenderOrder order, RenderManager* parent, std::string filter)
|
||||
: mParent(parent)
|
||||
, mUpdate(false)
|
||||
, mFilter(filter)
|
||||
{
|
||||
setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
|
@ -405,6 +406,7 @@ public:
|
|||
osg::ref_ptr<Drawable> mDrawable;
|
||||
MyGUI::RenderTargetInfo mInfo;
|
||||
bool mUpdate;
|
||||
std::string mFilter;
|
||||
};
|
||||
|
||||
|
||||
|
@ -436,6 +438,10 @@ RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, R
|
|||
{
|
||||
if (scalingFactor != 0.f)
|
||||
mInvScalingFactor = 1.f / scalingFactor;
|
||||
|
||||
|
||||
osg::ref_ptr<osg::Viewport> vp = mViewer->getCamera()->getViewport();
|
||||
setViewSize(vp->width(), vp->height());
|
||||
}
|
||||
|
||||
RenderManager::~RenderManager()
|
||||
|
@ -552,21 +558,13 @@ void GUICamera::collectDrawCalls(std::string filter)
|
|||
MyGUI::LayerManager* myGUILayers = MyGUI::LayerManager::getInstancePtr();
|
||||
if (myGUILayers != nullptr)
|
||||
{
|
||||
std::regex layerRegex{ filter, std::regex_constants::icase };
|
||||
for (unsigned i = 0; i < myGUILayers->getLayerCount(); i++)
|
||||
{
|
||||
auto layer = myGUILayers->getLayer(i);
|
||||
|
||||
auto name = layer->getName();
|
||||
|
||||
if (std::regex_search(name, layerRegex))
|
||||
{
|
||||
//std::cout << "Including Layer: " << layer->getName() << std::endl;
|
||||
if (name == filter)
|
||||
layer->renderToTarget(this, mUpdate);
|
||||
}
|
||||
else {
|
||||
//std::cout << "Excluding Layer: " << layer->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
end();
|
||||
|
@ -590,6 +588,11 @@ void RenderManager::setViewSize(int width, int height)
|
|||
if(width < 1) width = 1;
|
||||
if(height < 1) height = 1;
|
||||
|
||||
////#ifdef USE_OPENXR
|
||||
// width = 1024;
|
||||
// height = 1024;
|
||||
////#endif
|
||||
|
||||
mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor);
|
||||
|
||||
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);
|
||||
mGuiCameras.insert(camera);
|
||||
osg::ref_ptr<osg::Viewport> vp = mViewer->getCamera()->getViewport();
|
||||
setViewSize(vp->width(), vp->height());
|
||||
camera->setViewport(0, 0, mViewSize.width, mViewSize.height);
|
||||
camera->setViewSize(mViewSize);
|
||||
return camera;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ set(MYGUI_FILES
|
|||
openmw_box.skin.xml
|
||||
openmw_button.skin.xml
|
||||
openmw_chargen_birth.layout
|
||||
openmw_chargen_class_description.layout
|
||||
openmw_chargen_class.layout
|
||||
openmw_chargen_class_description.layout
|
||||
openmw_chargen_create_class.layout
|
||||
openmw_chargen_generate_class_result.layout
|
||||
openmw_chargen_race.layout
|
||||
|
@ -25,78 +25,80 @@ set(MYGUI_FILES
|
|||
openmw_chargen_select_attribute.layout
|
||||
openmw_chargen_select_skill.layout
|
||||
openmw_chargen_select_specialization.layout
|
||||
openmw_companion_window.layout
|
||||
openmw_confirmation_dialog.layout
|
||||
openmw_console.layout
|
||||
openmw_console.skin.xml
|
||||
openmw_container_window.layout
|
||||
openmw_container_window_vr.layout
|
||||
openmw_count_window.layout
|
||||
openmw_debug_window.layout
|
||||
openmw_debug_window.skin.xml
|
||||
openmw_dialogue_window.layout
|
||||
openmw_dialogue_window_vr.layout
|
||||
openmw_dialogue_window.skin.xml
|
||||
openmw_edit.skin.xml
|
||||
openmw_edit_effect.layout
|
||||
openmw_edit_note.layout
|
||||
openmw_enchanting_dialog.layout
|
||||
openmw_font.xml
|
||||
openmw_hud.layout
|
||||
openmw_hud_box.skin.xml
|
||||
openmw_hud_energybar.skin.xml
|
||||
openmw_hud.layout
|
||||
openmw_hud_vr.layout
|
||||
openmw_infobox.layout
|
||||
openmw_interactive_messagebox.layout
|
||||
openmw_interactive_messagebox_notransp.layout
|
||||
openmw_inventory_window.layout
|
||||
openmw_inventory_window_vr.layout
|
||||
openmw_itemselection_dialog.layout
|
||||
openmw_jail_screen.layout
|
||||
openmw_journal.layout
|
||||
openmw_journal.skin.xml
|
||||
openmw_layers.xml
|
||||
openmw_layers_vr.xml
|
||||
openmw_levelup_dialog.layout
|
||||
openmw_list.skin.xml
|
||||
openmw_loading_screen.layout
|
||||
openmw_magicselection_dialog.layout
|
||||
openmw_mainmenu.layout
|
||||
openmw_mainmenu.skin.xml
|
||||
openmw_map_window.layout
|
||||
openmw_map_window_vr.layout
|
||||
openmw_map_window.skin.xml
|
||||
openmw_map_window_vr.layout
|
||||
openmw_merchantrepair.layout
|
||||
openmw_messagebox.layout
|
||||
openmw_persuasion_dialog.layout
|
||||
openmw_pointer.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_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_repair.layout
|
||||
openmw_resources.xml
|
||||
openmw_savegame_dialog.layout
|
||||
openmw_screen_fader.layout
|
||||
openmw_screen_fader_hit.layout
|
||||
openmw_edit_note.layout
|
||||
openmw_debug_window.layout
|
||||
openmw_debug_window.skin.xml
|
||||
openmw_jail_screen.layout
|
||||
openmw_scroll.layout
|
||||
openmw_scroll.skin.xml
|
||||
openmw_settings.xml
|
||||
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
|
||||
../launcher/images/openmw.png
|
||||
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"?>
|
||||
|
||||
<MyGUI type="Layout">
|
||||
<Widget type="Widget" layer="StatusHUD" position="0 0 185 80" 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>
|
||||
<Widget type="Widget" layer="StatusHUD" position="0 0 255 91" name="_Main" align="Default">
|
||||
<!-- 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"/>
|
||||
</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="ToolTipLayout" value="HealthToolTip"/>
|
||||
<UserString key="ImageTexture_HealthImage" value="icons\k\health.dds"/>
|
||||
|
@ -17,7 +14,7 @@
|
|||
<Property key="NeedMouse" value="false"/>
|
||||
</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="ToolTipLayout" value="HealthToolTip"/>
|
||||
<UserString key="ImageTexture_HealthImage" value="icons\k\magicka.dds"/>
|
||||
|
@ -25,7 +22,7 @@
|
|||
<Property key="NeedMouse" value="false"/>
|
||||
</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="ToolTipLayout" value="HealthToolTip"/>
|
||||
<UserString key="ImageTexture_HealthImage" value="icons\k\fatigue.dds"/>
|
||||
|
@ -35,7 +32,7 @@
|
|||
</Widget>
|
||||
|
||||
<!-- 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">
|
||||
<Property key="NeedMouse" value="false"/>
|
||||
<Widget type="ItemWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="WeapImage">
|
||||
|
@ -48,7 +45,7 @@
|
|||
</Widget>
|
||||
|
||||
<!-- 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="SpellWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="SpellImage"/>
|
||||
<Property key="NeedMouse" value="false"/>
|
||||
|
@ -59,7 +56,7 @@
|
|||
</Widget>
|
||||
|
||||
<!-- 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"/>
|
||||
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
||||
<Property key="NeedMouse" value="false"/>
|
||||
|
@ -70,44 +67,12 @@
|
|||
</Widget>
|
||||
</Widget>
|
||||
|
||||
</Widget>
|
||||
<Widget type="Widget" layer="MiniMapHUD" position="0 0 300 92" name="_Main2" align="Stretch">
|
||||
<!-- 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"/>
|
||||
<!-- Spell effects box -->
|
||||
<Widget type="Widget" skin="HUD_Box_Transparent" position="0 0 20 20" align="Left Bottom" name="EffectBox">
|
||||
</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>
|
||||
|
||||
|
||||
<!-- 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="ScrollView" skin="MW_MapView" position="2 2 61 61" align="Left Bottom" name="MiniMap">
|
||||
|
@ -124,6 +89,40 @@
|
|||
</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 -->
|
||||
<Widget type="ImageBox" skin="HUD_Crosshair" position="0 0 32 32" align="Center Center" name="Crosshair">
|
||||
</Widget>
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
<Layer name="Overlay" overlapped="false" pick="false"/>
|
||||
<Layer name="AdditiveOverlay" type="AdditiveLayer" pick="false"/>
|
||||
<Layer name="StatusHUD" overlapped="false" pick="true"/>
|
||||
<Layer name="MiniMapHUD" 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="SpellWindow" overlapped="true" pick="true"/>
|
||||
<Layer name="MapWindow" 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="JournalBooks" type="ScalingLayer" pick="true">
|
||||
<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