From f3269a49c474ffe4d382c3d60826ad1cfbb7cdc4 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Fri, 25 Nov 2022 17:28:07 -0800 Subject: Changeset: 93 Branch comment: [] Port font and UTF-8 string utilities from p6503 --- source/30-game/Font.hpp | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 source/30-game/Font.hpp (limited to 'source/30-game/Font.hpp') diff --git a/source/30-game/Font.hpp b/source/30-game/Font.hpp new file mode 100644 index 0000000..cc64c0c --- /dev/null +++ b/source/30-game/Font.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include "Color.hpp" +#include "CommonVertexIndex.hpp" +#include "RcPtr.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +enum class FontType { + Regular, + Italic, + Bold, + BoldItalic, +}; + +struct GlyphVariant { + int horizontalAdvance; + float x0, y0; + float x1, y1; + float u0, v0; + float u1, v1; +}; + +// TODO optimize for memory when most glyphs don't have a non-regular variant +// such as CJK characters rarely use bold or italics +struct GlyphInfo { + char32_t codepoint; + GlyphVariant regular; + GlyphVariant italic; + GlyphVariant bold; + GlyphVariant boldItalic; +}; + +class Font : public RefCounted { +public: + static const char32_t* GetGlyphRangesDefault(); + static const char32_t* GetGlyphRangesKorean(); + static const char32_t* GetGlyphRangesJapanese(); + static const char32_t* GetGlyphRangesChineseFull(); + static const char32_t* GetGlyphRangesChineseSimplifiedCommon(); + static const char32_t* GetGlyphRangesCyrillic(); + static const char32_t* GetGlyphRangesThai(); + static const char32_t* GetGlyphRangesVietnamese(); + +private: + std::vector mGlyphs; + std::vector mGlyphLookup; + RcPtr mAtlas; + float mFontHeight; + int mFallbackGlyphIdx; + +public: + struct LoadingCandidate { + // No std::string_view here because iostreams only support null termianted string + const char* ttfPath; + const char32_t* glyphRange; + FontType type = FontType::Regular; + }; + + Font() = default; + Font(const Font&) = delete; + Font& operator=(const Font&) = delete; + Font(Font&&) = default; + Font& operator=(Font&&) = default; + + enum ErrorCode { + EC_Success, + EC_FileIOFailed, + EC_FontLoadingFailed, + }; + struct InitResult { + ErrorCode errorCode; + int failedItemIdx; + }; + + /// Initialize this font object from a list of ttf files. Each ttf covers a range of unicode characters, + /// and a specific font type, which are combined together into an atlas texture. + /// + /// \see FontType + /// \see Font::LoadingCandidate + InitResult Init(std::span candidates, float fontHeight, char32_t fallbackCodepoint = '?', int oversampleH = 1, int oversampleV = 1); + + float GetFontHeight() const; + int HorizontalAdvance(char32_t c, FontType type = FontType::Regular) const; + int HorizontalAdvance(std::string_view str, FontType type = FontType::Regular) const; + + int GetGlyphCount() const; + const GlyphInfo& GetFallbackGlyph() const; + + /// Find the glyph corresponding to the given codepoint. If none is present, return the fallback glyph + /// specified in Init(). + const GlyphInfo& FindGlyphFallback(char32_t codepoint) const; + /// Find the glyph corresponding to the given codepoint. If none is present, `nullptr` is returned. + const GlyphInfo* FindGlyph(char32_t codepoint) const; + + struct DrawTargetPointer { + // Draw target info + Vertex_PTC* vertices; + uint32_t* indices; + uint32_t initialVertexIdx; + + // Text info + glm::vec3 pos; + FontType type = FontType::Regular; + RgbaColor color = RgbaColor{}; + + // Output info, written to by DrawTo() + int glyphsRendered; + float horizontalAdvance; + }; + + /// Populate the target with quads, with first character's origin at `pos` and every vertex colored `color`. + /// User must allocate enough space for all characers beforehand (one way is to reserve the # of bytes). + /// Suitable for raw array allocations or something like PodVector that doesn't do zero-initialization on + /// resize. + /// + /// \see Font::DrawTargetPointer + void DrawTo(std::string_view text, DrawTargetPointer& t) const; + void DrawTo(std::u32string_view text, DrawTargetPointer& t) const; + + /// OpenGL texture containing the font atlas. Format is in GL_RED because we don't need the other channels, due to the + /// font atlas being black and white (in other words, opacity only). + const Texture& GetGlyphAtlas() const; +}; -- cgit v1.2.3-70-g09d2