ZappoManone more tryccd2f9811 years agoHistory
262 lines · 9.7 KB · C++
RawDownload
////  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/AudioScope.h"#include "Application.h"#include "ApplicationOverlay.h" #include "Util.h"#include "ui/Stats.h"#include "ui/AvatarInputs.h" 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; 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 screenvoid ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {    PROFILE_RANGE(__FUNCTION__);    CHECK_GL_ERROR();    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");     // TODO move to Application::idle()?    Stats::getInstance()->updateStats();    AvatarInputs::getInstance()->update();     buildFramebufferObject();        if (!_overlayFramebuffer) {        return; // we can't do anything without our frame buffer.    }     // Execute the batch into our framebuffer    gpu::Batch batch;    renderArgs->_batch = &batch;     int width = _overlayFramebuffer->getWidth();    int height = _overlayFramebuffer->getHeight();     batch.setViewportTransform(glm::ivec4(0, 0, width, height));     // 1) bind the framebuffer    batch.setFramebuffer(_overlayFramebuffer);     // 2) clear it...    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f };    float depth = 1.0f;    int stencil = 0;    batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil);     // Now render the overlay components together into a single texture    renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope    renderStatsAndLogs(renderArgs);  // currently renders nothing    renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line    renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture     renderArgs->_context->syncCache();    renderArgs->_context->render(batch);     renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch     CHECK_GL_ERROR();} void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {    PROFILE_RANGE(__FUNCTION__);    if (_uiTexture) {        gpu::Batch& batch = *renderArgs->_batch;        auto geometryCache = DependencyManager::get<GeometryCache>();         geometryCache->useSimpleDrawPipeline(batch);        batch.setProjectionTransform(mat4());        batch.setModelTransform(Transform());        batch.setViewTransform(Transform());        batch._glBindTexture(GL_TEXTURE_2D, _uiTexture);         geometryCache->renderUnitQuad(batch, glm::vec4(1));    }} void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {    PROFILE_RANGE(__FUNCTION__);     gpu::Batch& batch = *renderArgs->_batch;    auto geometryCache = DependencyManager::get<GeometryCache>();    geometryCache->useSimpleDrawPipeline(batch);    auto textureCache = DependencyManager::get<TextureCache>();    batch.setResourceTexture(0, textureCache->getWhiteTexture());    int width = renderArgs->_viewport.z;    int height = renderArgs->_viewport.w;    mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);    batch.setProjectionTransform(legacyProjection);    batch.setModelTransform(Transform());    batch.setViewTransform(Transform());    batch._glLineWidth(1.0f); // default        {        // Render all of the Script based "HUD" aka 2D overlays.        // note: we call them HUD, as opposed to 2D, only because there are some cases of 3D HUD overlays, like the        // cameral controls for the edit.js        qApp->getOverlays().renderHUD(renderArgs);                // Render the audio scope        int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0;        int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0;        DependencyManager::get<AudioScope>()->render(renderArgs, width, height);    }} 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);    }    */} 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 = *renderArgs->_batch;        auto geometryCache = DependencyManager::get<GeometryCache>();        geometryCache->useSimpleDrawPipeline(batch);        batch.setProjectionTransform(mat4());        batch.setModelTransform(mat4());        batch.setResourceTexture(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);    }} void ApplicationOverlay::buildFramebufferObject() {    PROFILE_RANGE(__FUNCTION__);     QSize desiredSize = qApp->getDeviceSize();    int currentWidth = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0;    int currentHeight = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0;    QSize frameBufferCurrentSize(currentWidth, currentHeight);        if (_overlayFramebuffer && desiredSize == frameBufferCurrentSize) {        // Already built        return;    }        if (_overlayFramebuffer) {        _overlayFramebuffer.reset();        _overlayDepthTexture.reset();        _overlayColorTexture.reset();    }     _overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());    auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);   auto width = desiredSize.width();   auto height = desiredSize.height();     // NOTE: I need to make sure this gpu::Sampler is using these values...    //    // 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);    // glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);    auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);   _overlayColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));   _overlayFramebuffer->setRenderBuffer(0, _overlayColorTexture);    auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);   _overlayDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));    _overlayFramebuffer->setDepthStencilBuffer(_overlayDepthTexture, depthFormat);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t