mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge pull request #2934 from Barnold1953/master
OverlayRenderer class and display Overlays to Oculus
This commit is contained in:
commit
1340ea49d3
7 changed files with 416 additions and 193 deletions
|
@ -102,15 +102,6 @@ const int STARTUP_JITTER_SAMPLES = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / 2
|
|||
// Startup optimistically with small jitter buffer that
|
||||
// will start playback on the second received audio packet.
|
||||
|
||||
const int MIRROR_VIEW_TOP_PADDING = 5;
|
||||
const int MIRROR_VIEW_LEFT_PADDING = 10;
|
||||
const int MIRROR_VIEW_WIDTH = 265;
|
||||
const int MIRROR_VIEW_HEIGHT = 215;
|
||||
const float MIRROR_FULLSCREEN_DISTANCE = 0.35f;
|
||||
const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
||||
const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
||||
const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
||||
|
||||
const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
|
||||
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
||||
|
||||
|
@ -173,7 +164,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_previousScriptLocation(),
|
||||
_runningScriptsWidget(new RunningScriptsWidget(_window)),
|
||||
_runningScriptsWidgetWasVisible(false),
|
||||
_trayIcon(new QSystemTrayIcon(_window))
|
||||
_trayIcon(new QSystemTrayIcon(_window)),
|
||||
_applicationOverlay()
|
||||
{
|
||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||
QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||
|
@ -630,10 +622,12 @@ void Application::paintGL() {
|
|||
|
||||
if (OculusManager::isConnected()) {
|
||||
OculusManager::display(whichCamera);
|
||||
|
||||
} else if (TV3DManager::isConnected()) {
|
||||
_glowEffect.prepare();
|
||||
TV3DManager::display(whichCamera);
|
||||
_glowEffect.render();
|
||||
|
||||
} else {
|
||||
_glowEffect.prepare();
|
||||
|
||||
|
@ -652,7 +646,7 @@ void Application::paintGL() {
|
|||
_rearMirrorTools->render(true);
|
||||
}
|
||||
|
||||
displayOverlay();
|
||||
_applicationOverlay.renderOverlay();
|
||||
}
|
||||
|
||||
_frameCount++;
|
||||
|
@ -2594,183 +2588,6 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom
|
|||
_viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||
}
|
||||
|
||||
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
|
||||
void Application::displayOverlay() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()");
|
||||
|
||||
// Render 2D overlay: I/O level bar graphs and text
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, _glWidget->width(), _glWidget->height(), 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// Display a single screen-size quad to create an alpha blended 'collision' flash
|
||||
if (_audio.getCollisionFlashesScreen()) {
|
||||
float collisionSoundMagnitude = _audio.getCollisionSoundMagnitude();
|
||||
const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f;
|
||||
if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) {
|
||||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude());
|
||||
}
|
||||
}
|
||||
|
||||
// Audio VU Meter and Mute Icon
|
||||
const int MUTE_ICON_SIZE = 24;
|
||||
const int AUDIO_METER_INSET = 2;
|
||||
const int MUTE_ICON_PADDING = 10;
|
||||
const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING;
|
||||
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
|
||||
const int AUDIO_METER_HEIGHT = 8;
|
||||
const int AUDIO_METER_GAP = 5;
|
||||
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
|
||||
|
||||
int audioMeterY;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||
} else {
|
||||
audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||
}
|
||||
|
||||
const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};
|
||||
const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};
|
||||
const float AUDIO_METER_RED[] = {1.0, 0.0, 0.0};
|
||||
const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
|
||||
const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
|
||||
const float CLIPPING_INDICATOR_TIME = 1.0f;
|
||||
const float AUDIO_METER_AVERAGING = 0.5;
|
||||
const float LOG2 = log(2.f);
|
||||
const float METER_LOUDNESS_SCALE = 2.8f / 5.f;
|
||||
const float LOG2_LOUDNESS_FLOOR = 11.f;
|
||||
float audioLevel = 0.f;
|
||||
float loudness = _audio.getLastInputLoudness() + 1.f;
|
||||
|
||||
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
|
||||
float log2loudness = log(_trailingAudioLoudness) / LOG2;
|
||||
|
||||
if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
|
||||
audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
||||
} else {
|
||||
audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
||||
}
|
||||
if (audioLevel > AUDIO_METER_SCALE_WIDTH) {
|
||||
audioLevel = AUDIO_METER_SCALE_WIDTH;
|
||||
}
|
||||
bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
||||
|
||||
if ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
|
||||
const float MAX_MAGNITUDE = 0.7f;
|
||||
float magnitude = MAX_MAGNITUDE * (1 - _audio.getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
|
||||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), magnitude, 1.0f);
|
||||
}
|
||||
|
||||
_audio.renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
|
||||
audioMeterY,
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
|
||||
|
||||
_audio.renderScope(_glWidget->width(), _glWidget->height());
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
if (isClipping) {
|
||||
glColor3f(1, 0, 0);
|
||||
} else {
|
||||
glColor3f(0.475f, 0.475f, 0.475f);
|
||||
}
|
||||
|
||||
audioMeterY += AUDIO_METER_HEIGHT;
|
||||
|
||||
glColor3f(0, 0, 0);
|
||||
// Draw audio meter background Quad
|
||||
glVertex2i(AUDIO_METER_X, audioMeterY);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
|
||||
glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
|
||||
|
||||
|
||||
if (audioLevel > AUDIO_RED_START) {
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_RED);
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
}
|
||||
// Draw Red Quad
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
audioLevel = AUDIO_RED_START;
|
||||
}
|
||||
if (audioLevel > AUDIO_GREEN_START) {
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_GREEN);
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
}
|
||||
// Draw Green Quad
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
audioLevel = AUDIO_GREEN_START;
|
||||
}
|
||||
// Draw Blue Quad
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_BLUE);
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
}
|
||||
// Draw Blue (low level) quad
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glEnd();
|
||||
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
|
||||
_myAvatar->renderHeadMouse(_glWidget->width(), _glWidget->height());
|
||||
}
|
||||
|
||||
// Display stats and log text onscreen
|
||||
glLineWidth(1.0f);
|
||||
glPointSize(1.0f);
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
// let's set horizontal offset to give stats some margin to mirror
|
||||
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
|
||||
int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
|
||||
// Onscreen text about position, servers, etc
|
||||
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess);
|
||||
// Bandwidth meter
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
|
||||
Stats::drawBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68);
|
||||
_bandwidthMeter.render(_glWidget->width(), _glWidget->height());
|
||||
}
|
||||
}
|
||||
|
||||
// Show on-screen msec timer
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||
char frameTimer[10];
|
||||
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
|
||||
int timerBottom =
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
||||
? 80 : 20;
|
||||
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
||||
}
|
||||
_nodeBoundsDisplay.drawOverlay();
|
||||
|
||||
// give external parties a change to hook in
|
||||
emit renderingOverlay();
|
||||
|
||||
_overlays.render2D();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
|
||||
float horizontalScale = _glWidget->width() / 2.0f;
|
||||
float verticalScale = _glWidget->height() / 2.0f;
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
#include "ui/LogDialog.h"
|
||||
#include "ui/UpdateDialog.h"
|
||||
#include "ui/overlays/Overlays.h"
|
||||
#include "ui/ApplicationOverlay.h"
|
||||
#include "ui/RunningScriptsWidget.h"
|
||||
#include "voxels/VoxelFade.h"
|
||||
#include "voxels/VoxelHideShowThread.h"
|
||||
|
@ -116,6 +117,15 @@ static const QString CUSTOM_URL_SCHEME = "hifi:";
|
|||
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees
|
||||
static const float BILLBOARD_DISTANCE = 5.0f; // meters
|
||||
|
||||
static const int MIRROR_VIEW_TOP_PADDING = 5;
|
||||
static const int MIRROR_VIEW_LEFT_PADDING = 10;
|
||||
static const int MIRROR_VIEW_WIDTH = 265;
|
||||
static const int MIRROR_VIEW_HEIGHT = 215;
|
||||
static const float MIRROR_FULLSCREEN_DISTANCE = 0.35f;
|
||||
static const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
||||
static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
||||
static const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
||||
|
||||
class Application : public QApplication {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -182,6 +192,7 @@ public:
|
|||
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
|
||||
VoxelSystem* getVoxels() { return &_voxels; }
|
||||
VoxelTree* getVoxelTree() { return _voxels.getTree(); }
|
||||
const VoxelPacketProcessor& getVoxelPacketProcessor() const { return _voxelProcessor; }
|
||||
ParticleTreeRenderer* getParticles() { return &_particles; }
|
||||
MetavoxelSystem* getMetavoxels() { return &_metavoxels; }
|
||||
ModelTreeRenderer* getModels() { return &_models; }
|
||||
|
@ -205,6 +216,13 @@ public:
|
|||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
float getFps() const { return _fps; }
|
||||
float getPacketsPerSecond() const { return _packetsPerSecond; }
|
||||
float getBytesPerSecond() const { return _bytesPerSecond; }
|
||||
const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; }
|
||||
|
||||
/// if you need to access the application settings, use lockSettings()/unlockSettings()
|
||||
QSettings* lockSettings() { _settingsMutex.lock(); return _settings; }
|
||||
|
@ -377,7 +395,6 @@ private:
|
|||
glm::vec3 getSunDirection();
|
||||
|
||||
void updateShadowMap();
|
||||
void displayOverlay();
|
||||
void renderRearViewMirror(const QRect& region, bool billboard = false);
|
||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||
|
||||
|
@ -552,6 +569,7 @@ private:
|
|||
TouchEvent _lastTouchEvent;
|
||||
|
||||
Overlays _overlays;
|
||||
ApplicationOverlay _applicationOverlay;
|
||||
|
||||
AudioReflector _audioReflector;
|
||||
RunningScriptsWidget* _runningScriptsWidget;
|
||||
|
|
|
@ -81,7 +81,11 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH
|
|||
|
||||
void OculusManager::display(Camera& whichCamera) {
|
||||
#ifdef HAVE_LIBOVR
|
||||
Application::getInstance()->getGlowEffect()->prepare();
|
||||
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
|
||||
// We only need to render the overlays to a texture once, then we just render the texture as a quad
|
||||
applicationOverlay.renderOverlay(true);
|
||||
|
||||
Application::getInstance()->getGlowEffect()->prepare();
|
||||
|
||||
// render the left eye view to the left side of the screen
|
||||
const StereoEyeParams& leftEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Left);
|
||||
|
@ -100,6 +104,8 @@ void OculusManager::display(Camera& whichCamera) {
|
|||
|
||||
Application::getInstance()->displaySide(whichCamera);
|
||||
|
||||
applicationOverlay.displayOverlayTextureOculus(whichCamera);
|
||||
|
||||
// and the right eye to the right side
|
||||
const StereoEyeParams& rightEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Right);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -115,6 +121,8 @@ void OculusManager::display(Camera& whichCamera) {
|
|||
|
||||
Application::getInstance()->displaySide(whichCamera);
|
||||
|
||||
applicationOverlay.displayOverlayTextureOculus(whichCamera);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
// restore our normal viewport
|
||||
|
|
|
@ -79,7 +79,7 @@ static void setPalm(float deltaTime, int index) {
|
|||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
|
||||
Model* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
||||
SkeletonModel* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
||||
int jointIndex;
|
||||
glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation());
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
|
|
|
@ -139,8 +139,7 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
|
|||
if (_isEmpty && _renderMode != DIFFUSE_ADD_MODE) {
|
||||
// copy the primary to the screen
|
||||
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
|
||||
QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO);
|
||||
|
||||
QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO);
|
||||
} else {
|
||||
maybeBind(destFBO);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
|
343
interface/src/ui/ApplicationOverlay.cpp
Normal file
343
interface/src/ui/ApplicationOverlay.cpp
Normal file
|
@ -0,0 +1,343 @@
|
|||
//
|
||||
// ApplicationOverlay.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Benjamin Arnold on 5/27/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ApplicationOverlay.h"
|
||||
|
||||
#include "ui/Stats.h"
|
||||
|
||||
ApplicationOverlay::ApplicationOverlay() : _framebufferObject(NULL) {
|
||||
|
||||
}
|
||||
|
||||
ApplicationOverlay::~ApplicationOverlay() {
|
||||
if (_framebufferObject != NULL) {
|
||||
delete _framebufferObject;
|
||||
}
|
||||
}
|
||||
|
||||
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
|
||||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
|
||||
Application* application = Application::getInstance();
|
||||
|
||||
Overlays& overlays = application->getOverlays();
|
||||
QGLWidget* glWidget = application->getGLWidget();
|
||||
MyAvatar* myAvatar = application->getAvatar();
|
||||
Audio* audio = application->getAudio();
|
||||
const VoxelPacketProcessor& voxelPacketProcessor = application->getVoxelPacketProcessor();
|
||||
BandwidthMeter* bandwidthMeter = application->getBandwidthMeter();
|
||||
NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
|
||||
|
||||
if (renderToTexture) {
|
||||
getFramebufferObject()->bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Render 2D overlay: I/O level bar graphs and text
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, glWidget->width(), glWidget->height(), 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// Display a single screen-size quad to create an alpha blended 'collision' flash
|
||||
if (audio->getCollisionFlashesScreen()) {
|
||||
float collisionSoundMagnitude = audio->getCollisionSoundMagnitude();
|
||||
const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f;
|
||||
if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) {
|
||||
renderCollisionOverlay(glWidget->width(), glWidget->height(), audio->getCollisionSoundMagnitude());
|
||||
}
|
||||
}
|
||||
|
||||
// Audio VU Meter and Mute Icon
|
||||
const int MUTE_ICON_SIZE = 24;
|
||||
const int AUDIO_METER_INSET = 2;
|
||||
const int MUTE_ICON_PADDING = 10;
|
||||
const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING;
|
||||
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
|
||||
const int AUDIO_METER_HEIGHT = 8;
|
||||
const int AUDIO_METER_GAP = 5;
|
||||
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
|
||||
|
||||
int audioMeterY;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||
} else {
|
||||
audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
|
||||
}
|
||||
|
||||
const float AUDIO_METER_BLUE[] = { 0.0, 0.0, 1.0 };
|
||||
const float AUDIO_METER_GREEN[] = { 0.0, 1.0, 0.0 };
|
||||
const float AUDIO_METER_RED[] = { 1.0, 0.0, 0.0 };
|
||||
const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
|
||||
const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
|
||||
const float CLIPPING_INDICATOR_TIME = 1.0f;
|
||||
const float AUDIO_METER_AVERAGING = 0.5;
|
||||
const float LOG2 = log(2.f);
|
||||
const float METER_LOUDNESS_SCALE = 2.8f / 5.f;
|
||||
const float LOG2_LOUDNESS_FLOOR = 11.f;
|
||||
float audioLevel = 0.f;
|
||||
float loudness = audio->getLastInputLoudness() + 1.f;
|
||||
|
||||
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
|
||||
float log2loudness = log(_trailingAudioLoudness) / LOG2;
|
||||
|
||||
if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
|
||||
audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
||||
} else {
|
||||
audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
|
||||
}
|
||||
if (audioLevel > AUDIO_METER_SCALE_WIDTH) {
|
||||
audioLevel = AUDIO_METER_SCALE_WIDTH;
|
||||
}
|
||||
bool isClipping = ((audio->getTimeSinceLastClip() > 0.f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
||||
|
||||
if ((audio->getTimeSinceLastClip() > 0.f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
|
||||
const float MAX_MAGNITUDE = 0.7f;
|
||||
float magnitude = MAX_MAGNITUDE * (1 - audio->getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
|
||||
renderCollisionOverlay(glWidget->width(), glWidget->height(), magnitude, 1.0f);
|
||||
}
|
||||
|
||||
audio->renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
|
||||
audioMeterY,
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
|
||||
|
||||
audio->renderScope(glWidget->width(), glWidget->height());
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
if (isClipping) {
|
||||
glColor3f(1, 0, 0);
|
||||
} else {
|
||||
glColor3f(0.475f, 0.475f, 0.475f);
|
||||
}
|
||||
|
||||
audioMeterY += AUDIO_METER_HEIGHT;
|
||||
|
||||
glColor3f(0, 0, 0);
|
||||
// Draw audio meter background Quad
|
||||
glVertex2i(AUDIO_METER_X, audioMeterY);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
|
||||
glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
|
||||
|
||||
if (audioLevel > AUDIO_RED_START) {
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_RED);
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
}
|
||||
// Draw Red Quad
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
audioLevel = AUDIO_RED_START;
|
||||
}
|
||||
if (audioLevel > AUDIO_GREEN_START) {
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_GREEN);
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
}
|
||||
// Draw Green Quad
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
audioLevel = AUDIO_GREEN_START;
|
||||
}
|
||||
// Draw Blue Quad
|
||||
if (!isClipping) {
|
||||
glColor3fv(AUDIO_METER_BLUE);
|
||||
} else {
|
||||
glColor3f(1, 1, 1);
|
||||
}
|
||||
// Draw Blue (low level) quad
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||
glEnd();
|
||||
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
|
||||
myAvatar->renderHeadMouse(glWidget->width(), glWidget->height());
|
||||
}
|
||||
|
||||
// Display stats and log text onscreen
|
||||
glLineWidth(1.0f);
|
||||
glPointSize(1.0f);
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
// let's set horizontal offset to give stats some margin to mirror
|
||||
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
|
||||
int voxelPacketsToProcess = voxelPacketProcessor.packetsToProcessCount();
|
||||
// Onscreen text about position, servers, etc
|
||||
Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(), application->getPacketsPerSecond(), application->getBytesPerSecond(), voxelPacketsToProcess);
|
||||
// Bandwidth meter
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
|
||||
Stats::drawBackground(0x33333399, glWidget->width() - 296, glWidget->height() - 68, 296, 68);
|
||||
bandwidthMeter->render(glWidget->width(), glWidget->height());
|
||||
}
|
||||
}
|
||||
|
||||
// Show on-screen msec timer
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||
char frameTimer[10];
|
||||
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
|
||||
int timerBottom =
|
||||
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
|
||||
? 80 : 20;
|
||||
drawText(glWidget->width() - 100, glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
|
||||
}
|
||||
nodeBoundsDisplay.drawOverlay();
|
||||
|
||||
// give external parties a change to hook in
|
||||
emit application->renderingOverlay();
|
||||
|
||||
overlays.render2D();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_LIGHTING);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
|
||||
|
||||
if (renderToTexture) {
|
||||
getFramebufferObject()->release();
|
||||
}
|
||||
}
|
||||
|
||||
// Draws the FBO texture for the screen
|
||||
void ApplicationOverlay::displayOverlayTexture(Camera& whichCamera) {
|
||||
|
||||
Application* application = Application::getInstance();
|
||||
QGLWidget* glWidget = application->getGLWidget();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, glWidget->width(), glWidget->height(), 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0, 0); glVertex2i(0, glWidget->height());
|
||||
glTexCoord2f(1, 0); glVertex2i(glWidget->width(), glWidget->height());
|
||||
glTexCoord2f(1, 1); glVertex2i(glWidget->width(), 0);
|
||||
glTexCoord2f(0, 1); glVertex2i(0, 0);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane.
|
||||
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
||||
|
||||
Application* application = Application::getInstance();
|
||||
|
||||
QGLWidget* glWidget = application->getGLWidget();
|
||||
MyAvatar* myAvatar = application->getAvatar();
|
||||
const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation();
|
||||
|
||||
// Calculates the world space width and height of the texture based on a desired FOV
|
||||
const float overlayFov = whichCamera.getFieldOfView() * PI / 180.0f;
|
||||
const float overlayDistance = 1;
|
||||
const float overlayAspectRatio = glWidget->width() / (float)glWidget->height();
|
||||
const float overlayHeight = overlayDistance * tan(overlayFov);
|
||||
const float overlayWidth = overlayHeight * overlayAspectRatio;
|
||||
const float halfOverlayWidth = overlayWidth / 2;
|
||||
const float halfOverlayHeight = overlayHeight / 2;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
// Transform to world space
|
||||
glm::quat rotation = whichCamera.getRotation();
|
||||
glm::vec3 axis2 = glm::axis(rotation);
|
||||
glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z);
|
||||
glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z);
|
||||
|
||||
// Translate to the front of the camera
|
||||
glm::vec3 pos = whichCamera.getPosition();
|
||||
glm::quat rot = myAvatar->getOrientation();
|
||||
glm::vec3 axis = glm::axis(rot);
|
||||
pos += rot * glm::vec3(0.0, 0.0, -overlayDistance);
|
||||
|
||||
glTranslatef(pos.x, pos.y, pos.z);
|
||||
glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1, 0); glVertex3f(-halfOverlayWidth, halfOverlayHeight, 0);
|
||||
glTexCoord2f(0, 0); glVertex3f(halfOverlayWidth, halfOverlayHeight, 0);
|
||||
glTexCoord2f(0, 1); glVertex3f(halfOverlayWidth, -halfOverlayHeight, 0);
|
||||
glTexCoord2f(1, 1); glVertex3f(-halfOverlayWidth, -halfOverlayHeight, 0);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() {
|
||||
if (!_framebufferObject) {
|
||||
_framebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size());
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
return _framebufferObject;
|
||||
}
|
||||
|
38
interface/src/ui/ApplicationOverlay.h
Normal file
38
interface/src/ui/ApplicationOverlay.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// ApplicationOverlay.h
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_ApplicationOverlay_h
|
||||
#define hifi_ApplicationOverlay_h
|
||||
|
||||
class Overlays;
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
// Handles the drawing of the overlays to the scree
|
||||
class ApplicationOverlay {
|
||||
public:
|
||||
|
||||
ApplicationOverlay();
|
||||
~ApplicationOverlay();
|
||||
|
||||
void renderOverlay(bool renderToTexture = false);
|
||||
void displayOverlayTexture(Camera& whichCamera);
|
||||
void displayOverlayTextureOculus(Camera& whichCamera);
|
||||
|
||||
// Getters
|
||||
QOpenGLFramebufferObject* getFramebufferObject();
|
||||
|
||||
private:
|
||||
|
||||
QOpenGLFramebufferObject* _framebufferObject;
|
||||
float _trailingAudioLoudness;
|
||||
};
|
||||
|
||||
#endif // hifi_ApplicationOverlay_h
|
Loading…
Reference in a new issue