/* * 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 "FontAtlasGenerator.hpp" #include "Base/Logger.hpp" namespace OpenVulkano::Scene { using namespace msdfgen; using namespace msdf_atlas; void FontAtlasGenerator::GenerateAtlas(const std::string& fontFile, const std::string& outputFile, const Charset& chset) { if (chset.empty()) { return; } // TODO: dynamic atlas and add only those symbols which are not present yet in current atlas Charset absentSymbols; for (auto c : chset) { if (!m_symbols.contains(c)) { absentSymbols.add(c); } } if (m_loadedFont == fontFile && absentSymbols.empty()) { return; } m_symbols.clear(); m_loadedFont = fontFile; std::vector glyphsGeometry; std::pair handlers = GetHandlers(fontFile); FreetypeHandle* ft = handlers.first; FontHandle* font = handlers.second; // FontGeometry is a helper class that loads a set of glyphs from a single font. FontGeometry fontGeometry(&glyphsGeometry); fontGeometry.loadCharset(font, 1, absentSymbols); TightAtlasPacker packer; packer.setDimensionsConstraint(DimensionsConstraint::SQUARE); int width = 1024, height = 1024; packer.setDimensions(width, height); // more value - more sdf impact packer.setPixelRange(26.0); packer.setMiterLimit(1.0); packer.pack(glyphsGeometry.data(), glyphsGeometry.size()); m_generator.resize(width, height); GeneratorAttributes attributes; m_generator.setAttributes(attributes); m_generator.setThreadCount(4); m_generator.generate(glyphsGeometry.data(), glyphsGeometry.size()); int idx = 0; BitmapConstRef storage = m_generator.atlasStorage(); for (const auto& glyph: glyphsGeometry) { unicode_t c = static_cast(glyph.getCodepoint()); GlyphInfo info; info.texture.resolution = Math::Vector3ui(storage.width, storage.height, 1); info.texture.textureBuffer = (msdfgen::byte*)storage.pixels; info.texture.format = OpenVulkano::DataFormat::R8_UNORM; info.texture.size = storage.width * storage.height * 1; // 1 channel info.geometry = glyph; info.glyphBox = m_generator.getLayout()[idx++]; m_symbols[c] = std::move(info); } savePng(m_generator.atlasStorage(), outputFile.c_str()); destroyFont(font); deinitializeFreetype(ft); } std::pair FontAtlasGenerator::GetHandlers(const std::string& fontFile) { FreetypeHandle* ft = initializeFreetype(); if (!ft) { throw std::runtime_error("Failed to initialize freetype"); } FontHandle* font = loadFont(ft, fontFile.data()); if (!font) { deinitializeFreetype(ft); throw std::runtime_error(fmt::format("Failed to load font from file {0}", fontFile.data())); } return { ft, font }; } }