overte-HifiExperiments/interface/src/ui/ApplicationOverlay.cpp
2015-06-29 10:55:13 -07:00

244 lines
8.4 KiB
C++

//
// ApplicationOverlay.cpp
// interface/src/ui/overlays
//
// Created by Benjamin Arnold on 5/27/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "InterfaceConfig.h"
#include <QOpenGLFramebufferObject>
#include <QOpenGLTexture>
#include <glm/gtc/type_ptr.hpp>
#include <avatar/AvatarManager.h>
#include <DeferredLightingEffect.h>
#include <GLMHelpers.h>
#include <gpu/GLBackend.h>
#include <gpu/GLBackendShared.h>
#include <GLMHelpers.h>
#include <OffscreenUi.h>
#include <CursorManager.h>
#include <PerfStat.h>
#include "AudioClient.h"
#include "audio/AudioIOStatsRenderer.h"
#include "audio/AudioScope.h"
#include "Application.h"
#include "ApplicationOverlay.h"
#include "Util.h"
#include "ui/Stats.h"
#include "ui/AvatarInputs.h"
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
const int AUDIO_METER_GAP = 5;
const int MUTE_ICON_PADDING = 10;
const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
static const float ORTHO_NEAR_CLIP = -10000;
static const float ORTHO_FAR_CLIP = 10000;
// TODO move somewhere useful
static void fboViewport(QOpenGLFramebufferObject* fbo) {
auto size = fbo->size();
glViewport(0, 0, size.width(), size.height());
}
ApplicationOverlay::ApplicationOverlay()
{
auto geometryCache = DependencyManager::get<GeometryCache>();
_domainStatusBorder = geometryCache->allocateID();
_magnifierBorder = geometryCache->allocateID();
// Once we move UI rendering and screen rendering to different
// threads, we need to use a sync object to deteremine when
// the current UI texture is no longer being read from, and only
// then release it back to the UI for re-use
auto offscreenUi = DependencyManager::get<OffscreenUi>();
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->lockTexture(textureId);
assert(!glGetError());
std::swap(_uiTexture, textureId);
if (textureId) {
offscreenUi->releaseTexture(textureId);
}
});
}
ApplicationOverlay::~ApplicationOverlay() {
}
// Renders the overlays either to a texture or to the screen
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
CHECK_GL_ERROR();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
// TODO move to Application::idle()?
Stats::getInstance()->updateStats();
AvatarInputs::getInstance()->update();
buildFramebufferObject();
// Execute the batch into our framebuffer
_overlayFramebuffer->bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
fboViewport(_overlayFramebuffer);
// Now render the overlay components together into a single texture
renderOverlays(renderArgs);
renderStatsAndLogs(renderArgs);
renderDomainConnectionStatusBorder(renderArgs);
renderQmlUi(renderArgs);
_overlayFramebuffer->release();
CHECK_GL_ERROR();
}
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
if (_uiTexture) {
gpu::Batch batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
geometryCache->useSimpleDrawPipeline(batch);
batch.setProjectionTransform(mat4());
batch.setModelTransform(mat4());
batch._glBindTexture(GL_TEXTURE_2D, _uiTexture);
geometryCache->renderUnitQuad(batch, glm::vec4(1));
renderArgs->_context->syncCache();
renderArgs->_context->render(batch);
}
}
void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
glm::vec2 size = qApp->getCanvasSize();
mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixf(glm::value_ptr(legacyProjection));
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// give external parties a change to hook in
emit qApp->renderingOverlay();
qApp->getOverlays().renderHUD(renderArgs);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
renderArgs->_context->syncCache();
fboViewport(_overlayFramebuffer);
}
void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
}
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
// Display stats and log text onscreen
// Determine whether to compute timing details
/*
// Show on-screen msec timer
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
auto canvasSize = qApp->getCanvasSize();
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
QString frameTimer = QString("%1\n").arg((int)(mSecsNow % 1000));
int timerBottom =
(Menu::getInstance()->isOptionChecked(MenuOption::Stats))
? 80 : 20;
drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
}
glPointSize(1.0f);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay();
nodeBoundsDisplay.drawOverlay();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
fboViewport(_overlayFramebuffer);
*/
}
void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
auto geometryCache = DependencyManager::get<GeometryCache>();
static std::once_flag once;
std::call_once(once, [&] {
QVector<vec2> points;
static const float B = 0.99f;
points.push_back(vec2(-B));
points.push_back(vec2(B, -B));
points.push_back(vec2(B));
points.push_back(vec2(-B, B));
points.push_back(vec2(-B));
geometryCache->updateVertices(_domainStatusBorder, points, CONNECTION_STATUS_BORDER_COLOR);
});
auto nodeList = DependencyManager::get<NodeList>();
if (nodeList && !nodeList->getDomainHandler().isConnected()) {
gpu::Batch batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
geometryCache->useSimpleDrawPipeline(batch);
batch.setProjectionTransform(mat4());
batch.setModelTransform(mat4());
batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
// TODO animate the disconnect border for some excitement while not connected?
//double usecs = usecTimestampNow();
//double secs = usecs / 1000000.0;
//float scaleAmount = 1.0f + (0.01f * sin(secs * 5.0f));
//batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount)));
geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder);
renderArgs->_context->syncCache();
renderArgs->_context->render(batch);
}
}
GLuint ApplicationOverlay::getOverlayTexture() {
if (!_overlayFramebuffer) {
return 0;
}
return _overlayFramebuffer->texture();
}
void ApplicationOverlay::buildFramebufferObject() {
QSize fboSize = qApp->getDeviceSize();
if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) {
// Already built
return;
}
if (_overlayFramebuffer) {
delete _overlayFramebuffer;
}
_overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth);
glBindTexture(GL_TEXTURE_2D, getOverlayTexture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, 0);
}