/* * 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 "Math/Math.hpp" #include "Scene/FreetypeHelper.hpp" #include #include namespace OpenVulkano::Scene { struct GlyphForPacking { uint32_t code; Math::Vector2i size; Math::Vector2d atlasPos; size_t firstGlyphByteInAtlas; }; struct Shelf { inline static std::vector CreateShelves(uint32_t atlasWidth, std::vector& glyphs, const FtFaceRecPtr& face); Shelf(uint32_t width, uint32_t height) : m_width(width), m_height(height), m_remainingWidth(width) {} bool HasSpaceForGlyph(uint32_t glyphWidth, uint32_t glyphHeight) const { return m_remainingWidth >= glyphWidth && m_height >= glyphHeight; } uint32_t GetWidth() const { return m_width; } uint32_t GetHeight() const { return m_height; } uint32_t GetNextGlyphPos() const { return m_nextGlyphPos; }; uint32_t GetOccupiedSize() const { return ((m_width - m_remainingWidth) * m_height); } std::optional AddGlyph(uint32_t glyphWidth, uint32_t glyphHeight) { if (!HasSpaceForGlyph(glyphWidth, glyphHeight)) { return {}; } uint32_t insertionPos = m_nextGlyphPos; m_nextGlyphPos += glyphWidth; m_remainingWidth -= glyphWidth; return insertionPos; } private: uint32_t m_width; uint32_t m_height; uint32_t m_remainingWidth; uint32_t m_nextGlyphPos = 0; }; std::vector Shelf::CreateShelves(uint32_t atlasWidth, std::vector& glyphs, const FtFaceRecPtr& face) { std::vector shelves; for (GlyphForPacking& glyph : glyphs) { FT_Error error = FT_Load_Char(face.get(), glyph.code, FT_LOAD_RENDER); if (error) { continue; } FT_GlyphSlot slot = face->glyph; bool needNewShelf = true; uint32_t totalPrevShelvesHeight = 0; for (Shelf& shelf : shelves) { if (std::optional insertionPosX = shelf.AddGlyph(glyph.size.x, glyph.size.y)) { glyph.firstGlyphByteInAtlas = *insertionPosX + (totalPrevShelvesHeight * atlasWidth); glyph.atlasPos.x = *insertionPosX; glyph.atlasPos.y = totalPrevShelvesHeight; needNewShelf = false; break; } totalPrevShelvesHeight += shelf.GetHeight(); } if (needNewShelf) { shelves.emplace_back(atlasWidth, glyph.size.y); shelves.back().AddGlyph(glyph.size.x, glyph.size.y); glyph.firstGlyphByteInAtlas = totalPrevShelvesHeight * atlasWidth; glyph.atlasPos.x = 0; glyph.atlasPos.y = totalPrevShelvesHeight; } } return shelves; } }