Separate rendering of window menus. It's still awkward. Needs polishing.

pull/615/head
Mads Buvik Sandvei 5 years ago
parent 7eaf015b87
commit 57e48cfc03

@ -122,14 +122,14 @@ if(BUILD_VR_OPENXR)
mwvr/openxrmanager.cpp
mwvr/openxrmanagerimpl.hpp
mwvr/openxrmanagerimpl.cpp
mwvr/openxrmenu.hpp
mwvr/openxrmenu.cpp
mwvr/vrgui.hpp
mwvr/vrgui.cpp
mwvr/openxrsession.hpp
mwvr/openxrsession.cpp
mwvr/openxrswapchain.hpp
mwvr/openxrswapchain.cpp
mwvr/openxrtexture.hpp
mwvr/openxrtexture.cpp
mwvr/vrtexture.hpp
mwvr/vrtexture.cpp
mwvr/openxrview.hpp
mwvr/openxrview.cpp
mwvr/openxrviewer.hpp

@ -562,18 +562,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(),
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts,
Version::getOpenmwVersionDescription(mResDir.string()), mCfgMgr.getUserConfigPath().string(),
#ifdef USE_OPENXR
true
#else
false
#endif
);
Version::getOpenmwVersionDescription(mResDir.string()), mCfgMgr.getUserConfigPath().string());
mEnvironment.setWindowManager (window);
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
#ifdef USE_OPENXR
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer));
#endif
if (!mSkipMenu)
{
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
@ -745,7 +743,7 @@ void OMW::Engine::go()
auto* xrViewer = MWVR::Environment::get().getViewer();
xrViewer->addChild(root);
mViewer->setSceneData(xrViewer);
mXrEnvironment.setMenuManager(new MWVR::OpenXRMenuManager(mViewer));
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer));
#endif
// Start the game

@ -66,7 +66,11 @@ namespace MWGui
HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender)
#ifdef USE_OPENXR
: WindowBase("openmw_hud_vr.layout")
#else
: WindowBase("openmw_hud.layout")
#endif
, LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map"))
, mHealth(nullptr)
, mMagicka(nullptr)
@ -99,7 +103,10 @@ namespace MWGui
, mIsDrowning(false)
, mDrowningFlashTheta(0.f)
{
#ifndef USE_OPENXR
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
#endif
mMainWidgetBaseSize = mMainWidget->getSize();
// Energy bars
getWidget(mHealthFrame, "HealthFrame");
@ -374,6 +381,9 @@ 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())
{
@ -587,6 +597,7 @@ namespace MWGui
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
#ifndef USE_OPENXR
// effect box can have variable width -> variable left coordinate
int effectsDx = 0;
if (!mMinimapBox->getVisible ())
@ -597,6 +608,11 @@ namespace MWGui
mCellNameBox->setVisible(false);
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
#else
// in VR mode, the effect box grows to the right and does not need repositioning
int width = std::max(mMainWidgetBaseSize.width, mEffectBox->getSize().width);
mMainWidget->setSize(width, mMainWidget->getHeight());
#endif
}
void HUD::updateEnemyHealthBar()

@ -80,6 +80,8 @@ namespace MWGui
int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft;
// bottom right elements
int mMinimapBoxBaseRight, mEffectBoxBaseRight;
// initial size
MyGUI::IntSize mMainWidgetBaseSize;
DragAndDrop* mDragAndDrop;

@ -56,7 +56,11 @@ namespace MWGui
{
InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem)
#ifdef USE_OPENXR
: WindowPinnableBase("openmw_inventory_window_vr.layout")
#else
: WindowPinnableBase("openmw_inventory_window.layout")
#endif
, mDragAndDrop(dragAndDrop)
, mSelectedItem(-1)
, mSortModel(nullptr)

@ -119,7 +119,7 @@ namespace MWGui
void sellItem(MyGUI::Widget* sender, int count);
void dragItem(MyGUI::Widget* sender, int count);
void onWindowResize(MyGUI::Window* _sender);
void onWindowResize(MyGUI::Window* _sender) override;
void onFilterChanged(MyGUI::Widget* _sender);
void onNameFilterChanged(MyGUI::EditBox* _sender);
void onAvatarClicked(MyGUI::Widget* _sender);

@ -5,6 +5,13 @@
#include <MyGUI_Gui.h>
#include <MyGUI_TextBox.h>
#include <MyGUI_Window.h>
#include <MyGUI_OverlappedLayer.h>
#include <MyGUI_SharedLayer.h>
#ifdef USE_OPENXR
#include "../mwvr/vrgui.hpp"
#include "../mwvr/vrenvironment.hpp"
#endif
namespace MWGui
{
@ -44,9 +51,21 @@ namespace MWGui
mMainWidget->setCoord(x,y,w,h);
}
void Layout::setCoordf(float x, float y, float w, float h)
{
mMainWidget->setRealCoord(x, y, w, h);
}
void Layout::setVisible(bool b)
{
mMainWidget->setVisible(b);
#ifdef USE_OPENXR
auto* vrGUIManager = MWVR::Environment::get().getGUIManager();
if (!vrGUIManager)
// May end up here before before rendering has been fully set up
return;
vrGUIManager->setVisible(this, b);
#endif
}
void Layout::setText(const std::string &name, const std::string &caption)
@ -64,6 +83,18 @@ namespace MWGui
window->setCaptionWithReplacing(title);
}
void Layout::setLayerPick(bool pick)
{
MyGUI::ILayer* layer = mMainWidget->getLayer();
// MyGUI exposes pick on the implementations of ILayer only, but not ILayer itself.
auto* oLayer = layer->castType<MyGUI::OverlappedLayer>(false);
auto* sLayer = layer->castType<MyGUI::SharedLayer>(false);
if (oLayer)
oLayer->setPick(pick);
if (sLayer)
sLayer->setPick(pick);
}
MyGUI::Widget* Layout::getWidget(const std::string &_name)
{
for (MyGUI::Widget* widget : mListWindowRoot)

@ -55,6 +55,7 @@ namespace MWGui
public:
void setCoord(int x, int y, int w, int h);
void setCoordf(float x, float y, float w, float h);
virtual void setVisible(bool b);
@ -63,6 +64,9 @@ namespace MWGui
// NOTE: this assume that mMainWidget is of type Window.
void setTitle(const std::string& title);
/// \note Affects the layer, not just the widget.
void setLayerPick(bool pick);
MyGUI::Widget* mMainWidget;
protected:

@ -640,7 +640,11 @@ namespace MWGui
// ------------------------------------------------------------------------------------------
MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue)
#ifdef USE_OPENXR
: WindowPinnableBase("openmw_map_window_vr.layout")
#else
: WindowPinnableBase("openmw_map_window.layout")
#endif
, LocalMapBase(customMarkers, localMapRender)
, NoDrop(drag, mMainWidget)
, mGlobalMap(0)

@ -65,8 +65,14 @@ namespace MWGui
int w=2;
for(auto rit = effects.rbegin(); rit != effects.rend(); rit++)
{
auto& effectInfoPair = *rit;
#if 0
// in VR mode, the effect box grows to the right so we want to invert the order to avoid reordering effects.
for (auto& effectInfoPair : effects)
{
#endif
const int effectId = effectInfoPair.first;
const ESM::MagicEffect* effect =
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(effectId);
@ -192,7 +198,10 @@ namespace MWGui
s = 0;
int diff = parent->getWidth() - s;
parent->setSize(s, parent->getHeight());
#ifndef USE_OPENXR
// in VR mode, the effect box grows to the right and does not need repositioning
parent->setPosition(parent->getLeft()+diff, parent->getTop());
#endif
}
// hide inactive effects

@ -31,7 +31,11 @@ namespace MWGui
{
SpellWindow::SpellWindow(DragAndDrop* drag)
#ifdef USE_OPENXR
: WindowPinnableBase("openmw_spell_window_vr.layout")
#else
: WindowPinnableBase("openmw_spell_window.layout")
#endif
, NoDrop(drag, mMainWidget)
, mSpellView(nullptr)
, mUpdateTimer(0.0f)

@ -25,7 +25,11 @@
namespace MWGui
{
StatsWindow::StatsWindow (DragAndDrop* drag)
#ifdef USE_OPENXR
: WindowPinnableBase("openmw_stats_window_vr.layout")
#else
: WindowPinnableBase("openmw_stats_window.layout")
#endif
, NoDrop(drag, mMainWidget)
, mSkillView(nullptr)
, mMajorSkills()

@ -50,7 +50,7 @@ namespace MWGui
void setExpelled (const std::set<std::string>& expelled);
void setBirthSign (const std::string &signId);
void onWindowResize(MyGUI::Window* window);
void onWindowResize(MyGUI::Window* window) override;
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
MyGUI::Widget* mLeftPane;

@ -12,6 +12,11 @@
#include "draganddrop.hpp"
#include "exposedwindow.hpp"
#ifdef USE_OPENXR
#include "../mwvr/vrgui.hpp"
#include "../mwvr/vrenvironment.hpp"
#endif
using namespace MWGui;
WindowBase::WindowBase(const std::string& parLayout)
@ -48,6 +53,7 @@ void WindowBase::onDoubleClick(MyGUI::Widget *_sender)
void WindowBase::setVisible(bool visible)
{
Log(Debug::Verbose) << mLayoutName << ".setVisible: " << visible;
bool wasVisible = mMainWidget->getVisible();
mMainWidget->setVisible(visible);
@ -55,6 +61,14 @@ void WindowBase::setVisible(bool visible)
onOpen();
else if (wasVisible)
onClose();
#ifdef USE_OPENXR
auto* vrGUIManager = MWVR::Environment::get().getGUIManager();
if (!vrGUIManager)
// May end up here before before rendering has been fully set up
return;
vrGUIManager->setVisible(this, visible);
#endif
}
bool WindowBase::isVisible()

@ -53,6 +53,9 @@ namespace MWGui
/// Called when GUI viewport changes size
virtual void onResChange(int width, int height) {}
/// Called when Window widget changes in size
virtual void onWindowResize(MyGUI::Window* window) {}
protected:
virtual void onTitleDoubleClicked();

@ -114,7 +114,7 @@
#ifdef USE_OPENXR
#include "../mwvr/vrenvironment.hpp"
#include "../mwvr/openxrmenu.hpp"
#include "../mwvr/vrgui.hpp"
#endif
namespace
@ -133,9 +133,8 @@ namespace MWGui
WindowManager::WindowManager(
osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& userDataPath, bool VRMode)
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& userDataPath)
: mStore(nullptr)
, mVRMode(VRMode)
, mResourceSystem(resourceSystem)
, mWorkQueue(workQueue)
, mViewer(viewer)
@ -202,7 +201,7 @@ namespace MWGui
, mVersionDescription(versionDescription)
{
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale, mVRMode);
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
mGuiPlatform->initialise(resourcePath, logpath);
mGui = new MyGUI::Gui;
@ -246,7 +245,11 @@ namespace MWGui
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
MyGUI::FactoryManager::getInstance().registerFactory<AutoSizedResourceSkin>("Resource", "AutoSizedResourceSkin");
#ifdef USE_OPENXR
MyGUI::ResourceManager::getInstance().load("core_vr.xml");
#else
MyGUI::ResourceManager::getInstance().load("core.xml");
#endif
WindowManager::loadUserFonts();
bool keyboardNav = Settings::Manager::getBool("keyboard navigation", "GUI");
@ -1890,7 +1893,7 @@ namespace MWGui
#ifdef USE_OPENXR
// Temporary hack to force update of menu placement
// (Menu gets recreated next tick)
auto* xrMenuManager = MWVR::Environment::get().getMenuManager();
auto* xrMenuManager = MWVR::Environment::get().getGUIManager();
#endif
mVideoWidget->eventKeyButtonPressed.clear();
@ -1935,7 +1938,7 @@ namespace MWGui
// (Menu gets recreated next tick)
if (xrMenuManager)
{
xrMenuManager->showMenus(false);
xrMenuManager->showGUIs(false);
xrMenuManager = nullptr;
}
#endif

@ -132,7 +132,7 @@ namespace MWGui
WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& localPath, bool VRMode);
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& localPath);
virtual ~WindowManager();
/// Set the ESMStore to use for retrieving of GUI-related strings.

@ -112,6 +112,11 @@ namespace MWRender
return position;
}
osg::Camera* Camera::getOsgCamera()
{
return mCamera;
}
void Camera::updateCamera()
{
updateCamera(mCamera);

@ -121,6 +121,8 @@ namespace MWRender
osg::Vec3d getFocalPoint();
osg::Camera* getOsgCamera();
/// Stores focal and camera world positions in passed arguments
void getPosition(osg::Vec3f &focal, osg::Vec3f &camera);

@ -2,6 +2,7 @@
#include <osg/Node>
#include <osg/ValueObject>
#include <osg/RenderInfo>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp>
@ -64,4 +65,21 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou
node->setStateSet(stateset);
}
MipmapCallback::~MipmapCallback()
{
}
void MipmapCallback::operator()(osg::RenderInfo& renderInfo) const
{
auto* gl = renderInfo.getState()->get<osg::GLExtensions>();
auto* tex = mTexture->getTextureObject(renderInfo.getContextID());
if (tex)
{
tex->bind();
gl->glGenerateMipmap(tex->target());
}
}
}

@ -2,12 +2,14 @@
#define OPENMW_MWRENDER_UTIL_H
#include <osg/NodeCallback>
#include <osg/Camera>
#include <osg/ref_ptr>
#include <string>
namespace osg
{
class Node;
class Texture2D;
}
namespace Resource
@ -32,6 +34,24 @@ namespace MWRender
// no traverse()
}
};
/// Draw callback for RTT that can be used to regenerate mipmaps
/// either as a predraw before use or a postdraw after RTT.
class MipmapCallback : public osg::Camera::DrawCallback
{
public:
MipmapCallback(osg::Texture2D* texture)
: mTexture(texture)
{}
~MipmapCallback();
void operator()(osg::RenderInfo& info) const override;
private:
osg::ref_ptr<osg::Texture2D> mTexture;
};
}
#endif

@ -732,6 +732,10 @@ OpenXRInput::getHandPoses(
XrSpaceVelocity velocity{ XR_TYPE_SPACE_VELOCITY };
location.next = &velocity;
CHECK_XRCMD(xrLocateSpace(mHandSpace[(int)Side::LEFT_HAND], referenceSpace, time, &location));
if (!location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
// Quat must have a magnitude of 1 but openxr sets it to 0 when tracking is unavailable.
// I want a no-track pose to still be valid
location.pose.orientation.w = 1;
handPoses[(int)Side::LEFT_HAND] = MWVR::Pose{
osg::fromXR(location.pose.position),
@ -740,6 +744,11 @@ OpenXRInput::getHandPoses(
};
CHECK_XRCMD(xrLocateSpace(mHandSpace[(int)Side::RIGHT_HAND], referenceSpace, time, &location));
if (!location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
// Quat must have a magnitude of 1 but openxr sets it to 0 when tracking is unavailable.
// I want a no-track pose to still be valid
location.pose.orientation.w = 1;
handPoses[(int)Side::RIGHT_HAND] = MWVR::Pose{
osg::fromXR(location.pose.position),
osg::fromXR(location.pose.orientation),
@ -817,15 +826,18 @@ private:
MWWorld::Ptr ptr = anim->mPointerTarget.mHitObject;
auto& dnd = MWBase::Environment::get().getWindowManager()->getDragAndDrop();
if (node && node->getName() == "XR Menu Geometry")
if (node && node->getName() == "VRGUILayer")
{
// Interseceted with the menu
// Inject mouse buttons
SDL_MouseButtonEvent arg;
if (onPress)
mousePressed(arg, SDL_BUTTON_LEFT);
else
mouseReleased(arg, SDL_BUTTON_LEFT);
// 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)
{
@ -851,6 +863,15 @@ private:
}
}
void OpenXRInputManager::injectMousePress(int sdlButton, bool onPress)
{
SDL_MouseButtonEvent arg;
if (onPress)
mousePressed(arg, sdlButton);
else
mouseReleased(arg, sdlButton);
}
OpenXRInputManager::OpenXRInputManager(
SDL_Window* window,
osg::ref_ptr<osgViewer::Viewer> viewer,
@ -903,19 +924,26 @@ private:
if (world && anim && anim->mPointerTarget.mHit)
{
auto* node = anim->mPointerTarget.mHitNode;
if (node)
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.y() = 1.f - (local.y() + 1.f) / 2.f;
local.z() = 1.f - (local.z() + 1.f) / 2.f;
mGuiCursorX = mInvUiScalingFactor * (local.x() * w);
mGuiCursorY = mInvUiScalingFactor * (local.y() * h);
mGuiCursorY = mInvUiScalingFactor * (local.z() * h);
MyGUI::InputManager::getInstance().injectMouseMove(int(mGuiCursorX), int(mGuiCursorY), 0);
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
vrGuiManager->setFocusLayer(userData->mLayer);
MyGUI::InputManager::getInstance().injectMouseMove((int)mGuiCursorX, (int)mGuiCursorY, 0);
}
else
{
vrGuiManager->setFocusLayer(nullptr);
}
}
@ -932,9 +960,9 @@ private:
MWInput::InputManager::update(dt, disableControls, disableEvents);
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
auto* xrMenuManager = Environment::get().getMenuManager();
if(xrMenuManager)
xrMenuManager->showMenus(guiMode);
auto* xrGUIManager = Environment::get().getGUIManager();
if(xrGUIManager)
xrGUIManager->showGUIs(guiMode);
setPlayerControlsEnabled(!guiMode);
@ -953,14 +981,14 @@ private:
void OpenXRInputManager::processEvent(const OpenXRActionEvent& event)
{
//auto* session = Environment::get().getSession();
auto* xrMenuManager = Environment::get().getMenuManager();
auto* xrGUIManager = Environment::get().getGUIManager();
switch (event.action)
{
case A_GameMenu:
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.
xrMenuManager->updatePose();
xrGUIManager->updatePose();
break;
case A_Screenshot:
screenshot();

@ -47,6 +47,8 @@ namespace MWVR
void updateActivationIndication(void);
void pointActivation(bool onPress);
void injectMousePress(int sdlButton, bool onPress);
std::unique_ptr<OpenXRInput> mXRInput;
std::unique_ptr<RealisticCombat::StateMachine> mRealisticCombat;
Pose mPreviousHeadPose{};

@ -3,7 +3,7 @@
#include <array>
#include "openxrmanager.hpp"
#include "openxrtexture.hpp"
#include "vrtexture.hpp"
struct XrCompositionLayerBaseHeader;

@ -222,6 +222,18 @@ namespace MWVR
if (mPrivate)
mPrivate->playerScale(stagePose);
}
Pose Pose::operator+(const Pose& rhs)
{
Pose pose = *this;
pose.position += this->orientation * rhs.position;
pose.orientation = rhs.orientation * this->orientation;
return pose;
}
const Pose& Pose::operator+=(const Pose& rhs)
{
*this = *this + rhs;
return *this;
}
}
std::ostream& operator <<(

@ -44,6 +44,9 @@ namespace MWVR
osg::Quat orientation{ 0,0,0,1 };
//! Speed of movement in VR space, expressed in meters per second
osg::Vec3 velocity{ 0,0,0 };
Pose operator+(const Pose& rhs);
const Pose& operator+=(const Pose& rhs);
};
using PoseSet = std::array<Pose, 2>;

@ -1,5 +1,5 @@
#include "openxrmanagerimpl.hpp"
#include "openxrtexture.hpp"
#include "vrtexture.hpp"
#include <components/debug/debuglog.hpp>
#include <components/sdlutil/sdlgraphicswindow.hpp>
@ -385,6 +385,12 @@ namespace MWVR
CHECK_XRCMD(xrLocateSpace(limbSpace, referenceSpace, predictedDisplayTime, &location));
//if (!(velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT))
// Log(Debug::Warning) << "Unable to acquire linear velocity";
if (!location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
{
// Quat must have a magnitude of 1 but openxr sets it to 0 when tracking is unavailable.
// I want a no-track pose to still be valid
location.pose.orientation.w = 1;
}
return MWVR::Pose{
osg::fromXR(location.pose.position),
osg::fromXR(location.pose.orientation),

@ -1,308 +0,0 @@
#include "openxrmenu.hpp"
#include "vrenvironment.hpp"
#include "openxrsession.hpp"
#include "openxrmanagerimpl.hpp"
#include "vranimation.hpp"
#include <openxr/openxr.h>
#include <osg/Texture2D>
#include <osg/ClipNode>
#include <osg/FrontFace>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include <osgViewer/Renderer>
#include "../mwrender/util.hpp"
#include "../mwrender/renderbin.hpp"
namespace MWVR
{
/// Draw callback for RTT that can be used to regenerate mipmaps
/// either as a predraw before use or a postdraw after RTT.
class MipmapCallback : public osg::Camera::DrawCallback
{
public:
MipmapCallback(osg::Texture2D* texture)
: mTexture(texture)
{}
void operator()(osg::RenderInfo& info) const override;
private:
osg::ref_ptr<osg::Texture2D> mTexture;
};
/// RTT camera used to draw the osg GUI to a texture
class GUICamera : public osg::Camera
{
public:
GUICamera()
{
setRenderOrder(osg::Camera::PRE_RENDER);
setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Make the texture just a little transparent to feel more natural in the game world.
setClearColor(osg::Vec4(0.f,0.f,0.f,.75f));
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::ABSOLUTE_RF);
setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
setName("MenuCamera");
setCullMask(SceneUtil::Mask_GUI);
setNodeMask(SceneUtil::Mask_RenderToTexture);
unsigned int rttSize = 4000;
setViewport(0, 0, rttSize, rttSize);
// No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph
// A double update would mess with the light collection (in addition to being plain redundant)
setUpdateCallback(new MWRender::NoTraverseCallback);
// Create the texture
mTexture = new osg::Texture2D;
mTexture->setTextureSize(rttSize, rttSize);
mTexture->setInternalFormat(GL_RGBA);
mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
attach(osg::Camera::COLOR_BUFFER, mTexture);
// Need to regenerate mipmaps every frame
setPostDrawCallback(new MipmapCallback(mTexture));
// Do not want to waste time on shadows when generating the GUI texture
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
// Put rendering as early as possible
getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin");
}
void setScene(osg::Node* scene)
{
if (mScene)
removeChild(mScene);
mScene = scene;
addChild(scene);
Log(Debug::Verbose) << "Set new scene: " << mScene->getName();
}
osg::Texture2D* getTexture() const
{
return mTexture.get();
}
private:
osg::ref_ptr<osg::Texture2D> mTexture;
osg::ref_ptr<osg::Node> mScene;
};
OpenXRMenu::OpenXRMenu(
osg::ref_ptr<osg::Group> geometryRoot,
osg::ref_ptr<osg::Group> cameraRoot,
osg::ref_ptr<osg::Node> menuSubgraph,
const std::string& title,
osg::Vec2 extent_meters,
Pose pose,
int width,
int height,
const osg::Vec4& clearColor,
osgViewer::Viewer* viewer)
: mTitle(title)
, mGeometryRoot(geometryRoot)
, mCameraRoot(cameraRoot)
, mMenuSubgraph(menuSubgraph)
{
osg::ref_ptr<osg::Vec3Array> vertices{ new osg::Vec3Array(4) };
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 = extent_meters * Environment::get().unitsPerMeter() / 2.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);
(*vertices)[0] = top_left;
(*vertices)[1] = bottom_left;
(*vertices)[2] = bottom_right;
(*vertices)[3] = top_right;
mGeometry->setVertexArray(vertices);
(*texCoords)[0].set(0.0f, 1.0f);
(*texCoords)[1].set(0.0f, 0.0f);
(*texCoords)[2].set(1.0f, 0.0f);
(*texCoords)[3].set(1.0f, 1.0f);
mGeometry->setTexCoordArray(0, texCoords);
(*normals)[0].set(0.0f, -1.0f, 0.0f);
mGeometry->setNormalArray(normals, osg::Array::BIND_OVERALL);
mGeometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
mGeometry->setDataVariance(osg::Object::DYNAMIC);
mGeometry->setSupportsDisplayList(false);
mGeometry->setName("XR Menu Geometry");
//mGeode->addDrawable(mGeometry);
// Define the camera that will render the menu texture
mGUICamera = new GUICamera();
mGUICamera->setScene(menuSubgraph);
// 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);
// Position in the game world
mTransform->setScale(osg::Vec3(extent_units.x(), extent_units.y(), 1.f));
mTransform->setAttitude(pose.orientation);
mTransform->setPosition(pose.position);
mTransform->addChild(mGeometry);
//mTransform->addChild(VRAnimation::createPointerGeometry());
// Add to scene graph
mGeometryRoot->addChild(mTransform);
mCameraRoot->addChild(mGUICamera);
}
OpenXRMenu::~OpenXRMenu()
{
mGeometryRoot->removeChild(mTransform);
mCameraRoot->removeChild(mGUICamera);
}
void OpenXRMenu::updateCallback()
{
}
void MipmapCallback::operator()(osg::RenderInfo& renderInfo) const
{
auto* gl = renderInfo.getState()->get<osg::GLExtensions>();
auto* tex = mTexture->getTextureObject(renderInfo.getContextID());
if (tex)
{
tex->bind();
gl->glGenerateMipmap(tex->target());
}
}
osg::Camera* OpenXRMenu::camera()
{
return mGUICamera.get();
}
osg::ref_ptr<osg::Texture2D> OpenXRMenu::menuTexture()
{
if (mGUICamera)
return mGUICamera->getTexture();
return nullptr;
}
void OpenXRMenu::updatePose(Pose pose)
{
mTransform->setAttitude(pose.orientation);
mTransform->setPosition(pose.position);
}
OpenXRMenuManager::OpenXRMenuManager(
osg::ref_ptr<osgViewer::Viewer> viewer)
: mOsgViewer(viewer)
{
mGUIGeometriesRoot->setName("XR GUI Geometry Root");
mGUICamerasRoot->setName("XR GUI Cameras Root");
auto* root = viewer->getSceneData();
SceneUtil::FindByNameVisitor findGUIVisitor("GUI Root");
root->accept(findGUIVisitor);
mGuiRoot = findGUIVisitor.mFoundNode;
if (!mGuiRoot)
{
Log(Debug::Error) << "GUI Root doesn't exist";
return;
}
SceneUtil::FindByNameVisitor findSceneVisitor("Scene Root");
root->accept(findSceneVisitor);
if(!findSceneVisitor.mFoundNode)
{
Log(Debug::Error) << "Scene Root doesn't exist";
return;
}
Log(Debug::Verbose) << "Root note: " << root->getName();
findSceneVisitor.mFoundNode->addChild(mGUIGeometriesRoot);
root->asGroup()->addChild(mGUICamerasRoot);
}
OpenXRMenuManager::~OpenXRMenuManager(void)
{
}
void OpenXRMenuManager::showMenus(bool show)
{
// TODO: Configurable menu dimensions
int width = 1000;
int height = 1000;
if (show && !mMenu)
{
updatePose();
mMenu.reset(new OpenXRMenu(
mGUIGeometriesRoot,
mGUICamerasRoot,
mGuiRoot,
"Main Menu",
osg::Vec2(1.5f, 1.5f),
mPose,
width,
height,
mOsgViewer->getCamera()->getClearColor(),
mOsgViewer
));
Log(Debug::Error) << "Created menu";
}
else if (!show && mMenu)
{
mMenu = nullptr;
Log(Debug::Error) << "Destroyed menu";
}
}
void OpenXRMenuManager::updatePose(void)
{
osg::Vec3 eye{};
osg::Vec3 center{};
osg::Vec3 up{};
auto* camera = mOsgViewer->getCamera();
if (!camera)
{
Log(Debug::Error) << "osg viewer has no camera";
return;
}
camera->getViewMatrixAsLookAt(eye, center, up);
// Position the menu about two thirds of a meter in front of the player
osg::Vec3 dir = center - eye;
dir.normalize();
mPose.position = eye + dir * Environment::get().unitsPerMeter() * 2.f / 3.f;
mPose.orientation = camera->getViewMatrix().getRotate().inverse();
if (mMenu)
mMenu->updatePose(mPose);
Log(Debug::Error) << "New menu pose: " << mPose;
}
}

@ -1,83 +0,0 @@
#ifndef OPENXR_MENU_HPP
#define OPENXR_MENU_HPP
#include <osg/Geometry>
#include <osg/TexMat>
#include <osg/Texture2D>
#include <osg/Camera>
#include <osg/PositionAttitudeTransform>
#include "openxrview.hpp"
#include "openxrlayer.hpp"
struct XrCompositionLayerQuad;
namespace MWVR
{
class GUICamera;
class OpenXRMenu
{
public:
OpenXRMenu(
osg::ref_ptr<osg::Group> geometryRoot,
osg::ref_ptr<osg::Group> cameraRoot,
osg::ref_ptr<osg::Node> menuSubgraph,
const std::string& title,
osg::Vec2 extent_meters,
Pose pose,
int width,
int height,
const osg::Vec4& clearColor,
osgViewer::Viewer* viewer);
~OpenXRMenu();
const std::string& title() const { return mTitle; }
void updateCallback();
void preRenderCallback(osg::RenderInfo& renderInfo);
void postRenderCallback(osg::RenderInfo& renderInfo);
osg::Camera* camera();
osg::ref_ptr<osg::Texture2D> menuTexture();
void updatePose(Pose pose);
public:
std::string mTitle;
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::Node> mMenuSubgraph;
osg::ref_ptr<osg::StateSet> mStateSet{ new osg::StateSet };
osg::ref_ptr<GUICamera> mGUICamera;
};
class OpenXRMenuManager
{
public:
OpenXRMenuManager(
osg::ref_ptr<osgViewer::Viewer> viewer);
~OpenXRMenuManager(void);
void showMenus(bool show);
void updatePose(void);
OpenXRMenu* getMenu(void) const { return mMenu.get(); }
private:
Pose mPose{};
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 };
osg::ref_ptr<osg::Node> mGuiRoot{ nullptr };
std::unique_ptr<OpenXRMenu> mMenu{ nullptr };
};
}
#endif

@ -22,7 +22,7 @@
#include <array>
#include <iostream>
#include "openxrsession.hpp"
#include "openxrmenu.hpp"
#include "vrgui.hpp"
#include <time.h>
namespace MWVR

@ -32,14 +32,14 @@ namespace MWVR {
osg::ref_ptr<OpenXRManager> mXR;
XrSwapchain mSwapchain = XR_NULL_HANDLE;
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainImageBuffers{};
//std::vector<osg::ref_ptr<OpenXRTextureBuffer> > mTextureBuffers{};
//std::vector<osg::ref_ptr<VRTexture> > mTextureBuffers{};
XrSwapchainSubImage mSubImage{};
int32_t mWidth = -1;
int32_t mHeight = -1;
int32_t mSamples = -1;
int64_t mSwapchainColorFormat = -1;
uint32_t mFBO = 0;
OpenXRTextureBuffer* mRenderBuffer = nullptr;
VRTexture* mRenderBuffer = nullptr;
};
OpenXRSwapchainImpl::OpenXRSwapchainImpl(
@ -99,8 +99,8 @@ namespace MWVR {
mSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mSwapchainImageBuffers.data())));
//for (const auto& swapchainImage : mSwapchainImageBuffers)
// mTextureBuffers.push_back(new OpenXRTextureBuffer(state, swapchainImage.image, mWidth, mHeight, 0));
mRenderBuffer = new OpenXRTextureBuffer(state, mWidth, mHeight, 0);
// mTextureBuffers.push_back(new VRTexture(state, swapchainImage.image, mWidth, mHeight, 0));
mRenderBuffer = new VRTexture(state, mWidth, mHeight, 0);
mSubImage.swapchain = mSwapchain;
mSubImage.imageRect.offset = { 0, 0 };
@ -181,7 +181,7 @@ namespace MWVR {
return impl().mSamples;
}
OpenXRTextureBuffer* OpenXRSwapchain::renderBuffer()
VRTexture* OpenXRSwapchain::renderBuffer()
{
return impl().mRenderBuffer;
}

@ -2,7 +2,7 @@
#define OPENXR_SWAPCHAIN_HPP
#include "openxrmanager.hpp"
#include "openxrtexture.hpp"
#include "vrtexture.hpp"
struct XrSwapchainSubImage;
@ -38,7 +38,7 @@ namespace MWVR
//! Samples of the view surface
int samples();
//! Get the current texture
OpenXRTextureBuffer* renderBuffer();
VRTexture* renderBuffer();
//! Get the private implementation
OpenXRSwapchainImpl& impl() { return *mPrivate; }
//! Get the private implementation

@ -154,16 +154,12 @@ namespace MWVR
}
void OpenXRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc, bool includeMenu)
void OpenXRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
{
//includeMenu = false;
mMirrorTextureSwapchain->beginFrame(gc);
int mirror_width = 0;
if(includeMenu)
mirror_width = mMirrorTextureSwapchain->width() / 3;
else
mirror_width = mMirrorTextureSwapchain->width() / 2;
int mirror_width = mMirrorTextureSwapchain->width() / 2;
mViews["RightEye"]->swapchain().renderBuffer()->blit(gc, 0, 0, mirror_width, mMirrorTextureSwapchain->height());
@ -172,44 +168,6 @@ namespace MWVR
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
if (includeMenu)
{
auto menuManager = Environment::get().getMenuManager();
if (menuManager)
{
auto menu = menuManager->getMenu();
if (menu)
{
auto texture = menu->menuTexture();
if (texture)
{
auto textureObject = texture->getTextureObject(state->getContextID());
if (textureObject)
{
auto textureId = textureObject->id();
Log(Debug::Verbose) << "texture id: " << textureId;
GLuint fbo = 0;
gl->glGenFramebuffers(1, &fbo);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, fbo);
gl->glFramebufferTexture2D(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0);
gl->glBlitFramebuffer(0, 0, texture->getTextureWidth(), texture->getTextureHeight(), 2 * mirror_width, 0, 3 * mirror_width, mMirrorTextureSwapchain->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
gl->glFramebufferTexture2D(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
gl->glDeleteFramebuffers(1, &fbo);
}
else
{
Log(Debug::Warning) << "Texture object was null";
}
}
}
}
}
mMirrorTextureSwapchain->endFrame(gc);
@ -267,7 +225,7 @@ namespace MWVR
mLayer->views = mCompositionLayerProjectionViews.data();
}
blitEyesToMirrorTexture(gc, false);
blitEyesToMirrorTexture(gc);
gc->swapBuffersImplementation();
}

@ -12,7 +12,7 @@
#include "openxrsession.hpp"
#include "openxrlayer.hpp"
#include "openxrworldview.hpp"
#include "openxrmenu.hpp"
#include "vrgui.hpp"
#include <components/sceneutil/positionattitudetransform.hpp>
struct XrCompositionLayerProjection;
@ -83,7 +83,7 @@ namespace MWVR
void traversals();
void preDrawCallback(osg::RenderInfo& info);
void postDrawCallback(osg::RenderInfo& info);
void blitEyesToMirrorTexture(osg::GraphicsContext* gc, bool includeMenu = true);
void blitEyesToMirrorTexture(osg::GraphicsContext* gc);
void swapBuffers(osg::GraphicsContext* gc) override;
void realize(osg::GraphicsContext* gc);

@ -5,7 +5,7 @@
#include "vranimation.hpp"
#include "openxrinputmanager.hpp"
#include "openxrsession.hpp"
#include "openxrmenu.hpp"
#include "vrgui.hpp"
#include "../mwbase/environment.hpp"
@ -29,9 +29,9 @@ void MWVR::Environment::cleanup()
if (mSession)
delete mSession;
mSession = nullptr;
if (mMenuManager)
delete mMenuManager;
mMenuManager = nullptr;
if (mGUIManager)
delete mGUIManager;
mGUIManager = nullptr;
if (mViewer)
delete mViewer;
mViewer = nullptr;
@ -65,14 +65,14 @@ void MWVR::Environment::setSession(MWVR::OpenXRSession* xrSession)
mSession = xrSession;
}
MWVR::OpenXRMenuManager* MWVR::Environment::getMenuManager() const
MWVR::VRGUIManager* MWVR::Environment::getGUIManager() const
{
return mMenuManager;
return mGUIManager;
}
void MWVR::Environment::setMenuManager(MWVR::OpenXRMenuManager* menuManager)
void MWVR::Environment::setGUIManager(MWVR::VRGUIManager* GUIManager)
{
mMenuManager = menuManager;
mGUIManager = GUIManager;
}
MWVR::VRAnimation* MWVR::Environment::getPlayerAnimation() const

@ -6,7 +6,7 @@ namespace MWVR
class VRAnimation;
class OpenXRInputManager;
class OpenXRSession;
class OpenXRMenuManager;
class VRGUIManager;
class OpenXRViewer;
class OpenXRManager;
@ -45,8 +45,8 @@ namespace MWVR
// which is stored in MWBase::Environment
// void setInputManager(MWVR::OpenXRInputManager*);
MWVR::OpenXRMenuManager* getMenuManager() const;
void setMenuManager(MWVR::OpenXRMenuManager* xrMenuManager);
MWVR::VRGUIManager* getGUIManager() const;
void setGUIManager(MWVR::VRGUIManager* xrGUIManager);
MWVR::VRAnimation* getPlayerAnimation() const;
void setPlayerAnimation(MWVR::VRAnimation* xrAnimation);
@ -65,7 +65,7 @@ namespace MWVR
private:
MWVR::OpenXRSession* mSession{ nullptr };
MWVR::OpenXRMenuManager* mMenuManager{ nullptr };
MWVR::VRGUIManager* mGUIManager{ nullptr };
MWVR::VRAnimation* mPlayerAnimation{ nullptr };
MWVR::OpenXRViewer* mViewer{ nullptr };
MWVR::OpenXRManager* mOpenXRManager{ nullptr };

@ -0,0 +1,512 @@
#include "vrgui.hpp"
#include "vrenvironment.hpp"
#include "openxrsession.hpp"
#include "openxrmanagerimpl.hpp"
#include "openxrinputmanager.hpp"
#include "vranimation.hpp"
#include <openxr/openxr.h>
#include <osg/Texture2D>
#include <osg/ClipNode>
#include <osg/FrontFace>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/myguiplatform/myguirendermanager.hpp>
#include <osgViewer/Renderer>
#include "../mwrender/util.hpp"
#include "../mwrender/renderbin.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "../mwrender/camera.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwgui/windowbase.hpp"
#include <MyGUI_Widget.h>
#include <MyGUI_ILayer.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_WidgetManager.h>
#include <MyGUI_Window.h>
namespace MWVR
{
/// RTT camera used to draw the osg GUI to a texture
class GUICamera : public osg::Camera
{
public:
GUICamera(int width, int height, osg::Vec4 clearColor)
{
setRenderOrder(osg::Camera::PRE_RENDER);
setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setCullingActive(false);
// Make the texture just a little transparent to feel more natural in the game world.
setClearColor(clearColor);
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::ABSOLUTE_RF);
setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
setName("GUICamera");
setCullMask(SceneUtil::Mask_GUI);
setNodeMask(SceneUtil::Mask_RenderToTexture);
setViewport(0, 0, width, height);
// No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph
// A double update would mess with the light collection (in addition to being plain redundant)
setUpdateCallback(new MWRender::NoTraverseCallback);
// Create the texture
mTexture = new osg::Texture2D;
mTexture->setTextureSize(width, height);
mTexture->setInternalFormat(GL_RGBA);
mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
mTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
attach(osg::Camera::COLOR_BUFFER, mTexture);
// Need to regenerate mipmaps every frame
setPostDrawCallback(new MWRender::MipmapCallback(mTexture));
// Do not want to waste time on shadows when generating the GUI texture
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
// Put rendering as early as possible
getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin");
}
void setScene(osg::Node* scene)
{
if (mScene)
removeChild(mScene);
mScene = scene;
addChild(scene);
Log(Debug::Verbose) << "Set new scene: " << mScene->getName();
}
osg::Texture2D* getTexture() const
{
return mTexture.get();
}
private:
osg::ref_ptr<osg::Texture2D> mTexture;
osg::ref_ptr<osg::Node> mScene;
};
class LayerUpdateCallback : public osg::Callback
{
public:
LayerUpdateCallback(VRGUILayer* layer)
: mLayer(layer)
{
}
bool run(osg::Object* object, osg::Object* data)
{
mLayer->update();
return traverse(object, data);
}
private:
VRGUILayer* mLayer;
};
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)
{
osg::ref_ptr<osg::Vec3Array> vertices{ new osg::Vec3Array(4) };
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;
// 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);
(*vertices)[0] = top_left;
(*vertices)[1] = bottom_left;
(*vertices)[2] = bottom_right;
(*vertices)[3] = top_right;
mGeometry->setVertexArray(vertices);
(*texCoords)[0].set(0.0f, 1.0f);
(*texCoords)[1].set(0.0f, 0.0f);
(*texCoords)[2].set(1.0f, 0.0f);
(*texCoords)[3].set(1.0f, 1.0f);
mGeometry->setTexCoordArray(0, texCoords);
(*normals)[0].set(0.0f, -1.0f, 0.0f);
mGeometry->setNormalArray(normals, osg::Array::BIND_OVERALL);
mGeometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
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);
osgMyGUI::RenderManager& renderManager = static_cast<osgMyGUI::RenderManager&>(MyGUI::RenderManager::getInstance());
mGUICamera->setScene(renderManager.createGUICamera(osg::Camera::NESTED_RENDER, filter));
// 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);
// Position in the game world
mTransform->setScale(osg::Vec3(extent_units.x(), 1.f, extent_units.y()));
mTransform->addChild(mGeometry);
// Add to scene graph
mGeometryRoot->addChild(mTransform);
mCameraRoot->addChild(mGUICamera);
mTransform->addUpdateCallback(new LayerUpdateCallback(this));
}
VRGUILayer::~VRGUILayer()
{
mGeometryRoot->removeChild(mTransform);
mCameraRoot->removeChild(mGUICamera);
}
osg::Camera* VRGUILayer::camera()
{
return mGUICamera.get();
}
osg::ref_ptr<osg::Texture2D> VRGUILayer::menuTexture()
{
if (mGUICamera)
return mGUICamera->getTexture();
return nullptr;
}
void VRGUILayer::updatePose()
{
osg::Vec3 eye{};
osg::Vec3 center{};
osg::Vec3 up{};
// 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)
{
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;
}
mLayerPose.orientation = mConfig.rotation * mTrackedPose.orientation;
if (mConfig.vertical)
{
// Force layer to be vertical
auto axis = osg::Z_AXIS;
osg::Quat vertical;
auto local = mLayerPose.orientation * axis;
vertical.makeRotate(local, axis);
mLayerPose.orientation = mLayerPose.orientation * vertical;
}
// Orient the offset and move the layer
mLayerPose.position = mTrackedPose.position + mLayerPose.orientation * mConfig.offset * MWVR::Environment::get().unitsPerMeter();
mTransform->setAttitude(mLayerPose.orientation);
mTransform->setPosition(mLayerPose.position);
}
void VRGUILayer::update()
{
if (mConfig.trackingMode == TrackingMode::Auto)
updatePose();
if (mConfig.stretch)
{
if (mWindow && mMyGUIWindow)
{
mWindow->setCoordf(0.f, 0.f, 1.f, 1.f);
mWindow->onWindowResize(mMyGUIWindow);
}
}
}
VRGUIManager::VRGUIManager(
osg::ref_ptr<osgViewer::Viewer> viewer)
: mOsgViewer(viewer)
{
mGUIGeometriesRoot->setName("XR GUI Geometry Root");
mGUICamerasRoot->setName("XR GUI Cameras Root");
auto* root = viewer->getSceneData();
SceneUtil::FindByNameVisitor findSceneVisitor("Scene Root");
root->accept(findSceneVisitor);
if(!findSceneVisitor.mFoundNode)
{
Log(Debug::Error) << "Scene Root doesn't exist";
return;
}
findSceneVisitor.mFoundNode->addChild(mGUIGeometriesRoot);
root->asGroup()->addChild(mGUICamerasRoot);
}
VRGUIManager::~VRGUIManager(void)
{
}
void VRGUIManager::showGUIs(bool show)
{
}
LayerConfig gDefaultConfig = LayerConfig
{
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
};
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
};
LayerConfig gPopupConfig = LayerConfig
{
false, // stretch
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
};
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},
{"Popup", gPopupConfig},
{"Windows", gWindowsConfig},
{"JournalBooks", gJournalBooksConfig},
{"SpellWindow", gSpellWindowConfig},
{"InventoryWindow", gInventoryWindowConfig},
{"MapWindow", gMapWindowConfig},
{"StatsWindow", gStatsWindowConfig},
{"Default", gDefaultConfig},
};
static std::set<std::string> layerBlacklist =
{
"Overlay"
};
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;
if (layerBlacklist.find(name) != layerBlacklist.end())
{
Log(Debug::Verbose) << "Blacklisted";
// Never pick an invisible layer
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();
}
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;
}
}
}
void VRGUIManager::updatePose(void)
{
for (auto& layer : mLayers)
layer.second->updatePose();
}
void VRGUIManager::setFocusLayer(VRGUILayer* layer)
{
if (mFocusLayer)
mFocusLayer->mWidget->setLayerPick(false);
mFocusLayer = layer;
if (mFocusLayer)
mFocusLayer->mWidget->setLayerPick(true);
}
}

@ -0,0 +1,129 @@
#ifndef OPENXR_MENU_HPP
#define OPENXR_MENU_HPP
#include <map>
#include <set>
#include <regex>
#include <osg/Geometry>
#include <osg/TexMat>
#include <osg/Texture2D>
#include <osg/Camera>
#include <osg/PositionAttitudeTransform>
#include "openxrview.hpp"
#include "openxrlayer.hpp"
namespace MyGUI
{
class Widget;
class Window;
}
namespace MWGui
{
class Layout;
class WindowBase;
}
struct XrCompositionLayerQuad;
namespace MWVR
{
class GUICamera;
class VRGUIManager;
enum class TrackingMode
{
Auto, //!< Update tracking every frame
Manual //!< Update tracking only on user request or when GUI visibility changes.
};
struct LayerConfig
{
bool stretch; //!< 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
TrackingMode trackingMode; //!< Tracking mode
bool vertical; //!< Make layer vertical regardless of tracking orientation
};
class VRGUILayer
{
public:
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();
osg::Camera* camera();
osg::ref_ptr<osg::Texture2D> menuTexture();
void updatePose();
void update();
public:
Pose mTrackedPose{};
Pose mLayerPose{};
LayerConfig mConfig;
std::string mFilter;
MWGui::Layout* mWidget;
MWGui::WindowBase* mWindow;
MyGUI::Window* mMyGUIWindow;
VRGUIManager* mParent;
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;
};
class VRGUILayerUserData : public osg::Referenced
{
public:
VRGUILayerUserData(VRGUILayer* layer) : mLayer(layer) {};
VRGUILayer* mLayer;
};
class VRGUIManager
{
public:
VRGUIManager(
osg::ref_ptr<osgViewer::Viewer> viewer);
~VRGUIManager(void);
void showGUIs(bool show);
void setVisible(MWGui::Layout*, bool visible);
void updatePose(void);
void setFocusLayer(VRGUILayer* layer);
private:
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;
VRGUILayer* mFocusLayer{ nullptr };
};
}
#endif

@ -1,5 +1,5 @@
#include "openxrviewer.hpp"
#include "openxrtexture.hpp"
#include "vrtexture.hpp"
#include <osg/Texture2D>
#include <osgViewer/Renderer>
#include <components/debug/debuglog.hpp>
@ -13,7 +13,7 @@
namespace MWVR
{
OpenXRTextureBuffer::OpenXRTextureBuffer(
VRTexture::VRTexture(
osg::ref_ptr<osg::State> state,
std::size_t width,
std::size_t height,
@ -71,12 +71,12 @@ namespace MWVR
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
}
OpenXRTextureBuffer::~OpenXRTextureBuffer()
VRTexture::~VRTexture()
{
destroy(nullptr);
}
void OpenXRTextureBuffer::destroy(osg::State* state)
void VRTexture::destroy(osg::State* state)
{
if (!state)
{
@ -102,14 +102,14 @@ namespace MWVR
mFBO = mDepthBuffer = mColorBuffer;
}
void OpenXRTextureBuffer::beginFrame(osg::GraphicsContext* gc)
void VRTexture::beginFrame(osg::GraphicsContext* gc)
{
auto state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFBO);
}
void OpenXRTextureBuffer::endFrame(osg::GraphicsContext* gc, uint32_t blitTarget)
void VRTexture::endFrame(osg::GraphicsContext* gc, uint32_t blitTarget)
{
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
@ -122,7 +122,7 @@ namespace MWVR
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
}
void OpenXRTextureBuffer::blit(osg::GraphicsContext* gc, int x, int y, int w, int h)
void VRTexture::blit(osg::GraphicsContext* gc, int x, int y, int w, int h)
{
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
@ -131,7 +131,7 @@ namespace MWVR
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
}
void OpenXRTextureBuffer::blit(osg::GraphicsContext* gc, int x, int y, int w, int h, int blitTarget)
void VRTexture::blit(osg::GraphicsContext* gc, int x, int y, int w, int h, int blitTarget)
{
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);

@ -10,11 +10,11 @@
namespace MWVR
{
class OpenXRTextureBuffer : public osg::Referenced
class VRTexture : public osg::Referenced
{
public:
OpenXRTextureBuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples);
~OpenXRTextureBuffer();
VRTexture(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples);
~VRTexture();
void destroy(osg::State* state);

@ -2,7 +2,7 @@
#include "mwvr/openxrmanager.hpp"
#include "mwvr/openxrsession.hpp"
#include "mwvr/openxrviewer.hpp"
#include "mwvr/openxrmenu.hpp"
#include "mwvr/vrgui.hpp"
#ifndef USE_OPENXR
#error "USE_OPENXR not defined"

@ -21,13 +21,13 @@ namespace osgMyGUI
void AdditiveLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update)
{
RenderManager& renderManager = static_cast<RenderManager&>(MyGUI::RenderManager::getInstance());
StateInjectableRenderTarget* injectableTarget = static_cast<StateInjectableRenderTarget*>(_target);
renderManager.setInjectState(mStateSet.get());
injectableTarget->setInjectState(mStateSet.get());
MyGUI::OverlappedLayer::renderToTarget(_target, _update);
renderManager.setInjectState(nullptr);
injectableTarget->setInjectState(nullptr);
}
}

@ -7,15 +7,14 @@
namespace osgMyGUI
{
Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::ImageManager *imageManager, float uiScalingFactor, bool VRMode)
Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::ImageManager *imageManager, float uiScalingFactor)
: mRenderManager(nullptr)
, mDataManager(nullptr)
, mLogManager(nullptr)
, mLogFacility(nullptr)
, mVRMode(VRMode)
{
mLogManager = new MyGUI::LogManager();
mRenderManager = new RenderManager(viewer, guiRoot, imageManager, uiScalingFactor, VRMode);
mRenderManager = new RenderManager(viewer, guiRoot, imageManager, uiScalingFactor);
mDataManager = new DataManager();
}

@ -30,7 +30,7 @@ namespace osgMyGUI
class Platform
{
public:
Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, float uiScalingFactor, bool VRMode);
Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, float uiScalingFactor);
~Platform();

@ -1,5 +1,7 @@
#include "myguirendermanager.hpp"
#include <regex>
#include <MyGUI_Gui.h>
#include <MyGUI_Timer.h>
#include <MyGUI_LayerManager.h>
@ -42,8 +44,10 @@
namespace osgMyGUI
{
class GUICamera;
class Drawable : public osg::Drawable {
osgMyGUI::RenderManager *mParent;
osgMyGUI::RenderManager *mManager;
osg::ref_ptr<osg::StateSet> mStateSet;
public:
@ -77,26 +81,26 @@ public:
{
public:
CollectDrawCalls()
: mRenderManager(nullptr)
: mCamera(nullptr)
, mFilter("")
{
}
void setRenderManager(osgMyGUI::RenderManager* renderManager)
void setCamera(osgMyGUI::GUICamera* camera)
{
mRenderManager = renderManager;
mCamera = camera;
}
virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const
void setFilter(std::string filter)
{
if (!mRenderManager)
return false;
mRenderManager->collectDrawCalls();
return false;
mFilter = filter;
}
virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const;
private:
osgMyGUI::RenderManager* mRenderManager;
GUICamera* mCamera;
std::string mFilter;
};
// Stage 2: execute the draw calls. Run during the Draw traversal. May run in parallel with the update traversal of the next frame.
@ -167,20 +171,24 @@ public:
}
public:
Drawable(osgMyGUI::RenderManager *parent = nullptr)
: mParent(parent)
Drawable(std::string filter = "", osgMyGUI::RenderManager *manager = nullptr, osgMyGUI::GUICamera* camera = nullptr)
: mManager(manager)
, mWriteTo(0)
, mReadFrom(0)
{
setSupportsDisplayList(false);
osg::ref_ptr<CollectDrawCalls> collectDrawCalls = new CollectDrawCalls;
collectDrawCalls->setRenderManager(mParent);
collectDrawCalls->setCamera(camera);
collectDrawCalls->setFilter(filter);
setCullCallback(collectDrawCalls);
osg::ref_ptr<FrameUpdate> frameUpdate = new FrameUpdate;
frameUpdate->setRenderManager(mParent);
setUpdateCallback(frameUpdate);
if (mManager)
{
osg::ref_ptr<FrameUpdate> frameUpdate = new FrameUpdate;
frameUpdate->setRenderManager(mManager);
setUpdateCallback(frameUpdate);
}
mStateSet = new osg::StateSet;
mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
@ -196,7 +204,7 @@ public:
}
Drawable(const Drawable &copy, const osg::CopyOp &copyop=osg::CopyOp::SHALLOW_COPY)
: osg::Drawable(copy, copyop)
, mParent(copy.mParent)
, mManager(copy.mManager)
, mStateSet(copy.mStateSet)
, mWriteTo(0)
, mReadFrom(0)
@ -349,15 +357,82 @@ osg::VertexBufferObject* OSGVertexBuffer::getVertexBuffer()
// ---------------------------------------------------------------------------
RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* imageManager, float scalingFactor, bool VRMode)
/// Camera used to draw a MyGUI layer
class GUICamera : public osg::Camera, public StateInjectableRenderTarget
{
public:
GUICamera(osg::Camera::RenderOrder order, RenderManager* parent, std::string filter)
: mParent(parent)
, mUpdate(false)
{
setReferenceFrame(osg::Transform::ABSOLUTE_RF);
setProjectionResizePolicy(osg::Camera::FIXED);
setProjectionMatrix(osg::Matrix::identity());
setViewMatrix(osg::Matrix::identity());
setRenderOrder(order);
setClearMask(GL_NONE);
setName("GUI Camera");
mDrawable = new Drawable(filter, parent, this);
mDrawable->setName("GUI Drawable");
addChild(mDrawable.get());
mDrawable->setCullingActive(false);
}
~GUICamera()
{
mParent->deleteGUICamera(this);
}
// Called by the cull traversal
/** @see IRenderTarget::begin */
void begin() override;
void end() override;
/** @see IRenderTarget::doRender */
void doRender(MyGUI::IVertexBuffer* buffer, MyGUI::ITexture* texture, size_t count) override;
void collectDrawCalls();
void collectDrawCalls(std::string filter);
void setViewSize(MyGUI::IntSize viewSize);
/** @see IRenderTarget::getInfo */
const MyGUI::RenderTargetInfo& getInfo() override { return mInfo; }
RenderManager* mParent;
osg::ref_ptr<Drawable> mDrawable;
MyGUI::RenderTargetInfo mInfo;
bool mUpdate;
};
void GUICamera::begin()
{
mDrawable->clear();
// variance will be recomputed based on textures being rendered in this frame
mDrawable->setDataVariance(osg::Object::STATIC);
}
bool Drawable::CollectDrawCalls::cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const
{
if (!mCamera)
return false;
if (mFilter.empty())
mCamera->collectDrawCalls();
else
mCamera->collectDrawCalls(mFilter);
return false;
}
RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* imageManager, float scalingFactor)
: mViewer(viewer)
, mSceneRoot(sceneroot)
, mImageManager(imageManager)
, mUpdate(false)
, mIsInitialise(false)
, mInvScalingFactor(1.f)
, mInjectState(nullptr)
, mVRMode(VRMode)
{
if (scalingFactor != 0.f)
mInvScalingFactor = 1.f / scalingFactor;
@ -367,9 +442,9 @@ RenderManager::~RenderManager()
{
MYGUI_PLATFORM_LOG(Info, "* Shutdown: "<<getClassTypeName());
if(mGuiRoot.valid())
mSceneRoot->removeChild(mGuiRoot.get());
mGuiRoot = nullptr;
for (auto guiCamera : mGuiCameras)
mSceneRoot->removeChild(guiCamera);
mGuiCameras.clear();
mSceneRoot = nullptr;
mViewer = nullptr;
@ -387,27 +462,7 @@ void RenderManager::initialise()
mVertexFormat = MyGUI::VertexColourType::ColourABGR;
mUpdate = false;
mDrawable = new Drawable(this);
mDrawable->setName("GUI Drawable");
osg::ref_ptr<osg::Camera> camera = new osg::Camera();
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
camera->setProjectionResizePolicy(osg::Camera::FIXED);
camera->setProjectionMatrix(osg::Matrix::identity());
camera->setViewMatrix(osg::Matrix::identity());
camera->setRenderOrder(mVRMode ? osg::Camera::NESTED_RENDER : osg::Camera::POST_RENDER);
camera->setClearMask(GL_NONE);
mDrawable->setCullingActive(false);
camera->addChild(mDrawable.get());
camera->setName("GUI Camera");
mGuiRoot = camera;
mSceneRoot->addChild(mGuiRoot.get());
osg::ref_ptr<osg::Viewport> vp = mViewer->getCamera()->getViewport();
setViewSize(vp->width(), vp->height());
mSceneRoot->addChild(createGUICamera(osg::Camera::POST_RENDER, ""));
MYGUI_PLATFORM_LOG(Info, getClassTypeName()<<" successfully initialized");
mIsInitialise = true;
@ -415,8 +470,12 @@ void RenderManager::initialise()
void RenderManager::shutdown()
{
mGuiRoot->removeChildren(0, mGuiRoot->getNumChildren());
mSceneRoot->removeChild(mGuiRoot);
// TODO: Is this method meaningful? Why not just let the destructor handle everything?
for (auto guiCamera : mGuiCameras)
{
guiCamera->removeChildren(0, guiCamera->getNumChildren());
mSceneRoot->removeChild(guiCamera);
}
}
MyGUI::IVertexBuffer* RenderManager::createVertexBuffer()
@ -429,15 +488,7 @@ void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer)
delete buffer;
}
void RenderManager::begin()
{
mDrawable->clear();
// variance will be recomputed based on textures being rendered in this frame
mDrawable->setDataVariance(osg::Object::STATIC);
}
void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count)
void GUICamera::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count)
{
Drawable::Batch batch;
batch.mVertexCount = count;
@ -450,31 +501,19 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text
if (batch.mTexture->getDataVariance() == osg::Object::DYNAMIC)
mDrawable->setDataVariance(osg::Object::DYNAMIC); // only for this frame, reset in begin()
}
if (mInjectState)
batch.mStateSet = mInjectState;
mDrawable->addBatch(batch);
}
void RenderManager::onRenderToTarget(IRenderTarget* _target, bool _update)
{
MyGUI::LayerManager* layers = MyGUI::LayerManager::getInstancePtr();
if (layers != nullptr)
{
for (unsigned i = 0; i < layers->getLayerCount(); i++)
{
auto layer = layers->getLayer(i);
layer->renderToTarget(_target, _update);
}
}
}
void RenderManager::setInjectState(osg::StateSet* stateSet)
void StateInjectableRenderTarget::setInjectState(osg::StateSet* stateSet)
{
mInjectState = stateSet;
}
void RenderManager::end()
void GUICamera::end()
{
}
@ -490,33 +529,90 @@ void RenderManager::update()
last_time = now_time;
}
void RenderManager::collectDrawCalls()
void GUICamera::collectDrawCalls()
{
begin();
onRenderToTarget(this, mUpdate);
MyGUI::LayerManager* myGUILayers = MyGUI::LayerManager::getInstancePtr();
if (myGUILayers != nullptr)
{
for (unsigned i = 0; i < myGUILayers->getLayerCount(); i++)
{
auto layer = myGUILayers->getLayer(i);
layer->renderToTarget(this, mUpdate);
}
}
end();
mUpdate = false;
}
void RenderManager::setViewSize(int width, int height)
void GUICamera::collectDrawCalls(std::string filter)
{
if(width < 1) width = 1;
if(height < 1) height = 1;
begin();
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);
mGuiRoot->setViewport(0, 0, width, height);
auto name = layer->getName();
mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor);
if (std::regex_search(name, layerRegex))
{
//std::cout << "Including Layer: " << layer->getName() << std::endl;
layer->renderToTarget(this, mUpdate);
}
else {
//std::cout << "Excluding Layer: " << layer->getName() << std::endl;
}
}
}
end();
mUpdate = false;
}
void GUICamera::setViewSize(MyGUI::IntSize viewSize)
{
mInfo.maximumDepth = 1;
mInfo.hOffset = 0;
mInfo.vOffset = 0;
mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width);
mInfo.pixScaleX = 1.0f / float(mViewSize.width);
mInfo.pixScaleY = 1.0f / float(mViewSize.height);
mInfo.aspectCoef = float(viewSize.height) / float(viewSize.width);
mInfo.pixScaleX = 1.0f / float(viewSize.width);
mInfo.pixScaleY = 1.0f / float(viewSize.height);
mUpdate = true;
}
void RenderManager::setViewSize(int width, int height)
{
if(width < 1) width = 1;
if(height < 1) height = 1;
mViewSize.set(width * mInvScalingFactor, height * mInvScalingFactor);
for (auto* camera : mGuiCameras)
{
GUICamera* guiCamera = static_cast<GUICamera*>(camera);
guiCamera->setViewport(0, 0, width, height);
guiCamera->setViewSize(mViewSize);
}
onResizeView(mViewSize);
mUpdate = true;
}
osg::ref_ptr<osg::Camera> RenderManager::createGUICamera(int order, std::string layerFilter)
{
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());
return camera;
}
void RenderManager::deleteGUICamera(GUICamera* camera)
{
mGuiCameras.erase(camera);
}

@ -4,6 +4,7 @@
#include <MyGUI_RenderManager.h>
#include <osg/ref_ptr>
#include <set>
namespace Resource
{
@ -27,36 +28,46 @@ namespace osgMyGUI
{
class Drawable;
class GUICamera;
class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget
class StateInjectableRenderTarget : public MyGUI::IRenderTarget
{
public:
StateInjectableRenderTarget() = default;
~StateInjectableRenderTarget() = default;
/** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to nullptr again. */
void setInjectState(osg::StateSet* stateSet);
protected:
osg::StateSet* mInjectState{ nullptr };
};
class RenderManager : public MyGUI::RenderManager
{
osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osg::Group> mSceneRoot;
osg::ref_ptr<Drawable> mDrawable;
osg::ref_ptr<GUICamera> mGuiCamera;
std::set<GUICamera*> mGuiCameras;
Resource::ImageManager* mImageManager;
MyGUI::IntSize mViewSize;
bool mUpdate;
MyGUI::VertexColourType mVertexFormat;
MyGUI::RenderTargetInfo mInfo;
typedef std::map<std::string, MyGUI::ITexture*> MapTexture;
MapTexture mTextures;
bool mIsInitialise;
osg::ref_ptr<osg::Camera> mGuiRoot;
float mInvScalingFactor;
osg::StateSet* mInjectState;
bool mVRMode;
void destroyAllResources();
public:
RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* imageManager, float scalingFactor, bool VRMode);
RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, Resource::ImageManager* imageManager, float scalingFactor);
virtual ~RenderManager();
void initialise();
@ -92,29 +103,12 @@ public:
// Called by the update traversal
void update();
// Called by the cull traversal
/** @see IRenderTarget::begin */
virtual void begin();
/** @see IRenderTarget::end */
virtual void end();
/** @see IRenderTarget::doRender */
void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) override;
/** @see IRenderTarget::onRenderToTarget */
void onRenderToTarget(IRenderTarget* _target, bool _update) override;
/** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to nullptr again. */
void setInjectState(osg::StateSet* stateSet);
/** @see IRenderTarget::getInfo */
virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; }
bool checkTexture(MyGUI::ITexture* _texture);
/*internal:*/
void collectDrawCalls();
void setViewSize(int width, int height);
osg::ref_ptr<osg::Camera> createGUICamera(int order, std::string layerFilter);
void deleteGUICamera(GUICamera* camera);
};
}

@ -87,7 +87,8 @@ namespace SceneUtil
}
}
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene),
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager)
: mShadowedScene(new osgShadow::ShadowedScene),
mShadowTechnique(new MWShadowTechnique),
mOutdoorShadowCastingMask(outdoorShadowCastingMask),
mIndoorShadowCastingMask(indoorShadowCastingMask)

@ -9,6 +9,7 @@ set(DDIRRELATIVE resources/mygui)
set(MYGUI_FILES
core.skin
core.xml
core_vr.xml
core_layouteditor.xml
openmw_alchemy_window.layout
openmw_book.layout
@ -36,17 +37,21 @@ set(MYGUI_FILES
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_journal.layout
openmw_journal.skin.xml
openmw_layers.xml
openmw_layers_vr.xml
openmw_list.skin.xml
openmw_mainmenu.layout
openmw_mainmenu.skin.xml
openmw_map_window.layout
openmw_map_window_vr.layout
openmw_map_window.skin.xml
openmw_messagebox.layout
openmw_pointer.xml
@ -57,7 +62,9 @@ set(MYGUI_FILES
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

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI>
<MyGUI type="List">
<List file="skins.xml" />
<List file="openmw_layers_vr.xml" />
<List file="openmw_pointer.xml" />
<List file="openmw_settings.xml" />
</MyGUI>
</MyGUI>

@ -0,0 +1,132 @@
<?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>
<!-- Energy bars -->
<Widget type="ProgressBar" skin="MW_EnergyBar_Yellow" position="0 0 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">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="HealthToolTip"/>
<UserString key="ImageTexture_HealthImage" value="icons\k\health.dds"/>
<Widget type="ProgressBar" skin="MW_EnergyBar_Red" position="0 0 65 12" align="Left Bottom" name="Health">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 53 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"/>
<Widget type="ProgressBar" skin="MW_EnergyBar_Blue" position="0 0 65 12" align="Left Bottom" name="Magicka">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 68 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"/>
<Widget type="ProgressBar" skin="MW_EnergyBar_Green" position="0 0 65 12" align="Left Bottom" name="Stamina">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<!-- Equipped weapon box -->
<Widget type="Button" skin="" position="69 38 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">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="ProgressBar" skin="MW_EnergyBar_Weapon" position="0 36 36 6" align="Left Bottom" name="WeapStatus">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<!-- Selected spell box -->
<Widget type="Button" position="109 38 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"/>
</Widget>
<Widget type="ProgressBar" skin="MW_EnergyBar_Magic" position="0 36 36 6" align="Left Bottom" name="SpellStatus">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<!-- Sneak indicator box -->
<Widget type="Button" skin="" position="149 38 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"/>
<Widget type="ImageBox" skin="ImageBox" position="2 2 32 32" align="Left Top" name="SneakImage">
<Property key="NeedMouse" value="false"/>
<Property key="ImageTexture" value="icons\k\stealth_sneak.dds"/>
</Widget>
</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"/>
</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="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="ImageBox" skin="RotatingSkin" position="0 0 32 32" align="Bottom Left" name="Compass">
<Property key="ImageTexture" value="textures\compass.dds"/>
</Widget>
<Widget type="Button" skin="" position_real="0 0 1 1" name="MiniMapButton" align="Stretch">
<Property key="Depth" value="10"/>
</Widget>
</Widget>
</Widget>
</Widget>
<!-- Crosshair -->
<Widget type="ImageBox" skin="HUD_Crosshair" position="0 0 32 32" align="Center Center" name="Crosshair">
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window_Pinnable" layer="InventoryWindow" position="0 0 600 300" name="_Main">
<Property key="MinSize" value="40 40"/>
<Widget type="Widget" skin="" position="0 0 224 223" align="Left Top" name="LeftPane">
<!-- Player encumbrance -->
<Widget type="MWDynamicStat" skin="MW_ChargeBar_Blue" position="8 8 212 24" name="EncumbranceBar" align="Left Top HStretch">
</Widget>
<!-- Avatar -->
<Widget type="Widget" skin="MW_Box" position="8 38 212 185" name="Avatar" align="Left Top Stretch">
<Widget type="ImageBox" skin="ImageBox" position="3 3 206 158" align="Stretch" name="AvatarImage">
<UserString key="ToolTipType" value="AvatarItemSelection"/>
</Widget>
<Widget type="TextBox" skin="ProgressText" position="0 161 212 24" align="HStretch Bottom" name="ArmorRating">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
</Widget>
<Widget type="Widget" skin="" position="228 0 350 223" align="Left Top" name="RightPane">
<!-- Items in inventory -->
<Widget type="ItemView" skin="MW_ItemView" position="0 38 350 185" name="ItemView" align="Left Top Stretch">
</Widget>
<!-- Categories -->
<Widget type="HBox" position="0 6 350 28" align="Left Top HStretch" name="Categories">
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="AllButton">
<Property key="Caption" value="#{sAllTab}"/>
<Property key="NeedKey" value="false"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="WeaponButton">
<Property key="Caption" value="#{sWeaponTab}"/>
<Property key="NeedKey" value="false"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="ApparelButton">
<Property key="Caption" value="#{sApparelTab}"/>
<Property key="NeedKey" value="false"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="MagicButton">
<Property key="Caption" value="#{sMagicTab}"/>
<Property key="NeedKey" value="false"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" 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>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layer" version="1.0">
<Layer name="Scene" overlapped="false" pick="false"/>
<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="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="Windows" overlapped="true" pick="true"/>
<Layer name="JournalBooks" type="ScalingLayer" pick="true">
<Property key="Size" value="600 520"/>
</Layer>
<Layer name="Debug" overlapped="true" pick="true"/>
<Layer name="Notification" overlapped="false" pick="false"/>
<Layer name="Popup" overlapped="true" pick="true"/>
<Layer name="DragAndDrop" overlapped="false" pick="false"/>
<Layer name="LoadingScreen" overlapped="false" pick="true"/>
<Layer name="MessageBox" overlapped="false" pick="true"/>
<Layer name="InputBlocker" overlapped="false" pick="true"/>
<Layer name="Pointer" overlapped="false" pick="false"/>
</MyGUI>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window_Pinnable" layer="MapWindow" position="0 0 300 300" name="_Main">
<Property key="MinSize" value="40 40"/>
<!-- Local map -->
<Widget type="ScrollView" skin="MW_MapView" position="0 0 284 264" align="Stretch" name="LocalMap">
<Widget type="ImageBox" skin="RotatingSkin" position="0 0 32 32" align="Top Left" name="CompassLocal">
<Property key="ImageTexture" value="textures\compass.dds"/>
</Widget>
<Widget type="Button" skin="" position_real="0 0 1 1" name="EventBoxLocal" align="Stretch">
<Property key="Depth" value="10"/>
</Widget>
</Widget>
<!-- Global map -->
<Widget type="ScrollView" skin="MW_MapView" position="0 0 284 264" align="Stretch" name="GlobalMap">
<Widget type="ImageBox" skin="ImageBox" position_real="0 0 1 1" align="Stretch" name="GlobalMapImage">
<Widget type="ImageBox" skin="ImageBox" position_real="0 0 1 1" align="Stretch" name="GlobalMapOverlay"/>
</Widget>
<Widget type="ImageBox" skin="RotatingSkin" position="0 0 32 32" align="Top Left" name="CompassGlobal">
<Property key="ImageTexture" value="textures\compass.dds"/>
</Widget>
<Widget type="Button" skin="" position_real="0 0 1 1" name="EventBoxGlobal" align="Stretch"/>
</Widget>
<!-- World button -->
<Widget type="AutoSizedButton" skin="MW_Button" position="213 233 61 22" align="Bottom Right" name="WorldButton">
<Property key="ExpandDirection" value="Left"/>
<Property key="NeedKey" value="false"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window_Pinnable" layer="SpellWindow" position="0 0 300 600" name="_Main">
<Property key="MinSize" value="40 40"/>
<!-- Effect box-->
<Widget type="Widget" skin="MW_Box" position="8 8 268 23" align="Left Top HStretch">
<Widget type="Widget" skin="" position="2 1 264 20" align="Left Top Stretch" name="EffectsBox"/>
</Widget>
<!-- Spell list -->
<Widget type="SpellView" skin="MW_SpellView" position="8 38 268 490" align="Left Top Stretch" name="SpellView">
</Widget>
<Widget type="HBox" position="8 535 268 23" align="Right Bottom HStretch">
<Widget type="Spacer"/>
<!-- Spell deletion button -->
<Widget type="AutoSizedButton" skin="MW_Button" align="Right Bottom" position="8 535 0 23" name="DeleteSpellButton">
<Property key="Caption" value="#{sDelete}"/>
<Property key="NeedKey" value="false"/>
</Widget>
</Widget>
<!-- Search box-->
<Widget type="EditBox" skin="MW_TextBoxEditWithBorder" position="8 535 268 23" align="Left Bottom HStretch" name="FilterEdit">
<UserString key="AcceptTab" value="true"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window_Pinnable" layer="StatsWindow" position="0 0 500 342" name="_Main">
<Property key="MinSize" value="244 114"/>
<Widget type="Widget" skin="" name="LeftPane" position="0 0 220 342">
<UserString key="LeftOffsetWidth" value="24"/>
<UserString key="LeftPaneRatio" value="0.44"/>
<!-- Player health stats -->
<Widget type="Widget" skin="MW_Box" position="8 8 212 62" align="Left Top HStretch">
<!-- Health -->
<Widget type="Widget" skin="" position="4 4 204 18" name="Health" align="Left Top HStretch">
<Property key="NeedMouse" value="true"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="HealthToolTip"/>
<UserString key="ImageTexture_HealthImage" value="icons\k\health.dds"/>
<Widget type="TextBox" skin="NormalText" position="0 0 70 18" name="Health_str" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
<Property key="Caption" value="#{sHealth}"/>
</Widget>
<Widget type="ProgressBar" skin="MW_Progress_Red" position="74 0 130 18" name="HBar" align="Right Top">
<Property key="NeedMouse" value="false"/>
<Widget type="TextBox" skin="ProgressText" position="0 0 130 14" name="HBarT" align="Right VCenter">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
</Widget>
<!-- Magicka -->
<Widget type="Widget" skin="" position="4 22 204 18" name="Magicka" align="Left Top HStretch">
<Property key="NeedMouse" value="true"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="HealthToolTip"/>
<UserString key="ImageTexture_HealthImage" value="icons\k\magicka.dds"/>
<Widget type="TextBox" skin="NormalText" position="0 0 70 18" name="Magicka_str" align="Left Top HStretch">
<Property key="Caption" value="#{sMagic}"/>
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="ProgressBar" skin="MW_Progress_Blue" position="74 0 130 18" name="MBar" align="Right Top">
<Property key="NeedMouse" value="false"/>
<Widget type="TextBox" skin="ProgressText" position="0 0 130 14" name="MBarT" align="Right VCenter">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
</Widget>
<!-- Fatigue -->
<Widget type="Widget" skin="" position="4 40 204 18" name="Fatigue" align="Left Top HStretch">
<Property key="NeedMouse" value="true"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="HealthToolTip"/>
<UserString key="ImageTexture_HealthImage" value="icons\k\fatigue.dds"/>
<Widget type="TextBox" skin="NormalText" position="0 0 70 18" name="Fatigue_str" align="Left Top HStretch">
<Property key="Caption" value="#{sFatigue}"/>
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="ProgressBar" skin="MW_Progress_Green" position="74 0 130 18" name="FBar" align="Right Top">
<Property key="NeedMouse" value="false"/>
<Widget type="TextBox" skin="ProgressText" position="0 0 130 14" name="FBarT" align="Right VCenter">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
</Widget>
</Widget>
<!-- Player level, race and class -->
<Widget type="Widget" skin="MW_Box" position="8 78 212 62" align="Top HStretch">
<Widget type="HBox" position="4 4 204 18" align="Top HStretch">
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 0 200 18" name="Level_str" align="Left Top">
<Property key="Caption" value="#{sLevel}"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="LevelToolTip"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="200 0 40 18" name="LevelText" align="Right Top">
<Property key="TextAlign" value="Right Top"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="LevelToolTip"/>
<UserString key="HStretch" value="true"/>
</Widget>
</Widget>
<Widget type="HBox" position="4 24 204 18" align="Top HStretch">
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 0 95 18" name="Race_str" align="Left Top">
<Property key="Caption" value="#{sRace}"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="RaceToolTip"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="104 0 200 18" name="RaceText" align="Left Top">
<Property key="TextAlign" value="Right Top"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="RaceToolTip"/>
<UserString key="HStretch" value="true"/>
</Widget>
</Widget>
<Widget type="HBox" position="4 42 204 18" align="Top HStretch">
<Widget type="AutoSizedTextBox" skin="NormalText" position="0 0 95 18" name="Class_str" align="Left Top">
<Property key="Caption" value="#{sClass}"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="ClassToolTip"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="104 0 200 18" name="ClassText" align="Left Top">
<Property key="TextAlign" value="Right Top"/>
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="ClassToolTip"/>
<UserString key="HStretch" value="true"/>
</Widget>
</Widget>
</Widget>
<Widget type="Widget" skin="MW_Box" position="8 148 212 152" align="Left Top Stretch">
<!-- TODO: this should be a scroll view -->
<Widget type="Widget" skin="" position="4 4 204 144" align="Left Top Stretch">
<Widget type="Button" skin="" position="0 0 204 18" name="Attrib1Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeStrength}"/>
<UserString key="Caption_AttributeDescription" value="#{sStrDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_strength.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib1" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal1" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 18 204 18" name="Attrib2Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeIntelligence}"/>
<UserString key="Caption_AttributeDescription" value="#{sIntDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_int.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib2" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal2" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 36 204 18" name="Attrib3Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeWillpower}"/>
<UserString key="Caption_AttributeDescription" value="#{sWilDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_wilpower.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib3" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal3" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 54 204 18" name="Attrib4Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeAgility}"/>
<UserString key="Caption_AttributeDescription" value="#{sAgiDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_agility.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib4" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal4" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 72 204 18" name="Attrib5Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeSpeed}"/>
<UserString key="Caption_AttributeDescription" value="#{sSpdDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_speed.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib5" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal5" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 90 204 18" name="Attrib6Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeEndurance}"/>
<UserString key="Caption_AttributeDescription" value="#{sEndDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_endurance.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib6" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal6" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 108 204 18" name="Attrib7Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributePersonality}"/>
<UserString key="Caption_AttributeDescription" value="#{sPerDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_personality.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib7" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal7" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<Widget type="Button" skin="" position="0 126 204 18" name="Attrib8Box" align="Left Top HStretch">
<UserString key="ToolTipType" value="Layout"/>
<UserString key="ToolTipLayout" value="AttributeToolTip"/>
<UserString key="Caption_AttributeName" value="#{sAttributeLuck}"/>
<UserString key="Caption_AttributeDescription" value="#{sLucDesc}"/>
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_luck.dds"/>
<Widget type="TextBox" skin="SandText" position="0 0 160 18" name="Attrib8" align="Left Top HStretch">
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="TextBox" skin="SandTextRight" position="160 0 44 18" name="AttribVal8" align="Right Top">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
</Widget>
</Widget>
</Widget>
<Widget type="Widget" skin="" name="RightPane" position="220 0 280 342">
<!-- Player skills, factions, birthsign and reputation -->
<Widget type="Widget" skin="MW_Box" position="8 8 248 292" align="Left Stretch" name="Skills">
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 240 284" align="Left Top Stretch" name="SkillView">
<Property key="CanvasAlign" value="Left Top"/>
</Widget>
</Widget>
</Widget>
</Widget>
</MyGUI>
Loading…
Cancel
Save