150 lines
5.3 KiB
C++
150 lines
5.3 KiB
C++
/*
|
|
* 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/IFontAtlasGenerator.hpp"
|
|
#include "Base/Logger.hpp"
|
|
#include <optional>
|
|
|
|
namespace OpenVulkano::Scene
|
|
{
|
|
namespace
|
|
{
|
|
Shader MakeLabelBgShader(const bool billboard)
|
|
{
|
|
Shader backgroundShader;
|
|
if (!billboard)
|
|
{
|
|
backgroundShader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/label");
|
|
}
|
|
else
|
|
{
|
|
backgroundShader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/labelBillboard");
|
|
// binding for billboard's buffer
|
|
DescriptorSetLayoutBinding binding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
|
|
binding.stageFlags = ShaderProgramType::Type::VERTEX;
|
|
backgroundShader.AddDescriptorSetLayoutBinding(binding, 4);
|
|
}
|
|
backgroundShader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/label");
|
|
backgroundShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING, 2);
|
|
backgroundShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 5);
|
|
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;
|
|
if (billboard)
|
|
{
|
|
for (auto& program : shader.shaderPrograms)
|
|
{
|
|
if (program.type == ShaderProgramType::VERTEX)
|
|
{
|
|
program.name = "Shader/textBillboard";
|
|
break;
|
|
}
|
|
}
|
|
DescriptorSetLayoutBinding billboardUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
|
|
billboardUniformBinding.stageFlags = ShaderProgramType::Type::VERTEX;
|
|
shader.AddDescriptorSetLayoutBinding(billboardUniformBinding, 4);
|
|
}
|
|
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<int>(type) << 1 | billboard];
|
|
}
|
|
}
|
|
|
|
LabelDrawable::LabelDrawable(const std::shared_ptr<AtlasData>& atlasData, const LabelDrawableSettings& settings, const bool isBillboard)
|
|
: Drawable(DrawEncoder::GetDrawEncoder<LabelDrawable>(), DrawPhase::MAIN), m_atlasData(atlasData), m_isBillboard(isBillboard)
|
|
{
|
|
if (atlasData->glyphs.empty() || !atlasData->texture.size)
|
|
{
|
|
throw std::runtime_error("Can't create label drawable. Either glyphs or texture is empty");
|
|
}
|
|
SetLabelSettings(settings);
|
|
SetShader(IsBillboard() ? &BACKGROUND_BILLBOARD_SHADER : &BACKGROUND_SHADER);
|
|
SetupBuffers();
|
|
}
|
|
|
|
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;
|
|
m_labelData.arrowLength = settings.arrowLength;
|
|
m_labelData.arrowWidth = settings.arrowWidth;
|
|
}
|
|
|
|
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->meta.lineHeight;
|
|
textDrawable.GenerateText(text, m_position);
|
|
textDrawable.SetShader(GetTextShader(m_atlasData->meta.atlasType, m_isBillboard));
|
|
m_bbox.Grow(textDrawable.GetBoundingBox());
|
|
// update position for next text entry
|
|
m_position.y = m_bbox.GetMin().y - lineHeight;
|
|
|
|
Math::Vector2f padding = m_settings.padding * 2;
|
|
if (m_settings.hasArrow) padding.y += m_settings.arrowLength;
|
|
|
|
m_labelData.textSize = Math::Vector2f(m_bbox.GetSize()) + padding * 2;
|
|
m_labelData.bboxCenter = { m_bbox.GetCenter() };
|
|
if (m_settings.hasArrow) m_labelData.bboxCenter.y -= m_settings.arrowLength;
|
|
}
|
|
|
|
void LabelDrawable::SetBillboardSettings(const BillboardControlBlock& settings)
|
|
{
|
|
m_billboardSettings = settings;
|
|
}
|
|
|
|
std::optional<RayHit> LabelDrawable::Intersect(const Ray& ray) const
|
|
{
|
|
return ray.IntersectAABB(m_bbox);
|
|
}
|
|
|
|
void LabelDrawable::SetupBuffers()
|
|
{
|
|
m_billboardBuffer.size = sizeof(BillboardControlBlock);
|
|
m_billboardBuffer.data = &m_billboardSettings;
|
|
m_billboardBuffer.setId = 4;
|
|
DescriptorSetLayoutBinding binding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
|
|
binding.stageFlags = ShaderProgramType::Type::VERTEX;
|
|
m_billboardBuffer.binding = binding;
|
|
|
|
m_labelBuffer.size = sizeof(LabelUniformData);
|
|
m_labelBuffer.data = &m_labelData;
|
|
m_labelBuffer.setId = 5;
|
|
m_labelBuffer.binding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
|
|
}
|
|
}
|