mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-14 01:13:31 +02:00
Breaking up overlay into rendering and compositing classes
This commit is contained in:
parent
e44b21ee0b
commit
00d8fe75ab
20 changed files with 1032 additions and 952 deletions
|
@ -333,8 +333,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_cursorVisible(true),
|
||||
_lastMouseMove(usecTimestampNow()),
|
||||
_lastMouseMoveWasSimulated(false),
|
||||
_touchAvgX(0.0f),
|
||||
_touchAvgY(0.0f),
|
||||
_isTouchPressed(false),
|
||||
_mousePressed(false),
|
||||
_enableProcessOctreeThread(true),
|
||||
|
@ -840,7 +838,7 @@ void Application::initializeUi() {
|
|||
VrMenu::executeQueuedLambdas();
|
||||
offscreenUi->setMouseTranslator([this](const QPointF& p){
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
|
||||
glm::vec2 pos = _compositor.screenToOverlay(toGlm(p));
|
||||
return QPointF(pos.x, pos.y);
|
||||
}
|
||||
return QPointF(p);
|
||||
|
@ -950,7 +948,7 @@ void Application::paintGL() {
|
|||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
displaySide(&renderArgs, _myCamera);
|
||||
_applicationOverlay.displayOverlayTexture(&renderArgs);
|
||||
_compositor.displayOverlayTexture(&renderArgs);
|
||||
glPopMatrix();
|
||||
|
||||
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||
|
@ -1551,8 +1549,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
_keyboardMouseDevice.mousePressEvent(event);
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
_mouseDragStartedX = getTrueMouseX();
|
||||
_mouseDragStartedY = getTrueMouseY();
|
||||
_mouseDragStarted = getTrueMouse();
|
||||
_mousePressed = true;
|
||||
|
||||
if (mouseOnScreen()) {
|
||||
|
@ -1654,22 +1651,18 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
|
|||
bool validTouch = false;
|
||||
if (activeWindow() == _window) {
|
||||
const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints();
|
||||
_touchAvgX = 0.0f;
|
||||
_touchAvgY = 0.0f;
|
||||
_touchAvg = vec2();
|
||||
int numTouches = tPoints.count();
|
||||
if (numTouches > 1) {
|
||||
for (int i = 0; i < numTouches; ++i) {
|
||||
_touchAvgX += tPoints[i].pos().x();
|
||||
_touchAvgY += tPoints[i].pos().y();
|
||||
_touchAvg += toGlm(tPoints[i].pos());
|
||||
}
|
||||
_touchAvgX /= (float)(numTouches);
|
||||
_touchAvgY /= (float)(numTouches);
|
||||
_touchAvg /= (float)(numTouches);
|
||||
validTouch = true;
|
||||
}
|
||||
}
|
||||
if (!_isTouchPressed) {
|
||||
_touchDragStartedAvgX = _touchAvgX;
|
||||
_touchDragStartedAvgY = _touchAvgY;
|
||||
_touchDragStartedAvg = _touchAvg;
|
||||
}
|
||||
_isTouchPressed = validTouch;
|
||||
}
|
||||
|
@ -1705,8 +1698,7 @@ void Application::touchEndEvent(QTouchEvent* event) {
|
|||
_keyboardMouseDevice.touchEndEvent(event);
|
||||
|
||||
// put any application specific touch behavior below here..
|
||||
_touchDragStartedAvgX = _touchAvgX;
|
||||
_touchDragStartedAvgY = _touchAvgY;
|
||||
_touchDragStartedAvg = _touchAvg;
|
||||
_isTouchPressed = false;
|
||||
|
||||
}
|
||||
|
@ -1855,9 +1847,9 @@ void Application::setFullscreen(bool fullscreen) {
|
|||
Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
|
||||
}
|
||||
|
||||
// The following code block is useful on platforms that can have a visible
|
||||
// app menu in a fullscreen window. However the OSX mechanism hides the
|
||||
// application menu for fullscreen apps, so the check is not required.
|
||||
// The following code block is useful on platforms that can have a visible
|
||||
// app menu in a fullscreen window. However the OSX mechanism hides the
|
||||
// application menu for fullscreen apps, so the check is not required.
|
||||
#ifndef Q_OS_MAC
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||
if (fullscreen) {
|
||||
|
@ -1927,11 +1919,6 @@ void Application::setEnableVRMode(bool enableVRMode) {
|
|||
OculusManager::recalibrate();
|
||||
} else {
|
||||
OculusManager::abandonCalibration();
|
||||
|
||||
_mirrorCamera.setHmdPosition(glm::vec3());
|
||||
_mirrorCamera.setHmdRotation(glm::quat());
|
||||
_myCamera.setHmdPosition(glm::vec3());
|
||||
_myCamera.setHmdRotation(glm::quat());
|
||||
}
|
||||
|
||||
resizeGL();
|
||||
|
@ -1943,44 +1930,34 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
|||
|
||||
bool Application::mouseOnScreen() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() &&
|
||||
getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight();
|
||||
ivec2 mouse = getMouse();
|
||||
if (!glm::all(glm::greaterThanEqual(mouse, ivec2()))) {
|
||||
return false;
|
||||
}
|
||||
ivec2 size = toGlm(_glWidget->getDeviceSize());
|
||||
if (!glm::all(glm::lessThanEqual(mouse, size))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Application::getMouseX() const {
|
||||
ivec2 Application::getMouse() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
|
||||
return pos.x;
|
||||
return _compositor.screenToOverlay(getTrueMouse());
|
||||
}
|
||||
return getTrueMouseX();
|
||||
return getTrueMouse();
|
||||
}
|
||||
|
||||
int Application::getMouseY() const {
|
||||
ivec2 Application::getMouseDragStarted() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
|
||||
return pos.y;
|
||||
return _compositor.screenToOverlay(getTrueMouseDragStarted());
|
||||
}
|
||||
return getTrueMouseY();
|
||||
return getTrueMouseDragStarted();
|
||||
}
|
||||
|
||||
int Application::getMouseDragStartedX() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(),
|
||||
getTrueMouseDragStartedY()));
|
||||
return pos.x;
|
||||
}
|
||||
return getTrueMouseDragStartedX();
|
||||
}
|
||||
|
||||
int Application::getMouseDragStartedY() const {
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(),
|
||||
getTrueMouseDragStartedY()));
|
||||
return pos.y;
|
||||
}
|
||||
return getTrueMouseDragStartedY();
|
||||
ivec2 Application::getTrueMouseDragStarted() const {
|
||||
return _mouseDragStarted;
|
||||
}
|
||||
|
||||
FaceTracker* Application::getActiveFaceTracker() {
|
||||
|
@ -3127,7 +3104,7 @@ PickRay Application::computePickRay(float x, float y) const {
|
|||
y /= size.y;
|
||||
PickRay result;
|
||||
if (isHMDMode()) {
|
||||
getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
||||
getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
||||
} else {
|
||||
if (QThread::currentThread() == activeRenderingThread) {
|
||||
getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
||||
|
@ -4809,12 +4786,8 @@ QSize Application::getDeviceSize() const {
|
|||
return _glWidget->getDeviceSize();
|
||||
}
|
||||
|
||||
int Application::getTrueMouseX() const {
|
||||
return _glWidget->mapFromGlobal(QCursor::pos()).x();
|
||||
}
|
||||
|
||||
int Application::getTrueMouseY() const {
|
||||
return _glWidget->mapFromGlobal(QCursor::pos()).y();
|
||||
ivec2 Application::getTrueMouse() const {
|
||||
return toGlm(_glWidget->mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
bool Application::isThrottleRendering() const {
|
||||
|
@ -4844,3 +4817,18 @@ qreal Application::getDevicePixelRatio() {
|
|||
return _window ? _window->windowHandle()->devicePixelRatio() : 1.0;
|
||||
}
|
||||
|
||||
mat4 Application::getEyeProjection(int eye) const {
|
||||
if (isHMDMode()) {
|
||||
return OculusManager::getEyeProjection(eye);
|
||||
}
|
||||
|
||||
return _viewFrustum.getProjection();
|
||||
}
|
||||
|
||||
mat4 Application::getEyePose(int eye) const {
|
||||
if (isHMDMode()) {
|
||||
return OculusManager::getEyePose(eye);
|
||||
}
|
||||
|
||||
return mat4();
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#include "ui/UpdateDialog.h"
|
||||
#include "ui/overlays/Overlays.h"
|
||||
#include "ui/ApplicationOverlay.h"
|
||||
#include "ui/ApplicationCompositor.h"
|
||||
#include "ui/RunningScriptsWidget.h"
|
||||
#include "ui/ToolWindow.h"
|
||||
#include "ui/UserInputMapper.h"
|
||||
|
@ -222,15 +223,21 @@ public:
|
|||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
bool mouseOnScreen() const;
|
||||
int getMouseX() const;
|
||||
int getMouseY() const;
|
||||
glm::ivec2 getTrueMousePosition() const;
|
||||
int getTrueMouseX() const;
|
||||
int getTrueMouseY() const;
|
||||
int getMouseDragStartedX() const;
|
||||
int getMouseDragStartedY() const;
|
||||
int getTrueMouseDragStartedX() const { return _mouseDragStartedX; }
|
||||
int getTrueMouseDragStartedY() const { return _mouseDragStartedY; }
|
||||
|
||||
ivec2 getMouse() const;
|
||||
ivec2 getTrueMouse() const;
|
||||
ivec2 getMouseDragStarted() const;
|
||||
ivec2 getTrueMouseDragStarted() const;
|
||||
|
||||
// TODO get rid of these and use glm types directly
|
||||
int getMouseX() const { return getMouse().x; }
|
||||
int getMouseY() const { return getMouse().y; }
|
||||
int getTrueMouseX() const { return getTrueMouse().x; }
|
||||
int getTrueMouseY() const { return getTrueMouse().y; }
|
||||
int getMouseDragStartedX() const { return getMouseDragStarted().x; }
|
||||
int getMouseDragStartedY() const { return getMouseDragStarted().y; }
|
||||
int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; }
|
||||
int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; }
|
||||
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
||||
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
|
@ -239,6 +246,8 @@ public:
|
|||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; }
|
||||
ApplicationCompositor& getApplicationCompositor() { return _compositor; }
|
||||
const ApplicationCompositor& getApplicationCompositor() const { return _compositor; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
float getFps() const { return _fps; }
|
||||
|
@ -333,6 +342,9 @@ public:
|
|||
bool isHMDMode() const;
|
||||
glm::quat getHeadOrientation() const;
|
||||
glm::vec3 getHeadPosition() const;
|
||||
glm::mat4 getHeadPose() const;
|
||||
glm::mat4 getEyePose(int eye) const;
|
||||
glm::mat4 getEyeProjection(int eye) const;
|
||||
|
||||
QRect getDesirableApplicationGeometry();
|
||||
RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }
|
||||
|
@ -584,18 +596,17 @@ private:
|
|||
Environment _environment;
|
||||
|
||||
bool _cursorVisible;
|
||||
int _mouseDragStartedX;
|
||||
int _mouseDragStartedY;
|
||||
ivec2 _mouseDragStarted;
|
||||
|
||||
quint64 _lastMouseMove;
|
||||
bool _lastMouseMoveWasSimulated;
|
||||
|
||||
glm::vec3 _mouseRayOrigin;
|
||||
glm::vec3 _mouseRayDirection;
|
||||
|
||||
float _touchAvgX;
|
||||
float _touchAvgY;
|
||||
float _touchDragStartedAvgX;
|
||||
float _touchDragStartedAvgY;
|
||||
vec2 _touchAvg;
|
||||
vec2 _touchDragStartedAvg;
|
||||
|
||||
bool _isTouchPressed; // true if multitouch has been pressed (clear when finished)
|
||||
|
||||
bool _mousePressed; // true if mouse has been pressed (clear when finished)
|
||||
|
@ -676,6 +687,7 @@ private:
|
|||
|
||||
Overlays _overlays;
|
||||
ApplicationOverlay _applicationOverlay;
|
||||
ApplicationCompositor _compositor;
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -49,8 +49,6 @@ Camera::Camera() :
|
|||
_mode(CAMERA_MODE_THIRD_PERSON),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)),
|
||||
_hmdPosition(),
|
||||
_hmdRotation(),
|
||||
_isKeepLookingAt(false),
|
||||
_lookingAt(0.0f, 0.0f, 0.0f)
|
||||
{
|
||||
|
@ -74,20 +72,6 @@ void Camera::setRotation(const glm::quat& rotation) {
|
|||
}
|
||||
}
|
||||
|
||||
void Camera::setHmdPosition(const glm::vec3& hmdPosition) {
|
||||
_hmdPosition = hmdPosition;
|
||||
if (_isKeepLookingAt) {
|
||||
lookAt(_lookingAt);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::setHmdRotation(const glm::quat& hmdRotation) {
|
||||
_hmdRotation = hmdRotation;
|
||||
if (_isKeepLookingAt) {
|
||||
lookAt(_lookingAt);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::setMode(CameraMode mode) {
|
||||
_mode = mode;
|
||||
emit modeUpdated(modeToString(mode));
|
||||
|
|
|
@ -45,26 +45,22 @@ public:
|
|||
|
||||
void setRotation(const glm::quat& rotation);
|
||||
void setProjection(const glm::mat4 & projection);
|
||||
void setHmdPosition(const glm::vec3& hmdPosition);
|
||||
void setHmdRotation(const glm::quat& hmdRotation);
|
||||
void setMode(CameraMode m);
|
||||
|
||||
glm::quat getRotation() const { return _rotation * _hmdRotation; }
|
||||
glm::quat getRotation() const { return _rotation; }
|
||||
const glm::mat4& getProjection() const { return _projection; }
|
||||
const glm::vec3& getHmdPosition() const { return _hmdPosition; }
|
||||
const glm::quat& getHmdRotation() const { return _hmdRotation; }
|
||||
CameraMode getMode() const { return _mode; }
|
||||
|
||||
public slots:
|
||||
QString getModeString() const;
|
||||
void setModeString(const QString& mode);
|
||||
|
||||
glm::vec3 getPosition() const { return _position + _hmdPosition; }
|
||||
glm::vec3 getPosition() const { return _position; }
|
||||
void setPosition(const glm::vec3& position);
|
||||
|
||||
void setOrientation(const glm::quat& orientation) { setRotation(orientation); }
|
||||
glm::quat getOrientation() const { return getRotation(); }
|
||||
|
||||
void setOrientation(const glm::quat& orientation) { setRotation(orientation); }
|
||||
|
||||
PickRay computePickRay(float x, float y);
|
||||
|
||||
// These only work on independent cameras
|
||||
|
@ -86,8 +82,6 @@ private:
|
|||
glm::vec3 _position;
|
||||
glm::quat _rotation;
|
||||
glm::mat4 _projection;
|
||||
glm::vec3 _hmdPosition;
|
||||
glm::quat _hmdRotation;
|
||||
bool _isKeepLookingAt;
|
||||
glm::vec3 _lookingAt;
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <QOpenGLTexture>
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
class AudioToolBox : public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
|
|
@ -1559,7 +1559,6 @@ void MyAvatar::renderLaserPointers() {
|
|||
|
||||
//Gets the tip position for the laser pointer
|
||||
glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
|
||||
const ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
|
||||
glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());
|
||||
|
||||
glm::vec3 position = palm->getPosition();
|
||||
|
@ -1568,7 +1567,8 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
|
|||
|
||||
|
||||
glm::vec3 result;
|
||||
if (applicationOverlay.calculateRayUICollisionPoint(position, direction, result)) {
|
||||
const auto& compositor = Application::getInstance()->getApplicationCompositor();
|
||||
if (compositor.calculateRayUICollisionPoint(position, direction, result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,9 @@ bool OculusManager::_eyePerFrameMode = false;
|
|||
ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count;
|
||||
ovrSizei OculusManager::_recommendedTexSize = { 0, 0 };
|
||||
float OculusManager::_offscreenRenderScale = 1.0;
|
||||
|
||||
static glm::mat4 _eyeProjections[ovrEye_Count];
|
||||
static glm::mat4 _combinedProjection;
|
||||
static ovrPosef _eyeRenderPoses[ovrEye_Count];
|
||||
|
||||
void OculusManager::initSdk() {
|
||||
ovr_Initialize();
|
||||
|
@ -173,9 +175,15 @@ void OculusManager::connect() {
|
|||
_eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;
|
||||
_eyeTextures[eye].Header.TextureSize = _renderTargetSize;
|
||||
_eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };
|
||||
ovrMatrix4f eyeProjection = ovrMatrix4f_Projection(_ovrHmd->MaxEyeFov[eye], DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
|
||||
_eyeProjections[eye] = toGlm(eyeProjection);
|
||||
});
|
||||
_eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;
|
||||
|
||||
ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0];
|
||||
combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan;
|
||||
_combinedProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
|
||||
|
||||
ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
|
||||
|
||||
ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position |
|
||||
|
@ -566,7 +574,6 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
ovrPosef eyePoses[ovrEye_Count];
|
||||
ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr);
|
||||
ovrHmd_BeginFrame(_ovrHmd, _frameIndex);
|
||||
static ovrPosef eyeRenderPose[ovrEye_Count];
|
||||
//Render each eye into an fbo
|
||||
for_each_eye(_ovrHmd, [&](ovrEyeType eye){
|
||||
// If we're in eye-per-frame mode, only render one eye
|
||||
|
@ -576,29 +583,17 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
return;
|
||||
}
|
||||
_lastEyeRendered = _activeEye = eye;
|
||||
eyeRenderPose[eye] = eyePoses[eye];
|
||||
_eyeRenderPoses[eye] = eyePoses[eye];
|
||||
// Set the camera rotation for this eye
|
||||
orientation.x = eyeRenderPose[eye].Orientation.x;
|
||||
orientation.y = eyeRenderPose[eye].Orientation.y;
|
||||
orientation.z = eyeRenderPose[eye].Orientation.z;
|
||||
orientation.w = eyeRenderPose[eye].Orientation.w;
|
||||
|
||||
// Update the application camera with the latest HMD position
|
||||
whichCamera.setHmdPosition(trackerPosition);
|
||||
whichCamera.setHmdRotation(orientation);
|
||||
|
||||
|
||||
vec3 eyePosition = toGlm(_eyeRenderPoses[eye].Position);
|
||||
eyePosition = whichCamera.getRotation() * eyePosition;
|
||||
quat eyeRotation = toGlm(_eyeRenderPoses[eye].Orientation);
|
||||
|
||||
// Update our camera to what the application camera is doing
|
||||
_camera->setRotation(whichCamera.getRotation());
|
||||
_camera->setPosition(whichCamera.getPosition());
|
||||
_camera->setRotation(whichCamera.getRotation() * eyeRotation);
|
||||
_camera->setPosition(whichCamera.getPosition() + eyePosition);
|
||||
configureCamera(*_camera);
|
||||
|
||||
// Store the latest left and right eye render locations for things that need to know
|
||||
glm::vec3 thisEyePosition = position + trackerPosition +
|
||||
(bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) *
|
||||
glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z));
|
||||
|
||||
_eyePositions[eye] = thisEyePosition;
|
||||
_camera->update(1.0f / Application::getInstance()->getFps());
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -615,7 +610,8 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
|
||||
renderArgs->_renderSide = RenderArgs::MONO;
|
||||
qApp->displaySide(renderArgs, *_camera, false);
|
||||
qApp->getApplicationOverlay().displayOverlayTextureHmd(renderArgs, *_camera);
|
||||
//qApp->getApplicationCompositor().displayOverlayTexture(renderArgs);
|
||||
qApp->getApplicationCompositor().displayOverlayTextureHmd(renderArgs, eye);
|
||||
});
|
||||
_activeEye = ovrEye_Count;
|
||||
|
||||
|
@ -661,7 +657,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)));
|
||||
//Renders the distorted mesh onto the screen
|
||||
renderDistortionMesh(eyeRenderPose);
|
||||
renderDistortionMesh(_eyeRenderPoses);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
glCanvas->swapBuffers();
|
||||
|
@ -877,3 +873,10 @@ int OculusManager::getHMDScreen() {
|
|||
return hmdScreenIndex;
|
||||
}
|
||||
|
||||
mat4 OculusManager::getEyeProjection(int eye) {
|
||||
return _eyeProjections[eye];
|
||||
}
|
||||
|
||||
mat4 OculusManager::getEyePose(int eye) {
|
||||
return toGlm(_eyeRenderPoses[eye]);
|
||||
}
|
|
@ -81,6 +81,9 @@ public:
|
|||
static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
|
||||
|
||||
static int getHMDScreen();
|
||||
|
||||
static glm::mat4 getEyeProjection(int eye);
|
||||
static glm::mat4 getEyePose(int eye);
|
||||
|
||||
private:
|
||||
static void initSdk();
|
||||
|
|
|
@ -489,7 +489,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
|
|||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)
|
||||
|| Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||
pos = qApp->getApplicationOverlay().getPalmClickLocation(palm);
|
||||
pos = qApp->getApplicationCompositor().getPalmClickLocation(palm);
|
||||
} else {
|
||||
// Get directon relative to avatar orientation
|
||||
glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
|
||||
|
|
|
@ -120,7 +120,7 @@ void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) {
|
|||
glLoadIdentity();
|
||||
renderArgs->_renderSide = RenderArgs::MONO;
|
||||
qApp->displaySide(renderArgs, eyeCamera, false);
|
||||
qApp->getApplicationOverlay().displayOverlayTexture(renderArgs);
|
||||
qApp->getApplicationCompositor().displayOverlayTexture(renderArgs);
|
||||
_activeEye = NULL;
|
||||
}, [&]{
|
||||
// render right side view
|
||||
|
|
|
@ -25,9 +25,9 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
|
|||
|
||||
glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
|
||||
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
|
||||
const auto& compositor = Application::getInstance()->getApplicationCompositor();
|
||||
|
||||
return applicationOverlay.calculateRayUICollisionPoint(position, direction, result);
|
||||
return compositor.calculateRayUICollisionPoint(position, direction, result);
|
||||
}
|
||||
|
||||
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
|
||||
|
@ -40,7 +40,7 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte
|
|||
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
|
||||
glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction);
|
||||
glm::vec3 eulers = ::safeEulerAngles(rotation);
|
||||
return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationOverlay()
|
||||
return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor()
|
||||
.sphericalToOverlay(glm::vec2(eulers.y, -eulers.x)));
|
||||
}
|
||||
return QScriptValue::NullValue;
|
||||
|
|
|
@ -27,11 +27,11 @@ public:
|
|||
static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
public slots:
|
||||
void toggleMagnifier() { Application::getInstance()->getApplicationOverlay().toggleMagnifier(); };
|
||||
void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); };
|
||||
|
||||
private:
|
||||
HMDScriptingInterface() {};
|
||||
bool getMagnifier() const { return Application::getInstance()->getApplicationOverlay().hasMagnifier(); };
|
||||
bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); };
|
||||
bool isHMDMode() const { return Application::getInstance()->isHMDMode(); }
|
||||
|
||||
bool getHUDLookAtPosition3D(glm::vec3& result) const;
|
||||
|
|
757
interface/src/ui/ApplicationCompositor.cpp
Normal file
757
interface/src/ui/ApplicationCompositor.cpp
Normal file
|
@ -0,0 +1,757 @@
|
|||
//
|
||||
// ApplicationCompositor.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Benjamin Arnold on 5/27/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "ApplicationCompositor.h"
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <gpu/Texture.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <CursorManager.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "audio/AudioIOStatsRenderer.h"
|
||||
#include "audio/AudioScope.h"
|
||||
#include "audio/AudioToolBox.h"
|
||||
#include "Application.h"
|
||||
#include "devices/CameraToolBox.h"
|
||||
|
||||
#include "Util.h"
|
||||
#include "ui/Stats.h"
|
||||
|
||||
#include "../../libraries/render-utils/standardTransformPNTC_vert.h"
|
||||
#include "../../libraries/render-utils/standardDrawTexture_frag.h"
|
||||
|
||||
// Used to animate the magnification windows
|
||||
static const float MAG_SPEED = 0.08f;
|
||||
|
||||
static const quint64 MSECS_TO_USECS = 1000ULL;
|
||||
|
||||
static const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
|
||||
static const float reticleSize = TWO_PI / 100.0f;
|
||||
|
||||
static const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
|
||||
static const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
||||
|
||||
static const float CURSOR_PIXEL_SIZE = 32.0f;
|
||||
static const float MOUSE_PITCH_RANGE = 1.0f * PI;
|
||||
static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
|
||||
static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);
|
||||
|
||||
static gpu::BufferPointer _hemiVertices;
|
||||
static gpu::BufferPointer _hemiIndices;
|
||||
static int _hemiIndexCount{ 0 };
|
||||
|
||||
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
||||
glm::vec3 getPoint(float yaw, float pitch) {
|
||||
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
|
||||
glm::sin(-pitch),
|
||||
glm::cos(-pitch) * (-glm::cos(yaw)));
|
||||
}
|
||||
|
||||
|
||||
//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
|
||||
//be multiplied by dir and added to origin to get the location of the collision
|
||||
bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
|
||||
{
|
||||
//Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
|
||||
|
||||
//Compute A, B and C coefficients
|
||||
float a = glm::dot(dir, dir);
|
||||
float b = 2 * glm::dot(dir, origin);
|
||||
float c = glm::dot(origin, origin) - (r * r);
|
||||
|
||||
//Find discriminant
|
||||
float disc = b * b - 4 * a * c;
|
||||
|
||||
// if discriminant is negative there are no real roots, so return
|
||||
// false as ray misses sphere
|
||||
if (disc < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute q as described above
|
||||
float distSqrt = sqrtf(disc);
|
||||
float q;
|
||||
if (b < 0) {
|
||||
q = (-b - distSqrt) / 2.0;
|
||||
} else {
|
||||
q = (-b + distSqrt) / 2.0;
|
||||
}
|
||||
|
||||
// compute t0 and t1
|
||||
float t0 = q / a;
|
||||
float t1 = c / q;
|
||||
|
||||
// make sure t0 is smaller than t1
|
||||
if (t0 > t1) {
|
||||
// if t0 is bigger than t1 swap them around
|
||||
float temp = t0;
|
||||
t0 = t1;
|
||||
t1 = temp;
|
||||
}
|
||||
|
||||
// if t1 is less than zero, the object is in the ray's negative direction
|
||||
// and consequently the ray misses the sphere
|
||||
if (t1 < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if t0 is less than zero, the intersection point is at t1
|
||||
if (t0 < 0) {
|
||||
*result = t1;
|
||||
return true;
|
||||
} else { // else the intersection point is at t0
|
||||
*result = t0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationCompositor::ApplicationCompositor() {
|
||||
memset(_reticleActive, 0, sizeof(_reticleActive));
|
||||
memset(_magActive, 0, sizeof(_reticleActive));
|
||||
memset(_magSizeMult, 0, sizeof(_magSizeMult));
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
_reticleQuad = geometryCache->allocateID();
|
||||
_magnifierQuad = geometryCache->allocateID();
|
||||
_audioRedQuad = geometryCache->allocateID();
|
||||
_audioGreenQuad = geometryCache->allocateID();
|
||||
_audioBlueQuad = geometryCache->allocateID();
|
||||
_domainStatusBorder = geometryCache->allocateID();
|
||||
_magnifierBorder = geometryCache->allocateID();
|
||||
}
|
||||
|
||||
ApplicationCompositor::~ApplicationCompositor() {
|
||||
}
|
||||
|
||||
void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
auto cursor = cursorManager.getCursor(cursorIndex);
|
||||
auto iconId = cursor->getIcon();
|
||||
if (!_cursors.count(iconId)) {
|
||||
auto iconPath = cursorManager.getIconImage(cursor->getIcon());
|
||||
_cursors[iconId] = DependencyManager::get<TextureCache>()->
|
||||
getImageTexture(iconPath);
|
||||
}
|
||||
batch.setUniformTexture(0, _cursors[iconId]);
|
||||
}
|
||||
|
||||
|
||||
// Draws the FBO texture for the screen
|
||||
void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) {
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint texture = qApp->getApplicationOverlay().getOverlayTexture();
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
renderArgs->_context->syncCache();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
gpu::Batch batch;
|
||||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setViewTransform(Transform());
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch._glBindTexture(GL_TEXTURE_2D, texture);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha));
|
||||
|
||||
// Doesn't actually render
|
||||
renderPointers();
|
||||
|
||||
|
||||
//draw the mouse pointer
|
||||
vec2 canvasSize = qApp->getCanvasSize();
|
||||
|
||||
// Get the mouse coordinates and convert to NDC [-1, 1]
|
||||
vec2 mousePosition = vec2(qApp->getMouse());
|
||||
mousePosition /= canvasSize;
|
||||
mousePosition *= 2.0f;
|
||||
mousePosition -= 1.0f;
|
||||
mousePosition.y *= -1.0f;
|
||||
|
||||
Transform model;
|
||||
model.setTranslation(vec3(mousePosition, 0));
|
||||
vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize;
|
||||
model.setScale(vec3(mouseSize, 1.0f));
|
||||
batch.setModelTransform(model);
|
||||
bindCursorTexture(batch);
|
||||
vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
|
||||
geometryCache->renderUnitQuad(batch, vec4(1));
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
|
||||
|
||||
vec2 getPolarCoordinates(const PalmData& palm) {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
auto avatarOrientation = myAvatar->getOrientation();
|
||||
auto eyePos = myAvatar->getDefaultEyePosition();
|
||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
|
||||
// Direction of the tip relative to the eye
|
||||
glm::vec3 tipDirection = tip - eyePos;
|
||||
// orient into avatar space
|
||||
tipDirection = glm::inverse(avatarOrientation) * tipDirection;
|
||||
// Normalize for trig functions
|
||||
tipDirection = glm::normalize(tipDirection);
|
||||
// Convert to polar coordinates
|
||||
glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y));
|
||||
return polar;
|
||||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) {
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint texture = qApp->getApplicationOverlay().getOverlayTexture();
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
gpu::Batch batch;
|
||||
DependencyManager::get<GeometryCache>()->useSimpleDrawPipeline(batch);
|
||||
batch._glDisable(GL_DEPTH_TEST);
|
||||
batch._glDisable(GL_CULL_FACE);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, texture);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
batch.setViewTransform(Transform());
|
||||
batch.setProjectionTransform(qApp->getEyeProjection(eye));
|
||||
mat4 eyePose = qApp->getEyePose(eye);
|
||||
glm::mat4 overlayXfm = glm::inverse(eyePose);
|
||||
batch.setModelTransform(overlayXfm);
|
||||
drawSphereSection(batch);
|
||||
|
||||
// Doesn't actually render
|
||||
renderPointers();
|
||||
vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize);
|
||||
|
||||
bindCursorTexture(batch);
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
//Controller Pointers
|
||||
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
|
||||
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
glm::vec2 polar = getPolarCoordinates(palm);
|
||||
// Convert to quaternion
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
// Render reticle at location
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
}
|
||||
}
|
||||
|
||||
//Mouse Pointer
|
||||
if (_reticleActive[MOUSE]) {
|
||||
glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(),
|
||||
_reticlePosition[MOUSE].y()));
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
}
|
||||
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
|
||||
|
||||
void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const {
|
||||
cursorPos *= qApp->getCanvasSize();
|
||||
const glm::vec2 projection = screenToSpherical(cursorPos);
|
||||
// The overlay space orientation of the mouse coordinates
|
||||
const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
|
||||
// FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE.
|
||||
// Now we need to account for the actual camera position relative to the overlay
|
||||
glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT);
|
||||
|
||||
|
||||
// We need the RAW camera orientation and position, because this is what the overlay is
|
||||
// rendered relative to
|
||||
const glm::vec3 overlayPosition = qApp->getCamera()->getPosition();
|
||||
const glm::quat overlayOrientation = qApp->getCamera()->getRotation();
|
||||
|
||||
// Intersection UI overlay space
|
||||
glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
|
||||
glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius;
|
||||
intersectionWithUi += overlayPosition;
|
||||
|
||||
// Intersection in world space
|
||||
origin = overlayPosition;
|
||||
direction = glm::normalize(intersectionWithUi - origin);
|
||||
}
|
||||
|
||||
//Caculate the click location using one of the sixense controllers. Scale is not applied
|
||||
QPoint ApplicationCompositor::getPalmClickLocation(const PalmData *palm) const {
|
||||
QPoint rv;
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
if (qApp->isHMDMode()) {
|
||||
glm::vec2 polar = getPolarCoordinates(*palm);
|
||||
glm::vec2 point = sphericalToScreen(-polar);
|
||||
rv.rx() = point.x;
|
||||
rv.ry() = point.y;
|
||||
} else {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::dmat4 projection;
|
||||
qApp->getProjectionMatrix(&projection);
|
||||
glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
|
||||
glm::vec3 eyePos = myAvatar->getDefaultEyePosition();
|
||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
|
||||
glm::vec3 tipPos = invOrientation * (tip - eyePos);
|
||||
|
||||
glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
|
||||
glm::vec3 ndcSpacePos;
|
||||
if (clipSpacePos.w != 0) {
|
||||
ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w;
|
||||
}
|
||||
|
||||
rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x);
|
||||
rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//Finds the collision point of a world space ray
|
||||
bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation());
|
||||
|
||||
glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition());
|
||||
glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction);
|
||||
|
||||
float t;
|
||||
if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){
|
||||
result = position + direction * t;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Renders optional pointers
|
||||
void ApplicationCompositor::renderPointers() {
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
//glEnable(GL_BLEND);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
//bindCursorTexture();
|
||||
|
||||
if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
|
||||
//If we are in oculus, render reticle later
|
||||
if (_lastMouseMove == 0) {
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
}
|
||||
QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY());
|
||||
|
||||
static const int MAX_IDLE_TIME = 3;
|
||||
if (_reticlePosition[MOUSE] != position) {
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
} else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) {
|
||||
//float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians
|
||||
//OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll));
|
||||
glm::vec3 result;
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
if (calculateRayUICollisionPoint(myAvatar->getEyePosition(),
|
||||
myAvatar->getOrientation() * orientation * IDENTITY_FRONT,
|
||||
result)) {
|
||||
glm::vec3 lookAtDirection = glm::inverse(myAvatar->getOrientation()) * (result - myAvatar->getDefaultEyePosition());
|
||||
glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection));
|
||||
glm::vec2 screenPos = sphericalToScreen(spericalPos);
|
||||
position = QPoint(screenPos.x, screenPos.y);
|
||||
// FIXME
|
||||
//glCanvas->cursor().setPos(glCanvas->mapToGlobal(position));
|
||||
} else {
|
||||
qDebug() << "No collision point";
|
||||
}
|
||||
}
|
||||
|
||||
_reticlePosition[MOUSE] = position;
|
||||
_reticleActive[MOUSE] = true;
|
||||
_magActive[MOUSE] = _magnifier;
|
||||
_reticleActive[LEFT_CONTROLLER] = false;
|
||||
_reticleActive[RIGHT_CONTROLLER] = false;
|
||||
} else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
|
||||
_lastMouseMove = 0;
|
||||
//only render controller pointer if we aren't already rendering a mouse pointer
|
||||
_reticleActive[MOUSE] = false;
|
||||
_magActive[MOUSE] = false;
|
||||
renderControllerPointers();
|
||||
}
|
||||
//glBindTexture(GL_TEXTURE_2D, 0);
|
||||
//glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void ApplicationCompositor::renderControllerPointers() {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
//Static variables used for storing controller state
|
||||
static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL };
|
||||
static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false };
|
||||
static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false };
|
||||
|
||||
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
|
||||
|
||||
for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
|
||||
const int index = palmIndex - 1;
|
||||
|
||||
const PalmData* palmData = NULL;
|
||||
|
||||
if (palmIndex >= handData->getPalms().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handData->getPalms()[palmIndex].isActive()) {
|
||||
palmData = &handData->getPalms()[palmIndex];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
int controllerButtons = palmData->getControllerButtons();
|
||||
|
||||
//Check for if we should toggle or drag the magnification window
|
||||
if (controllerButtons & BUTTON_3) {
|
||||
if (isPressed[index] == false) {
|
||||
//We are now dragging the window
|
||||
isPressed[index] = true;
|
||||
//set the pressed time in us
|
||||
pressedTime[index] = usecTimestampNow();
|
||||
stateWhenPressed[index] = _magActive[index];
|
||||
}
|
||||
} else if (isPressed[index]) {
|
||||
isPressed[index] = false;
|
||||
//If the button was only pressed for < 250 ms
|
||||
//then disable it.
|
||||
|
||||
const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS;
|
||||
if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) {
|
||||
_magActive[index] = !stateWhenPressed[index];
|
||||
}
|
||||
}
|
||||
|
||||
//if we have the oculus, we should make the cursor smaller since it will be
|
||||
//magnified
|
||||
if (qApp->isHMDMode()) {
|
||||
|
||||
QPoint point = getPalmClickLocation(palmData);
|
||||
|
||||
_reticlePosition[index] = point;
|
||||
|
||||
//When button 2 is pressed we drag the mag window
|
||||
if (isPressed[index]) {
|
||||
_magActive[index] = true;
|
||||
}
|
||||
|
||||
// If oculus is enabled, we draw the crosshairs later
|
||||
continue;
|
||||
}
|
||||
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
int mouseX, mouseY;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
|
||||
QPoint res = getPalmClickLocation(palmData);
|
||||
mouseX = res.x();
|
||||
mouseY = res.y();
|
||||
} else {
|
||||
// Get directon relative to avatar orientation
|
||||
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
|
||||
|
||||
// Get the angles, scaled between (-0.5,0.5)
|
||||
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
|
||||
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
|
||||
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
|
||||
|
||||
mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
}
|
||||
|
||||
//If the cursor is out of the screen then don't render it
|
||||
if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) {
|
||||
_reticleActive[index] = false;
|
||||
continue;
|
||||
}
|
||||
_reticleActive[index] = true;
|
||||
|
||||
|
||||
const float reticleSize = 40.0f;
|
||||
|
||||
mouseX -= reticleSize / 2.0f;
|
||||
mouseY += reticleSize / 2.0f;
|
||||
|
||||
|
||||
glm::vec2 topLeft(mouseX, mouseY);
|
||||
glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize);
|
||||
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Renders a small magnification of the currently bound texture at the coordinates
|
||||
void ApplicationCompositor::renderMagnifier(const glm::vec2& magPos, float sizeMult, bool showBorder) {
|
||||
if (!_magnifier) {
|
||||
return;
|
||||
}
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
|
||||
const int widgetWidth = canvasSize.x;
|
||||
const int widgetHeight = canvasSize.y;
|
||||
|
||||
const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
|
||||
const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
|
||||
// Magnification Texture Coordinates
|
||||
const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
|
||||
const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
|
||||
const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
|
||||
const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
|
||||
|
||||
const float newHalfWidth = halfWidth * MAGNIFY_MULT;
|
||||
const float newHalfHeight = halfHeight * MAGNIFY_MULT;
|
||||
//Get yaw / pitch value for the corners
|
||||
const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth,
|
||||
magPos.y - newHalfHeight));
|
||||
const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth,
|
||||
magPos.y + newHalfHeight));
|
||||
|
||||
const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y);
|
||||
const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y);
|
||||
const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y);
|
||||
const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight
|
||||
|| topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) {
|
||||
QVector<glm::vec3> border;
|
||||
border << topLeft;
|
||||
border << bottomLeft;
|
||||
border << bottomRight;
|
||||
border << topRight;
|
||||
border << topLeft;
|
||||
geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha));
|
||||
|
||||
_previousMagnifierBottomLeft = bottomLeft;
|
||||
_previousMagnifierBottomRight = bottomRight;
|
||||
_previousMagnifierTopLeft = topLeft;
|
||||
_previousMagnifierTopRight = topRight;
|
||||
}
|
||||
|
||||
glPushMatrix(); {
|
||||
if (showBorder) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glLineWidth(1.0f);
|
||||
//Outer Line
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha };
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft,
|
||||
glm::vec2(magnifyULeft, magnifyVBottom),
|
||||
glm::vec2(magnifyURight, magnifyVBottom),
|
||||
glm::vec2(magnifyURight, magnifyVTop),
|
||||
glm::vec2(magnifyULeft, magnifyVTop),
|
||||
magnifierColor, _magnifierQuad);
|
||||
|
||||
} glPopMatrix();
|
||||
}
|
||||
|
||||
void ApplicationCompositor::buildHemiVertices(
|
||||
const float fov, const float aspectRatio, const int slices, const int stacks) {
|
||||
static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
|
||||
if (textureFOV == fov && textureAspectRatio == aspectRatio) {
|
||||
return;
|
||||
}
|
||||
|
||||
textureFOV = fov;
|
||||
textureAspectRatio = aspectRatio;
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
_hemiVertices = gpu::BufferPointer(new gpu::Buffer());
|
||||
_hemiIndices = gpu::BufferPointer(new gpu::Buffer());
|
||||
|
||||
|
||||
if (fov >= PI) {
|
||||
qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
|
||||
}
|
||||
|
||||
//UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
|
||||
|
||||
vec3 pos;
|
||||
vec2 uv;
|
||||
// Compute vertices positions and texture UV coordinate
|
||||
// Create and write to buffer
|
||||
for (int i = 0; i < stacks; i++) {
|
||||
uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
|
||||
// abs(theta) <= fov / 2.0f
|
||||
float pitch = -fov * (uv.y - 0.5f);
|
||||
for (int j = 0; j < slices; j++) {
|
||||
uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
|
||||
// abs(phi) <= fov * aspectRatio / 2.0f
|
||||
float yaw = -fov * aspectRatio * (uv.x - 0.5f);
|
||||
pos = getPoint(yaw, pitch);
|
||||
static const vec4 color(1);
|
||||
_hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos);
|
||||
_hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv);
|
||||
_hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute number of indices needed
|
||||
static const int VERTEX_PER_TRANGLE = 3;
|
||||
static const int TRIANGLE_PER_RECTANGLE = 2;
|
||||
int numberOfRectangles = (slices - 1) * (stacks - 1);
|
||||
_hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
|
||||
|
||||
// Compute indices order
|
||||
std::vector<GLushort> indices;
|
||||
for (int i = 0; i < stacks - 1; i++) {
|
||||
for (int j = 0; j < slices - 1; j++) {
|
||||
GLushort bottomLeftIndex = i * slices + j;
|
||||
GLushort bottomRightIndex = bottomLeftIndex + 1;
|
||||
GLushort topLeftIndex = bottomLeftIndex + slices;
|
||||
GLushort topRightIndex = topLeftIndex + 1;
|
||||
// FIXME make a z-order curve for better vertex cache locality
|
||||
indices.push_back(topLeftIndex);
|
||||
indices.push_back(bottomLeftIndex);
|
||||
indices.push_back(topRightIndex);
|
||||
|
||||
indices.push_back(topRightIndex);
|
||||
indices.push_back(bottomLeftIndex);
|
||||
indices.push_back(bottomRightIndex);
|
||||
}
|
||||
}
|
||||
_hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]);
|
||||
}
|
||||
|
||||
|
||||
void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) {
|
||||
buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80);
|
||||
static const int VERTEX_DATA_SLOT = 0;
|
||||
static const int TEXTURE_DATA_SLOT = 1;
|
||||
static const int COLOR_DATA_SLOT = 2;
|
||||
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
|
||||
streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA));
|
||||
batch.setInputFormat(streamFormat);
|
||||
|
||||
static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4);
|
||||
gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
|
||||
gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element);
|
||||
gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
|
||||
batch.setInputBuffer(VERTEX_DATA_SLOT, posView);
|
||||
batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView);
|
||||
batch.setInputBuffer(COLOR_DATA_SLOT, colView);
|
||||
batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount);
|
||||
}
|
||||
|
||||
|
||||
glm::vec2 ApplicationCompositor::directionToSpherical(const glm::vec3& direction) {
|
||||
glm::vec2 result;
|
||||
// Compute yaw
|
||||
glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z));
|
||||
result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection));
|
||||
if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) {
|
||||
result.x = -glm::abs(result.x);
|
||||
} else {
|
||||
result.x = glm::abs(result.x);
|
||||
}
|
||||
// Compute pitch
|
||||
result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 ApplicationCompositor::sphericalToDirection(const glm::vec2& sphericalPos) {
|
||||
glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f));
|
||||
return rotation * IDENTITY_FRONT;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) {
|
||||
auto screenSize = qApp->getCanvasSize();
|
||||
glm::vec2 result;
|
||||
result.x = -(screenPos.x / screenSize.x - 0.5f);
|
||||
result.y = (screenPos.y / screenSize.y - 0.5f);
|
||||
result.x *= MOUSE_YAW_RANGE;
|
||||
result.y *= MOUSE_PITCH_RANGE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::sphericalToScreen(const glm::vec2& sphericalPos) {
|
||||
glm::vec2 result = sphericalPos;
|
||||
result.x *= -1.0;
|
||||
result /= MOUSE_RANGE;
|
||||
result += 0.5f;
|
||||
result *= qApp->getCanvasSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::sphericalToOverlay(const glm::vec2& sphericalPos) const {
|
||||
glm::vec2 result = sphericalPos;
|
||||
result.x *= -1.0;
|
||||
result /= _textureFov;
|
||||
result.x /= _textureAspectRatio;
|
||||
result += 0.5f;
|
||||
result *= qApp->getCanvasSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::overlayToSpherical(const glm::vec2& overlayPos) const {
|
||||
glm::vec2 result = overlayPos;
|
||||
result /= qApp->getCanvasSize();
|
||||
result -= 0.5f;
|
||||
result *= _textureFov;
|
||||
result.x *= _textureAspectRatio;
|
||||
result.x *= -1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::screenToOverlay(const glm::vec2& screenPos) const {
|
||||
return sphericalToOverlay(screenToSpherical(screenPos));
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) const {
|
||||
return sphericalToScreen(overlayToSpherical(overlayPos));
|
||||
}
|
118
interface/src/ui/ApplicationCompositor.h
Normal file
118
interface/src/ui/ApplicationCompositor.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis Arnold on 2015/06/13
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ApplicationOverlayCompositor_h
|
||||
#define hifi_ApplicationOverlayCompositor_h
|
||||
|
||||
#include <QObject>
|
||||
#include <cstdint>
|
||||
|
||||
#include <GeometryCache.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
class Camera;
|
||||
class PalmData;
|
||||
class RenderArgs;
|
||||
|
||||
const float MAGNIFY_WIDTH = 220.0f;
|
||||
const float MAGNIFY_HEIGHT = 100.0f;
|
||||
const float MAGNIFY_MULT = 2.0f;
|
||||
|
||||
const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
// Handles the drawing of the overlays to the screen
|
||||
// TODO, move divide up the rendering, displaying and input handling
|
||||
// facilities of this class
|
||||
class ApplicationCompositor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ApplicationCompositor();
|
||||
~ApplicationCompositor();
|
||||
|
||||
void displayOverlayTexture(RenderArgs* renderArgs);
|
||||
void displayOverlayTextureHmd(RenderArgs* renderArgs, int eye);
|
||||
|
||||
QPoint getPalmClickLocation(const PalmData *palm) const;
|
||||
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
|
||||
|
||||
bool hasMagnifier() const { return _magnifier; }
|
||||
void toggleMagnifier() { _magnifier = !_magnifier; }
|
||||
|
||||
float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
|
||||
void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
|
||||
|
||||
// Converter from one frame of reference to another.
|
||||
// Frame of reference:
|
||||
// Direction: Ray that represents the spherical values
|
||||
// Screen: Position on the screen (x,y)
|
||||
// Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch)
|
||||
// Overlay: Position on the overlay (x,y)
|
||||
// (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen.
|
||||
// This allows for picking outside of the screen projection in 3D.
|
||||
glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
|
||||
glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
|
||||
glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const;
|
||||
glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const;
|
||||
void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const;
|
||||
GLuint getOverlayTexture();
|
||||
|
||||
static glm::vec2 directionToSpherical(const glm::vec3 & direction);
|
||||
static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos);
|
||||
static glm::vec2 screenToSpherical(const glm::vec2 & screenPos);
|
||||
static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos);
|
||||
|
||||
private:
|
||||
void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov);
|
||||
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
|
||||
void buildHemiVertices(const float fov, const float aspectRatio, const int slices, const int stacks);
|
||||
void drawSphereSection(gpu::Batch& batch);
|
||||
|
||||
void renderPointers();
|
||||
void renderMagnifier(const glm::vec2& magPos, float sizeMult, bool showBorder);
|
||||
|
||||
void renderControllerPointers();
|
||||
void renderPointersOculus();
|
||||
|
||||
float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
|
||||
float _textureFov{ glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE) };
|
||||
float _textureAspectRatio{ 1.0f };
|
||||
int _hemiVerticesID{ GeometryCache::UNKNOWN_ID };
|
||||
|
||||
enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES };
|
||||
bool _reticleActive[NUMBER_OF_RETICLES];
|
||||
QPoint _reticlePosition[NUMBER_OF_RETICLES];
|
||||
bool _magActive[NUMBER_OF_RETICLES];
|
||||
float _magSizeMult[NUMBER_OF_RETICLES];
|
||||
quint64 _lastMouseMove{ 0 };
|
||||
bool _magnifier{ true };
|
||||
|
||||
float _alpha{ 1.0f };
|
||||
float _oculusUIRadius{ 1.0f };
|
||||
|
||||
QMap<uint16_t, gpu::TexturePointer> _cursors;
|
||||
|
||||
int _reticleQuad;
|
||||
int _magnifierQuad;
|
||||
int _audioRedQuad;
|
||||
int _audioGreenQuad;
|
||||
int _audioBlueQuad;
|
||||
int _domainStatusBorder;
|
||||
int _magnifierBorder;
|
||||
|
||||
int _previousBorderWidth{ -1 };
|
||||
int _previousBorderHeight{ -1 };
|
||||
|
||||
glm::vec3 _previousMagnifierBottomLeft;
|
||||
glm::vec3 _previousMagnifierBottomRight;
|
||||
glm::vec3 _previousMagnifierTopLeft;
|
||||
glm::vec3 _previousMagnifierTopRight;
|
||||
};
|
||||
|
||||
#endif // hifi_ApplicationOverlayCompositor_h
|
|
@ -36,114 +36,20 @@
|
|||
#include "Util.h"
|
||||
#include "ui/Stats.h"
|
||||
|
||||
#include "../../libraries/render-utils/standardTransformPNTC_vert.h"
|
||||
#include "../../libraries/render-utils/standardDrawTexture_frag.h"
|
||||
|
||||
// Used to animate the magnification windows
|
||||
const float MAG_SPEED = 0.08f;
|
||||
|
||||
const quint64 MSECS_TO_USECS = 1000ULL;
|
||||
|
||||
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
|
||||
const float reticleSize = TWO_PI / 100.0f;
|
||||
|
||||
|
||||
const int AUDIO_METER_GAP = 5;
|
||||
const int MUTE_ICON_PADDING = 10;
|
||||
const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
|
||||
const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
||||
|
||||
static const float MOUSE_PITCH_RANGE = 1.0f * PI;
|
||||
static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
|
||||
static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE);
|
||||
|
||||
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
||||
glm::vec3 getPoint(float yaw, float pitch) {
|
||||
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
|
||||
glm::sin(-pitch),
|
||||
glm::cos(-pitch) * (-glm::cos(yaw)));
|
||||
}
|
||||
|
||||
//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
|
||||
//be multiplied by dir and added to origin to get the location of the collision
|
||||
bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
|
||||
{
|
||||
//Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
|
||||
|
||||
//Compute A, B and C coefficients
|
||||
float a = glm::dot(dir, dir);
|
||||
float b = 2 * glm::dot(dir, origin);
|
||||
float c = glm::dot(origin, origin) - (r * r);
|
||||
|
||||
//Find discriminant
|
||||
float disc = b * b - 4 * a * c;
|
||||
|
||||
// if discriminant is negative there are no real roots, so return
|
||||
// false as ray misses sphere
|
||||
if (disc < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute q as described above
|
||||
float distSqrt = sqrtf(disc);
|
||||
float q;
|
||||
if (b < 0) {
|
||||
q = (-b - distSqrt) / 2.0;
|
||||
} else {
|
||||
q = (-b + distSqrt) / 2.0;
|
||||
}
|
||||
|
||||
// compute t0 and t1
|
||||
float t0 = q / a;
|
||||
float t1 = c / q;
|
||||
|
||||
// make sure t0 is smaller than t1
|
||||
if (t0 > t1) {
|
||||
// if t0 is bigger than t1 swap them around
|
||||
float temp = t0;
|
||||
t0 = t1;
|
||||
t1 = temp;
|
||||
}
|
||||
|
||||
// if t1 is less than zero, the object is in the ray's negative direction
|
||||
// and consequently the ray misses the sphere
|
||||
if (t1 < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if t0 is less than zero, the intersection point is at t1
|
||||
if (t0 < 0) {
|
||||
*result = t1;
|
||||
return true;
|
||||
} else { // else the intersection point is at t0
|
||||
*result = t0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationOverlay::ApplicationOverlay() :
|
||||
_textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)),
|
||||
_textureAspectRatio(1.0f),
|
||||
_lastMouseMove(0),
|
||||
_magnifier(true),
|
||||
_alpha(1.0f),
|
||||
_oculusUIRadius(1.0f),
|
||||
_trailingAudioLoudness(0.0f),
|
||||
_previousBorderWidth(-1),
|
||||
_previousBorderHeight(-1),
|
||||
_previousMagnifierBottomLeft(),
|
||||
_previousMagnifierBottomRight(),
|
||||
_previousMagnifierTopLeft(),
|
||||
_previousMagnifierTopRight(),
|
||||
_framebufferObject(nullptr)
|
||||
{
|
||||
memset(_reticleActive, 0, sizeof(_reticleActive));
|
||||
memset(_magActive, 0, sizeof(_reticleActive));
|
||||
memset(_magSizeMult, 0, sizeof(_magSizeMult));
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
_reticleQuad = geometryCache->allocateID();
|
||||
_magnifierQuad = geometryCache->allocateID();
|
||||
_audioRedQuad = geometryCache->allocateID();
|
||||
_audioGreenQuad = geometryCache->allocateID();
|
||||
_audioBlueQuad = geometryCache->allocateID();
|
||||
|
@ -159,7 +65,7 @@ ApplicationOverlay::ApplicationOverlay() :
|
|||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->lockTexture(textureId);
|
||||
assert(!glGetError());
|
||||
std::swap(_newUiTexture, textureId);
|
||||
std::swap(_uiTexture, textureId);
|
||||
if (textureId) {
|
||||
offscreenUi->releaseTexture(textureId);
|
||||
}
|
||||
|
@ -172,13 +78,10 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
Overlays& overlays = qApp->getOverlays();
|
||||
|
||||
_textureFov = glm::radians(_hmdUIAngularSize);
|
||||
glm::vec2 size = qApp->getCanvasSize();
|
||||
_textureAspectRatio = aspect(size);
|
||||
|
||||
//Handle fading and deactivation/activation of UI
|
||||
Overlays& overlays = qApp->getOverlays();
|
||||
glm::vec2 size = qApp->getCanvasSize();
|
||||
// TODO Handle fading and deactivation/activation of UI
|
||||
|
||||
// Render 2D overlay
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
@ -210,10 +113,8 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
|
||||
overlays.renderHUD(renderArgs);
|
||||
|
||||
renderPointers();
|
||||
|
||||
renderDomainConnectionStatusBorder();
|
||||
if (_newUiTexture) {
|
||||
if (_uiTexture) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
@ -221,7 +122,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBindTexture(GL_TEXTURE_2D, _newUiTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, _uiTexture);
|
||||
DependencyManager::get<GeometryCache>()->renderUnitQuad();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
@ -241,472 +142,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
_framebufferObject->release();
|
||||
}
|
||||
|
||||
gpu::PipelinePointer ApplicationOverlay::getDrawPipeline() {
|
||||
if (!_standardDrawPipeline) {
|
||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
// enable decal blend
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
|
||||
_standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
|
||||
return _standardDrawPipeline;
|
||||
}
|
||||
|
||||
void ApplicationOverlay::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
auto cursor = cursorManager.getCursor(cursorIndex);
|
||||
auto iconId = cursor->getIcon();
|
||||
if (!_cursors.count(iconId)) {
|
||||
auto iconPath = cursorManager.getIconImage(cursor->getIcon());
|
||||
_cursors[iconId] = DependencyManager::get<TextureCache>()->
|
||||
getImageTexture(iconPath);
|
||||
}
|
||||
batch.setUniformTexture(0, _cursors[iconId]);
|
||||
}
|
||||
|
||||
#define CURSOR_PIXEL_SIZE 32.0f
|
||||
|
||||
// Draws the FBO texture for the screen
|
||||
void ApplicationOverlay::displayOverlayTexture(RenderArgs* renderArgs) {
|
||||
if (_alpha == 0.0f || !_framebufferObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
|
||||
gpu::Batch batch;
|
||||
Transform model;
|
||||
//DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true);
|
||||
batch.setPipeline(getDrawPipeline());
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setViewTransform(model);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
DependencyManager::get<GeometryCache>()->renderUnitQuad(batch, vec4(vec3(1), _alpha));
|
||||
|
||||
//draw the mouse pointer
|
||||
glm::vec2 canvasSize = qApp->getCanvasSize();
|
||||
|
||||
// Get the mouse coordinates and convert to NDC [-1, 1]
|
||||
vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY());
|
||||
mousePosition /= canvasSize;
|
||||
mousePosition *= 2.0f;
|
||||
mousePosition -= 1.0f;
|
||||
mousePosition.y *= -1.0f;
|
||||
model.setTranslation(vec3(mousePosition, 0));
|
||||
glm::vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize;
|
||||
model.setScale(vec3(mouseSize, 1.0f));
|
||||
batch.setModelTransform(model);
|
||||
bindCursorTexture(batch);
|
||||
glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
|
||||
DependencyManager::get<GeometryCache>()->renderUnitQuad(batch, vec4(1));
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
|
||||
|
||||
static gpu::BufferPointer _hemiVertices;
|
||||
static gpu::BufferPointer _hemiIndices;
|
||||
static int _hemiIndexCount{ 0 };
|
||||
|
||||
glm::vec2 getPolarCoordinates(const PalmData& palm) {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
auto avatarOrientation = myAvatar->getOrientation();
|
||||
auto eyePos = myAvatar->getDefaultEyePosition();
|
||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
|
||||
// Direction of the tip relative to the eye
|
||||
glm::vec3 tipDirection = tip - eyePos;
|
||||
// orient into avatar space
|
||||
tipDirection = glm::inverse(avatarOrientation) * tipDirection;
|
||||
// Normalize for trig functions
|
||||
tipDirection = glm::normalize(tipDirection);
|
||||
// Convert to polar coordinates
|
||||
glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y));
|
||||
return polar;
|
||||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
void ApplicationOverlay::displayOverlayTextureHmd(RenderArgs* renderArgs, Camera& whichCamera) {
|
||||
if (_alpha == 0.0f || !_framebufferObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
|
||||
gpu::Batch batch;
|
||||
batch.setPipeline(getDrawPipeline());
|
||||
batch._glDisable(GL_DEPTH_TEST);
|
||||
batch._glDisable(GL_CULL_FACE);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
batch.setProjectionTransform(whichCamera.getProjection());
|
||||
batch.setViewTransform(Transform());
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const quat& avatarOrientation = myAvatar->getOrientation();
|
||||
quat hmdOrientation = qApp->getCamera()->getHmdRotation();
|
||||
vec3 hmdPosition = glm::inverse(avatarOrientation) * qApp->getCamera()->getHmdPosition();
|
||||
mat4 overlayXfm = glm::mat4_cast(glm::inverse(hmdOrientation)) * glm::translate(mat4(), -hmdPosition);
|
||||
batch.setModelTransform(Transform(overlayXfm));
|
||||
drawSphereSection(batch);
|
||||
|
||||
|
||||
bindCursorTexture(batch);
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize);
|
||||
//Controller Pointers
|
||||
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
|
||||
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
glm::vec2 polar = getPolarCoordinates(palm);
|
||||
// Convert to quaternion
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
// Render reticle at location
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
}
|
||||
}
|
||||
|
||||
//Mouse Pointer
|
||||
if (_reticleActive[MOUSE]) {
|
||||
glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(),
|
||||
_reticlePosition[MOUSE].y()));
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
}
|
||||
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
|
||||
|
||||
void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const {
|
||||
cursorPos *= qApp->getCanvasSize();
|
||||
const glm::vec2 projection = screenToSpherical(cursorPos);
|
||||
// The overlay space orientation of the mouse coordinates
|
||||
const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
|
||||
// FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE.
|
||||
// Now we need to account for the actual camera position relative to the overlay
|
||||
glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT);
|
||||
|
||||
|
||||
const glm::vec3& hmdPosition = qApp->getCamera()->getHmdPosition();
|
||||
const glm::quat& hmdOrientation = qApp->getCamera()->getHmdRotation();
|
||||
|
||||
// We need the RAW camera orientation and position, because this is what the overlay is
|
||||
// rendered relative to
|
||||
const glm::vec3 overlayPosition = qApp->getCamera()->getPosition() - hmdPosition;
|
||||
const glm::quat overlayOrientation = qApp->getCamera()->getRotation() * glm::inverse(hmdOrientation);
|
||||
|
||||
// Intersection UI overlay space
|
||||
glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
|
||||
glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius;
|
||||
intersectionWithUi += overlayPosition;
|
||||
|
||||
// Intersection in world space
|
||||
origin = overlayPosition + hmdPosition;
|
||||
direction = glm::normalize(intersectionWithUi - origin);
|
||||
}
|
||||
|
||||
//Caculate the click location using one of the sixense controllers. Scale is not applied
|
||||
QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
|
||||
QPoint rv;
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
if (qApp->isHMDMode()) {
|
||||
glm::vec2 polar = getPolarCoordinates(*palm);
|
||||
glm::vec2 point = sphericalToScreen(-polar);
|
||||
rv.rx() = point.x;
|
||||
rv.ry() = point.y;
|
||||
} else {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::dmat4 projection;
|
||||
qApp->getProjectionMatrix(&projection);
|
||||
glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
|
||||
glm::vec3 eyePos = myAvatar->getDefaultEyePosition();
|
||||
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
|
||||
glm::vec3 tipPos = invOrientation * (tip - eyePos);
|
||||
|
||||
glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
|
||||
glm::vec3 ndcSpacePos;
|
||||
if (clipSpacePos.w != 0) {
|
||||
ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w;
|
||||
}
|
||||
|
||||
rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x);
|
||||
rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//Finds the collision point of a world space ray
|
||||
bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation());
|
||||
|
||||
glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition());
|
||||
glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction);
|
||||
|
||||
float t;
|
||||
if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){
|
||||
result = position + direction * t;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Renders optional pointers
|
||||
void ApplicationOverlay::renderPointers() {
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
//glEnable(GL_BLEND);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
//bindCursorTexture();
|
||||
|
||||
if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
|
||||
//If we are in oculus, render reticle later
|
||||
if (_lastMouseMove == 0) {
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
}
|
||||
QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY());
|
||||
|
||||
static const int MAX_IDLE_TIME = 3;
|
||||
if (_reticlePosition[MOUSE] != position) {
|
||||
_lastMouseMove = usecTimestampNow();
|
||||
} else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) {
|
||||
//float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians
|
||||
//OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll));
|
||||
glm::vec3 result;
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
if (calculateRayUICollisionPoint(myAvatar->getEyePosition(),
|
||||
myAvatar->getOrientation() * orientation * IDENTITY_FRONT,
|
||||
result)) {
|
||||
glm::vec3 lookAtDirection = glm::inverse(myAvatar->getOrientation()) * (result - myAvatar->getDefaultEyePosition());
|
||||
glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection));
|
||||
glm::vec2 screenPos = sphericalToScreen(spericalPos);
|
||||
position = QPoint(screenPos.x, screenPos.y);
|
||||
// FIXME
|
||||
//glCanvas->cursor().setPos(glCanvas->mapToGlobal(position));
|
||||
} else {
|
||||
qDebug() << "No collision point";
|
||||
}
|
||||
}
|
||||
|
||||
_reticlePosition[MOUSE] = position;
|
||||
_reticleActive[MOUSE] = true;
|
||||
_magActive[MOUSE] = _magnifier;
|
||||
_reticleActive[LEFT_CONTROLLER] = false;
|
||||
_reticleActive[RIGHT_CONTROLLER] = false;
|
||||
} else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
|
||||
_lastMouseMove = 0;
|
||||
//only render controller pointer if we aren't already rendering a mouse pointer
|
||||
_reticleActive[MOUSE] = false;
|
||||
_magActive[MOUSE] = false;
|
||||
renderControllerPointers();
|
||||
}
|
||||
//glBindTexture(GL_TEXTURE_2D, 0);
|
||||
//glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderControllerPointers() {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
//Static variables used for storing controller state
|
||||
static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL };
|
||||
static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false };
|
||||
static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false };
|
||||
|
||||
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
|
||||
|
||||
for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
|
||||
const int index = palmIndex - 1;
|
||||
|
||||
const PalmData* palmData = NULL;
|
||||
|
||||
if (palmIndex >= handData->getPalms().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handData->getPalms()[palmIndex].isActive()) {
|
||||
palmData = &handData->getPalms()[palmIndex];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
int controllerButtons = palmData->getControllerButtons();
|
||||
|
||||
//Check for if we should toggle or drag the magnification window
|
||||
if (controllerButtons & BUTTON_3) {
|
||||
if (isPressed[index] == false) {
|
||||
//We are now dragging the window
|
||||
isPressed[index] = true;
|
||||
//set the pressed time in us
|
||||
pressedTime[index] = usecTimestampNow();
|
||||
stateWhenPressed[index] = _magActive[index];
|
||||
}
|
||||
} else if (isPressed[index]) {
|
||||
isPressed[index] = false;
|
||||
//If the button was only pressed for < 250 ms
|
||||
//then disable it.
|
||||
|
||||
const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS;
|
||||
if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) {
|
||||
_magActive[index] = !stateWhenPressed[index];
|
||||
}
|
||||
}
|
||||
|
||||
//if we have the oculus, we should make the cursor smaller since it will be
|
||||
//magnified
|
||||
if (qApp->isHMDMode()) {
|
||||
|
||||
QPoint point = getPalmClickLocation(palmData);
|
||||
|
||||
_reticlePosition[index] = point;
|
||||
|
||||
//When button 2 is pressed we drag the mag window
|
||||
if (isPressed[index]) {
|
||||
_magActive[index] = true;
|
||||
}
|
||||
|
||||
// If oculus is enabled, we draw the crosshairs later
|
||||
continue;
|
||||
}
|
||||
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
int mouseX, mouseY;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
|
||||
QPoint res = getPalmClickLocation(palmData);
|
||||
mouseX = res.x();
|
||||
mouseY = res.y();
|
||||
} else {
|
||||
// Get directon relative to avatar orientation
|
||||
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection();
|
||||
|
||||
// Get the angles, scaled between (-0.5,0.5)
|
||||
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
|
||||
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
|
||||
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult();
|
||||
|
||||
mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
}
|
||||
|
||||
//If the cursor is out of the screen then don't render it
|
||||
if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) {
|
||||
_reticleActive[index] = false;
|
||||
continue;
|
||||
}
|
||||
_reticleActive[index] = true;
|
||||
|
||||
|
||||
const float reticleSize = 40.0f;
|
||||
|
||||
mouseX -= reticleSize / 2.0f;
|
||||
mouseY += reticleSize / 2.0f;
|
||||
|
||||
|
||||
glm::vec2 topLeft(mouseX, mouseY);
|
||||
glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize);
|
||||
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Renders a small magnification of the currently bound texture at the coordinates
|
||||
void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) {
|
||||
if (!_magnifier) {
|
||||
return;
|
||||
}
|
||||
auto canvasSize = qApp->getCanvasSize();
|
||||
|
||||
const int widgetWidth = canvasSize.x;
|
||||
const int widgetHeight = canvasSize.y;
|
||||
|
||||
const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
|
||||
const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
|
||||
// Magnification Texture Coordinates
|
||||
const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
|
||||
const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
|
||||
const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
|
||||
const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
|
||||
|
||||
const float newHalfWidth = halfWidth * MAGNIFY_MULT;
|
||||
const float newHalfHeight = halfHeight * MAGNIFY_MULT;
|
||||
//Get yaw / pitch value for the corners
|
||||
const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth,
|
||||
magPos.y - newHalfHeight));
|
||||
const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth,
|
||||
magPos.y + newHalfHeight));
|
||||
|
||||
const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y);
|
||||
const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y);
|
||||
const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y);
|
||||
const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight
|
||||
|| topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) {
|
||||
QVector<glm::vec3> border;
|
||||
border << topLeft;
|
||||
border << bottomLeft;
|
||||
border << bottomRight;
|
||||
border << topRight;
|
||||
border << topLeft;
|
||||
geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha));
|
||||
|
||||
_previousMagnifierBottomLeft = bottomLeft;
|
||||
_previousMagnifierBottomRight = bottomRight;
|
||||
_previousMagnifierTopLeft = topLeft;
|
||||
_previousMagnifierTopRight = topRight;
|
||||
}
|
||||
|
||||
glPushMatrix(); {
|
||||
if (showBorder) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glLineWidth(1.0f);
|
||||
//Outer Line
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha };
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft,
|
||||
glm::vec2(magnifyULeft, magnifyVBottom),
|
||||
glm::vec2(magnifyURight, magnifyVBottom),
|
||||
glm::vec2(magnifyURight, magnifyVTop),
|
||||
glm::vec2(magnifyULeft, magnifyVTop),
|
||||
magnifierColor, _magnifierQuad);
|
||||
|
||||
} glPopMatrix();
|
||||
}
|
||||
|
||||
const int AUDIO_METER_GAP = 5;
|
||||
const int MUTE_ICON_PADDING = 10;
|
||||
|
||||
void ApplicationOverlay::renderCameraToggle() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) {
|
||||
return;
|
||||
|
@ -915,101 +350,10 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ApplicationOverlay::buildHemiVertices(
|
||||
const float fov, const float aspectRatio, const int slices, const int stacks) {
|
||||
static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
|
||||
if (textureFOV == fov && textureAspectRatio == aspectRatio) {
|
||||
return;
|
||||
}
|
||||
|
||||
textureFOV = fov;
|
||||
textureAspectRatio = aspectRatio;
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
_hemiVertices = gpu::BufferPointer(new gpu::Buffer());
|
||||
_hemiIndices = gpu::BufferPointer(new gpu::Buffer());
|
||||
|
||||
|
||||
if (fov >= PI) {
|
||||
qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
|
||||
}
|
||||
|
||||
//UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
|
||||
|
||||
vec3 pos;
|
||||
vec2 uv;
|
||||
// Compute vertices positions and texture UV coordinate
|
||||
// Create and write to buffer
|
||||
for (int i = 0; i < stacks; i++) {
|
||||
uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
|
||||
// abs(theta) <= fov / 2.0f
|
||||
float pitch = -fov * (uv.y - 0.5f);
|
||||
for (int j = 0; j < slices; j++) {
|
||||
uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
|
||||
// abs(phi) <= fov * aspectRatio / 2.0f
|
||||
float yaw = -fov * aspectRatio * (uv.x - 0.5f);
|
||||
pos = getPoint(yaw, pitch);
|
||||
static const vec4 color(1);
|
||||
_hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos);
|
||||
_hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv);
|
||||
_hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute number of indices needed
|
||||
static const int VERTEX_PER_TRANGLE = 3;
|
||||
static const int TRIANGLE_PER_RECTANGLE = 2;
|
||||
int numberOfRectangles = (slices - 1) * (stacks - 1);
|
||||
_hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
|
||||
|
||||
// Compute indices order
|
||||
std::vector<GLushort> indices;
|
||||
for (int i = 0; i < stacks - 1; i++) {
|
||||
for (int j = 0; j < slices - 1; j++) {
|
||||
GLushort bottomLeftIndex = i * slices + j;
|
||||
GLushort bottomRightIndex = bottomLeftIndex + 1;
|
||||
GLushort topLeftIndex = bottomLeftIndex + slices;
|
||||
GLushort topRightIndex = topLeftIndex + 1;
|
||||
// FIXME make a z-order curve for better vertex cache locality
|
||||
indices.push_back(topLeftIndex);
|
||||
indices.push_back(bottomLeftIndex);
|
||||
indices.push_back(topRightIndex);
|
||||
|
||||
indices.push_back(topRightIndex);
|
||||
indices.push_back(bottomLeftIndex);
|
||||
indices.push_back(bottomRightIndex);
|
||||
}
|
||||
}
|
||||
_hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]);
|
||||
}
|
||||
|
||||
|
||||
void ApplicationOverlay::drawSphereSection(gpu::Batch& batch) {
|
||||
buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80);
|
||||
static const int VERTEX_DATA_SLOT = 0;
|
||||
static const int TEXTURE_DATA_SLOT = 1;
|
||||
static const int COLOR_DATA_SLOT = 2;
|
||||
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
|
||||
streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA));
|
||||
batch.setInputFormat(streamFormat);
|
||||
|
||||
static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4);
|
||||
gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
|
||||
gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element);
|
||||
gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
|
||||
batch.setInputBuffer(VERTEX_DATA_SLOT, posView);
|
||||
batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView);
|
||||
batch.setInputBuffer(COLOR_DATA_SLOT, colView);
|
||||
batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount);
|
||||
}
|
||||
|
||||
|
||||
GLuint ApplicationOverlay::getOverlayTexture() {
|
||||
if (!_framebufferObject) {
|
||||
return 0;
|
||||
}
|
||||
return _framebufferObject->texture();
|
||||
}
|
||||
|
||||
|
@ -1036,71 +380,3 @@ void ApplicationOverlay::buildFramebufferObject() {
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::directionToSpherical(const glm::vec3& direction) {
|
||||
glm::vec2 result;
|
||||
// Compute yaw
|
||||
glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z));
|
||||
result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection));
|
||||
if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) {
|
||||
result.x = -glm::abs(result.x);
|
||||
} else {
|
||||
result.x = glm::abs(result.x);
|
||||
}
|
||||
// Compute pitch
|
||||
result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 ApplicationOverlay::sphericalToDirection(const glm::vec2& sphericalPos) {
|
||||
glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f));
|
||||
return rotation * IDENTITY_FRONT;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::screenToSpherical(const glm::vec2& screenPos) {
|
||||
auto screenSize = qApp->getCanvasSize();
|
||||
glm::vec2 result;
|
||||
result.x = -(screenPos.x / screenSize.x - 0.5f);
|
||||
result.y = (screenPos.y / screenSize.y - 0.5f);
|
||||
result.x *= MOUSE_YAW_RANGE;
|
||||
result.y *= MOUSE_PITCH_RANGE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::sphericalToScreen(const glm::vec2& sphericalPos) {
|
||||
glm::vec2 result = sphericalPos;
|
||||
result.x *= -1.0;
|
||||
result /= MOUSE_RANGE;
|
||||
result += 0.5f;
|
||||
result *= qApp->getCanvasSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::sphericalToOverlay(const glm::vec2& sphericalPos) const {
|
||||
glm::vec2 result = sphericalPos;
|
||||
result.x *= -1.0;
|
||||
result /= _textureFov;
|
||||
result.x /= _textureAspectRatio;
|
||||
result += 0.5f;
|
||||
result *= qApp->getCanvasSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::overlayToSpherical(const glm::vec2& overlayPos) const {
|
||||
glm::vec2 result = overlayPos;
|
||||
result /= qApp->getCanvasSize();
|
||||
result -= 0.5f;
|
||||
result *= _textureFov;
|
||||
result.x *= _textureAspectRatio;
|
||||
result.x *= -1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::screenToOverlay(const glm::vec2& screenPos) const {
|
||||
return sphericalToOverlay(screenToSpherical(screenPos));
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::overlayToScreen(const glm::vec2& overlayPos) const {
|
||||
return sphericalToScreen(overlayToSpherical(overlayPos));
|
||||
}
|
||||
|
|
|
@ -13,16 +13,8 @@
|
|||
#define hifi_ApplicationOverlay_h
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
class Camera;
|
||||
class Overlays;
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
const float MAGNIFY_WIDTH = 220.0f;
|
||||
const float MAGNIFY_HEIGHT = 100.0f;
|
||||
const float MAGNIFY_MULT = 2.0f;
|
||||
|
||||
const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
// Handles the drawing of the overlays to the screen
|
||||
// TODO, move divide up the rendering, displaying and input handling
|
||||
// facilities of this class
|
||||
|
@ -33,83 +25,19 @@ public:
|
|||
~ApplicationOverlay();
|
||||
|
||||
void renderOverlay(RenderArgs* renderArgs);
|
||||
void displayOverlayTexture(RenderArgs* renderArgs);
|
||||
void displayOverlayTextureStereo(RenderArgs* renderArgs, Camera& whichCamera, float aspectRatio, float fov);
|
||||
void displayOverlayTextureHmd(RenderArgs* renderArgs, Camera& whichCamera);
|
||||
|
||||
QPoint getPalmClickLocation(const PalmData *palm) const;
|
||||
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
|
||||
|
||||
bool hasMagnifier() const { return _magnifier; }
|
||||
void toggleMagnifier() { _magnifier = !_magnifier; }
|
||||
|
||||
float getHmdUIAngularSize() const { return _hmdUIAngularSize; }
|
||||
void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; }
|
||||
|
||||
// Converter from one frame of reference to another.
|
||||
// Frame of reference:
|
||||
// Direction: Ray that represents the spherical values
|
||||
// Screen: Position on the screen (x,y)
|
||||
// Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch)
|
||||
// Overlay: Position on the overlay (x,y)
|
||||
// (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen.
|
||||
// This allows for picking outside of the screen projection in 3D.
|
||||
glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const;
|
||||
glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const;
|
||||
glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const;
|
||||
glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const;
|
||||
void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const;
|
||||
GLuint getOverlayTexture();
|
||||
|
||||
static glm::vec2 directionToSpherical(const glm::vec3 & direction);
|
||||
static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos);
|
||||
static glm::vec2 screenToSpherical(const glm::vec2 & screenPos);
|
||||
static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos);
|
||||
|
||||
private:
|
||||
void buildHemiVertices(const float fov, const float aspectRatio, const int slices, const int stacks);
|
||||
void drawSphereSection(gpu::Batch& batch);
|
||||
float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE;
|
||||
QOpenGLFramebufferObject* _framebufferObject;
|
||||
|
||||
void renderPointers();
|
||||
void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
|
||||
|
||||
void renderControllerPointers();
|
||||
void renderPointersOculus();
|
||||
|
||||
void renderAudioMeter();
|
||||
void renderCameraToggle();
|
||||
void renderStatsAndLogs();
|
||||
void renderDomainConnectionStatusBorder();
|
||||
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
|
||||
|
||||
void buildFramebufferObject();
|
||||
|
||||
float _textureFov;
|
||||
float _textureAspectRatio;
|
||||
int _hemiVerticesID{ GeometryCache::UNKNOWN_ID };
|
||||
|
||||
|
||||
enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES };
|
||||
bool _reticleActive[NUMBER_OF_RETICLES];
|
||||
QPoint _reticlePosition[NUMBER_OF_RETICLES];
|
||||
bool _magActive[NUMBER_OF_RETICLES];
|
||||
float _magSizeMult[NUMBER_OF_RETICLES];
|
||||
quint64 _lastMouseMove;
|
||||
bool _magnifier;
|
||||
|
||||
float _alpha = 1.0f;
|
||||
float _oculusUIRadius;
|
||||
float _trailingAudioLoudness;
|
||||
|
||||
|
||||
QMap<uint16_t, gpu::TexturePointer> _cursors;
|
||||
|
||||
GLuint _newUiTexture{ 0 };
|
||||
GLuint _uiTexture{ 0 };
|
||||
|
||||
int _reticleQuad;
|
||||
int _magnifierQuad;
|
||||
int _audioRedQuad;
|
||||
int _audioGreenQuad;
|
||||
int _audioBlueQuad;
|
||||
|
@ -119,15 +47,7 @@ private:
|
|||
int _previousBorderWidth;
|
||||
int _previousBorderHeight;
|
||||
|
||||
glm::vec3 _previousMagnifierBottomLeft;
|
||||
glm::vec3 _previousMagnifierBottomRight;
|
||||
glm::vec3 _previousMagnifierTopLeft;
|
||||
glm::vec3 _previousMagnifierTopRight;
|
||||
|
||||
gpu::PipelinePointer _standardDrawPipeline;
|
||||
|
||||
gpu::PipelinePointer getDrawPipeline();
|
||||
|
||||
QOpenGLFramebufferObject* _framebufferObject;
|
||||
};
|
||||
|
||||
#endif // hifi_ApplicationOverlay_h
|
||||
|
|
|
@ -175,7 +175,7 @@ void PreferencesDialog::loadPreferences() {
|
|||
|
||||
ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond());
|
||||
|
||||
ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getHmdUIAngularSize());
|
||||
ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize());
|
||||
|
||||
SixenseManager& sixense = SixenseManager::getInstance();
|
||||
ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());
|
||||
|
@ -239,7 +239,7 @@ void PreferencesDialog::savePreferences() {
|
|||
|
||||
qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value());
|
||||
|
||||
qApp->getApplicationOverlay().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
|
||||
qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
|
||||
|
||||
SixenseManager& sixense = SixenseManager::getInstance();
|
||||
sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
|
||||
|
|
|
@ -258,7 +258,7 @@ void Overlays::deleteOverlay(unsigned int id) {
|
|||
unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||
glm::vec2 pointCopy = point;
|
||||
if (qApp->isHMDMode()) {
|
||||
pointCopy = qApp->getApplicationOverlay().screenToOverlay(point);
|
||||
pointCopy = qApp->getApplicationCompositor().screenToOverlay(point);
|
||||
}
|
||||
|
||||
QReadLocker lock(&_lock);
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include "RenderUtilsLogging.h"
|
||||
#include "GeometryCache.h"
|
||||
|
||||
#include "standardTransformPNTC_vert.h"
|
||||
#include "standardDrawTexture_frag.h"
|
||||
|
||||
//#define WANT_DEBUG
|
||||
|
||||
const int GeometryCache::UNKNOWN_ID = -1;
|
||||
|
@ -1817,6 +1820,23 @@ QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QS
|
|||
return geometry.staticCast<Resource>();
|
||||
}
|
||||
|
||||
void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch) {
|
||||
if (!_standardDrawPipeline) {
|
||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
// enable decal blend
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
|
||||
_standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
batch.setPipeline(_standardDrawPipeline);
|
||||
}
|
||||
|
||||
const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
|
||||
|
||||
NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,
|
||||
|
@ -2385,3 +2405,4 @@ int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -252,6 +252,9 @@ public:
|
|||
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
|
||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
||||
|
||||
/// Set a batch to the simple pipeline, returning the previous pipeline
|
||||
void useSimpleDrawPipeline(gpu::Batch& batch);
|
||||
|
||||
protected:
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
|
@ -269,6 +272,7 @@ private:
|
|||
int vertexSize;
|
||||
};
|
||||
|
||||
gpu::PipelinePointer _standardDrawPipeline;
|
||||
QHash<float, gpu::BufferPointer> _cubeVerticies;
|
||||
QHash<Vec2Pair, gpu::BufferPointer> _cubeColors;
|
||||
gpu::BufferPointer _wireCubeIndexBuffer;
|
||||
|
@ -276,7 +280,7 @@ private:
|
|||
QHash<float, gpu::BufferPointer> _solidCubeVertices;
|
||||
QHash<Vec2Pair, gpu::BufferPointer> _solidCubeColors;
|
||||
gpu::BufferPointer _solidCubeIndexBuffer;
|
||||
|
||||
|
||||
class BatchItemDetails {
|
||||
public:
|
||||
static int population;
|
||||
|
|
Loading…
Reference in a new issue