1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-30 18:15:33 +00:00
openmw-tes3mp/apps/openmw/mwvr/openxrmenu.cpp

304 lines
9.1 KiB
C++
Raw Normal View History

#include "openxrmenu.hpp"
#include "openxrenvironment.hpp"
#include "openxrsession.hpp"
#include "openxrmanagerimpl.hpp"
#include <openxr/openxr.h>
#include <osg/Texture2D>
2020-03-01 22:05:38 +00:00
#include <osg/ClipNode>
#include <osg/FrontFace>
2020-03-04 23:04:23 +00:00
#include <osg/BlendFunc>
#include <osg/Depth>
#include <components/sceneutil/visitor.hpp>
2020-03-01 22:05:38 +00:00
#include <components/sceneutil/shadow.hpp>
#include <osgViewer/Renderer>
#include "../mwrender/util.hpp"
2020-03-04 23:04:23 +00:00
#include "../mwrender/renderbin.hpp"
namespace MWVR
{
2020-03-01 22:05:38 +00:00
class Menus : public osg::Camera
{
public:
Menus()
{
setRenderOrder(osg::Camera::PRE_RENDER);
setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2020-03-04 23:04:23 +00:00
// Give bg a tint of green just to stand out, for testing
setClearColor(osg::Vec4(0.f,0.f,0.f,.75f));
2020-03-01 22:05:38 +00:00
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::ABSOLUTE_RF);
setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
2020-03-04 23:04:23 +00:00
setName("MenuCamera");
2020-03-01 22:05:38 +00:00
setCullMask(MWRender::Mask_GUI);
setNodeMask(MWRender::Mask_RenderToTexture);
2020-03-04 23:04:23 +00:00
unsigned int rttSize = 4000;
2020-03-01 22:05:38 +00:00
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);
mMenuTexture = new osg::Texture2D;
mMenuTexture->setTextureSize(rttSize, rttSize);
2020-03-04 23:04:23 +00:00
mMenuTexture->setInternalFormat(GL_RGBA);
mMenuTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
2020-03-01 22:05:38 +00:00
mMenuTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
mMenuTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mMenuTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
2020-03-04 23:04:23 +00:00
2020-03-01 22:05:38 +00:00
attach(osg::Camera::COLOR_BUFFER, mMenuTexture);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
2020-03-04 23:04:23 +00:00
getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin");
2020-03-01 22:05:38 +00:00
}
void setScene(osg::Node* scene)
{
if (mScene)
removeChild(mScene);
mScene = scene;
addChild(scene);
2020-03-04 23:04:23 +00:00
Log(Debug::Verbose) << "Set new scene: " << mScene->getName();
2020-03-01 22:05:38 +00:00
}
osg::Texture2D* getMenuTexture() const
{
return mMenuTexture.get();
}
private:
osg::ref_ptr<osg::Texture2D> mMenuTexture;
osg::ref_ptr<osg::Node> mScene;
};
class PredrawCallback : public osg::Camera::DrawCallback
{
public:
PredrawCallback(OpenXRMenu* menu)
: mMenu(menu)
{}
void operator()(osg::RenderInfo& info) const override { mMenu->preRenderCallback(info); };
private:
OpenXRMenu* mMenu;
};
class PostdrawCallback : public osg::Camera::DrawCallback
{
public:
PostdrawCallback(OpenXRMenu* menu)
: mMenu(menu)
{}
void operator()(osg::RenderInfo& info) const override { mMenu->postRenderCallback(info); };
private:
OpenXRMenu* mMenu;
};
OpenXRMenu::OpenXRMenu(
osg::ref_ptr<osg::Group> parent,
2020-03-01 22:05:38 +00:00
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)
, mParent(parent)
, 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) };
osg::ref_ptr<osg::Vec4Array> colors{ new osg::Vec4Array(1) };
2020-03-04 23:04:23 +00:00
// Units are divided by 2 because geometry has an extent of 2 (-1 to 1)
auto extent_units = extent_meters * OpenXREnvironment::get().unitsPerMeter() / 2.f;
2020-03-04 23:04:23 +00:00
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);
2020-03-04 23:04:23 +00:00
(*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);
2020-03-04 23:04:23 +00:00
(*colors)[0].set(1.0f, 1.0f, 1.0f, 1.0f);
mGeometry->setNormalArray(normals, osg::Array::BIND_OVERALL);
2020-03-04 23:04:23 +00:00
//mGeometry->setColorArray(colors, osg::Array::BIND_OVERALL);
mGeometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
mGeometry->setDataVariance(osg::Object::DYNAMIC);
mGeometry->setSupportsDisplayList(false);
2020-03-01 22:05:38 +00:00
mMenuCamera = new Menus();
mMenuCamera->setScene(menuSubgraph);
mStateSet->setTextureAttributeAndModes(0, menuTexture(), osg::StateAttribute::ON);
mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
2020-03-04 23:04:23 +00:00
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);
2020-03-04 23:04:23 +00:00
mTransform->setScale(osg::Vec3(extent_units.x(), extent_units.y(), 1.f));
mTransform->setAttitude(pose.orientation);
mTransform->setPosition(pose.position);
mGeode->addDrawable(mGeometry);
mTransform->addChild(mGeode);
mParent->addChild(mTransform);
2020-03-04 23:04:23 +00:00
2020-03-04 23:04:23 +00:00
SceneUtil::FindByNameVisitor findRootVisitor("OpenXRRoot", osg::NodeVisitor::TRAVERSE_PARENTS);
mParent->accept(findRootVisitor);
findRootVisitor.mFoundNode->addChild(mMenuCamera.get());
}
OpenXRMenu::~OpenXRMenu()
{
mParent->removeChild(mTransform);
2020-03-04 23:04:23 +00:00
SceneUtil::FindByNameVisitor findRootVisitor("OpenXRRoot", osg::NodeVisitor::TRAVERSE_PARENTS);
mParent->accept(findRootVisitor);
findRootVisitor.mFoundNode->removeChild(mMenuCamera.get());
}
void OpenXRMenu::updateCallback()
{
}
2020-03-01 22:05:38 +00:00
osg::Camera* OpenXRMenu::camera()
{
2020-03-01 22:05:38 +00:00
return mMenuCamera.get();
}
osg::ref_ptr<osg::Texture2D> OpenXRMenu::menuTexture()
{
if (mMenuCamera)
return mMenuCamera->getMenuTexture();
return nullptr;
}
void OpenXRMenu::updatePose(Pose pose)
{
mTransform->setAttitude(pose.orientation);
mTransform->setPosition(pose.position);
}
2020-02-29 22:53:56 +00:00
OpenXRMenuManager::OpenXRMenuManager(
osg::ref_ptr<osgViewer::Viewer> viewer)
: mOsgViewer(viewer)
{
mMenusRoot->setName("XR Menus Root");
auto* root = viewer->getSceneData();
SceneUtil::FindByNameVisitor findGUIVisitor("GUI Root");
root->accept(findGUIVisitor);
mGuiRoot = findGUIVisitor.mFoundNode;
if (!mGuiRoot)
2020-03-04 23:04:23 +00:00
{
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();
2020-03-04 23:04:23 +00:00
findSceneVisitor.mFoundNode->addChild(mMenusRoot);
2020-02-29 22:53:56 +00:00
}
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(
mMenusRoot,
mGuiRoot,
"Main Menu",
2020-03-04 23:04:23 +00:00
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";
}
2020-02-29 22:53:56 +00:00
}
void OpenXRMenuManager::updatePose(void)
2020-02-29 22:53:56 +00:00
{
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);
2020-03-04 23:04:23 +00:00
// Position the menu about two thirds of a meter in front of the player
osg::Vec3 dir = center - eye;
dir.normalize();
2020-03-04 23:04:23 +00:00
mPose.position = eye + dir * OpenXREnvironment::get().unitsPerMeter() * 2.f / 3.f;
mPose.orientation = camera->getViewMatrix().getRotate().inverse();
if (mMenu)
mMenu->updatePose(mPose);
Log(Debug::Error) << "New menu pose: " << mPose;
2020-02-29 22:53:56 +00:00
}
}