Working on display plugins

This commit is contained in:
Brad Davis 2015-06-05 00:00:57 -07:00
parent edfb1305af
commit 1b7efe9a02
25 changed files with 430 additions and 269 deletions

View file

@ -90,6 +90,7 @@
#include <UserActivityLogger.h>
#include <UUID.h>
#include <VrMenu.h>
#include <ui/ApplicationOverlayCompositor.h>
#include "Application.h"
#include "AudioClient.h"
@ -101,6 +102,7 @@
#include "Util.h"
#include "InterfaceLogging.h"
#include "GlWindow.h"
#include "avatar/AvatarManager.h"
#include "audio/AudioToolBox.h"
@ -506,29 +508,39 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
ResourceCache::setRequestLimit(3);
_window->setCentralWidget(new QWidget());
_offscreenContext->create();
_offscreenContext->makeCurrent();
_glWindow = new GlWindow(_offscreenContext->getContext());
QWidget* container = QWidget::createWindowContainer(_glWindow);
container->setFocusPolicy(Qt::StrongFocus);
_window->setCentralWidget(container);
_window->restoreGeometry();
_window->setVisible(true);
container->setFocus();
_offscreenContext->makeCurrent();
initializeGL();
// initialization continues in initializeGL when OpenGL context is ready
_menuBarHeight = Menu::getInstance()->height();
#if 0
_fullscreenMenuWidget->setParent(_glWidget);
#endif
_menuBarHeight = Menu::getInstance()->height();
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
setFullscreen(true); // Initialize menu bar show/hide
}
#endif
_toolWindow = new ToolWindow();
_toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
_toolWindow->setWindowTitle("Tools");
_offscreenContext->create();
_compositor = CompositorPtr(new ApplicationOverlayCompositor());
_offscreenContext->makeCurrent();
initializeGL();
// initialization continues in initializeGL when OpenGL context is ready
// Tell our entity edit sender about our known jurisdictions
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
@ -949,15 +961,16 @@ void Application::paintGL() {
// has completed before we start trying to read from it in another context. However
// once we have multi-threaded rendering, this will almost certainly be critical,
// but may be better handled with a fence object
glFinish();
// glFinish();
_offscreenContext->doneCurrent();
Q_ASSERT(!QOpenGLContext::currentContext());
displayPlugin->preDisplay();
displayPlugin->display(gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)), finalFbo->getSize(),
_applicationOverlay.getOverlayTexture(), getCanvasSize());
GLuint finalTexture = _compositor->composite(displayPlugin,
gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)), finalFbo->getSize(),
_applicationOverlay.getOverlayTexture(), getCanvasSize());
displayPlugin->preDisplay();
displayPlugin->display(finalTexture, finalFbo->getSize());
displayPlugin->finishFrame();
Q_ASSERT(!QOpenGLContext::currentContext());
_offscreenContext->makeCurrent();
@ -1427,7 +1440,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
return;
}
#if 0
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
// Show/hide menu bar in fullscreen
if (event->globalY() > _menuBarHeight) {
@ -1438,6 +1451,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
Menu::getInstance()->setFixedHeight(_menuBarHeight);
}
}
#endif
_entities.mouseMoveEvent(event, deviceID);
@ -1764,6 +1778,7 @@ void Application::idle() {
emit checkBackgroundDownloads();
}
#if 0
void Application::setFullscreen(bool fullscreen) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen) != fullscreen) {
Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen);
@ -1822,7 +1837,6 @@ void Application::setFullscreen(bool fullscreen) {
}
}
#if 0
void Application::setEnable3DTVMode(bool enable3DTVMode) {
resizeGL();
}
@ -3006,8 +3020,11 @@ PickRay Application::computePickRay(float x, float y) const {
if (isHMDMode()) {
getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
} else {
auto frustum = activeRenderingThread ? getDisplayViewFrustum() : getViewFrustum();
frustum->computePickRay(x, y, result.origin, result.direction);
if (QThread::currentThread() == activeRenderingThread) {
getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
} else {
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
}
}
return result;
}
@ -3214,7 +3231,7 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
skybox = skyStage->getSkybox();
if (skybox) {
gpu::Batch batch;
model::Skybox::render(batch, _viewFrustum, *skybox);
model::Skybox::render(batch, _displayViewFrustum, *skybox);
gpu::GLBackend::renderBatch(batch);
glUseProgram(0);
@ -4656,6 +4673,6 @@ void Application::addMenuItem(const QString& path, std::function<void()> onClick
}
QMainWindow* Application::getAppMainWindow() {
return _window;
GlWindow* Application::getVisibleWindow() {
return _glWindow;
}

View file

@ -48,7 +48,6 @@
#include "DatagramProcessor.h"
#include "Environment.h"
#include "FileLogger.h"
#include "GLCanvas.h"
#include "Menu.h"
#include "PacketHeaders.h"
#include "Physics.h"
@ -91,6 +90,9 @@ class MainWindow;
class Node;
class ProgramObject;
class ScriptEngine;
class GlWindow;
class ApplicationOverlayCompositor;
using CompositorPtr = std::shared_ptr<ApplicationOverlayCompositor>;
static const float NODE_ADDED_RED = 0.0f;
static const float NODE_ADDED_GREEN = 1.0f;
@ -137,6 +139,7 @@ class Application;
typedef bool (Application::* AcceptURLMethod)(const QString &);
class Application : public QApplication, public AbstractViewStateInterface, AbstractScriptingServicesInterface, PluginContainer {
Q_OBJECT
@ -299,7 +302,7 @@ public:
// Plugin container support
virtual void addMenuItem(const QString& path, std::function<void()> onClicked, bool checkable, bool checked, const QString& groupName);
virtual QMainWindow* getAppMainWindow();
virtual GlWindow* getVisibleWindow();
private:
DisplayPlugin * getActiveDisplayPlugin();
@ -446,8 +449,11 @@ private slots:
void connectedToDomain(const QString& hostname);
#if 0
friend class HMDToolsDialog;
void setFullscreen(bool fullscreen);
#endif
void cameraMenuChanged();
void closeMirrorView();
@ -544,6 +550,8 @@ private:
ViewFrustum _shadowViewFrustum;
quint64 _lastQueriedTime;
CompositorPtr _compositor;
float _trailingAudioLoudness;
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
@ -653,6 +661,7 @@ private:
QThread _settingsThread;
QTimer _settingsTimer;
GlWindow* _glWindow{ nullptr };
void checkSkeleton();
QWidget* _fullscreenMenuWidget = new QWidget();

View file

@ -98,9 +98,12 @@ void MainWindow::changeEvent(QEvent* event) {
emit windowShown(true);
}
#if 0
if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen());
}
#endif
} else if (event->type() == QEvent::ActivationChange) {
if (isActiveWindow()) {
emit windowShown(true);

View file

@ -239,6 +239,7 @@ Menu::Menu() {
displayModeGroup->setExclusive(true);
}
#if 0
addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::Fullscreen,
#ifdef Q_OS_MAC
@ -249,6 +250,7 @@ Menu::Menu() {
false,
qApp,
SLOT(setFullscreen(bool)));
#endif
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson,
0, // QML Qt::Key_P,
@ -260,6 +262,7 @@ Menu::Menu() {
0, // QML Qt::Key_H,
false, qApp, SLOT(cameraMenuChanged()));
#if 0
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools,
#ifdef Q_OS_MAC
Qt::META | Qt::Key_H,
@ -269,6 +272,7 @@ Menu::Menu() {
false,
dialogsManager.data(),
SLOT(hmdTools(bool)));
#endif
addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0,
dialogsManager.data(), SLOT(editAttachments()));

View file

@ -194,12 +194,10 @@ namespace MenuOption {
const QString FilterSixense = "Smooth Sixense Movement";
const QString FirstPerson = "First Person";
const QString FrameTimer = "Show Timer";
const QString Fullscreen = "Fullscreen";
const QString FullscreenMirror = "Fullscreen Mirror";
const QString GlowWhenSpeaking = "Glow When Speaking";
const QString NamesAboveHeads = "Names Above Heads";
const QString GoToUser = "Go To User";
const QString HMDTools = "HMD Tools";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";

View file

@ -0,0 +1,209 @@
#include "ApplicationOverlayCompositor.h"
#include <TextureCache.h>
#include <PathUtils.h>
#include <ViewFrustum.h>
#include <MatrixStack.h>
#include <gpu/GLBackend.h>
#define DEFAULT_HMD_UI_ANGULAR_SIZE 72.0f
ApplicationOverlayCompositor::ApplicationOverlayCompositor() {
using namespace oglplus;
auto currentContext = QOpenGLContext::currentContext();
Q_ASSERT(currentContext);
_canvas.create(currentContext);
_canvas.makeCurrent();
Q_ASSERT(0 == glGetError());
currentContext = QOpenGLContext::currentContext();
Q_ASSERT(currentContext);
Context::ClearColor(0, 0, 0, 1);
Q_ASSERT(0 == glGetError());
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
Q_ASSERT(0 == glGetError());
Context::Disable(Capability::Blend);
Q_ASSERT(0 == glGetError());
Context::Disable(Capability::DepthTest);
Q_ASSERT(0 == glGetError());
Context::Disable(Capability::CullFace);
Q_ASSERT(0 == glGetError());
_program = loadDefaultShader();
_plane = loadPlane(_program);
_program = loadDefaultShader();
_plane = loadPlane(_program);
_hmdUiSurface = loadSphereSection(_program, glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE));
_crosshairTexture = DependencyManager::get<TextureCache>()->
getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
}
GLuint ApplicationOverlayCompositor::composite(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
using namespace oglplus;
_canvas.makeCurrent();
if (!_fbo || sceneSize != _fbo->size) {
_fbo = BasicFramebufferWrapperPtr(new BasicFramebufferWrapper());
_fbo->Init(sceneSize);
}
_fbo->Bound(Framebuffer::Target::Draw, [&] {
Context::Clear().ColorBuffer();
if (plugin->isHmd()) {
compositeHmd(plugin, sceneTexture, sceneSize, overlayTexture, overlaySize);
} else if (plugin->isStereo()) {
compositeStereo(plugin, sceneTexture, sceneSize, overlayTexture, overlaySize);
} else {
composite2D(plugin, sceneTexture, sceneSize, overlayTexture, overlaySize);
}
});
GLuint result = GetName(_fbo->color);
_canvas.doneCurrent();
return result;
}
void ApplicationOverlayCompositor::composite2D(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
using namespace oglplus;
const uvec2 size = toGlm(plugin->getDeviceSize());
Q_ASSERT(0 == glGetError());
Context::Viewport(size.x, size.y);
_program->Bind();
Mat4Uniform(*_program, "ModelView").Set(mat4());
Mat4Uniform(*_program, "Projection").Set(mat4());
glBindTexture(GL_TEXTURE_2D, sceneTexture);
_plane->Use();
_plane->Draw();
Context::Enable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, overlayTexture);
_plane->Draw();
Context::Disable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, 0);
// FIXME add the cursor
Q_ASSERT(0 == glGetError());
}
template <typename F>
void sbs_for_each_eye(const uvec2& size, F f) {
QRect r(QPoint(0, 0), QSize(size.x / 2, size.y));
for_each_eye([&](Eye eye) {
oglplus::Context::Viewport(r.x(), r.y(), r.width(), r.height());
f(eye);
}, [&] {
r.moveLeft(r.width());
});
}
void ApplicationOverlayCompositor::compositeStereo(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
using namespace oglplus;
Q_ASSERT(0 == glGetError());
const uvec2 size = sceneSize;
Context::Viewport(size.x, size.y);
_program->Bind();
Mat4Uniform(*_program, "ModelView").Set(mat4());
Mat4Uniform(*_program, "Projection").Set(mat4());
glBindTexture(GL_TEXTURE_2D, sceneTexture);
_plane->Use();
_plane->Draw();
// FIXME the
const float screenAspect = aspect(size);
const GLfloat distance = 1.0f;
const GLfloat halfQuadHeight = distance * tan(DEFAULT_FIELD_OF_VIEW_DEGREES);
const GLfloat halfQuadWidth = halfQuadHeight * screenAspect;
const GLfloat quadWidth = halfQuadWidth * 2.0f;
const GLfloat quadHeight = halfQuadHeight * 2.0f;
vec3 quadSize(quadWidth, quadHeight, 1.0f);
quadSize = vec3(1.0f) / quadSize;
using namespace oglplus;
Context::Enable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, overlayTexture);
mat4 pr = glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), screenAspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP);
Mat4Uniform(*_program, "Projection").Set(pr);
// Position the camera relative to the overlay texture
MatrixStack mv;
mv.translate(vec3(0, 0, -distance)).scale(vec3(0.7f, 0.7f / screenAspect, 1.0f)); // .scale(vec3(quadWidth, quadHeight, 1.0));
sbs_for_each_eye(size, [&](Eye eye) {
mv.withPush([&] {
// translate
mv.top() = plugin->getModelview(eye, mv.top());
Mat4Uniform(*_program, "ModelView").Set(mv.top());
_plane->Draw();
});
});
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glm::vec2 canvasSize = plugin->getCanvasSize();
glm::vec2 mouse = vec2(0); // toGlm(_window->mapFromGlobal(QCursor::pos()));
mouse /= canvasSize;
mouse *= 2.0f;
mouse -= 1.0f;
mouse.y *= -1.0f;
sbs_for_each_eye(size, [&](Eye eye) {
mv.withPush([&] {
// translate
mv.top() = plugin->getModelview(eye, mv.top());
mv.translate(mouse);
//mv.scale(0.05f);
mv.scale(vec3(0.025f, 0.05f, 1.0f));
Mat4Uniform(*_program, "ModelView").Set(mv.top());
_plane->Draw();
});
});
Context::Disable(Capability::Blend);
}
void ApplicationOverlayCompositor::compositeHmd(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
using namespace oglplus;
auto size = sceneSize;
Context::Viewport(size.x, size.y);
glClearColor(0, 0, 0, 0);
Context::Clear().ColorBuffer();
_program->Bind();
Mat4Uniform(*_program, "Projection").Set(mat4());
Mat4Uniform(*_program, "ModelView").Set(mat4());
glBindTexture(GL_TEXTURE_2D, sceneTexture);
_plane->Use();
_plane->Draw();
Context::Enable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, overlayTexture);
for_each_eye([&](Eye eye) {
Context::Viewport(eye == Left ? 0 : size.x / 2, 0, size.x / 2, size.y);
glm::mat4 m = plugin->getProjection(eye, glm::mat4());
Mat4Uniform(*_program, "Projection").Set(m);
Mat4Uniform(*_program, "ModelView").Set(glm::scale(glm::inverse(plugin->getModelview(eye, mat4())), vec3(1)));
_hmdUiSurface->Use();
_hmdUiSurface->Draw();
});
Context::Disable(Capability::Blend);
}

View file

@ -0,0 +1,37 @@
#pragma once
#include <gpu/Texture.h>
#include <display-plugins/DisplayPlugin.h>
#include <display-plugins/OglplusHelpers.h>
#include <OffscreenGlCanvas.h>
class ApplicationOverlayCompositor {
public:
ApplicationOverlayCompositor();
GLuint composite(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize);
private:
OffscreenGlCanvas _canvas;
BasicFramebufferWrapperPtr _fbo;
ProgramPtr _program;
ShapeWrapperPtr _plane;
ShapeWrapperPtr _hmdUiSurface;
gpu::TexturePointer _crosshairTexture;
void composite2D(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize);
void compositeStereo(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize);
void compositeHmd(DisplayPlugin* plugin,
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize);
};
using CompositorPtr = std::shared_ptr<ApplicationOverlayCompositor>;

View file

@ -68,13 +68,12 @@ public:
* OpenGL context
*/
virtual void preDisplay() = 0;
/**
* Sends the scene texture and the overlay texture to the display plugin.
* The plugin is responsible for compositing these and adding rendering of
* additional elements like mouse and hydra pointers as required
* Sends the scene texture to the display plugin.
*/
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) = 0;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) = 0;
/**
* Called by the application immeidately after display. For OpenGL based
* displays, this is the best place to put the buffer swap

View file

@ -7,32 +7,47 @@
//
#include "MainWindowOpenGLDisplayPlugin.h"
#include <GlWindow.h>
#include <QOpenGLContext>
#include <plugins/PluginContainer.h>
#include <QWidget>
#include <QMainWindow>
#include <GlWindow.h>
#include <plugins/PluginContainer.h>
MainWindowOpenGLDisplayPlugin::MainWindowOpenGLDisplayPlugin() {
}
void MainWindowOpenGLDisplayPlugin::activate(PluginContainer * container) {
WindowOpenGLDisplayPlugin::activate(container);
GlWindow* MainWindowOpenGLDisplayPlugin::createWindow(PluginContainer * container) {
return container->getVisibleWindow();
}
void MainWindowOpenGLDisplayPlugin::customizeWindow(PluginContainer * container) {
// Can't set the central widget here, because it seems to mess up the context creation.
}
void MainWindowOpenGLDisplayPlugin::customizeContext(PluginContainer * container) {
WindowOpenGLDisplayPlugin::customizeContext(container);
QWidget* widget = QWidget::createWindowContainer(_window);
auto mainWindow = container->getAppMainWindow();
mainWindow->setCentralWidget(widget);
mainWindow->resize(mainWindow->geometry().size());
_window->resize(_window->geometry().size());
void MainWindowOpenGLDisplayPlugin::destroyWindow() {
_window = nullptr;
}
void MainWindowOpenGLDisplayPlugin::deactivate() {
WindowOpenGLDisplayPlugin::deactivate();
void MainWindowOpenGLDisplayPlugin::display(
GLuint finalTexture, const glm::uvec2& sceneSize) {
OpenGLDisplayPlugin::display(finalTexture, sceneSize);
return;
using namespace oglplus;
glClearColor(0, 1, 0, 1);
uvec2 size = toGlm(getDeviceSize());
Context::Viewport(size.x, size.y);
Context::Clear().ColorBuffer();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, finalTexture);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(-1, -1);
glTexCoord2f(1, 0);
glVertex2f(1, -1);
glTexCoord2f(1, 1);
glVertex2f(1, 1);
glTexCoord2f(0, 1);
glVertex2f(-1, 1);
glEnd();
}

View file

@ -9,17 +9,16 @@
#include "WindowOpenGLDisplayPlugin.h"
class GlWindow;
class QSurfaceFormat;
class QGLWidget;
class MainWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
Q_OBJECT
public:
MainWindowOpenGLDisplayPlugin();
virtual void activate(PluginContainer * container) override;
virtual void deactivate() override;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
protected:
virtual void customizeWindow(PluginContainer * container) override;
virtual void customizeContext(PluginContainer * container) override;
virtual GlWindow* createWindow(PluginContainer * container) override final;
virtual void customizeWindow(PluginContainer * container) override final;
virtual void destroyWindow() override final;
};

View file

@ -49,8 +49,7 @@ QWindow* NullDisplayPlugin::getWindow() const {
void NullDisplayPlugin::preRender() {}
void NullDisplayPlugin::preDisplay() {}
void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {}
void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {}
void NullDisplayPlugin::finishFrame() {}
void NullDisplayPlugin::activate(PluginContainer * container) {}

View file

@ -29,7 +29,6 @@ public:
virtual QWindow* getWindow() const;
virtual void preRender();
virtual void preDisplay();
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize);
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize);
virtual void finishFrame();
};

View file

@ -29,12 +29,12 @@
#include <NumericalConstants.h>
typedef std::shared_ptr<oglplus::Framebuffer> FramebufferPtr;
typedef std::shared_ptr<oglplus::shapes::ShapeWrapper> ShapeWrapperPtr;
typedef std::shared_ptr<oglplus::Buffer> BufferPtr;
typedef std::shared_ptr<oglplus::VertexArray> VertexArrayPtr;
typedef std::shared_ptr<oglplus::Program> ProgramPtr;
typedef oglplus::Uniform<mat4> Mat4Uniform;
using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
using BufferPtr = std::shared_ptr<oglplus::Buffer>;
using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
using ProgramPtr = std::shared_ptr<oglplus::Program>;
using Mat4Uniform = oglplus::Uniform<mat4>;
ProgramPtr loadDefaultShader();
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
@ -56,8 +56,8 @@ template <
struct FramebufferWrapper {
uvec2 size;
oglplus::Framebuffer fbo;
C color{ 0 };
D depth{ 0 };
C color;
D depth;
FramebufferWrapper() {}
@ -112,8 +112,7 @@ protected:
virtual void initDone() = 0;
};
struct BasicFramebufferWrapper : public FramebufferWrapper < oglplus::Texture, oglplus::Renderbuffer > {
struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
protected:
virtual void initDepth() override {
using namespace oglplus;
@ -131,9 +130,9 @@ protected:
.WrapS(TextureWrap::ClampToEdge)
.WrapT(TextureWrap::ClampToEdge)
.Image2D(
0, PixelDataInternalFormat::RGBA8,
size.x, size.y,
0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
0, PixelDataInternalFormat::RGBA8,
size.x, size.y,
0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
);
}
@ -146,4 +145,6 @@ protected:
fbo.Complete(target);
});
}
};
};
using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;

View file

@ -8,11 +8,6 @@
#include "OpenGLDisplayPlugin.h"
#include <QOpenGLContext>
#include <TextureCache.h>
#include <PathUtils.h>
#include <QOpenGLContext>
#include <QCursor>
#include <QCoreApplication>
#include <GLWindow.h>
@ -50,8 +45,6 @@ void OpenGLDisplayPlugin::customizeContext(PluginContainer * container) {
_program = loadDefaultShader();
_plane = loadPlane(_program);
Context::ClearColor(0, 0, 0, 1);
_crosshairTexture = DependencyManager::get<TextureCache>()->
getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
}
void OpenGLDisplayPlugin::activate(PluginContainer * container) {
@ -60,11 +53,11 @@ void OpenGLDisplayPlugin::activate(PluginContainer * container) {
void OpenGLDisplayPlugin::deactivate() {
_timer.stop();
makeCurrent();
Q_ASSERT(0 == glGetError());
_plane.reset();
_program.reset();
_crosshairTexture.reset();
doneCurrent();
}
@ -109,25 +102,15 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
}
void OpenGLDisplayPlugin::display(
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
makeCurrent();
Q_ASSERT(0 == glGetError());
uvec2 size = toGlm(getDeviceSize());
GLuint finalTexture, const glm::uvec2& sceneSize) {
using namespace oglplus;
uvec2 size = toGlm(getDeviceSize());
Context::Viewport(size.x, size.y);
glClearColor(0, 1, 1, 1);
Context::Clear().ColorBuffer().DepthBuffer();
Context::Clear().ColorBuffer();
_program->Bind();
Mat4Uniform(*_program, "ModelView").Set(mat4());
Mat4Uniform(*_program, "Projection").Set(mat4());
glBindTexture(GL_TEXTURE_2D, sceneTexture);
glBindTexture(GL_TEXTURE_2D, finalTexture);
_plane->Use();
_plane->Draw();
Context::Enable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, overlayTexture);
_plane->Draw();
Context::Disable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, 0);
Q_ASSERT(0 == glGetError());
}

View file

@ -9,13 +9,12 @@
#include <QTimer>
#include <gpu/Texture.h>
#include "DisplayPlugin.h"
#include "OglplusHelpers.h"
class GlWindow;
class QOpenGLContext;
class OpenGLDisplayPlugin : public DisplayPlugin {
public:
OpenGLDisplayPlugin();
@ -29,9 +28,7 @@ public:
virtual bool eventFilter(QObject* receiver, QEvent* event) override;
void display(
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) override;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
protected:
@ -43,10 +40,9 @@ protected:
virtual void doneCurrent() = 0;
virtual void swapBuffers() = 0;
QTimer _timer;
ProgramPtr _program;
QTimer _timer;
ProgramPtr _program;
ShapeWrapperPtr _plane;
gpu::TexturePointer _crosshairTexture;
};

View file

@ -17,7 +17,7 @@
#include <QGLContext>
#include <QGLWidget>
#include "plugins/PluginContainer.h"
#if 0
WidgetOpenGLDisplayPlugin::WidgetOpenGLDisplayPlugin() {
}
@ -105,4 +105,5 @@ void WidgetOpenGLDisplayPlugin::removeEventFilter(QObject* filter) {
QWindow* WidgetOpenGLDisplayPlugin::getWindow() const {
return _widget->windowHandle();
}
}
#endif

View file

@ -42,7 +42,7 @@ void WindowOpenGLDisplayPlugin::initSurfaceFormat(QSurfaceFormat& format) {
void WindowOpenGLDisplayPlugin::activate(PluginContainer * container) {
OpenGLDisplayPlugin::activate(container);
_window = new GlWindow(QOpenGLContext::currentContext());
_window = createWindow(container);
QSurfaceFormat format;
initSurfaceFormat(format);
@ -57,6 +57,14 @@ void WindowOpenGLDisplayPlugin::activate(PluginContainer * container) {
void WindowOpenGLDisplayPlugin::deactivate() {
OpenGLDisplayPlugin::deactivate();
destroyWindow();
}
GlWindow* WindowOpenGLDisplayPlugin::createWindow(PluginContainer * container) {
return new GlWindow(QOpenGLContext::currentContext());
}
void WindowOpenGLDisplayPlugin::destroyWindow() {
_window->deleteLater();
_window = nullptr;
}
@ -87,4 +95,4 @@ void WindowOpenGLDisplayPlugin::removeEventFilter(QObject* filter) {
QWindow* WindowOpenGLDisplayPlugin::getWindow() const {
return _window;
}
}

View file

@ -28,10 +28,14 @@ public:
virtual void removeEventFilter(QObject* filter) override;
protected:
virtual GlWindow* createWindow(PluginContainer * container);
virtual void customizeWindow(PluginContainer * container) = 0;
virtual void destroyWindow();
virtual void makeCurrent() override;
virtual void doneCurrent() override;
virtual void swapBuffers() override;
virtual void customizeWindow(PluginContainer * container) = 0;
virtual void initSurfaceFormat(QSurfaceFormat& format);
GlWindow* _window{ nullptr };

View file

@ -30,13 +30,6 @@
#include "../OglplusHelpers.h"
#define DEFAULT_HMD_UI_ANGULAR_SIZE 72.0f
using oglplus::Framebuffer;
using oglplus::DefaultFramebuffer;
// A base class for FBO wrappers that need to use the Oculus C
// API to manage textures via ovrHmd_CreateSwapTextureSetGL,
@ -44,7 +37,10 @@ using oglplus::DefaultFramebuffer;
template <typename C>
struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> {
ovrHmd hmd;
RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {};
RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {
color = 0;
depth = 0;
};
void Resize(const uvec2 & size) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
@ -181,6 +177,7 @@ void OculusWin32DisplayPlugin::activate(PluginContainer * container) {
Q_ASSERT(false);
qFatal("Failed to acquire HMD");
}
// Parent class relies on our _hmd intialization, so it must come after that.
ovrLayerEyeFov& sceneLayer = getSceneLayer();
memset(&sceneLayer, 0, sizeof(ovrLayerEyeFov));
@ -200,7 +197,6 @@ void OculusWin32DisplayPlugin::activate(PluginContainer * container) {
//uiLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft | ovrLayerFlag_HighQuality;
//uiLayer.QuadPoseCenter.Orientation = { 0, 0, 0, 1 };
//uiLayer.QuadPoseCenter.Position = { 0, 0, -1 };
OculusBaseDisplayPlugin::activate(container);
}
@ -209,9 +205,6 @@ void OculusWin32DisplayPlugin::customizeContext(PluginContainer * container) {
//_texture = DependencyManager::get<TextureCache>()->
// getImageTexture(PathUtils::resourcesPath() + "/images/cube_texture.png");
_uiSurface = loadSphereSection(_program, glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE), aspect(getCanvasSize()));
uvec2 mirrorSize = toGlm(_window->geometry().size());
_mirrorFbo = MirrorFboPtr(new MirrorFramebufferWrapper(_hmd));
_mirrorFbo->Init(mirrorSize);
@ -233,7 +226,6 @@ void OculusWin32DisplayPlugin::deactivate() {
makeCurrent();
_sceneFbo.reset();
_mirrorFbo.reset();
_uiSurface.reset();
doneCurrent();
PerformanceTimer::setActive(false);
@ -244,11 +236,8 @@ void OculusWin32DisplayPlugin::deactivate() {
ovr_Shutdown();
}
void OculusWin32DisplayPlugin::display(
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
void OculusWin32DisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
using namespace oglplus;
// Need to make sure only the display plugin is responsible for
// controlling vsync
wglSwapIntervalEXT(0);
@ -257,68 +246,19 @@ void OculusWin32DisplayPlugin::display(
auto size = _sceneFbo->size;
Context::Viewport(size.x, size.y);
glClearColor(0, 0, 0, 0);
Context::Clear().ColorBuffer();
_program->Bind();
Mat4Uniform(*_program, "Projection").Set(mat4());
Mat4Uniform(*_program, "ModelView").Set(mat4());
glBindTexture(GL_TEXTURE_2D, sceneTexture);
glBindTexture(GL_TEXTURE_2D, finalTexture);
_plane->Use();
_plane->Draw();
Context::Enable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, overlayTexture);
for_each_eye([&](Eye eye) {
Context::Viewport(eye == Left ? 0 : size.x / 2, 0, size.x / 2, size.y);
Mat4Uniform(*_program, "Projection").Set(_compositeEyeProjections[eye]);
Mat4Uniform(*_program, "ModelView").Set(glm::scale(glm::inverse(getModelview(eye, mat4())), vec3(1)));
_uiSurface->Use();
_uiSurface->Draw();
});
Context::Disable(Capability::Blend);
});
/*
An alternative way to render the UI is to pass it specifically as a composition layer to
the Oculus SDK which should technically result in higher quality. However, the SDK doesn't
have a mechanism to present the image as a sphere section, which is our desired look.
*/
#if 0
ovrLayerQuad& uiLayer = getUiLayer();
if (nullptr == uiLayer.ColorTexture || overlaySize != _uiFbo->size) {
_uiFbo->Resize(overlaySize);
uiLayer.ColorTexture = _uiFbo->color;
uiLayer.Viewport.Size.w = overlaySize.x;
uiLayer.Viewport.Size.h = overlaySize.y;
float overlayAspect = aspect(overlaySize);
uiLayer.QuadSize.x = 1.0f;
uiLayer.QuadSize.y = 1.0f / overlayAspect;
}
_uiFbo->Bound([&] {
Q_ASSERT(0 == glGetError());
using namespace oglplus;
Context::Viewport(_uiFbo->size.x, _uiFbo->size.y);
glClearColor(0, 0, 0, 0);
Context::Clear().ColorBuffer();
_program->Bind();
glBindTexture(GL_TEXTURE_2D, overlayTexture);
_plane->Use();
_plane->Draw();
Q_ASSERT(0 == glGetError());
});
#endif
ovrLayerEyeFov& sceneLayer = getSceneLayer();
ovr_for_each_eye([&](ovrEyeType eye) {
sceneLayer.RenderPose[eye] = _eyePoses[eye];
});
auto windowSize = toGlm(getDeviceSize());
/*
@ -377,6 +317,39 @@ bool OculusWin32DisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
otherwise the swapbuffer delay will interefere with the framerate of the headset
*/
void OculusWin32DisplayPlugin::finishFrame() {
// swapBuffers();
swapBuffers();
doneCurrent();
};
#if 0
/*
An alternative way to render the UI is to pass it specifically as a composition layer to
the Oculus SDK which should technically result in higher quality. However, the SDK doesn't
have a mechanism to present the image as a sphere section, which is our desired look.
*/
ovrLayerQuad& uiLayer = getUiLayer();
if (nullptr == uiLayer.ColorTexture || overlaySize != _uiFbo->size) {
_uiFbo->Resize(overlaySize);
uiLayer.ColorTexture = _uiFbo->color;
uiLayer.Viewport.Size.w = overlaySize.x;
uiLayer.Viewport.Size.h = overlaySize.y;
float overlayAspect = aspect(overlaySize);
uiLayer.QuadSize.x = 1.0f;
uiLayer.QuadSize.y = 1.0f / overlayAspect;
}
_uiFbo->Bound([&] {
Q_ASSERT(0 == glGetError());
using namespace oglplus;
Context::Viewport(_uiFbo->size.x, _uiFbo->size.y);
glClearColor(0, 0, 0, 0);
Context::Clear().ColorBuffer();
_program->Bind();
glBindTexture(GL_TEXTURE_2D, overlayTexture);
_plane->Use();
_plane->Draw();
Q_ASSERT(0 == glGetError());
});
#endif

View file

@ -26,12 +26,11 @@ public:
virtual void activate(PluginContainer * container) override;
virtual void deactivate() override;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) override;
virtual bool eventFilter(QObject* receiver, QEvent* event) override;
protected:
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
virtual void customizeContext(PluginContainer * container) override;
// Do not perform swap in finish
virtual void finishFrame() override;
@ -45,5 +44,4 @@ private:
SwapFboPtr _sceneFbo;
MirrorFboPtr _mirrorFbo;
ovrLayerEyeFov _sceneLayer;
ShapeWrapperPtr _uiSurface;
};

View file

@ -26,11 +26,6 @@ const QString & InterleavedStereoDisplayPlugin::getName() {
InterleavedStereoDisplayPlugin::InterleavedStereoDisplayPlugin() {
}
void InterleavedStereoDisplayPlugin::display(
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
}
void InterleavedStereoDisplayPlugin::customizeContext(PluginContainer * container) {
StereoDisplayPlugin::customizeContext(container);
// Set up the stencil buffers? Or use a custom shader?

View file

@ -15,9 +15,6 @@ public:
InterleavedStereoDisplayPlugin();
virtual const QString & getName() override;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) override;
// initialize OpenGL context settings needed by the plugin
virtual void customizeContext(PluginContainer * container) override;

View file

@ -26,83 +26,3 @@ const QString & SideBySideStereoDisplayPlugin::getName() {
SideBySideStereoDisplayPlugin::SideBySideStereoDisplayPlugin() {
}
template <typename F>
void sbs_for_each_eye(const uvec2& size, F f) {
QRect r(QPoint(0, 0), QSize(size.x / 2, size.y));
for_each_eye([&](Eye eye) {
oglplus::Context::Viewport(r.x(), r.y(), r.width(), r.height());
f(eye);
}, [&] {
r.moveLeft(r.width());
});
}
void SideBySideStereoDisplayPlugin::display(
GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) {
makeCurrent();
Q_ASSERT(0 == glGetError());
uvec2 size = toGlm(getDeviceSize());
using namespace oglplus;
Context::Viewport(size.x, size.y);
Context::Clear().ColorBuffer();
_program->Bind();
Mat4Uniform(*_program, "ModelView").Set(mat4());
Mat4Uniform(*_program, "Projection").Set(mat4());
glBindTexture(GL_TEXTURE_2D, sceneTexture);
_plane->Use();
_plane->Draw();
// FIXME the
const float screenAspect = aspect(size);
const GLfloat distance = 1.0f;
const GLfloat halfQuadHeight = distance * tan(DEFAULT_FIELD_OF_VIEW_DEGREES);
const GLfloat halfQuadWidth = halfQuadHeight * screenAspect;
const GLfloat quadWidth = halfQuadWidth * 2.0f;
const GLfloat quadHeight = halfQuadHeight * 2.0f;
vec3 quadSize(quadWidth, quadHeight, 1.0f);
quadSize = vec3(1.0f) / quadSize;
using namespace oglplus;
Context::Enable(Capability::Blend);
glBindTexture(GL_TEXTURE_2D, overlayTexture);
mat4 pr = glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), screenAspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP);
Mat4Uniform(*_program, "Projection").Set(pr);
// Position the camera relative to the overlay texture
MatrixStack mv;
mv.translate(vec3(0, 0, -distance)).scale(vec3(0.7f, 0.7f / screenAspect, 1.0f)); // .scale(vec3(quadWidth, quadHeight, 1.0));
sbs_for_each_eye(size, [&](Eye eye) {
mv.withPush([&] {
// translate
mv.top() = getModelview(eye, mv.top());
Mat4Uniform(*_program, "ModelView").Set(mv.top());
_plane->Draw();
});
});
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glm::vec2 canvasSize = getCanvasSize();
glm::vec2 mouse = toGlm(_window->mapFromGlobal(QCursor::pos()));
mouse /= canvasSize;
mouse *= 2.0f;
mouse -= 1.0f;
mouse.y *= -1.0f;
sbs_for_each_eye(size, [&](Eye eye) {
mv.withPush([&] {
// translate
mv.top() = getModelview(eye, mv.top());
mv.translate(mouse);
//mv.scale(0.05f);
mv.scale(vec3(0.025f, 0.05f, 1.0f));
Mat4Uniform(*_program, "ModelView").Set(mv.top());
_plane->Draw();
});
});
Context::Disable(Capability::Blend);
}

View file

@ -14,9 +14,6 @@ class SideBySideStereoDisplayPlugin : public StereoDisplayPlugin {
public:
SideBySideStereoDisplayPlugin();
virtual const QString & getName() override;
void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
GLuint overlayTexture, const glm::uvec2& overlaySize) override;
private:
static const QString NAME;
};

View file

@ -2,10 +2,10 @@
#include <QString>
class QMainWindow;
class GlWindow;
class PluginContainer {
public:
virtual void addMenuItem(const QString& path, std::function<void()> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
virtual QMainWindow* getAppMainWindow() = 0;
virtual GlWindow* getVisibleWindow() = 0;
};