add bounding box for text drawable and add possibility to share data among different instances

This commit is contained in:
ohyzha
2024-08-22 13:27:08 +03:00
parent 31390ec9ae
commit 4fce5fd1de
2 changed files with 75 additions and 35 deletions

View File

@@ -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<char>& 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<AtlasData>();
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<uint32_t, GlyphInfo>& glyphData, Texture* atlasTex,
const TextConfig& config)
TextDrawable::TextDrawable(const std::shared_ptr<AtlasData>& 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<Texture*>(&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<uint32_t, GlyphInfo>* 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<Texture*>(&m_fontAtlasGenerator->GetAtlas());
symbols = &m_fontAtlasGenerator->GetGlyphsInfo();
}
// just in case if FontAtlasGenerator changed it's atlas
m_material.texture = const_cast<Texture*>(&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>& 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())

View File

@@ -33,32 +33,42 @@ namespace OpenVulkano::Scene
//bool sdfMultiChannel = false;
};
struct AtlasData
{
std::map<uint32_t, GlyphInfo> glyphs;
AtlasMetadata meta;
std::unique_ptr<Image::Image> img;
Texture texture;
};
class TextDrawable : public SimpleDrawable
{
public:
static Shader& GetSdfDefaultShader();
static Shader& GetMsdfDefaultShader();
TextDrawable(const TextConfig& config = TextConfig());
TextDrawable(const Array<char>& 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<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config = TextConfig());
TextDrawable(const std::map<uint32_t, GlyphInfo>& glyphData, Texture* atlasTex, const TextConfig& config = TextConfig());
TextDrawable(const std::shared_ptr<AtlasData>& 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>& atlasData);
Math::AABB& GetBoundingBox() { return m_bbox; }
TextConfig& GetConfig() { return m_cfg; }
Shader* GetShader() { return m_shader; }
std::shared_ptr<AtlasData> 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<uint32_t, GlyphInfo> m_glyphs;
AtlasMetadata m_meta;
std::unique_ptr<Image::Image> m_img;
std::optional<Texture> m_texture;
std::shared_ptr<AtlasData> m_atlasData;
Math::AABB m_bbox;
IFontAtlasGenerator* m_fontAtlasGenerator = nullptr;
Shader* m_shader = nullptr;
TextConfig m_cfg;