Merge pull request #4831 from jherico/plugins_pt2

Display plugins part 2
This commit is contained in:
Brad Hefta-Gaub 2015-05-13 20:40:33 -07:00
commit 77019eafa7
20 changed files with 278 additions and 135 deletions

38
cmake/externals/openvr/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,38 @@
include(ExternalProject)
include(SelectLibraryConfigurations)
set(EXTERNAL_NAME OpenVR)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/ValveSoftware/openvr/archive/0.9.0.zip
URL_MD5 4fbde7759f604aaa68b9c40d628cc34a
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/headers CACHE TYPE INTERNAL)
if (WIN32)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/win32/openvr_api.lib CACHE TYPE INTERNAL)
elseif(APPLE)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx32/libopenvr_api.dylib CACHE TYPE INTERNAL)
elseif(NOT ANDROID)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux32/libopenvr_api.so CACHE TYPE INTERNAL)
endif()

View file

@ -0,0 +1,21 @@
#
# FindLibOVR.cmake
#
# Try to find the LibOVR library to use the Oculus
# Once done this will define
#
# OPENVR_FOUND - system found LibOVR
# OPENVR_INCLUDE_DIRS - the LibOVR include directory
# OPENVR_LIBRARIES - Link this to use LibOVR
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
if (NOT ANDROID)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OPENVR DEFAULT_MSG OPENVR_INCLUDE_DIRS OPENVR_LIBRARIES)
endif()
mark_as_advanced(OPENVR_INCLUDE_DIRS OPENVR_LIBRARIES OPENVR_SEARCH_DIRS)

View file

@ -36,8 +36,22 @@ endif ()
configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h")
configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVersion.h")
macro(GroupSources curdir)
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
foreach(child ${children})
if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${curdir}/${child})
GroupSources(${curdir}/${child})
else()
string(REPLACE "/" "\\" groupname ${curdir})
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
endif()
endforeach()
endmacro()
# grab the implementation and header files from src dirs
file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h")
GroupSources("src")
# Add SpeechRecognizer if on Windows or OS X, otherwise remove
if (WIN32)
@ -58,6 +72,7 @@ find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg W
# grab the ui files in resources/ui
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
source_group("UI Files" FILES ${QT_UI_FILES})
# have qt5 wrap them and generate the appropriate header files
qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")

View file

@ -839,6 +839,11 @@ void Application::paintGL() {
PerformanceWarning warn(showWarnings, "Application::paintGL()");
resizeGL();
{
PerformanceTimer perfTimer("renderOverlay");
_applicationOverlay.renderOverlay();
}
glEnable(GL_LINE_SMOOTH);
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
@ -921,13 +926,9 @@ void Application::paintGL() {
glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,
0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
{
PerformanceTimer perfTimer("renderOverlay");
_applicationOverlay.renderOverlay();
_applicationOverlay.displayOverlayTexture();
}
_applicationOverlay.displayOverlayTexture();
}
if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
@ -3078,7 +3079,11 @@ PickRay Application::computePickRay(float x, float y) const {
if (isHMDMode()) {
ApplicationOverlay::computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
} else {
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
if (activeRenderingThread) {
getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
} else {
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
}
}
return result;
}
@ -3133,6 +3138,16 @@ ViewFrustum* Application::getDisplayViewFrustum() {
return &_displayViewFrustum;
}
const ViewFrustum* Application::getDisplayViewFrustum() const {
#ifdef DEBUG
if (QThread::currentThread() != activeRenderingThread) {
// FIXME, should this be an assert?
qWarning() << "Calling Application::getDisplayViewFrustum() from outside the active rendering thread or outside rendering, did you mean Application::getViewFrustum()?";
}
#endif
return &_displayViewFrustum;
}
void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs::RenderSide renderSide) {
activeRenderingThread = QThread::currentThread();
PROFILE_RANGE(__FUNCTION__);

View file

@ -205,6 +205,7 @@ public:
// which might be different from the viewFrustum, i.e. shadowmap
// passes, mirror window passes, etc
ViewFrustum* getDisplayViewFrustum();
const ViewFrustum* getDisplayViewFrustum() const;
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
EntityTreeRenderer* getEntities() { return &_entities; }

View file

@ -520,12 +520,6 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
return;
}
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
// We only need to render the overlays to a texture once, then we just render the texture on the hemisphere
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
applicationOverlay.renderOverlay();
//Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
DependencyManager::get<GlowEffect>()->prepare();
@ -614,9 +608,8 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
//glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z);
_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].HmdToEyeViewOffset.x, -_eyeRenderDesc[eye].HmdToEyeViewOffset.y, -_eyeRenderDesc[eye].HmdToEyeViewOffset.z));
Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO);
applicationOverlay.displayOverlayTextureHmd(*_camera);
qApp->displaySide(*_camera, false, RenderArgs::MONO);
qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera);
});
_activeEye = ovrEye_Count;

View file

@ -92,74 +92,40 @@ void TV3DManager::display(Camera& whichCamera) {
int portalW = deviceSize.width() / 2;
int portalH = deviceSize.height();
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
// We only need to render the overlays to a texture once, then we just render the texture as a quad
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
applicationOverlay.renderOverlay();
DependencyManager::get<GlowEffect>()->prepare();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
// render left side view
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
Camera eyeCamera;
eyeCamera.setRotation(whichCamera.getRotation());
eyeCamera.setPosition(whichCamera.getPosition());
glEnable(GL_SCISSOR_TEST);
glPushMatrix();
{
_activeEye = &_leftEye;
forEachEye([&](eyeFrustum& eye){
_activeEye = &eye;
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // reset projection matrix
glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum
glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum
GLfloat p[4][4];
// Really?
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
float cotangent = p[1][1];
GLfloat fov = atan(1.0f / cotangent);
glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
applicationOverlay.displayOverlayTextureStereo(whichCamera, _aspect, fov);
qApp->displaySide(eyeCamera, false, RenderArgs::MONO);
qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
_activeEye = NULL;
}
glPopMatrix();
glDisable(GL_SCISSOR_TEST);
// render right side view
portalX = deviceSize.width() / 2;
glEnable(GL_SCISSOR_TEST);
// render left side view
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
glPushMatrix();
{
_activeEye = &_rightEye;
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // reset projection matrix
glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set right view frustum
GLfloat p[4][4];
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
GLfloat cotangent = p[1][1];
GLfloat fov = atan(1.0f / cotangent);
glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
applicationOverlay.displayOverlayTextureStereo(whichCamera, _aspect, fov);
_activeEye = NULL;
}
}, [&]{
// render right side view
portalX = deviceSize.width() / 2;
});
glPopMatrix();
glDisable(GL_SCISSOR_TEST);
@ -167,11 +133,13 @@ void TV3DManager::display(Camera& whichCamera) {
auto fboSize = finalFbo->getSize();
// Get the ACTUAL device size for the BLIT
deviceSize = qApp->getDeviceSize();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fboSize.x, fboSize.y,
0, 0, deviceSize.width(), deviceSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// reset the viewport to how we started
glViewport(0, 0, deviceSize.width(), deviceSize.height());

View file

@ -44,6 +44,20 @@ private:
static eyeFrustum _leftEye;
static eyeFrustum _rightEye;
static eyeFrustum* _activeEye;
// The first function is the code executed for each eye
// while the second is code to be executed between the two eyes.
// The use case here is to modify the output viewport coordinates
// for the new eye.
// FIXME: we'd like to have a default empty lambda for the second parameter,
// but gcc 4.8.1 complains about it due to a bug. See
// http://stackoverflow.com/questions/25490662/lambda-as-default-parameter-to-a-member-function-template
template<typename F, typename FF>
static void forEachEye(F f, FF ff) {
f(_leftEye);
ff();
f(_rightEye);
}
};
#endif // hifi_TV3DManager_h

View file

@ -15,7 +15,6 @@
#include <Application.h>
#include <avatar/AvatarManager.h>
#include <devices/OculusManager.h>
#include <LODManager.h>
#include "BillboardOverlay.h"
@ -292,8 +291,8 @@ void Overlays::deleteOverlay(unsigned int id) {
unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
glm::vec2 pointCopy = point;
if (OculusManager::isConnected()) {
pointCopy = Application::getInstance()->getApplicationOverlay().screenToOverlay(point);
if (qApp->isHMDMode()) {
pointCopy = qApp->getApplicationOverlay().screenToOverlay(point);
}
QReadLocker lock(&_lock);

View file

@ -10,6 +10,7 @@
//
#include "GPULogging.h"
#include "GLBackendShared.h"
#include <glm/gtc/type_ptr.hpp>
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
{
@ -521,3 +522,29 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
(void) CHECK_GL_ERROR();
}
void GLBackend::loadMatrix(GLenum target, const glm::mat4 & m) {
glMatrixMode(target);
glLoadMatrixf(glm::value_ptr(m));
}
void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) {
switch (target) {
case GL_MODELVIEW_MATRIX:
case GL_PROJECTION_MATRIX:
break;
// Lazy cheating
case GL_MODELVIEW:
target = GL_MODELVIEW_MATRIX;
break;
case GL_PROJECTION:
target = GL_PROJECTION_MATRIX;
break;
default:
Q_ASSERT_X(false, "GLBackend::fetchMatrix", "Bad matrix target");
}
glGetFloatv(target, glm::value_ptr(m));
}

View file

@ -79,6 +79,9 @@ public:
static GLShader* syncGPUObject(const Shader& shader);
static GLuint getShaderID(const ShaderPointer& shader);
static void loadMatrix(GLenum target, const glm::mat4 & m);
static void fetchMatrix(GLenum target, glm::mat4 & m);
class GLState : public GPUObject {
public:
class Command {

View file

@ -142,22 +142,12 @@ gpu::FramebufferPointer GlowEffect::render() {
gpu::FramebufferPointer destFBO = textureCache->getSecondaryFramebuffer();
if (!_enabled || _isEmpty) {
// copy the primary to the screen
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO);
glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(),
0, 0, framebufferSize.width(), framebufferSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
} else {
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
glViewport(0, 0, framebufferSize.width(), framebufferSize.height());
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
renderFullscreenQuad();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO);
glBlitFramebuffer(
0, 0, framebufferSize.width(), framebufferSize.height(),
0, 0, framebufferSize.width(), framebufferSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
} else {
// diffuse into the secondary/tertiary (alternating between frames)
auto oldDiffusedFBO =

View file

@ -1 +0,0 @@
#include "MatrixStack.h"

View file

@ -0,0 +1,43 @@
//
// OffscreenGlCanvas.cpp
// interface/src/renderer
//
// Created by Bradley Austin Davis on 2014/04/09.
// 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
//
#include "OffscreenGlContext.h"
OffscreenGlContext::OffscreenGlContext() {
}
void OffscreenGlContext::create(QOpenGLContext * sharedContext) {
QSurfaceFormat format;
format.setDepthBufferSize(16);
format.setStencilBufferSize(8);
format.setMajorVersion(4);
format.setMinorVersion(1);
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
_context.setFormat(format);
if (nullptr != sharedContext) {
_context.setShareContext(sharedContext);
}
_context.create();
_offscreenSurface.setFormat(_context.format());
_offscreenSurface.create();
}
bool OffscreenGlContext::makeCurrent() {
return _context.makeCurrent(&_offscreenSurface);
}
void OffscreenGlContext::doneCurrent() {
_context.doneCurrent();
}

View file

@ -0,0 +1,33 @@
//
// OffscreenGlCanvas.h
// interface/src/renderer
//
// Created by Bradley Austin Davis on 2014/04/09.
// 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
//
#pragma once
#ifndef hifi_OffscreenGlContext_h
#define hifi_OffscreenGlContext_h
#include <QOpenGLContext>
#include <QOffscreenSurface>
class OffscreenGlContext : public QObject {
public:
OffscreenGlContext();
void create(QOpenGLContext * sharedContext = nullptr);
bool makeCurrent();
void doneCurrent();
QOpenGLContext * getContext() {
return &_context;
}
protected:
QOpenGLContext _context;
QOffscreenSurface _offscreenSurface;
};
#endif // hifi_OffscreenGlCanvas_h

View file

@ -12,6 +12,8 @@
#ifndef hifi_RenderUtil_h
#define hifi_RenderUtil_h
#include <MatrixStack.h>
/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax).
void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f);

View file

@ -548,18 +548,23 @@ float TextRenderer::draw(float x, float y, const QString & str,
float scale = (_pointSize / DEFAULT_POINT_SIZE) * 0.25f;
glm::vec2 result;
MatrixStack::withGlMatrices([&] {
MatrixStack::withPushAll([&] {
MatrixStack & mv = MatrixStack::modelview();
// scale the modelview into font units
// FIXME migrate the constant scale factor into the geometry of the
// fonts so we don't have to flip the Y axis here and don't have to
// scale at all.
mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale));
// The font does all the OpenGL work
if (_font) {
result = _font->drawString(x, y, str, actualColor, _effectType, bounds / scale);
}
});
MatrixStack & pr = MatrixStack::projection();
gpu::GLBackend::fetchMatrix(GL_MODELVIEW_MATRIX, mv.top());
gpu::GLBackend::fetchMatrix(GL_PROJECTION_MATRIX, pr.top());
// scale the modelview into font units
// FIXME migrate the constant scale factor into the geometry of the
// fonts so we don't have to flip the Y axis here and don't have to
// scale at all.
mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale));
// The font does all the OpenGL work
if (_font) {
result = _font->drawString(x, y, str, actualColor, _effectType, bounds / scale);
}
});
return result.x;
}

View file

@ -24,7 +24,7 @@ MenuItemProperties::MenuItemProperties() :
afterItem(""),
isCheckable(false),
isChecked(false),
isSeparator(false)
isSeparator(false)
{
};

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis
// Copyright 2013 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 "MatrixStack.h"

View file

@ -1,21 +1,10 @@
/************************************************************************************
Authors : Bradley Austin Davis <bdavis@saintandreas.org>
Copyright : Copyright Brad Davis. All Rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************************/
//
// Created by Bradley Austin Davis
// Copyright 2013 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
//
#pragma once
#include <glm/glm.hpp>
@ -26,10 +15,6 @@
#include <glm/gtc/matrix_transform.hpp>
#include <stack>
#include <gpu/GPUConfig.h>
class MatrixStack : public std::stack<glm::mat4> {
public:
@ -183,22 +168,5 @@ public:
stack2.withPush(f);
});
}
template <typename Function>
static void withGlMatrices(Function f) {
// Push the current stack, and then copy the values out of OpenGL
withPushAll([&] {
// Fetch the current matrices out of GL stack
// FIXME, eliminate the usage of deprecated GL
MatrixStack & mv = MatrixStack::modelview();
MatrixStack & pr = MatrixStack::projection();
glm::mat4 & mvm = mv.top();
glGetFloatv(GL_MODELVIEW_MATRIX, &(mvm[0][0]));
glm::mat4 & prm = pr.top();
glGetFloatv(GL_PROJECTION_MATRIX, &(prm[0][0]));
f();
});
}
};