//// ApplicationOverlay.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 <QOpenGLFramebufferObject>#include <PerfStat.h> #include "Application.h"#include "ApplicationOverlay.h"#include "devices/OculusManager.h" #include "ui/Stats.h" // Used to fade the UIconst float FADE_SPEED = 0.08f;// Used to animate the magnification windowsconst float MAG_SPEED = 0.08f; const quint64 MSECS_TO_USECS = 1000ULL; // Fast helper functionsinline float max(float a, float b) { return (a > b) ? a : b;} inline float min(float a, float b) { return (a < b) ? a : b;} ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL), _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE), _alpha(1.0f), _oculusuiRadius(1.0f), _crosshairTexture(0) { memset(_reticleActive, 0, sizeof(_reticleActive)); memset(_magActive, 0, sizeof(_reticleActive)); memset(_magSizeMult, 0, sizeof(_magSizeMult));} ApplicationOverlay::~ApplicationOverlay() { if (_framebufferObject != NULL) { delete _framebufferObject; }} 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 CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; // Renders the overlays either to a texture or to the screenvoid ApplicationOverlay::renderOverlay(bool renderToTexture) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); _textureFov = Menu::getInstance()->getOculusUIAngularSize() * RADIANS_PER_DEGREE; Application* application = Application::getInstance(); Overlays& overlays = application->getOverlays(); GLCanvas* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); //Handle fading and deactivation/activation of UI if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { _alpha += FADE_SPEED; if (_alpha > 1.0f) { _alpha = 1.0f; } } else { _alpha -= FADE_SPEED; if (_alpha <= 0.0f) { _alpha = 0.0f; } } if (renderToTexture) { getFramebufferObject()->bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Render 2D overlay glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, glWidget->width(), glWidget->height(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); renderAudioMeter(); if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { myAvatar->renderHeadMouse(glWidget->width(), glWidget->height()); } renderStatsAndLogs(); // give external parties a change to hook in emit application->renderingOverlay(); overlays.render2D(); renderPointers(); renderDomainConnectionStatusBorder(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); if (renderToTexture) { getFramebufferObject()->release(); }} // Draws the FBO texture for the screenvoid ApplicationOverlay::displayOverlayTexture() { if (_alpha == 0.0f) { return; } Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBegin(GL_QUADS); glColor4f(1.0f, 1.0f, 1.0f, _alpha); glTexCoord2f(0, 0); glVertex2i(0, glWidget->getDeviceHeight()); glTexCoord2f(1, 0); glVertex2i(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); glTexCoord2f(1, 1); glVertex2i(glWidget->getDeviceWidth(), 0); glTexCoord2f(0, 1); glVertex2i(0, 0); glEnd(); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glPopMatrix(); glDisable(GL_TEXTURE_2D);} void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); //invert y direction y = 1.0 - y; //Get position on hemisphere UI x = sin((x - 0.5f) * _textureFov); y = sin((y - 0.5f) * _textureFov); float dist = sqrt(x * x + y * y); float z = -sqrt(1.0f - dist * dist); glm::vec3 relativePosition = myAvatar->getDefaultEyePosition() + glm::normalize(myAvatar->getOrientation() * glm::vec3(x, y, z)); //Rotate the UI pick ray by the avatar orientation direction = glm::normalize(relativePosition - Application::getInstance()->getCamera()->getPosition());} // Calculates the click location on the screen by taking into account any// opened magnification windows.void ApplicationOverlay::getClickLocation(int &x, int &y) const { int dx; int dy; const float xRange = MAGNIFY_WIDTH * MAGNIFY_MULT / 2.0f; const float yRange = MAGNIFY_HEIGHT * MAGNIFY_MULT / 2.0f; //Loop through all magnification windows for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { if (_magActive[i]) { dx = x - _magX[i]; dy = y - _magY[i]; //Check to see if they clicked inside a mag window if (abs(dx) <= xRange && abs(dy) <= yRange) { //Move the click to the actual UI location by inverting the magnification x = dx / MAGNIFY_MULT + _magX[i]; y = dy / MAGNIFY_MULT + _magY[i]; return; } } }} //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 collisionbool 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; }} //Caculate the click location using one of the sixense controllers. Scale is not appliedQPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); glm::vec3 eyePos = myAvatar->getHead()->getEyePosition(); glm::quat orientation = glm::inverse(myAvatar->getOrientation()); glm::vec3 dir = orientation * glm::normalize(application->getCamera()->getPosition() - tip); //direction of ray goes towards camera glm::vec3 tipPos = orientation * (tip - eyePos); QPoint rv; if (OculusManager::isConnected()) { float t; //We back the ray up by dir to ensure that it will not start inside the UI. glm::vec3 adjustedPos = tipPos - dir; //Find intersection of crosshair ray. if (raySphereIntersect(dir, adjustedPos, _oculusuiRadius * myAvatar->getScale(), &t)){ glm::vec3 collisionPos = adjustedPos + dir * t; //Normalize it in case its not a radius of 1 collisionPos = glm::normalize(collisionPos); //If we hit the back hemisphere, mark it as not a collision if (collisionPos.z > 0) { rv.setX(INT_MAX); rv.setY(INT_MAX); } else { float u = asin(collisionPos.x) / (_textureFov)+0.5f; float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f); rv.setX(u * glWidget->width()); rv.setY(v * glWidget->height()); } } else { //if they did not click on the overlay, just set the coords to INT_MAX rv.setX(INT_MAX); rv.setY(INT_MAX); } } else { glm::dmat4 projection; application->getProjectionMatrix(&projection); 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) * glWidget->width()); rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glWidget->height()); } return rv;} //Finds the collision point of a world space raybool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); glm::quat orientation = myAvatar->getOrientation(); glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->getEyePosition()); glm::vec3 relativeDirection = orientation * direction; float t; if (raySphereIntersect(relativeDirection, relativePosition, _oculusuiRadius * myAvatar->getScale(), &t)){ result = position + direction * t; return true; } return false;} // Draws the FBO texture for Oculus rift.void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_alpha == 0.0f) { return; } Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); glMatrixMode(GL_MODELVIEW); glDepthMask(GL_TRUE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.01f); //Update and draw the magnifiers glPushMatrix(); const glm::quat& orientation = myAvatar->getOrientation(); const glm::vec3& position = myAvatar->getDefaultEyePosition(); glm::mat4 rotation = glm::toMat4(orientation); glTranslatef(position.x, position.y, position.z); glMultMatrixf(&rotation[0][0]); for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { if (_magActive[i]) { _magSizeMult[i] += MAG_SPEED; if (_magSizeMult[i] > 1.0f) { _magSizeMult[i] = 1.0f; } } else { _magSizeMult[i] -= MAG_SPEED; if (_magSizeMult[i] < 0.0f) { _magSizeMult[i] = 0.0f; } } if (_magSizeMult[i] > 0.0f) { //Render magnifier, but dont show border for mouse magnifier renderMagnifier(_magX[i], _magY[i], _magSizeMult[i], i != MOUSE); } } glPopMatrix(); glDepthMask(GL_FALSE); glDisable(GL_ALPHA_TEST); glColor4f(1.0f, 1.0f, 1.0f, _alpha); renderTexturedHemisphere(); renderPointersOculus(myAvatar->getDefaultEyePosition()); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_LIGHTING); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } // Draws the FBO texture for 3DTV.void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { if (_alpha == 0.0f) { return; } Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // Transform to world space glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis2 = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); // Translate to the front of the camera glm::vec3 pos = whichCamera.getPosition(); glm::quat rot = myAvatar->getOrientation(); glm::vec3 axis = glm::axis(rot); glTranslatef(pos.x, pos.y, pos.z); glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); glColor4f(1.0f, 1.0f, 1.0f, _alpha); //Render const GLfloat distance = 1.0f; const GLfloat halfQuadHeight = distance * tan(fov); const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; const GLfloat quadWidth = halfQuadWidth * 2.0f; const GLfloat quadHeight = halfQuadHeight * 2.0f; GLfloat x = -halfQuadWidth; GLfloat y = -halfQuadHeight; glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance); glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance); glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance); glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance); glEnd(); if (_crosshairTexture == 0) { _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); } //draw the mouse pointer glBindTexture(GL_TEXTURE_2D, _crosshairTexture); const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; x -= reticleSize / 2.0f;Lines 1–500 of 1262. Load more
// // ApplicationOverlay.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 <QOpenGLFramebufferObject> #include <PerfStat.h> #include "Application.h" #include "ApplicationOverlay.h" #include "devices/OculusManager.h" #include "ui/Stats.h" // Used to fade the UI const float FADE_SPEED = 0.08f; // Used to animate the magnification windows const float MAG_SPEED = 0.08f; const quint64 MSECS_TO_USECS = 1000ULL; // Fast helper functions inline float max(float a, float b) { return (a > b) ? a : b; } inline float min(float a, float b) { return (a < b) ? a : b; } ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL), _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE), _alpha(1.0f), _oculusuiRadius(1.0f), _crosshairTexture(0) { memset(_reticleActive, 0, sizeof(_reticleActive)); memset(_magActive, 0, sizeof(_reticleActive)); memset(_magSizeMult, 0, sizeof(_magSizeMult)); } ApplicationOverlay::~ApplicationOverlay() { if (_framebufferObject != NULL) { delete _framebufferObject; } } 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 CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(bool renderToTexture) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); _textureFov = Menu::getInstance()->getOculusUIAngularSize() * RADIANS_PER_DEGREE; Application* application = Application::getInstance(); Overlays& overlays = application->getOverlays(); GLCanvas* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); //Handle fading and deactivation/activation of UI if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { _alpha += FADE_SPEED; if (_alpha > 1.0f) { _alpha = 1.0f; } } else { _alpha -= FADE_SPEED; if (_alpha <= 0.0f) { _alpha = 0.0f; } } if (renderToTexture) { getFramebufferObject()->bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Render 2D overlay glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, glWidget->width(), glWidget->height(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); renderAudioMeter(); if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { myAvatar->renderHeadMouse(glWidget->width(), glWidget->height()); } renderStatsAndLogs(); // give external parties a change to hook in emit application->renderingOverlay(); overlays.render2D(); renderPointers(); renderDomainConnectionStatusBorder(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); if (renderToTexture) { getFramebufferObject()->release(); } } // Draws the FBO texture for the screen void ApplicationOverlay::displayOverlayTexture() { if (_alpha == 0.0f) { return; } Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBegin(GL_QUADS); glColor4f(1.0f, 1.0f, 1.0f, _alpha); glTexCoord2f(0, 0); glVertex2i(0, glWidget->getDeviceHeight()); glTexCoord2f(1, 0); glVertex2i(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); glTexCoord2f(1, 1); glVertex2i(glWidget->getDeviceWidth(), 0); glTexCoord2f(0, 1); glVertex2i(0, 0); glEnd(); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glPopMatrix(); glDisable(GL_TEXTURE_2D); } void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); //invert y direction y = 1.0 - y; //Get position on hemisphere UI x = sin((x - 0.5f) * _textureFov); y = sin((y - 0.5f) * _textureFov); float dist = sqrt(x * x + y * y); float z = -sqrt(1.0f - dist * dist); glm::vec3 relativePosition = myAvatar->getDefaultEyePosition() + glm::normalize(myAvatar->getOrientation() * glm::vec3(x, y, z)); //Rotate the UI pick ray by the avatar orientation direction = glm::normalize(relativePosition - Application::getInstance()->getCamera()->getPosition()); } // Calculates the click location on the screen by taking into account any // opened magnification windows. void ApplicationOverlay::getClickLocation(int &x, int &y) const { int dx; int dy; const float xRange = MAGNIFY_WIDTH * MAGNIFY_MULT / 2.0f; const float yRange = MAGNIFY_HEIGHT * MAGNIFY_MULT / 2.0f; //Loop through all magnification windows for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { if (_magActive[i]) { dx = x - _magX[i]; dy = y - _magY[i]; //Check to see if they clicked inside a mag window if (abs(dx) <= xRange && abs(dy) <= yRange) { //Move the click to the actual UI location by inverting the magnification x = dx / MAGNIFY_MULT + _magX[i]; y = dy / MAGNIFY_MULT + _magY[i]; return; } } } } //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; } } //Caculate the click location using one of the sixense controllers. Scale is not applied QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); glm::vec3 eyePos = myAvatar->getHead()->getEyePosition(); glm::quat orientation = glm::inverse(myAvatar->getOrientation()); glm::vec3 dir = orientation * glm::normalize(application->getCamera()->getPosition() - tip); //direction of ray goes towards camera glm::vec3 tipPos = orientation * (tip - eyePos); QPoint rv; if (OculusManager::isConnected()) { float t; //We back the ray up by dir to ensure that it will not start inside the UI. glm::vec3 adjustedPos = tipPos - dir; //Find intersection of crosshair ray. if (raySphereIntersect(dir, adjustedPos, _oculusuiRadius * myAvatar->getScale(), &t)){ glm::vec3 collisionPos = adjustedPos + dir * t; //Normalize it in case its not a radius of 1 collisionPos = glm::normalize(collisionPos); //If we hit the back hemisphere, mark it as not a collision if (collisionPos.z > 0) { rv.setX(INT_MAX); rv.setY(INT_MAX); } else { float u = asin(collisionPos.x) / (_textureFov)+0.5f; float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f); rv.setX(u * glWidget->width()); rv.setY(v * glWidget->height()); } } else { //if they did not click on the overlay, just set the coords to INT_MAX rv.setX(INT_MAX); rv.setY(INT_MAX); } } else { glm::dmat4 projection; application->getProjectionMatrix(&projection); 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) * glWidget->width()); rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glWidget->height()); } 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 { Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); glm::quat orientation = myAvatar->getOrientation(); glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->getEyePosition()); glm::vec3 relativeDirection = orientation * direction; float t; if (raySphereIntersect(relativeDirection, relativePosition, _oculusuiRadius * myAvatar->getScale(), &t)){ result = position + direction * t; return true; } return false; } // Draws the FBO texture for Oculus rift. void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_alpha == 0.0f) { return; } Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); glMatrixMode(GL_MODELVIEW); glDepthMask(GL_TRUE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.01f); //Update and draw the magnifiers glPushMatrix(); const glm::quat& orientation = myAvatar->getOrientation(); const glm::vec3& position = myAvatar->getDefaultEyePosition(); glm::mat4 rotation = glm::toMat4(orientation); glTranslatef(position.x, position.y, position.z); glMultMatrixf(&rotation[0][0]); for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { if (_magActive[i]) { _magSizeMult[i] += MAG_SPEED; if (_magSizeMult[i] > 1.0f) { _magSizeMult[i] = 1.0f; } } else { _magSizeMult[i] -= MAG_SPEED; if (_magSizeMult[i] < 0.0f) { _magSizeMult[i] = 0.0f; } } if (_magSizeMult[i] > 0.0f) { //Render magnifier, but dont show border for mouse magnifier renderMagnifier(_magX[i], _magY[i], _magSizeMult[i], i != MOUSE); } } glPopMatrix(); glDepthMask(GL_FALSE); glDisable(GL_ALPHA_TEST); glColor4f(1.0f, 1.0f, 1.0f, _alpha); renderTexturedHemisphere(); renderPointersOculus(myAvatar->getDefaultEyePosition()); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_LIGHTING); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } // Draws the FBO texture for 3DTV. void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { if (_alpha == 0.0f) { return; } Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // Transform to world space glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis2 = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); // Translate to the front of the camera glm::vec3 pos = whichCamera.getPosition(); glm::quat rot = myAvatar->getOrientation(); glm::vec3 axis = glm::axis(rot); glTranslatef(pos.x, pos.y, pos.z); glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); glColor4f(1.0f, 1.0f, 1.0f, _alpha); //Render const GLfloat distance = 1.0f; const GLfloat halfQuadHeight = distance * tan(fov); const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; const GLfloat quadWidth = halfQuadWidth * 2.0f; const GLfloat quadHeight = halfQuadHeight * 2.0f; GLfloat x = -halfQuadWidth; GLfloat y = -halfQuadHeight; glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance); glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance); glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance); glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance); glEnd(); if (_crosshairTexture == 0) { _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); } //draw the mouse pointer glBindTexture(GL_TEXTURE_2D, _crosshairTexture); const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; x -= reticleSize / 2.0f;