mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 20:24:03 +02:00
Working on display plugins
This commit is contained in:
parent
c0d84cfc54
commit
ac93d2c721
37 changed files with 780 additions and 452 deletions
4
cmake/externals/openvr/CMakeLists.txt
vendored
4
cmake/externals/openvr/CMakeLists.txt
vendored
|
@ -7,8 +7,8 @@ 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
|
||||
URL https://github.com/ValveSoftware/openvr/archive/0.9.1.zip
|
||||
URL_MD5 f986f5a6815e9454c53c5bf58ce02fdc
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
#include "gpu/Batch.h"
|
||||
#include "gpu/GLBackend.h"
|
||||
|
||||
#include "plugins/render/DisplayPlugin.h"
|
||||
#include "plugins/display/DisplayPlugin.h"
|
||||
|
||||
#include "scripting/AccountScriptingInterface.h"
|
||||
#include "scripting/AudioDeviceScriptingInterface.h"
|
||||
|
@ -341,6 +341,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
|
||||
_lastFaceTrackerUpdate(0)
|
||||
{
|
||||
_offscreenContext = new OffscreenGlCanvas();
|
||||
setInstance(this);
|
||||
#ifdef Q_OS_WIN
|
||||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||
|
@ -823,13 +824,10 @@ void Application::paintGL() {
|
|||
PerformanceTimer perfTimer("paintGL");
|
||||
|
||||
_offscreenContext->makeCurrent();
|
||||
Q_ASSERT(_offscreenContext->getContext() == QOpenGLContext::currentContext());
|
||||
|
||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||
resizeGL();
|
||||
Q_ASSERT(_offscreenContext->getContext() == QOpenGLContext::currentContext());
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
|
@ -853,6 +851,7 @@ void Application::paintGL() {
|
|||
// is orthongonal to the (body's) Y axis
|
||||
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation());
|
||||
}
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
static const float THIRD_PERSON_CAMERA_DISTANCE = 1.5f;
|
||||
_myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
|
||||
|
@ -862,6 +861,7 @@ void Application::paintGL() {
|
|||
} else {
|
||||
_myCamera.setRotation(_myAvatar->getHead()->getOrientation());
|
||||
}
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
_myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||
_myCamera.setPosition(_myAvatar->getDefaultEyePosition() +
|
||||
|
@ -890,26 +890,51 @@ void Application::paintGL() {
|
|||
auto primaryFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
auto finalFbo = primaryFbo;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFbo));
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Viewport is assigned to the size of the framebuffer
|
||||
QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize();
|
||||
glViewport(0, 0, size.width(), size.height());
|
||||
if (displayPlugin->isStereo()) {
|
||||
QRect r(QPoint(0, 0), QSize(size.width() / 2, size.height()));
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
glViewport(r.x(), r.y(), r.width(), r.height());
|
||||
glScissor(r.x(), r.y(), r.width(), r.height());
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
displaySide(_myCamera);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
// FIXME Fetch the projection matrix from the plugin
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
glm::vec2 mpos = getActiveDisplayPlugin()->getUiMousePosition();
|
||||
_rearMirrorTools->render(true, QPoint(mpos.x, mpos.y));
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
renderRearViewMirror(_mirrorViewRect);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
Camera eyeCamera;
|
||||
eyeCamera.setRotation(_myCamera.getRotation());
|
||||
eyeCamera.setPosition(_myCamera.getPosition());
|
||||
displaySide(eyeCamera);
|
||||
glPopMatrix();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
glm::vec2 mpos = getActiveDisplayPlugin()->getUiMousePosition();
|
||||
_rearMirrorTools->render(true, QPoint(mpos.x, mpos.y));
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
renderRearViewMirror(_mirrorViewRect);
|
||||
}
|
||||
r.moveLeft(r.width());
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
glViewport(0, 0, size.width(), size.height());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
displaySide(_myCamera);
|
||||
glPopMatrix();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
glm::vec2 mpos = getActiveDisplayPlugin()->getUiMousePosition();
|
||||
_rearMirrorTools->render(true, QPoint(mpos.x, mpos.y));
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
renderRearViewMirror(_mirrorViewRect);
|
||||
}
|
||||
}
|
||||
|
||||
finalFbo = DependencyManager::get<GlowEffect>()->render();
|
||||
}
|
||||
|
||||
|
@ -1123,8 +1148,6 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
// auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
// return offscreenUi->eventFilter(object, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1876,14 +1899,6 @@ ivec2 Application::getMouseDragStarted() const {
|
|||
return getActiveDisplayPlugin()->trueMouseToUiMouse(getTrueMouseDragStarted());
|
||||
}
|
||||
|
||||
int Application::getMouseDragStartedX() const {
|
||||
return getMouseDragStarted().x;
|
||||
}
|
||||
|
||||
int Application::getMouseDragStartedY() const {
|
||||
return getMouseDragStarted().y;
|
||||
}
|
||||
|
||||
FaceTracker* Application::getActiveFaceTracker() {
|
||||
auto faceshift = DependencyManager::get<Faceshift>();
|
||||
auto dde = DependencyManager::get<DdeFaceTracker>();
|
||||
|
@ -2460,7 +2475,7 @@ void Application::update(float deltaTime) {
|
|||
PerformanceTimer perfTimer("overlays");
|
||||
_overlays.update(deltaTime);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("myAvatar");
|
||||
updateMyAvatarLookAtPosition();
|
||||
|
@ -3422,8 +3437,6 @@ void Application::getProjectionMatrix(glm::dmat4* projectionMatrix) {
|
|||
void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const {
|
||||
_displayViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||
// allow 3DTV/Oculus to override parameters from camera
|
||||
getActiveDisplayPlugin()->overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||
}
|
||||
|
||||
bool Application::getShadowsEnabled() {
|
||||
|
@ -4573,136 +4586,10 @@ void Application::friendsWindowClosed() {
|
|||
_friendsWindow = NULL;
|
||||
}
|
||||
|
||||
|
||||
void Application::postLambdaEvent(std::function<void()> f) {
|
||||
QCoreApplication::postEvent(this, new LambdaEvent(f));
|
||||
}
|
||||
|
||||
PickRay Application::computePickRay() const {
|
||||
return computePickRay(getTrueMouseX(), getTrueMouseY());
|
||||
}
|
||||
|
||||
glm::uvec2 Application::getCanvasSize() const {
|
||||
return getActiveDisplayPlugin()->getCanvasSize();
|
||||
}
|
||||
|
||||
QSize Application::getDeviceSize() const {
|
||||
return getActiveDisplayPlugin()->getDeviceSize();
|
||||
}
|
||||
|
||||
bool Application::hasFocus() const {
|
||||
return getActiveDisplayPlugin()->hasFocus();
|
||||
}
|
||||
|
||||
glm::vec2 Application::getViewportDimensions() const {
|
||||
return toGlm(getDeviceSize());
|
||||
}
|
||||
|
||||
glm::ivec2 Application::getTrueMousePosition() const {
|
||||
return getActiveDisplayPlugin()->getTrueMousePosition();
|
||||
}
|
||||
|
||||
glm::quat Application::getHeadOrientation() const {
|
||||
return getActiveDisplayPlugin()->headOrientation();
|
||||
}
|
||||
|
||||
glm::vec3 Application::getHeadPosition() const {
|
||||
return getActiveDisplayPlugin()->headTranslation();
|
||||
}
|
||||
|
||||
bool Application::isThrottleRendering() const {
|
||||
return getActiveDisplayPlugin()->isThrottled();
|
||||
}
|
||||
|
||||
|
||||
using DisplayPluginPointer = QSharedPointer<DisplayPlugin>;
|
||||
|
||||
#include "plugins/render/NullDisplayPlugin.h"
|
||||
#include "plugins/render/WindowDisplayPlugin.h"
|
||||
#include "plugins/render/LegacyDisplayPlugin.h"
|
||||
#include "plugins/render/OculusDisplayPlugin.h"
|
||||
|
||||
static DisplayPluginPointer _displayPlugin{ nullptr };
|
||||
|
||||
DisplayPlugin * Application::getActiveDisplayPlugin() {
|
||||
if (nullptr == _displayPlugin) {
|
||||
updateDisplayMode();
|
||||
Q_ASSERT(_displayPlugin);
|
||||
}
|
||||
return _displayPlugin.data();
|
||||
}
|
||||
|
||||
const DisplayPlugin * Application::getActiveDisplayPlugin() const {
|
||||
return ((Application*)this)->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {
|
||||
auto menu = Menu::getInstance();
|
||||
MenuItemProperties item(MenuOption::OutputMenu, displayPlugin->getName(), "", true, active);
|
||||
item.isSeparator = false;
|
||||
Q_ASSERT(!menu->menuItemExists(MenuOption::OutputMenu, item.menuItemName));
|
||||
menu->addMenuItem(item);
|
||||
Q_ASSERT(menu->menuItemExists(MenuOption::OutputMenu, item.menuItemName));
|
||||
}
|
||||
|
||||
using DisplayPluginList = QVector<DisplayPluginPointer>;
|
||||
|
||||
// FIXME move to a plugin manager class
|
||||
static const DisplayPluginList & getDisplayPlugins() {
|
||||
static DisplayPluginList RENDER_PLUGINS;
|
||||
static bool init = false;
|
||||
if (!init) {
|
||||
DisplayPluginPointer displayPlugin = DisplayPluginPointer(new LegacyDisplayPlugin()); // new WindowDisplayPlugin();
|
||||
if (displayPlugin->isSupported()) {
|
||||
displayPlugin->init();
|
||||
RENDER_PLUGINS.push_back(DisplayPluginPointer(displayPlugin));
|
||||
QObject::connect(displayPlugin.data(), &DisplayPlugin::requestRender, [] {
|
||||
qApp->paintGL();
|
||||
});
|
||||
QObject::connect(displayPlugin.data(), &DisplayPlugin::recommendedFramebufferSizeChanged, [](const QSize & size) {
|
||||
DependencyManager::get<TextureCache>()->setFrameBufferSize(size * qApp->getRenderResolutionScale());
|
||||
qApp->resizeGL();
|
||||
});
|
||||
addDisplayPluginToMenu(displayPlugin, true);
|
||||
}
|
||||
|
||||
displayPlugin = DisplayPluginPointer(new NullDisplayPlugin());
|
||||
if (displayPlugin->isSupported()) {
|
||||
#ifdef DEBUG
|
||||
addDisplayPluginToMenu(displayPlugin);
|
||||
#endif
|
||||
displayPlugin->init();
|
||||
RENDER_PLUGINS.push_back(DisplayPluginPointer(displayPlugin));
|
||||
}
|
||||
}
|
||||
return RENDER_PLUGINS;
|
||||
}
|
||||
|
||||
void Application::updateDisplayMode() {
|
||||
auto menu = Menu::getInstance();
|
||||
DisplayPluginPointer newDisplayPlugin;
|
||||
foreach(DisplayPluginPointer displayPlugin, getDisplayPlugins()) {
|
||||
QString name = displayPlugin->getName();
|
||||
QAction* action = menu->getActionForOption(name);
|
||||
if (action->isChecked()) {
|
||||
newDisplayPlugin = displayPlugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_displayPlugin != newDisplayPlugin) {
|
||||
if (_displayPlugin) {
|
||||
_displayPlugin->deactivate();
|
||||
}
|
||||
_offscreenContext->makeCurrent();
|
||||
_displayPlugin = newDisplayPlugin;
|
||||
if (_displayPlugin) {
|
||||
_displayPlugin->activate();
|
||||
}
|
||||
_offscreenContext->makeCurrent();
|
||||
}
|
||||
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
|
||||
}
|
||||
|
||||
void Application::initPlugins() {
|
||||
#if 0
|
||||
OculusManager::init();
|
||||
|
@ -4715,9 +4602,40 @@ void Application::shutdownPlugins() {
|
|||
#endif
|
||||
}
|
||||
|
||||
glm::vec3 Application::getHeadPosition() const {
|
||||
return getActiveDisplayPlugin()->headTranslation();
|
||||
}
|
||||
|
||||
glm::ivec2 Application::getMouse() const {
|
||||
return getActiveDisplayPlugin()->getUiMousePosition();
|
||||
glm::quat Application::getHeadOrientation() const {
|
||||
return getActiveDisplayPlugin()->headOrientation();
|
||||
}
|
||||
|
||||
glm::uvec2 Application::getCanvasSize() const {
|
||||
return getActiveDisplayPlugin()->getCanvasSize();
|
||||
}
|
||||
|
||||
QSize Application::getDeviceSize() const {
|
||||
return getActiveDisplayPlugin()->getDeviceSize();
|
||||
}
|
||||
|
||||
PickRay Application::computePickRay() const {
|
||||
return computePickRay(getTrueMouseX(), getTrueMouseY());
|
||||
}
|
||||
|
||||
bool Application::isThrottleRendering() const {
|
||||
return getActiveDisplayPlugin()->isThrottled();
|
||||
}
|
||||
|
||||
bool Application::hasFocus() const {
|
||||
return getActiveDisplayPlugin()->hasFocus();
|
||||
}
|
||||
|
||||
glm::vec2 Application::getViewportDimensions() const {
|
||||
return toGlm(getDeviceSize());
|
||||
}
|
||||
|
||||
glm::ivec2 Application::getTrueMousePosition() const {
|
||||
return getActiveDisplayPlugin()->getTrueMousePosition();
|
||||
}
|
||||
|
||||
void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) {
|
||||
|
@ -4735,3 +4653,131 @@ qreal Application::getDevicePixelRatio() {
|
|||
return _window ? _window->windowHandle()->devicePixelRatio() : 1.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
using DisplayPluginPointer = QSharedPointer<DisplayPlugin>;
|
||||
|
||||
#include "plugins/display/NullDisplayPlugin.h"
|
||||
#include "plugins/display/WindowDisplayPlugin.h"
|
||||
#include "plugins/display/LegacyDisplayPlugin.h"
|
||||
#include "plugins/display/OculusDisplayPlugin.h"
|
||||
#include "plugins/display/Tv3dDisplayPlugin.h"
|
||||
#include "plugins/display/WindowDisplayPlugin.h"
|
||||
|
||||
static DisplayPluginPointer _displayPlugin{ nullptr };
|
||||
|
||||
DisplayPlugin * Application::getActiveDisplayPlugin() {
|
||||
if (nullptr == _displayPlugin) {
|
||||
updateDisplayMode();
|
||||
Q_ASSERT(_displayPlugin);
|
||||
}
|
||||
return _displayPlugin.data();
|
||||
}
|
||||
|
||||
const DisplayPlugin * Application::getActiveDisplayPlugin() const {
|
||||
return ((Application*)this)->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {
|
||||
auto menu = Menu::getInstance();
|
||||
QString name = displayPlugin->getName();
|
||||
Q_ASSERT(!menu->menuItemExists(MenuOption::OutputMenu, name));
|
||||
|
||||
static QActionGroup* displayPluginGroup = nullptr;
|
||||
if (!displayPluginGroup) {
|
||||
displayPluginGroup = new QActionGroup(menu);
|
||||
displayPluginGroup->setExclusive(true);
|
||||
}
|
||||
auto parent = menu->getMenu(MenuOption::OutputMenu);
|
||||
auto action = menu->addActionToQMenuAndActionHash(parent,
|
||||
name, 0, qApp,
|
||||
SLOT(updateDisplayMode()));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(active);
|
||||
displayPluginGroup->addAction(action);
|
||||
Q_ASSERT(menu->menuItemExists(MenuOption::OutputMenu, name));
|
||||
}
|
||||
|
||||
using DisplayPluginList = QVector<DisplayPluginPointer>;
|
||||
|
||||
// FIXME move to a plugin manager class
|
||||
static const DisplayPluginList & getDisplayPlugins() {
|
||||
static DisplayPluginList RENDER_PLUGINS;
|
||||
static bool init = false;
|
||||
if (!init) {
|
||||
init = true;
|
||||
DisplayPluginPointer displayPlugin = DisplayPluginPointer(new LegacyDisplayPlugin()); // new WindowDisplayPlugin();
|
||||
if (displayPlugin->isSupported()) {
|
||||
displayPlugin->init();
|
||||
RENDER_PLUGINS.push_back(DisplayPluginPointer(displayPlugin));
|
||||
QObject::connect(displayPlugin.data(), &DisplayPlugin::requestRender, [] {
|
||||
qApp->paintGL();
|
||||
});
|
||||
QObject::connect(displayPlugin.data(), &DisplayPlugin::recommendedFramebufferSizeChanged, [](const QSize & size) {
|
||||
qApp->resizeGL();
|
||||
});
|
||||
addDisplayPluginToMenu(displayPlugin, true);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
displayPlugin = DisplayPluginPointer(new NullDisplayPlugin());
|
||||
if (displayPlugin->isSupported()) {
|
||||
addDisplayPluginToMenu(displayPlugin);
|
||||
displayPlugin->init();
|
||||
RENDER_PLUGINS.push_back(DisplayPluginPointer(displayPlugin));
|
||||
}
|
||||
#endif
|
||||
|
||||
displayPlugin = DisplayPluginPointer(new Tv3dDisplayPlugin());
|
||||
if (displayPlugin->isSupported()) {
|
||||
addDisplayPluginToMenu(displayPlugin);
|
||||
displayPlugin->init();
|
||||
RENDER_PLUGINS.push_back(DisplayPluginPointer(displayPlugin));
|
||||
}
|
||||
|
||||
displayPlugin = DisplayPluginPointer(new WindowDisplayPlugin());
|
||||
if (displayPlugin->isSupported()) {
|
||||
addDisplayPluginToMenu(displayPlugin);
|
||||
displayPlugin->init();
|
||||
RENDER_PLUGINS.push_back(DisplayPluginPointer(displayPlugin));
|
||||
QObject::connect(displayPlugin.data(), &DisplayPlugin::requestRender, [] {
|
||||
qApp->paintGL();
|
||||
});
|
||||
QObject::connect(displayPlugin.data(), &DisplayPlugin::recommendedFramebufferSizeChanged, [](const QSize & size) {
|
||||
qApp->resizeGL();
|
||||
});
|
||||
}
|
||||
}
|
||||
return RENDER_PLUGINS;
|
||||
}
|
||||
|
||||
void Application::updateDisplayMode() {
|
||||
auto menu = Menu::getInstance();
|
||||
DisplayPluginPointer newDisplayPlugin;
|
||||
foreach(DisplayPluginPointer displayPlugin, getDisplayPlugins()) {
|
||||
QString name = displayPlugin->getName();
|
||||
QAction* action = menu->getActionForOption(name);
|
||||
if (action->isChecked()) {
|
||||
newDisplayPlugin = displayPlugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_displayPlugin != newDisplayPlugin) {
|
||||
if (newDisplayPlugin) {
|
||||
_offscreenContext->makeCurrent();
|
||||
newDisplayPlugin->activate();
|
||||
_offscreenContext->makeCurrent();
|
||||
}
|
||||
std::swap(newDisplayPlugin, _displayPlugin);
|
||||
if (newDisplayPlugin) {
|
||||
newDisplayPlugin->deactivate();
|
||||
_offscreenContext->makeCurrent();
|
||||
}
|
||||
}
|
||||
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
|
||||
}
|
||||
|
||||
glm::ivec2 Application::getMouse() const {
|
||||
return getActiveDisplayPlugin()->getUiMousePosition();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include <StDev.h>
|
||||
#include <TextureCache.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <OffscreenGlContext.h>
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "Bookmarks.h"
|
||||
|
@ -84,6 +83,7 @@ class QMouseEvent;
|
|||
class QSystemTrayIcon;
|
||||
class QTouchEvent;
|
||||
class QWheelEvent;
|
||||
class OffscreenGlCanvas;
|
||||
|
||||
class FaceTracker;
|
||||
class MainWindow;
|
||||
|
@ -222,23 +222,22 @@ public:
|
|||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
bool mouseOnScreen() const;
|
||||
|
||||
glm::ivec2 getMouse() const;
|
||||
int getMouseX() const { return getMouse().x; }
|
||||
int getMouseY() const { return getMouse().y; }
|
||||
inline glm::ivec2 getMouse() const;
|
||||
inline int getMouseX() const { return getMouse().x; }
|
||||
inline int getMouseY() const { return getMouse().y; }
|
||||
|
||||
glm::ivec2 getTrueMousePosition() const;
|
||||
int getTrueMouseX() const { return getTrueMousePosition().x; }
|
||||
int getTrueMouseY() const { return getTrueMousePosition().y; }
|
||||
inline glm::ivec2 getTrueMousePosition() const;
|
||||
inline int getTrueMouseX() const { return getTrueMousePosition().x; }
|
||||
inline int getTrueMouseY() const { return getTrueMousePosition().y; }
|
||||
|
||||
glm::ivec2 getMouseDragStarted() const;
|
||||
int getMouseDragStartedX() const;
|
||||
int getMouseDragStartedY() const;
|
||||
inline glm::ivec2 getMouseDragStarted() const;
|
||||
inline int getMouseDragStartedX() const { return getMouseDragStarted().x; }
|
||||
inline int getMouseDragStartedY() const { return getMouseDragStarted().y; }
|
||||
|
||||
const glm::ivec2 & getTrueMouseDragStarted() const { return _mouseDragStarted; }
|
||||
int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; }
|
||||
int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; }
|
||||
inline const glm::ivec2& getTrueMouseDragStarted() const { return _mouseDragStarted; }
|
||||
inline int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; }
|
||||
inline int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; }
|
||||
|
||||
|
||||
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
||||
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
|
@ -521,7 +520,7 @@ private:
|
|||
|
||||
bool _dependencyManagerIsSetup;
|
||||
|
||||
OffscreenGlContext* _offscreenContext{ new OffscreenGlContext() };
|
||||
OffscreenGlCanvas* _offscreenContext;
|
||||
|
||||
MainWindow* _window;
|
||||
|
||||
|
@ -666,8 +665,6 @@ private:
|
|||
QThread _settingsThread;
|
||||
QTimer _settingsTimer;
|
||||
|
||||
|
||||
|
||||
void checkSkeleton();
|
||||
|
||||
QWidget* _fullscreenMenuWidget = new QWidget();
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include <UserActivityLogger.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "plugins/render/DisplayPlugin.h"
|
||||
#include "plugins/display/DisplayPlugin.h"
|
||||
#include "AvatarManager.h"
|
||||
#include "Environment.h"
|
||||
#include "Menu.h"
|
||||
|
|
|
@ -92,7 +92,9 @@ int main(int argc, const char* argv[]) {
|
|||
usecTimestampNowForceClockSkew(clockSkew);
|
||||
qCDebug(interfaceapp, "clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
|
||||
}
|
||||
|
||||
// Oculus initialization MUST PRECEDE OpenGL context creation.
|
||||
// The nature of the Application constructor means this has to be either here,
|
||||
// or in the main window ctor, before GL startup.
|
||||
Application::initPlugins();
|
||||
|
||||
int exitCode;
|
||||
|
@ -109,7 +111,6 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
|
||||
Application::shutdownPlugins();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
ReleaseMutex(mutex);
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "plugins/Plugin.h"
|
||||
#include "plugins/render/DisplayPlugin.h"
|
||||
#include "plugins/display/DisplayPlugin.h"
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
|
|
@ -70,24 +70,31 @@ public:
|
|||
// Convert from screen mouse coordinates to UI mouse coordinates
|
||||
virtual glm::ivec2 trueMouseToUiMouse(const glm::ivec2 & position) const { return position; };
|
||||
|
||||
virtual PickRay computePickRay(const glm::vec2 & pos) const = 0;
|
||||
virtual PickRay computePickRay(const glm::vec2 & pos) const {
|
||||
// FIXME make pure virtual
|
||||
return PickRay();
|
||||
};
|
||||
virtual bool isMouseOnScreen() const;
|
||||
virtual void overrideOffAxisFrustum(
|
||||
float& left, float& right, float& bottom, float& top,
|
||||
float& nearVal, float& farVal,
|
||||
glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { }
|
||||
|
||||
// Stereo specific methods
|
||||
virtual glm::mat4 getProjection(Eye eye) const {
|
||||
return glm::mat4();
|
||||
}
|
||||
|
||||
// HMD specific methods
|
||||
// TODO move these into another class
|
||||
virtual glm::mat4 headPose() const {
|
||||
static const glm::mat4 pose; return pose;
|
||||
}
|
||||
|
||||
virtual glm::quat headOrientation() const {
|
||||
static const glm::quat orientation; return orientation;
|
||||
}
|
||||
|
||||
virtual glm::vec3 headTranslation() const {
|
||||
static const glm::vec3 tranlsation; return tranlsation;
|
||||
}
|
||||
|
||||
virtual void abandonCalibration() {}
|
||||
virtual void resetSensors() {}
|
||||
virtual float devicePixelRatio() { return 1.0; }
|
|
@ -27,6 +27,8 @@ void LegacyDisplayPlugin::activate() {
|
|||
QOpenGLContext * sourceContext = QOpenGLContext::currentContext();
|
||||
QSurfaceFormat format;
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
|
||||
|
||||
QOpenGLContext * newContext = new QOpenGLContext();
|
||||
newContext->setFormat(format);
|
||||
_window->setContext(
|
||||
|
@ -49,9 +51,10 @@ void LegacyDisplayPlugin::activate() {
|
|||
void LegacyDisplayPlugin::deactivate() {
|
||||
_window->removeEventFilter(DependencyManager::get<OffscreenUi>().data());
|
||||
_window->removeEventFilter(qApp);
|
||||
if (qApp->getWindow()) {
|
||||
qApp->getWindow()->setCentralWidget(oldWidget);
|
||||
}
|
||||
// FIXME, during shutdown, this causes an NPE. Need to deactivate the plugin before the main window is destroyed.
|
||||
// if (qApp->getWindow()) {
|
||||
// qApp->getWindow()->setCentralWidget(oldWidget);
|
||||
// }
|
||||
// stop the glWidget frame timer so it doesn't call paintGL
|
||||
_window->stopFrameTimer();
|
||||
_window->doneCurrent();
|
||||
|
@ -63,18 +66,6 @@ QSize LegacyDisplayPlugin::getDeviceSize() const {
|
|||
return _window->getDeviceSize();
|
||||
}
|
||||
|
||||
void LegacyDisplayPlugin::makeCurrent() {
|
||||
_window->makeCurrent();
|
||||
}
|
||||
|
||||
void LegacyDisplayPlugin::doneCurrent() {
|
||||
_window->doneCurrent();
|
||||
}
|
||||
|
||||
void LegacyDisplayPlugin::swapBuffers() {
|
||||
_window->swapBuffers();
|
||||
}
|
||||
|
||||
void LegacyDisplayPlugin::idle() {
|
||||
_window->updateGL();
|
||||
}
|
|
@ -30,8 +30,5 @@ public:
|
|||
virtual void preDisplay();
|
||||
|
||||
protected:
|
||||
virtual void makeCurrent();
|
||||
virtual void doneCurrent();
|
||||
virtual void swapBuffers();
|
||||
virtual void idle();
|
||||
};
|
|
@ -35,10 +35,11 @@ void SimpleGlDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& scene
|
|||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClearColor(0, 0, 1, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glViewport(0, 0, getDeviceSize().width(), getDeviceSize().height());
|
||||
if (sceneTexture) {
|
||||
glBindTexture(GL_TEXTURE_2D, sceneTexture);
|
||||
glBegin(GL_QUADS);
|
||||
|
@ -74,7 +75,7 @@ void SimpleGlDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& scene
|
|||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
Q_ASSERT(!glGetError());
|
||||
//Q_ASSERT(!glGetError());
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
@ -84,5 +85,5 @@ void SimpleGlDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& scene
|
|||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glFinish();
|
||||
doneCurrent();
|
||||
}
|
||||
|
82
interface/src/plugins/display/SimpleDisplayPlugin.h
Normal file
82
interface/src/plugins/display/SimpleDisplayPlugin.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// SimpleDisplayPlugin.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/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
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "DisplayPlugin.h"
|
||||
|
||||
#include <QCursor>
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <GLMHelpers.h>
|
||||
#include <RenderUtil.h>
|
||||
#include <GlWindow.h>
|
||||
|
||||
class SimpleGlDisplayPlugin : public DisplayPlugin {
|
||||
public:
|
||||
virtual void activate();
|
||||
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
|
||||
GLuint overlayTexture, const glm::uvec2& overlaySize);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SimpleDisplayPlugin : public SimpleGlDisplayPlugin {
|
||||
public:
|
||||
virtual glm::ivec2 getTrueMousePosition() const {
|
||||
return toGlm(_window->mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
protected:
|
||||
void makeCurrent() final {
|
||||
_window->makeCurrent();
|
||||
}
|
||||
|
||||
void doneCurrent() final {
|
||||
_window->doneCurrent();
|
||||
}
|
||||
|
||||
void swapBuffers() final {
|
||||
_window->swapBuffers();
|
||||
}
|
||||
|
||||
protected:
|
||||
T * _window{ nullptr };
|
||||
};
|
||||
|
||||
|
||||
class GlWindowDisplayPlugin : public SimpleDisplayPlugin<GlWindow> {
|
||||
public:
|
||||
virtual void activate() {
|
||||
Q_ASSERT(nullptr == _window);
|
||||
_window = new GlWindow(QOpenGLContext::currentContext());
|
||||
}
|
||||
|
||||
virtual void deactivate() {
|
||||
Q_ASSERT(nullptr != _window);
|
||||
_window->hide();
|
||||
_window->destroy();
|
||||
_window->deleteLater();
|
||||
_window = nullptr;
|
||||
}
|
||||
|
||||
virtual QSize getDeviceSize() const final {
|
||||
return _window->geometry().size() * _window->devicePixelRatio();
|
||||
}
|
||||
|
||||
virtual glm::ivec2 getCanvasSize() const final {
|
||||
return toGlm(_window->geometry().size());
|
||||
}
|
||||
|
||||
virtual bool hasFocus() const {
|
||||
return _window->isActive();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
278
interface/src/plugins/display/Tv3dDisplayPlugin.cpp
Normal file
278
interface/src/plugins/display/Tv3dDisplayPlugin.cpp
Normal file
|
@ -0,0 +1,278 @@
|
|||
//
|
||||
// Tv3dDisplayPlugin.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/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
|
||||
//
|
||||
|
||||
#include "Tv3dDisplayPlugin.h"
|
||||
#include <GlWindow.h>
|
||||
|
||||
const QString Tv3dDisplayPlugin::NAME("Tv3dDisplayPlugin");
|
||||
|
||||
const QString & Tv3dDisplayPlugin::getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
void Tv3dDisplayPlugin::display(
|
||||
GLuint sceneTexture, const glm::uvec2& sceneSize,
|
||||
GLuint overlayTexture, const glm::uvec2& overlaySize) {
|
||||
makeCurrent();
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (sceneTexture) {
|
||||
glBindTexture(GL_TEXTURE_2D, sceneTexture);
|
||||
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();
|
||||
}
|
||||
|
||||
if (overlayTexture) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glBindTexture(GL_TEXTURE_2D, overlayTexture);
|
||||
|
||||
QSize size = getDeviceSize();
|
||||
QRect r(QPoint(0, 0), QSize(size.width() / 2, size.height()));
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
glViewport(r.x(), r.y(), r.width(), r.height());
|
||||
glScissor(r.x(), r.y(), r.width(), r.height());
|
||||
|
||||
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();
|
||||
|
||||
r.moveLeft(r.width());
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
Q_ASSERT(!glGetError());
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glFinish();
|
||||
}
|
||||
|
||||
/*
|
||||
void Tv3dDisplayPlugin::activate() {
|
||||
GlWindowDisplayPlugin::activate();
|
||||
_window->setFlags(Qt::FramelessWindowHint);
|
||||
_window->setPosition(100, 100);
|
||||
_window->resize(512, 512);
|
||||
_window->setVisible(true);
|
||||
_window->show();
|
||||
}
|
||||
|
||||
void Tv3dDisplayPlugin::deactivate() {
|
||||
GlWindowDisplayPlugin::deactivate();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
glm::ivec2 LegacyDisplayPlugin::getCanvasSize() const {
|
||||
return toGlm(_window->size());
|
||||
}
|
||||
|
||||
bool LegacyDisplayPlugin::hasFocus() const {
|
||||
return _window->hasFocus();
|
||||
}
|
||||
|
||||
PickRay LegacyDisplayPlugin::computePickRay(const glm::vec2 & pos) const {
|
||||
return PickRay();
|
||||
}
|
||||
|
||||
bool isMouseOnScreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void LegacyDisplayPlugin::preDisplay() {
|
||||
SimpleDisplayPlugin::preDisplay();
|
||||
auto size = toGlm(_window->size());
|
||||
glViewport(0, 0, size.x, size.y);
|
||||
}
|
||||
|
||||
bool LegacyDisplayPlugin::isThrottled() const {
|
||||
return _window->isThrottleRendering();
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
int TV3DManager::_screenWidth = 1;
|
||||
int TV3DManager::_screenHeight = 1;
|
||||
double TV3DManager::_aspect = 1.0;
|
||||
eyeFrustum TV3DManager::_leftEye;
|
||||
eyeFrustum TV3DManager::_rightEye;
|
||||
eyeFrustum* TV3DManager::_activeEye = NULL;
|
||||
|
||||
|
||||
bool TV3DManager::isConnected() {
|
||||
return Menu::getInstance()->isOptionChecked(MenuOption::Enable3DTVMode);
|
||||
}
|
||||
|
||||
void TV3DManager::connect() {
|
||||
auto deviceSize = qApp->getDeviceSize();
|
||||
configureCamera(*(qApp->getCamera()), deviceSize.width(), deviceSize.height());
|
||||
}
|
||||
|
||||
|
||||
// The basic strategy of this stereoscopic rendering is explained here:
|
||||
// http://www.orthostereo.com/geometryopengl.html
|
||||
void TV3DManager::setFrustum(const Camera& whichCamera) {
|
||||
const double DTR = 0.0174532925; // degree to radians
|
||||
const double IOD = 0.05; //intraocular distance
|
||||
double fovy = DEFAULT_FIELD_OF_VIEW_DEGREES; // field of view in y-axis
|
||||
double nearZ = DEFAULT_NEAR_CLIP; // near clipping plane
|
||||
double screenZ = 0.25f; // screen projection plane
|
||||
|
||||
double top = nearZ * tan(DTR * fovy / 2.0); //sets top of frustum based on fovy and near clipping plane
|
||||
double right = _aspect * top; // sets right of frustum based on aspect ratio
|
||||
double frustumshift = (IOD / 2) * nearZ / screenZ;
|
||||
|
||||
_leftEye.top = top;
|
||||
_leftEye.bottom = -top;
|
||||
_leftEye.left = -right + frustumshift;
|
||||
_leftEye.right = right + frustumshift;
|
||||
_leftEye.modelTranslation = IOD / 2;
|
||||
|
||||
_rightEye.top = top;
|
||||
_rightEye.bottom = -top;
|
||||
_rightEye.left = -right - frustumshift;
|
||||
_rightEye.right = right - frustumshift;
|
||||
_rightEye.modelTranslation = -IOD / 2;
|
||||
}
|
||||
|
||||
void TV3DManager::configureCamera(Camera& whichCamera_, int screenWidth, int screenHeight) {
|
||||
const Camera& whichCamera = whichCamera_;
|
||||
|
||||
if (screenHeight == 0) {
|
||||
screenHeight = 1; // prevent divide by 0
|
||||
}
|
||||
_screenWidth = screenWidth;
|
||||
_screenHeight = screenHeight;
|
||||
_aspect = (double)_screenWidth / (double)_screenHeight;
|
||||
setFrustum(whichCamera);
|
||||
|
||||
glViewport(0, 0, _screenWidth, _screenHeight); // sets drawing viewport
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void TV3DManager::display(Camera& whichCamera) {
|
||||
double nearZ = DEFAULT_NEAR_CLIP; // near clipping plane
|
||||
double farZ = DEFAULT_FAR_CLIP; // far clipping plane
|
||||
|
||||
// left eye portal
|
||||
int portalX = 0;
|
||||
int portalY = 0;
|
||||
QSize deviceSize = qApp->getDeviceSize() *
|
||||
qApp->getRenderResolutionScale();
|
||||
int portalW = deviceSize.width() / 2;
|
||||
int portalH = deviceSize.height();
|
||||
|
||||
|
||||
DependencyManager::get<GlowEffect>()->prepare();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
Camera eyeCamera;
|
||||
eyeCamera.setRotation(whichCamera.getRotation());
|
||||
eyeCamera.setPosition(whichCamera.getPosition());
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glPushMatrix();
|
||||
forEachEye([&](eyeFrustum& eye) {
|
||||
_activeEye = &eye;
|
||||
glViewport(portalX, portalY, portalW, portalH);
|
||||
glScissor(portalX, portalY, portalW, portalH);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity(); // reset projection matrix
|
||||
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(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
qApp->displaySide(eyeCamera, false, RenderArgs::MONO);
|
||||
#if 0
|
||||
qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
|
||||
#endif
|
||||
_activeEye = NULL;
|
||||
}, [&] {
|
||||
// render right side view
|
||||
portalX = deviceSize.width() / 2;
|
||||
});
|
||||
glPopMatrix();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
auto finalFbo = DependencyManager::get<GlowEffect>()->render();
|
||||
auto fboSize = finalFbo->getSize();
|
||||
// Get the ACTUAL device size for the BLIT
|
||||
deviceSize = qApp->getDeviceSize();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void TV3DManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) {
|
||||
if (_activeEye) {
|
||||
left = _activeEye->left;
|
||||
right = _activeEye->right;
|
||||
bottom = _activeEye->bottom;
|
||||
top = _activeEye->top;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
28
interface/src/plugins/display/Tv3dDisplayPlugin.h
Normal file
28
interface/src/plugins/display/Tv3dDisplayPlugin.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Tv3dDisplayPlugin.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SimpleDisplayPlugin.h"
|
||||
#include "LegacyDisplayPlugin.h"
|
||||
|
||||
class Tv3dDisplayPlugin : public LegacyDisplayPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const QString NAME;
|
||||
virtual const QString & getName();
|
||||
|
||||
virtual bool isStereo() const final { return true; }
|
||||
void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
|
||||
GLuint overlayTexture, const glm::uvec2& overlaySize);
|
||||
//virtual bool isMouseOnScreen() const { return true; }
|
||||
//virtual bool isThrottled() const;
|
||||
//virtual void preDisplay();
|
||||
};
|
|
@ -25,41 +25,15 @@ const QString & WindowDisplayPlugin::getName() {
|
|||
}
|
||||
|
||||
void WindowDisplayPlugin::activate() {
|
||||
Q_ASSERT(nullptr == _window);
|
||||
|
||||
_context = new QOpenGLContext;
|
||||
|
||||
_window = new QWindow;
|
||||
_window->setSurfaceType(QSurface::OpenGLSurface);
|
||||
GlWindowDisplayPlugin::activate();
|
||||
_window->installEventFilter(this);
|
||||
glMatrixMode(0);
|
||||
{
|
||||
QSurfaceFormat format;
|
||||
format.setDepthBufferSize(0);
|
||||
format.setStencilBufferSize(0);
|
||||
format.setVersion(4, 1);
|
||||
// Ugh....
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
_window->setFormat(format);
|
||||
_context->setFormat(format);
|
||||
}
|
||||
|
||||
_context->setShareContext(QOpenGLContext::currentContext());
|
||||
_context->create();
|
||||
|
||||
_window->show();
|
||||
|
||||
_timer.start(8);
|
||||
}
|
||||
|
||||
void WindowDisplayPlugin::deactivate() {
|
||||
_timer.stop();
|
||||
_context->doneCurrent();
|
||||
_context->deleteLater();
|
||||
_context = nullptr;
|
||||
_window->hide();
|
||||
_window->destroy();
|
||||
_window = nullptr;
|
||||
GlWindowDisplayPlugin::deactivate();
|
||||
}
|
||||
|
||||
bool WindowDisplayPlugin::eventFilter(QObject* object, QEvent* event) {
|
||||
|
@ -80,25 +54,6 @@ bool WindowDisplayPlugin::eventFilter(QObject* object, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
QSize WindowDisplayPlugin::getRecommendedFramebufferSize() const {
|
||||
return _window->size();
|
||||
}
|
||||
|
||||
void WindowDisplayPlugin::makeCurrent() {
|
||||
_context->makeCurrent(_window);
|
||||
QSize windowSize = _window->size();
|
||||
glViewport(0, 0, windowSize.width(), windowSize.height());
|
||||
}
|
||||
|
||||
void WindowDisplayPlugin::doneCurrent() {
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
void WindowDisplayPlugin::swapBuffers() {
|
||||
_context->swapBuffers(_window);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
//
|
|
@ -11,11 +11,10 @@
|
|||
|
||||
#include "SimpleDisplayPlugin.h"
|
||||
|
||||
#include <QWindow>
|
||||
#include <QOpenGLContext>
|
||||
#include <GlWindow.h>
|
||||
#include <QTimer>
|
||||
|
||||
class WindowDisplayPlugin : public SimpleDisplayPlugin<QWindow> {
|
||||
class WindowDisplayPlugin : public GlWindowDisplayPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const QString NAME;
|
||||
|
@ -27,14 +26,6 @@ public:
|
|||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
virtual bool eventFilter(QObject* object, QEvent* event);
|
||||
virtual QSize getRecommendedFramebufferSize() const;
|
||||
|
||||
protected:
|
||||
virtual void makeCurrent();
|
||||
virtual void doneCurrent();
|
||||
virtual void swapBuffers();
|
||||
|
||||
private:
|
||||
QTimer _timer;
|
||||
QOpenGLContext * _context{ nullptr };
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
//
|
||||
// SimpleDisplayPlugin.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/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
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "DisplayPlugin.h"
|
||||
|
||||
#include <QCursor>
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <GLMHelpers.h>
|
||||
#include <RenderUtil.h>
|
||||
|
||||
class SimpleGlDisplayPlugin : public DisplayPlugin {
|
||||
public:
|
||||
virtual void activate();
|
||||
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize,
|
||||
GLuint overlayTexture, const glm::uvec2& overlaySize);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SimpleDisplayPlugin : public SimpleGlDisplayPlugin {
|
||||
public:
|
||||
virtual glm::ivec2 getTrueMousePosition() const {
|
||||
return toGlm(_window->mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
protected:
|
||||
T * _window;
|
||||
};
|
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// Tv3dDisplayPlugin.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/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
|
||||
//
|
||||
|
||||
#include "Tv3dDisplayPlugin.h"
|
||||
|
||||
const QString Tv3dDisplayPlugin::NAME("Tv3dDisplayPlugin");
|
||||
|
||||
const QString & Tv3dDisplayPlugin::getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
|
||||
void Tv3dDisplayPlugin::overrideOffAxisFrustum(
|
||||
float& left, float& right, float& bottom, float& top,
|
||||
float& nearVal, float& farVal,
|
||||
glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const {
|
||||
|
||||
#if 0
|
||||
if (_activeEye) {
|
||||
left = _activeEye->left;
|
||||
right = _activeEye->right;
|
||||
bottom = _activeEye->bottom;
|
||||
top = _activeEye->top;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
} else if (TV3DManager::isConnected()) {
|
||||
|
||||
TV3DManager::display(_myCamera);
|
||||
|
||||
} else {
|
||||
#endif
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// Tv3dDisplayPlugin.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StereoDisplayPlugin.h"
|
||||
|
||||
class Tv3dDisplayPlugin : public StereoDisplayPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const QString NAME;
|
||||
virtual const QString & getName();
|
||||
|
||||
virtual void overrideOffAxisFrustum(
|
||||
float& left, float& right, float& bottom, float& top,
|
||||
float& nearVal, float& farVal,
|
||||
glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
|
||||
|
||||
};
|
|
@ -194,7 +194,7 @@ void ApplicationOverlay::renderOverlay() {
|
|||
Overlays& overlays = qApp->getOverlays();
|
||||
|
||||
glm::uvec2 size = qApp->getCanvasSize();
|
||||
if (!_framebufferObject || size == toGlm(_framebufferObject->size())) {
|
||||
if (!_framebufferObject || size != toGlm(_framebufferObject->size())) {
|
||||
if(_framebufferObject) {
|
||||
delete _framebufferObject;
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origi
|
|||
|
||||
// Intersection UI overlay space
|
||||
glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
|
||||
glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius;
|
||||
glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _hmdUIRadius;
|
||||
intersectionWithUi += overlayPosition;
|
||||
|
||||
// Intersection in world space
|
||||
|
|
|
@ -82,6 +82,8 @@ private:
|
|||
float _magSizeMult[NUMBER_OF_RETICLES];
|
||||
quint64 _lastMouseMove;
|
||||
bool _magnifier;
|
||||
float _hmdUIRadius{ 1.0 };
|
||||
|
||||
|
||||
float _alpha = 1.0f;
|
||||
float _trailingAudioLoudness;
|
||||
|
|
|
@ -294,7 +294,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
if (qApp->isHMDMode()) {
|
||||
pointCopy = qApp->getApplicationOverlay().screenToOverlay(point);
|
||||
}
|
||||
|
||||
|
||||
QReadLocker lock(&_lock);
|
||||
QMapIterator<unsigned int, Overlay*> i(_overlaysHUD);
|
||||
i.toBack();
|
||||
|
|
77
libraries/render-utils/src/GlWindow.cpp
Normal file
77
libraries/render-utils/src/GlWindow.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/05/21
|
||||
// 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 "GlWindow.h"
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLDebugLogger>
|
||||
|
||||
static QSurfaceFormat getDefaultFormat() {
|
||||
QSurfaceFormat format;
|
||||
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setVersion(4, 1);
|
||||
#ifdef DEBUG
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
#endif
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
return format;
|
||||
}
|
||||
|
||||
GlWindow::GlWindow(QOpenGLContext * shareContext) : GlWindow(getDefaultFormat(), shareContext) {
|
||||
}
|
||||
|
||||
GlWindow::GlWindow(const QSurfaceFormat& format, QOpenGLContext * shareContext) {
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
setFormat(format);
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
if (shareContext) {
|
||||
_context->setShareContext(shareContext);
|
||||
}
|
||||
_context->create();
|
||||
}
|
||||
|
||||
static QOpenGLDebugLogger* logger{ nullptr };
|
||||
|
||||
GlWindow::~GlWindow() {
|
||||
if (logger) {
|
||||
makeCurrent();
|
||||
delete logger;
|
||||
logger = nullptr;
|
||||
}
|
||||
_context->doneCurrent();
|
||||
_context->deleteLater();
|
||||
_context = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void GlWindow::makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
#ifdef DEBUG
|
||||
if (!logger) {
|
||||
logger = new QOpenGLDebugLogger(this);
|
||||
if (logger->initialize()) {
|
||||
connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage& message) {
|
||||
qDebug() << message;
|
||||
});
|
||||
logger->startLogging(QOpenGLDebugLogger::LoggingMode::SynchronousLogging);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GlWindow::doneCurrent() {
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
void GlWindow::swapBuffers() {
|
||||
_context->swapBuffers(this);
|
||||
}
|
||||
|
29
libraries/render-utils/src/GlWindow.h
Normal file
29
libraries/render-utils/src/GlWindow.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/05/21
|
||||
// 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
|
||||
#ifndef hifi_GlWindow_h
|
||||
#define hifi_GlWindow_h
|
||||
|
||||
#include <QWindow>
|
||||
#include <QSurfaceFormat>
|
||||
|
||||
class QOpenGLContext;
|
||||
|
||||
class GlWindow : public QWindow {
|
||||
QOpenGLContext * _context{ nullptr };
|
||||
public:
|
||||
GlWindow(QOpenGLContext * shareContext = nullptr);
|
||||
GlWindow(const QSurfaceFormat& format, QOpenGLContext * shareContext = nullptr);
|
||||
virtual ~GlWindow();
|
||||
void makeCurrent();
|
||||
void doneCurrent();
|
||||
void swapBuffers();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -175,11 +175,12 @@ gpu::FramebufferPointer GlowEffect::render() {
|
|||
_diffuseProgram->release();
|
||||
}
|
||||
|
||||
destFBO = oldDiffusedFBO;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
// add diffused texture to the primary
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(newDiffusedFBO->getRenderBuffer(0)));
|
||||
|
||||
destFBO = oldDiffusedFBO;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
|
||||
glViewport(0, 0, framebufferSize.width(), framebufferSize.height());
|
||||
_addSeparateProgram->bind();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
#include "OffscreenGlCanvas.h"
|
||||
#include <QOpenGLDebugLogger>
|
||||
|
||||
OffscreenGlCanvas::OffscreenGlCanvas() {
|
||||
}
|
||||
|
@ -27,16 +28,35 @@ void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) {
|
|||
format.setMajorVersion(4);
|
||||
format.setMinorVersion(1);
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
#ifdef DEBUG
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
#endif
|
||||
_context.setFormat(format);
|
||||
}
|
||||
_context.create();
|
||||
|
||||
_offscreenSurface.setFormat(_context.format());
|
||||
_offscreenSurface.create();
|
||||
|
||||
}
|
||||
|
||||
bool OffscreenGlCanvas::makeCurrent() {
|
||||
return _context.makeCurrent(&_offscreenSurface);
|
||||
bool result = _context.makeCurrent(&_offscreenSurface);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (result && !_logger) {
|
||||
_logger = new QOpenGLDebugLogger(this);
|
||||
if (_logger->initialize()) {
|
||||
connect(_logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage& message) {
|
||||
qDebug() << message;
|
||||
});
|
||||
_logger->enableMessages(QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::HighSeverity);
|
||||
_logger->startLogging(QOpenGLDebugLogger::LoggingMode::SynchronousLogging);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void OffscreenGlCanvas::doneCurrent() {
|
||||
|
|
|
@ -15,16 +15,22 @@
|
|||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
|
||||
class QOpenGLDebugLogger;
|
||||
|
||||
class OffscreenGlCanvas : public QObject {
|
||||
public:
|
||||
OffscreenGlCanvas();
|
||||
void create(QOpenGLContext* sharedContext = nullptr);
|
||||
bool makeCurrent();
|
||||
void doneCurrent();
|
||||
QOpenGLContext* getContext() {
|
||||
return &_context;
|
||||
}
|
||||
|
||||
protected:
|
||||
QOpenGLContext _context;
|
||||
QOffscreenSurface _offscreenSurface;
|
||||
QOpenGLDebugLogger * _logger{ nullptr };
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// 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();
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
//
|
||||
// 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
|
Loading…
Reference in a new issue