add opportunity to pack atlas and meta data in same file
This commit is contained in:
1
3rdParty/msdf/CMakeLists.txt
vendored
1
3rdParty/msdf/CMakeLists.txt
vendored
@@ -85,6 +85,7 @@ function(LinkMsdf TARGET)
|
|||||||
set(STATIC_LIB_EXT "a")
|
set(STATIC_LIB_EXT "a")
|
||||||
set(freetype_lib_name "libfreetype")
|
set(freetype_lib_name "libfreetype")
|
||||||
endif()
|
endif()
|
||||||
|
target_include_directories(${TARGET} PUBLIC "${VCPKG_SRC_DIR}/installed/${TRIPLET}/include")
|
||||||
# link freetype first to fix linkage issues on linux
|
# link freetype first to fix linkage issues on linux
|
||||||
target_link_libraries(${TARGET} PUBLIC "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib/${freetype_lib_name}.${STATIC_LIB_EXT}")
|
target_link_libraries(${TARGET} PUBLIC "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib/${freetype_lib_name}.${STATIC_LIB_EXT}")
|
||||||
file(GLOB installed_libs "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib/*.${STATIC_LIB_EXT}")
|
file(GLOB installed_libs "${VCPKG_SRC_DIR}/installed/${TRIPLET}/lib/*.${STATIC_LIB_EXT}")
|
||||||
|
|||||||
@@ -67,13 +67,15 @@ namespace OpenVulkano
|
|||||||
m_drawablesPool.resize(N);
|
m_drawablesPool.resize(N);
|
||||||
|
|
||||||
#ifdef MSDFGEN_AVAILABLE
|
#ifdef MSDFGEN_AVAILABLE
|
||||||
Charset charset = Charset::ASCII;
|
Charset charset = FontAtlasGenerator::LoadAllGlyphs(fontPath);
|
||||||
for (unicode_t c = 0x0410; c <= 0x041F; c++)
|
//Charset charset = Charset::ASCII;
|
||||||
{
|
//for (unicode_t c = 0x0410; c <= 0x041F; c++)
|
||||||
// some unicode values
|
//{
|
||||||
charset.add(c);
|
// // some unicode values
|
||||||
}
|
// charset.add(c);
|
||||||
m_atlasGenerator.GenerateAtlas(fontPath, charset, "roboto-regular-atlas.png");
|
//}
|
||||||
|
m_atlasGenerator.GenerateAtlas(fontPath, charset);
|
||||||
|
m_atlasGenerator.SaveAtlasMetadataInfo("atlas_metadata", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < texts.size(); i++)
|
for (int i = 0; i < texts.size(); i++)
|
||||||
@@ -81,16 +83,19 @@ namespace OpenVulkano
|
|||||||
#ifdef MSDFGEN_AVAILABLE
|
#ifdef MSDFGEN_AVAILABLE
|
||||||
TextDrawable* t = new TextDrawable(&m_atlasGenerator, texts[i].second);
|
TextDrawable* t = new TextDrawable(&m_atlasGenerator, texts[i].second);
|
||||||
#else
|
#else
|
||||||
auto metadataInfo = resourceLoader.GetResource("atlas_metadata");
|
auto metadataInfo = resourceLoader.GetResource("full_atlas_metadata_packed");
|
||||||
auto data = resourceLoader.GetResource("roboto-regular-atlas.png");
|
TextDrawable* t = new TextDrawable(metadataInfo, texts[i].second);
|
||||||
Image::ImageLoaderPng loader;
|
// OR use separate texture + metadata file
|
||||||
static auto image = loader.loadData(reinterpret_cast<uint8_t*>(data.Data()), data.Size());
|
//auto metadataInfo = resourceLoader.GetResource("atlas_metadata");
|
||||||
static Texture tex;
|
//auto data = resourceLoader.GetResource("roboto-regular-atlas.png");
|
||||||
tex.resolution = image->resolution;
|
//Image::ImageLoaderPng loader;
|
||||||
tex.textureBuffer = image->data.Data();
|
//static auto image = loader.loadData(reinterpret_cast<uint8_t*>(data.Data()), data.Size());
|
||||||
tex.format = image->dataFormat;
|
//static Texture tex;
|
||||||
tex.size = image->data.Size(); // 1 channel
|
//tex.resolution = image->resolution;
|
||||||
TextDrawable* t = new TextDrawable(metadataInfo, &tex, texts[i].second);
|
//tex.textureBuffer = image->data.Data();
|
||||||
|
//tex.format = image->dataFormat;
|
||||||
|
//tex.size = image->data.Size(); // 1 channel
|
||||||
|
//TextDrawable* t = new TextDrawable(metadataInfo, &tex, texts[i].second);
|
||||||
#endif // MSDFGEN_AVAILABLE
|
#endif // MSDFGEN_AVAILABLE
|
||||||
t->GenerateText(texts[i].first);
|
t->GenerateText(texts[i].first);
|
||||||
m_drawablesPool[i] = t;
|
m_drawablesPool[i] = t;
|
||||||
|
|||||||
Binary file not shown.
BIN
examples/ExampleSources/full_atlas_metadata_packed
Normal file
BIN
examples/ExampleSources/full_atlas_metadata_packed
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 449 KiB |
@@ -7,6 +7,8 @@
|
|||||||
#include "FontAtlasGenerator.hpp"
|
#include "FontAtlasGenerator.hpp"
|
||||||
#include "Base/Logger.hpp"
|
#include "Base/Logger.hpp"
|
||||||
#include "Scene/AtlasMetadata.hpp"
|
#include "Scene/AtlasMetadata.hpp"
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
namespace OpenVulkano::Scene
|
namespace OpenVulkano::Scene
|
||||||
@@ -14,7 +16,41 @@ namespace OpenVulkano::Scene
|
|||||||
using namespace msdfgen;
|
using namespace msdfgen;
|
||||||
using namespace msdf_atlas;
|
using namespace msdf_atlas;
|
||||||
|
|
||||||
void FontAtlasGenerator::GenerateAtlas(const std::string& fontFile, const Charset& charset, const std::optional<std::string>& pngOutput)
|
Charset FontAtlasGenerator::LoadAllGlyphs(const std::variant<std::string, Array<char>>& data)
|
||||||
|
{
|
||||||
|
FT_Library library;
|
||||||
|
auto error = FT_Init_FreeType(&library);
|
||||||
|
if (error) { throw std::runtime_error("Could not initalize freetype library\n"); }
|
||||||
|
FT_Face face;
|
||||||
|
if (std::holds_alternative<std::string>(data))
|
||||||
|
{
|
||||||
|
error = FT_New_Face(library, std::get<0>(data).c_str(), 0, &face);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& arr = std::get<1>(data);
|
||||||
|
error = FT_New_Memory_Face(library, (const FT_Byte*)(arr.Data()), arr.Size(), 0, &face);
|
||||||
|
}
|
||||||
|
if (error == FT_Err_Unknown_File_Format) { throw std::runtime_error("Unknown font file format\n"); }
|
||||||
|
else if (error) { throw std::runtime_error("Font file could not be opened or read or it's corrupted\n"); }
|
||||||
|
|
||||||
|
// some fancy font without unicode charmap
|
||||||
|
if (face->charmap == nullptr) { throw std::runtime_error("Selected font doesn't contain unicode charmap"); }
|
||||||
|
Charset s;
|
||||||
|
FT_UInt glyphIndex;
|
||||||
|
FT_ULong unicode = FT_Get_First_Char(face, &glyphIndex);
|
||||||
|
while (glyphIndex != 0)
|
||||||
|
{
|
||||||
|
s.add(unicode);
|
||||||
|
unicode = FT_Get_Next_Char(face, unicode, &glyphIndex);
|
||||||
|
}
|
||||||
|
FT_Done_Face(face);
|
||||||
|
FT_Done_FreeType(library);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontAtlasGenerator::GenerateAtlas(const std::string& fontFile, const Charset& charset,
|
||||||
|
const std::optional<std::string>& pngOutput)
|
||||||
{
|
{
|
||||||
if (charset.empty())
|
if (charset.empty())
|
||||||
{
|
{
|
||||||
@@ -47,20 +83,43 @@ namespace OpenVulkano::Scene
|
|||||||
Generate(ft, font, charset, pngOutput);
|
Generate(ft, font, charset, pngOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontAtlasGenerator::SaveAtlasMetadataInfo(const std::string& outputFile) const
|
void FontAtlasGenerator::SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile) const
|
||||||
{
|
{
|
||||||
if (m_symbols.empty())
|
if (m_symbols.empty())
|
||||||
{
|
{
|
||||||
Logger::DATA->info("No glyphs loaded. Nothing to save.");
|
Logger::DATA->info("No glyphs loaded. Nothing to save.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::fstream fs(outputFile.c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
|
std::string fileName = outputFile;
|
||||||
|
int extraMode = std::ios_base::trunc;
|
||||||
|
uint32_t packedFlag = 0;
|
||||||
|
if (packIntoSingleFile)
|
||||||
|
{
|
||||||
|
size_t ext = outputFile.find_last_of('.');
|
||||||
|
if (ext == std::string::npos)
|
||||||
|
{
|
||||||
|
fileName += "_packed";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileName.insert(ext - 1, "_packed");
|
||||||
|
}
|
||||||
|
savePng(m_generator.atlasStorage(), fileName.c_str());
|
||||||
|
extraMode = std::ios_base::app;
|
||||||
|
packedFlag = 1;
|
||||||
|
}
|
||||||
|
std::fstream fs(fileName.c_str(), std::ios_base::out | std::ios_base::binary | extraMode);
|
||||||
fs.write(reinterpret_cast<const char*>(&m_meta), sizeof(AtlasMetadata));
|
fs.write(reinterpret_cast<const char*>(&m_meta), sizeof(AtlasMetadata));
|
||||||
|
uint64_t metadataBytes = sizeof(AtlasMetadata);
|
||||||
for (const auto& [key, val] : m_symbols)
|
for (const auto& [key, val] : m_symbols)
|
||||||
{
|
{
|
||||||
fs.write(reinterpret_cast<const char*>(&key), sizeof(uint32_t));
|
fs.write(reinterpret_cast<const char*>(&key), sizeof(uint32_t));
|
||||||
fs.write(reinterpret_cast<const char*>(&val), sizeof(GlyphInfo));
|
fs.write(reinterpret_cast<const char*>(&val), sizeof(GlyphInfo));
|
||||||
|
metadataBytes += sizeof(uint32_t);
|
||||||
|
metadataBytes += sizeof(GlyphInfo);
|
||||||
}
|
}
|
||||||
|
fs.write(reinterpret_cast<const char*>(&metadataBytes), sizeof(uint64_t));
|
||||||
|
fs.write(reinterpret_cast<const char*>(&packedFlag), sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontAtlasGenerator::Generate(FreetypeHandle* ft, FontHandle* font, const Charset& chset,
|
void FontAtlasGenerator::Generate(FreetypeHandle* ft, FontHandle* font, const Charset& chset,
|
||||||
@@ -77,7 +136,10 @@ namespace OpenVulkano::Scene
|
|||||||
int width = 1024, height = 1024;
|
int width = 1024, height = 1024;
|
||||||
packer.setDimensions(width, height);
|
packer.setDimensions(width, height);
|
||||||
// more value - more sdf impact
|
// more value - more sdf impact
|
||||||
packer.setPixelRange(26.0);
|
// this setup is tricky. with low value and large amount of characters visible artifacts (extra lines) may appear.
|
||||||
|
// with high value and large amount of characters sdf deals huge impact and characters are not readable anymore.
|
||||||
|
const double pixelRange = std::min((width / (double)chset.size()) * 3, 26.0);
|
||||||
|
packer.setPixelRange(pixelRange);
|
||||||
packer.setMiterLimit(1.0);
|
packer.setMiterLimit(1.0);
|
||||||
packer.pack(glyphsGeometry.data(), glyphsGeometry.size());
|
packer.pack(glyphsGeometry.data(), glyphsGeometry.size());
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <variant>
|
||||||
#include "Scene/AtlasMetadata.hpp"
|
#include "Scene/AtlasMetadata.hpp"
|
||||||
#include "Scene/Texture.hpp"
|
#include "Scene/Texture.hpp"
|
||||||
#include "msdfgen.h"
|
#include "msdfgen.h"
|
||||||
@@ -24,11 +25,12 @@ namespace OpenVulkano::Scene
|
|||||||
class FontAtlasGenerator
|
class FontAtlasGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static Charset LoadAllGlyphs(const std::variant<std::string, Array<char>>& data);
|
||||||
void GenerateAtlas(const std::string& fontFile, const Charset& charset = Charset::ASCII,
|
void GenerateAtlas(const std::string& fontFile, const Charset& charset = Charset::ASCII,
|
||||||
const std::optional<std::string>& pngOutput = std::nullopt);
|
const std::optional<std::string>& pngOutput = std::nullopt);
|
||||||
void GenerateAtlas(const msdfgen::byte* fontData, int length, const Charset& charset = Charset::ASCII,
|
void GenerateAtlas(const msdfgen::byte* fontData, int length, const Charset& charset = Charset::ASCII,
|
||||||
const std::optional<std::string>& pngOutput = std::nullopt);
|
const std::optional<std::string>& pngOutput = std::nullopt);
|
||||||
void SaveAtlasMetadataInfo(const std::string& outputFile) const;
|
void SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile = true) const;
|
||||||
const Texture& GetAtlas() const { return m_atlasTex; }
|
const Texture& GetAtlas() const { return m_atlasTex; }
|
||||||
std::map<uint32_t, GlyphInfo>& GetGlyphsInfo() { return m_symbols; }
|
std::map<uint32_t, GlyphInfo>& GetGlyphsInfo() { return m_symbols; }
|
||||||
AtlasMetadata& GetAtlasMetadata() { return m_meta; }
|
AtlasMetadata& GetAtlasMetadata() { return m_meta; }
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "Host/ResourceLoader.hpp"
|
#include "Host/ResourceLoader.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <utf8.h>
|
#include <utf8.h>
|
||||||
|
#include "Image/ImageLoader.hpp"
|
||||||
|
|
||||||
namespace OpenVulkano::Scene
|
namespace OpenVulkano::Scene
|
||||||
{
|
{
|
||||||
@@ -40,6 +41,16 @@ namespace OpenVulkano::Scene
|
|||||||
return textDefaultShader;
|
return textDefaultShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, const TextConfig& config)
|
||||||
|
: TextDrawable(atlasMetadata, nullptr, config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextDrawable::TextDrawable(const std::string& atlasMetadataFile, const TextConfig& config)
|
||||||
|
: TextDrawable(OpenVulkano::Utils::ReadFile(atlasMetadataFile), nullptr, config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
TextDrawable::TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config)
|
TextDrawable::TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config)
|
||||||
: TextDrawable(OpenVulkano::Utils::ReadFile(atlasMetadataFile), atlasTex, config)
|
: TextDrawable(OpenVulkano::Utils::ReadFile(atlasMetadataFile), atlasTex, config)
|
||||||
{
|
{
|
||||||
@@ -47,20 +58,46 @@ namespace OpenVulkano::Scene
|
|||||||
|
|
||||||
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config)
|
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config)
|
||||||
{
|
{
|
||||||
size_t len = atlasMetadata.Size();
|
uint32_t isPacked;
|
||||||
size_t read_bytes = 0;
|
std::memcpy(&isPacked, atlasMetadata.Data() + (atlasMetadata.Size() - sizeof(uint32_t)), sizeof(uint32_t));
|
||||||
|
uint64_t metadataBytes;
|
||||||
|
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);
|
||||||
|
if (isPacked)
|
||||||
|
{
|
||||||
|
m_material.texture = new Texture();
|
||||||
|
m_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(); // 1 channel
|
||||||
|
m_material.texture->textureBuffer = m_img->data.Data();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (atlasTex == nullptr) { throw std::runtime_error("Atlas texture cannot be null with non-packed atlas metadata"); }
|
||||||
|
m_material.texture = atlasTex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// metadata info
|
||||||
|
size_t read_bytes = offsetToMetadata;
|
||||||
|
size_t readMetadataBytes = 0;
|
||||||
uint32_t unicode = 0;
|
uint32_t unicode = 0;
|
||||||
std::memcpy(&m_meta, atlasMetadata.Data(), sizeof(AtlasMetadata));
|
|
||||||
|
std::memcpy(&m_meta, atlasMetadata.Data() + read_bytes, sizeof(AtlasMetadata));
|
||||||
read_bytes += sizeof(AtlasMetadata);
|
read_bytes += sizeof(AtlasMetadata);
|
||||||
while (read_bytes < len)
|
readMetadataBytes += sizeof(AtlasMetadata);
|
||||||
|
while (readMetadataBytes < metadataBytes)
|
||||||
{
|
{
|
||||||
std::memcpy(&unicode, atlasMetadata.Data() + read_bytes, sizeof(uint32_t));
|
std::memcpy(&unicode, atlasMetadata.Data() + read_bytes, sizeof(uint32_t));
|
||||||
read_bytes += sizeof(uint32_t);
|
read_bytes += sizeof(uint32_t);
|
||||||
|
readMetadataBytes += sizeof(uint32_t);
|
||||||
GlyphInfo& info = m_glyphs[unicode];
|
GlyphInfo& info = m_glyphs[unicode];
|
||||||
std::memcpy(&info, atlasMetadata.Data() + read_bytes, sizeof(GlyphInfo));
|
std::memcpy(&info, atlasMetadata.Data() + read_bytes, sizeof(GlyphInfo));
|
||||||
read_bytes += sizeof(GlyphInfo);
|
read_bytes += sizeof(GlyphInfo);
|
||||||
|
readMetadataBytes += sizeof(GlyphInfo);
|
||||||
}
|
}
|
||||||
m_material.texture = atlasTex;
|
|
||||||
m_cfg = config;
|
m_cfg = config;
|
||||||
m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3);
|
m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "UniformBuffer.hpp"
|
#include "UniformBuffer.hpp"
|
||||||
#include "Base/Logger.hpp"
|
#include "Base/Logger.hpp"
|
||||||
#include "AtlasMetadata.hpp"
|
#include "AtlasMetadata.hpp"
|
||||||
|
#include "Image/Image.hpp"
|
||||||
#if __has_include("msdfgen.h")
|
#if __has_include("msdfgen.h")
|
||||||
#include "msdfgen.h"
|
#include "msdfgen.h"
|
||||||
#include "msdfgen-ext.h"
|
#include "msdfgen-ext.h"
|
||||||
@@ -48,6 +49,8 @@ namespace OpenVulkano::Scene
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Shader& GetDefaultShader();
|
static Shader& GetDefaultShader();
|
||||||
|
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 std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config = TextConfig());
|
||||||
TextDrawable(const Array<char>& atlasMetadata, 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::map<uint32_t, GlyphInfo>& glyphData, Texture* atlasTex, const TextConfig& config = TextConfig());
|
||||||
@@ -77,6 +80,7 @@ namespace OpenVulkano::Scene
|
|||||||
UniformBuffer m_uniBuffer;
|
UniformBuffer m_uniBuffer;
|
||||||
std::map<uint32_t, GlyphInfo> m_glyphs;
|
std::map<uint32_t, GlyphInfo> m_glyphs;
|
||||||
AtlasMetadata m_meta;
|
AtlasMetadata m_meta;
|
||||||
|
std::unique_ptr<Image::Image> m_img;
|
||||||
#ifdef MSDFGEN_AVAILABLE
|
#ifdef MSDFGEN_AVAILABLE
|
||||||
FontAtlasGenerator* m_fontAtlasGenerator = nullptr;
|
FontAtlasGenerator* m_fontAtlasGenerator = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user