/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "LabelDrawable.hpp" #include "Scene/TextDrawable.hpp" #include "Scene/DrawEncoder.hpp" #include "Scene/Vertex.hpp" #include "Scene/Shader/Shader.hpp" #include "Scene/Text/IFontAtlasGenerator.hpp" #include "Scene/Text/FontAtlasType.hpp" #include namespace OpenVulkano::Scene { namespace { Shader MakeLabelBgShader(const bool billboard) { Shader backgroundShader; backgroundShader.AddShaderProgram(ShaderProgramType::VERTEX, billboard ? "Shader/labelBillboard" : "Shader/label"); backgroundShader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/label"); backgroundShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING, 2); backgroundShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 4); backgroundShader.topology = Topology::TRIANGLE_STRIP; backgroundShader.cullMode = CullMode::NONE; return backgroundShader; } Shader MakeLabelTextShader(const FontAtlasType type, const bool billboard) { Shader shader = TextDrawable::MakeDefaultShader(type); shader.depthCompareOp = CompareOp::LESS_OR_EQUAL; shader.EnableDepthBias(); if (billboard) { for (auto& program : shader.shaderPrograms) { if (program.type == ShaderProgramType::VERTEX) { program.name = "Shader/textBillboard"; break; } } DescriptorSetLayoutBinding billboardUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; shader.AddDescriptorSetLayoutBinding(billboardUniformBinding, 4); shader.depthBiasConstant = 0.01f; } return shader; } Shader BACKGROUND_SHADER = MakeLabelBgShader(false); Shader BACKGROUND_BILLBOARD_SHADER = MakeLabelBgShader(true); std::array TEXT_SHADERS = { MakeLabelTextShader(FontAtlasType::SDF, false), MakeLabelTextShader(FontAtlasType::SDF, true), MakeLabelTextShader(FontAtlasType::MSDF, false), MakeLabelTextShader(FontAtlasType::MSDF, true), MakeLabelTextShader(FontAtlasType::BITMAP, false), MakeLabelTextShader(FontAtlasType::BITMAP, true), }; Shader* GetTextShader(const FontAtlasType type, const bool billboard) { return &TEXT_SHADERS[(static_cast(type) << 1) + billboard]; } } LabelDrawable::LabelDrawable(const std::shared_ptr& atlasData, const LabelDrawableSettings& settings) : Drawable(DrawEncoder::GetDrawEncoder(), DrawPhase::MAIN), m_atlasData(atlasData) , m_labelBuffer(sizeof(LabelUniformData), &m_labelData, 4) { if (!atlasData || !*atlasData) throw std::runtime_error("Can't create label drawable. Either glyphs or texture is empty"); SetLabelSettings(settings); SetShader(IsBillboard() ? &BACKGROUND_BILLBOARD_SHADER : &BACKGROUND_SHADER); } void LabelDrawable::SetLabelSettings(const LabelDrawableSettings& settings) { m_settings = settings; m_labelData.color = settings.backgroundColor; m_labelData.hasRoundedCorners = settings.hasRoundedCorners; m_labelData.hasArrow = settings.hasArrow; m_labelData.cornerRadius = settings.cornerRadius * settings.cornerRadius * settings.scale; m_labelData.arrowLength = settings.arrowLength * settings.scale; m_labelData.arrowWidth = settings.arrowWidth * settings.scale; } void LabelDrawable::AddText(const std::string& text, const TextConfig& config) { if (text.empty()) return; TextDrawable& textDrawable = m_texts.emplace_back(m_atlasData, config); textDrawable.GetConfig().backgroundColor.a = 0; // do not render glyph's background double lineHeight = m_atlasData->GetLineHeight(); textDrawable.GenerateText(text, m_position, m_settings.scale); textDrawable.SetShader(GetTextShader(m_atlasData->GetAtlasType(), IsBillboard())); m_bbox.Grow(textDrawable.GetBoundingBox()); // update position for next text entry m_position.y = m_bbox.GetMin().y - lineHeight * m_settings.scale; Math::Vector2f padding = m_settings.padding * 2 * m_settings.scale; if (m_settings.hasArrow) padding.y += m_settings.arrowLength * m_settings.scale; m_labelData.textSize = m_bbox.GetSize() + padding; m_labelData.bboxCenter = m_bbox.GetCenter(); if (m_settings.hasArrow) m_labelData.bboxCenter.y -= m_settings.arrowLength * 0.5f * m_settings.scale; } std::optional LabelDrawable::Intersect(const Ray& ray) const { return ray.IntersectAABB(m_bbox); } }