118 lines
4.3 KiB
C++
118 lines
4.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 "Scene/Text/FontAtlasType.hpp"
|
|
#include <optional>
|
|
|
|
|
|
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<int>(type) << 1 | billboard];
|
|
}
|
|
}
|
|
|
|
LabelDrawable::LabelDrawable(const std::shared_ptr<FontAtlas>& atlasData, const LabelDrawableSettings& settings)
|
|
: Drawable(DrawEncoder::GetDrawEncoder<LabelDrawable>(), 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;
|
|
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->GetLineHeight();
|
|
textDrawable.GenerateText(text, m_position);
|
|
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;
|
|
|
|
Math::Vector2f padding = m_settings.padding * 2;
|
|
if (m_settings.hasArrow) padding.y += m_settings.arrowLength;
|
|
|
|
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;
|
|
}
|
|
|
|
std::optional<RayHit> LabelDrawable::Intersect(const Ray& ray) const
|
|
{
|
|
return ray.IntersectAABB(m_bbox);
|
|
}
|
|
}
|