275 lines · 11.2 KB · C++
RawDownload
////  DrawStatus.cpp//  render/src/render////  Created by Niraj Venkat on 6/29/15.//  Copyright 2015 High Fidelity, Inc.//  Copyright 2024 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "DrawStatus.h" #include <algorithm>#include <assert.h> #include <PerfStat.h>#include <ViewFrustum.h> #include "TransitionStage.h" #include <gpu/Context.h> #include <shaders/Shaders.h> #include "Args.h" using namespace render; void DrawStatusConfig::dirtyHelper() {    _isEnabled = showNetwork || showDisplay || showFade;    emit dirty();} gpu::PipelinePointer DrawStatus::_drawItemBoundsPipeline;gpu::PipelinePointer DrawStatus::_drawItemStatusPipeline;gpu::Stream::FormatPointer DrawStatus::_vertexFormat; const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() {    if (!_drawItemBoundsPipeline) {        gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::drawItemBounds);         auto state = std::make_shared<gpu::State>();         state->setDepthTest(true, false, ComparisonFunction::LESS_EQUAL);         // Blend on transparent        state->setBlendFunction(true,            gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,            gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);         // Good to go add the brand new pipeline        _drawItemBoundsPipeline = gpu::Pipeline::create(program, state);    }    return _drawItemBoundsPipeline;} const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() {    if (!_drawItemStatusPipeline) {        gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render::program::drawItemStatus);         auto state = std::make_shared<gpu::State>();         state->setDepthTest(false, false, ComparisonFunction::LESS_EQUAL);         // Blend on transparent        state->setBlendFunction(true,            gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,            gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);         // Good to go add the brand new pipeline        _drawItemStatusPipeline = gpu::Pipeline::create(program, state);    }    return _drawItemStatusPipeline;} void DrawStatus::setStatusIconMap(const gpu::TexturePointer& map) {    _statusIconMap = map;} const gpu::TexturePointer DrawStatus::getStatusIconMap() const {    return _statusIconMap;} void DrawStatus::configure(const Config& config) {    _showDisplay = config.showDisplay;    _showNetwork = config.showNetwork;    _showFade = config.showFade;} void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inItems) {    assert(renderContext->args);    assert(renderContext->args->hasViewFrustum());    RenderArgs* args = renderContext->args;    auto& scene = renderContext->_scene;    const int NUM_STATUS_VEC4_PER_ITEM = 2;    const int VEC4_LENGTH = 4;     // First thing, we collect the bound and the status for all the items we want to render    int nbItems = 0;    render::ItemBounds itemBounds;    std::vector<std::pair<glm::ivec4, glm::ivec4>> itemStatus;     for (size_t i = 0; i < inItems.size(); ++i) {        const auto& item = inItems[i];        if (!item.bound.isInvalid()) {            if (!item.bound.isNull()) {                itemBounds.emplace_back(render::ItemBound(item.id, item.bound));            } else {                itemBounds.emplace_back(item.id, AABox(item.bound.getCorner(), 0.1f));            }             auto& itemScene = scene->getItem(item.id);             if (_showNetwork || _showFade) {                const static auto invalid = glm::ivec4(Item::Status::Value::INVALID.getPackedData());                itemStatus.emplace_back(invalid, invalid);                int vec4Num = 0;                int vec4Component = 0;                 if (_showNetwork) {                    auto itemStatusPointer = itemScene.getStatus();                    if (itemStatusPointer) {                        // Query the current status values, this is where the statusGetter lambda get called                        auto&& currentStatusValues = itemStatusPointer->getCurrentValues();                        for (const auto& statusValue : currentStatusValues) {                            if (vec4Num == NUM_STATUS_VEC4_PER_ITEM) {                                // Ran out of space                                break;                            }                             auto& value = (vec4Num == 0 ? itemStatus[nbItems].first : itemStatus[nbItems].second);                            value[vec4Component] = statusValue.getPackedData();                             ++vec4Component;                            if (vec4Component == VEC4_LENGTH) {                                vec4Component = 0;                                ++vec4Num;                            }                        }                    }                }                 if (_showFade && vec4Num != NUM_STATUS_VEC4_PER_ITEM) {                    auto& value = (vec4Num == 0 ? itemStatus[nbItems].first : itemStatus[nbItems].second);                     Item::Status::Value status;                    auto transitionID = itemScene.getTransitionId();                    if (transitionID != INVALID_INDEX) {                        // We have a transition. Show this icon.                        status.setScale(1.0f);                        // Is this a valid transition ID according to FadeJob?                        auto transitionStage = scene->getStage<TransitionStage>();                        if (transitionStage) {                            if (transitionStage->isTransitionUsed(transitionID)) {                                // Valid, active transition                                status.setColor(Item::Status::Value::CYAN);                            } else {                                // Render item has a defined transition ID, but it's unallocated and isn't being processed                                status.setColor(Item::Status::Value::RED);                            }                            // Set icon based on transition type                            auto& transition = transitionStage->getElement(transitionID);                            switch (transition.eventType) {                            case TransitionType::USER_ENTER_DOMAIN:                                status.setIcon((unsigned char)Item::Status::Icon::USER_TRANSITION_IN);                                break;                            case TransitionType::USER_LEAVE_DOMAIN:                                status.setIcon((unsigned char)Item::Status::Icon::USER_TRANSITION_OUT);                                break;                            case TransitionType::ELEMENT_ENTER_DOMAIN:                                status.setIcon((unsigned char)Item::Status::Icon::GENERIC_TRANSITION_IN);                                break;                            case TransitionType::ELEMENT_LEAVE_DOMAIN:                                status.setIcon((unsigned char)Item::Status::Icon::GENERIC_TRANSITION_OUT);                                break;                            default:                                status.setIcon((unsigned char)Item::Status::Icon::GENERIC_TRANSITION);                                break;                            }                        } else {                            // No way to determine transition                            status.setScale(0.0f);                        }                    } else {                        status.setScale(0.0f);                    }                    value[vec4Component] = status.getPackedData();                     ++vec4Component;                    if (vec4Component == VEC4_LENGTH) {                        vec4Component = 0;                        ++vec4Num;                    }                }            }             nbItems++;        }    }     if (nbItems == 0) {        return;    }     if (!_boundsBuffer) {        _boundsBuffer = std::make_shared<gpu::Buffer>(gpu::Buffer::ResourceBuffer, sizeof(render::ItemBound));    }     // Alright, something to render let's do it    gpu::doInBatch("DrawStatus::run", args->_context, [&](gpu::Batch& batch) {        batch.setViewportTransform(args->_viewport);        batch.setSavedViewProjectionTransform(_transformSlot);        batch.setModelTransform(Transform());         // bind the one gpu::Pipeline we need        batch.setPipeline(getDrawItemBoundsPipeline());         _boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());         if (_showDisplay) {            batch.setResourceBuffer(0, _boundsBuffer);            batch.draw(gpu::LINES, (gpu::uint32) itemBounds.size() * 24, 0);        }        batch.setResourceBuffer(0, 0);         batch.setResourceTexture(0, gpu::TextureView(getStatusIconMap(), 0));         batch.setPipeline(getDrawItemStatusPipeline());         if (_showNetwork || _showFade) {            if (!_instanceBuffer) {                _instanceBuffer = std::make_shared<gpu::Buffer>(gpu::Buffer::VertexBuffer);// VKTODO: is this correct?            }             struct InstanceData {                vec4 boundPos;                vec4 boundDim;                ivec4 status0;                ivec4 status1;            };             if (!_vertexFormat) {                _vertexFormat = std::make_shared<gpu::Stream::Format>();                _vertexFormat->setAttribute(0, 0, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW), offsetof(InstanceData, boundPos), gpu::Stream::PER_INSTANCE);                _vertexFormat->setAttribute(1, 0, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW), offsetof(InstanceData, boundDim), gpu::Stream::PER_INSTANCE);                _vertexFormat->setAttribute(2, 0, gpu::Element(gpu::VEC4, gpu::INT32, gpu::XYZW), offsetof(InstanceData, status0), gpu::Stream::PER_INSTANCE);                _vertexFormat->setAttribute(3, 0, gpu::Element(gpu::VEC4, gpu::INT32, gpu::XYZW), offsetof(InstanceData, status1), gpu::Stream::PER_INSTANCE);            }             batch.setInputFormat(_vertexFormat);            std::vector<InstanceData> instanceData;            instanceData.resize(itemBounds.size());            for (size_t i = 0; i < itemBounds.size(); i++) {                InstanceData& item = instanceData[i];                const auto& bound = itemBounds[i].bound;                const auto& status = itemStatus[i];                item.boundPos = vec4(bound.getCorner(), 1.0f);                item.boundDim = vec4(bound.getScale(), 1.0f);                item.status0 = status.first;                item.status1 = status.second;            }             auto instanceBufferSize = sizeof(InstanceData) * instanceData.size();            if (_instanceBuffer->getSize() < instanceBufferSize) {                _instanceBuffer->resize(instanceBufferSize);            }            _instanceBuffer->setSubData(0, instanceData);            batch.setInputBuffer(0, _instanceBuffer, 0, sizeof(InstanceData));            batch.drawInstanced((uint32_t)instanceData.size(), gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM);        }        batch.setResourceTexture(0, 0);    });}

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