From 4fce5fd1de9a5f1ed7cb13373e77f64e7a1620a1 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Thu, 22 Aug 2024 13:27:08 +0300 Subject: [PATCH] add bounding box for text drawable and add possibility to share data among different instances --- openVulkanoCpp/Scene/TextDrawable.cpp | 90 ++++++++++++++++++--------- openVulkanoCpp/Scene/TextDrawable.hpp | 20 ++++-- 2 files changed, 75 insertions(+), 35 deletions(-) diff --git a/openVulkanoCpp/Scene/TextDrawable.cpp b/openVulkanoCpp/Scene/TextDrawable.cpp index 39f2a71..190d807 100644 --- a/openVulkanoCpp/Scene/TextDrawable.cpp +++ b/openVulkanoCpp/Scene/TextDrawable.cpp @@ -30,7 +30,9 @@ namespace OpenVulkano::Scene sdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/text"); sdfDefaultShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); sdfDefaultShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); - sdfDefaultShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); + DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; + desc.stageFlags = ShaderProgramType::FRAGMENT; + sdfDefaultShader.AddDescriptorSetLayoutBinding(desc); sdfDefaultShader.alphaBlend = true; sdfDefaultShader.cullMode = CullMode::NONE; once = false; @@ -48,7 +50,9 @@ namespace OpenVulkano::Scene msdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/msdfText"); msdfDefaultShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); msdfDefaultShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); - msdfDefaultShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); + DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; + desc.stageFlags = ShaderProgramType::FRAGMENT; + msdfDefaultShader.AddDescriptorSetLayoutBinding(desc); msdfDefaultShader.alphaBlend = true; msdfDefaultShader.cullMode = CullMode::NONE; once = false; @@ -56,6 +60,13 @@ namespace OpenVulkano::Scene return msdfDefaultShader; } + TextDrawable::TextDrawable(const TextConfig& config) + { + m_cfg = config; + m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); + m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; + } + TextDrawable::TextDrawable(const Array& atlasMetadata, const TextConfig& config) : TextDrawable(atlasMetadata, nullptr, config) { @@ -79,20 +90,22 @@ namespace OpenVulkano::Scene std::memcpy(&metadataBytes, atlasMetadata.Data() + (atlasMetadata.Size() - sizeof(uint32_t) - sizeof(uint64_t)), sizeof(uint64_t)); uint64_t offsetToMetadata = atlasMetadata.Size() - metadataBytes - sizeof(uint32_t) - sizeof(uint64_t); + m_atlasData = std::make_shared(); if (isPacked) { - m_texture = Texture(); - m_material.texture = &m_texture.value(); - m_img = Image::IImageLoader::loadData((const uint8_t*) atlasMetadata.Data(), + m_atlasData->texture = Texture(); + m_material.texture = &m_atlasData->texture; + m_atlasData->img = Image::IImageLoader::loadData((const uint8_t*) atlasMetadata.Data(), offsetToMetadata); - m_material.texture->format = m_img->dataFormat; - m_material.texture->resolution = m_img->resolution; - m_material.texture->size = m_img->data.Size(); - m_material.texture->textureBuffer = m_img->data.Data(); + m_material.texture->format = m_atlasData->img->dataFormat; + m_material.texture->resolution = m_atlasData->img->resolution; + m_material.texture->size = m_atlasData->img->data.Size(); + m_material.texture->textureBuffer = m_atlasData->img->data.Data(); } else { if (atlasTex == nullptr) { throw std::runtime_error("Atlas texture cannot be null with non-packed atlas metadata"); } + m_atlasData->texture = *atlasTex; m_material.texture = atlasTex; } @@ -101,7 +114,7 @@ namespace OpenVulkano::Scene size_t readMetadataBytes = 0; uint32_t unicode = 0; - std::memcpy(&m_meta, atlasMetadata.Data() + read_bytes, sizeof(AtlasMetadata)); + std::memcpy(&m_atlasData->meta, atlasMetadata.Data() + read_bytes, sizeof(AtlasMetadata)); read_bytes += sizeof(AtlasMetadata); readMetadataBytes += sizeof(AtlasMetadata); while (readMetadataBytes < metadataBytes) @@ -109,24 +122,27 @@ namespace OpenVulkano::Scene std::memcpy(&unicode, atlasMetadata.Data() + read_bytes, sizeof(uint32_t)); read_bytes += sizeof(uint32_t); readMetadataBytes += sizeof(uint32_t); - GlyphInfo& info = m_glyphs[unicode]; + GlyphInfo& info = m_atlasData->glyphs[unicode]; std::memcpy(&info, atlasMetadata.Data() + read_bytes, sizeof(GlyphInfo)); read_bytes += sizeof(GlyphInfo); readMetadataBytes += sizeof(GlyphInfo); } m_cfg = config; m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); + m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; } - TextDrawable::TextDrawable(const std::map& glyphData, Texture* atlasTex, - const TextConfig& config) + TextDrawable::TextDrawable(const std::shared_ptr& atlasData, const TextConfig& config) { - if (!atlasTex) { throw std::runtime_error("Atlas texture is nullptr"); } - if (glyphData.empty()) { throw std::runtime_error("Glyphs are not loaded"); } - m_material.texture = atlasTex; - m_glyphs = glyphData; + if (!atlasData || atlasData->glyphs.empty() || !atlasData->texture.textureBuffer) + { + throw std::runtime_error("Cannot initialize text drawable with empty atlas data"); + } + m_atlasData = atlasData; + m_material.texture = &atlasData->texture; m_cfg = config; m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); + m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; } TextDrawable::TextDrawable(IFontAtlasGenerator* fontAtlasGenerator, const TextConfig& config) @@ -137,6 +153,7 @@ namespace OpenVulkano::Scene m_cfg = config; m_material.texture = const_cast(&m_fontAtlasGenerator->GetAtlas()); m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); + m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; } void TextDrawable::GenerateText(const std::string& text, const Math::Vector3f& pos) @@ -170,23 +187,16 @@ namespace OpenVulkano::Scene std::map* symbols; if (m_fontAtlasGenerator) { - if (m_fontAtlasGenerator->GetGlyphsInfo().empty() && !m_glyphs.empty()) - { - // texture is set in ctor - symbols = &m_glyphs; - } - else - { - // just in case if FontAtlasGenerator changed it's atlas - m_material.texture = const_cast(&m_fontAtlasGenerator->GetAtlas()); - symbols = &m_fontAtlasGenerator->GetGlyphsInfo(); - } + // just in case if FontAtlasGenerator changed it's atlas + m_material.texture = const_cast(&m_fontAtlasGenerator->GetAtlas()); + symbols = &m_fontAtlasGenerator->GetGlyphsInfo(); meta = &m_fontAtlasGenerator->GetAtlasMetadata(); } else { - symbols = &m_glyphs; - meta = &m_meta; + m_material.texture = &m_atlasData->texture; + symbols = &m_atlasData->glyphs; + meta = &m_atlasData->meta; } const Texture& atlasTex = *m_material.texture; @@ -196,6 +206,8 @@ namespace OpenVulkano::Scene const double lineHeight = meta->lineHeight; double posY = pos.y; int i = 0; + Math::Vector3f bmin(pos), bmax(pos); + bool firstGlyph = true; while (begin != end) { uint32_t c = utf8::next(begin, end); @@ -251,11 +263,29 @@ namespace OpenVulkano::Scene // TODO: change to lower value(or ideally remove completely) to avoid overlapping and make less space between symbols // when setting for depth comparison operator will be available( <= ) cursorX += info.advance + 0.08; + if (firstGlyph) + { + bmin.x = m_geometry.vertices[vIdx].position.x; + firstGlyph = false; + } + bmax.x = std::max(bmax.x, m_geometry.vertices[vIdx + 1].position.x); + bmax.y = std::max(bmax.y, m_geometry.vertices[vIdx + 2].position.y); + bmin.y = std::min(bmin.y, m_geometry.vertices[vIdx + 1].position.y); ++i; } + m_bbox.Init(bmin, bmax); SimpleDrawable::Init(m_shader, &m_geometry, &m_material, &m_uniBuffer); } + void TextDrawable::SetAtlasData(const std::shared_ptr& atlasData) + { + if (!atlasData || atlasData->glyphs.empty() || !atlasData->texture.textureBuffer) + { + throw std::runtime_error("Cannot initialize text drawable with empty atlas data"); + } + m_atlasData = atlasData; + } + void TextDrawable::SetFontAtlasGenerator(IFontAtlasGenerator* fontAtlasGenerator) { if (!fontAtlasGenerator || fontAtlasGenerator->GetGlyphsInfo().empty()) diff --git a/openVulkanoCpp/Scene/TextDrawable.hpp b/openVulkanoCpp/Scene/TextDrawable.hpp index 1cc99b4..3e898f0 100644 --- a/openVulkanoCpp/Scene/TextDrawable.hpp +++ b/openVulkanoCpp/Scene/TextDrawable.hpp @@ -33,32 +33,42 @@ namespace OpenVulkano::Scene //bool sdfMultiChannel = false; }; + struct AtlasData + { + std::map glyphs; + AtlasMetadata meta; + std::unique_ptr img; + Texture texture; + }; + class TextDrawable : public SimpleDrawable { public: static Shader& GetSdfDefaultShader(); static Shader& GetMsdfDefaultShader(); + TextDrawable(const TextConfig& config = TextConfig()); TextDrawable(const Array& atlasMetadata, const TextConfig& config = TextConfig()); TextDrawable(const std::string& atlasMetadataFile, const TextConfig& config = TextConfig()); TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config = TextConfig()); TextDrawable(const Array& atlasMetadata, Texture* atlasTex, const TextConfig& config = TextConfig()); - TextDrawable(const std::map& glyphData, Texture* atlasTex, const TextConfig& config = TextConfig()); + TextDrawable(const std::shared_ptr& atlasData, const TextConfig& config = TextConfig()); TextDrawable(IFontAtlasGenerator* fontAtlasGenerator, const TextConfig& config = TextConfig()); void GenerateText(const std::string& text, const Math::Vector3f& pos = Math::Vector3f(0.f)); void SetConfig(const TextConfig& cfg) { m_cfg = cfg; } void SetShader(Shader* shader) { m_shader = shader; } + void SetAtlasData(const std::shared_ptr& atlasData); + Math::AABB& GetBoundingBox() { return m_bbox; } TextConfig& GetConfig() { return m_cfg; } Shader* GetShader() { return m_shader; } + std::shared_ptr GetAtlasData() { return m_atlasData; } void SetFontAtlasGenerator(IFontAtlasGenerator* fontAtlasGenerator); IFontAtlasGenerator* GetFontAtlasGenerator() { return m_fontAtlasGenerator; } private: Geometry m_geometry; Material m_material; UniformBuffer m_uniBuffer; - std::map m_glyphs; - AtlasMetadata m_meta; - std::unique_ptr m_img; - std::optional m_texture; + std::shared_ptr m_atlasData; + Math::AABB m_bbox; IFontAtlasGenerator* m_fontAtlasGenerator = nullptr; Shader* m_shader = nullptr; TextConfig m_cfg;