Index: ps/trunk/source/graphics/Font.h =================================================================== --- ps/trunk/source/graphics/Font.h (revision 26049) +++ ps/trunk/source/graphics/Font.h (revision 26050) @@ -1,99 +1,101 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_FONT #define INCLUDED_FONT #include "graphics/Texture.h" #include "lib/res/handle.h" /** * Storage for a bitmap font. Loaded by CFontManager. */ class CFont { - friend class CFontManager; - CFont() {} public: struct GlyphData { float u0, v0, u1, v1; i16 x0, y0, x1, y1; i16 xadvance; u8 defined; }; /** * Relatively efficient lookup of GlyphData from 16-bit Unicode codepoint. * This is stored as a sparse 2D array, exploiting the knowledge that a font * typically only supports a small number of 256-codepoint blocks, so most * elements of m_Data will be NULL. */ class GlyphMap { NONCOPYABLE(GlyphMap); public: GlyphMap(); ~GlyphMap(); void set(u16 i, const GlyphData& val); const GlyphData* get(u16 i) const { if (!m_Data[i >> 8]) return NULL; if (!m_Data[i >> 8][i & 0xff].defined) return NULL; return &m_Data[i >> 8][i & 0xff]; } private: GlyphData* m_Data[256]; }; bool HasRGB() const { return m_HasRGB; } int GetLineSpacing() const { return m_LineSpacing; } int GetHeight() const { return m_Height; } int GetCharacterWidth(wchar_t c) const; void CalculateStringSize(const wchar_t* string, int& w, int& h) const; void GetGlyphBounds(float& x0, float& y0, float& x1, float& y1) const { x0 = m_BoundsX0; y0 = m_BoundsY0; x1 = m_BoundsX1; y1 = m_BoundsY1; } const GlyphMap& GetGlyphs() const { return m_Glyphs; } CTexturePtr GetTexture() const { return m_Texture; } private: + friend class CFontManager; + + CFont() = default; + CTexturePtr m_Texture; bool m_HasRGB; // true if RGBA, false if ALPHA GlyphMap m_Glyphs; int m_LineSpacing; int m_Height; // height of a capital letter, roughly // Bounding box of all glyphs float m_BoundsX0; float m_BoundsY0; float m_BoundsX1; float m_BoundsY1; }; #endif // INCLUDED_FONT Index: ps/trunk/source/graphics/FontManager.cpp =================================================================== --- ps/trunk/source/graphics/FontManager.cpp (revision 26049) +++ ps/trunk/source/graphics/FontManager.cpp (revision 26050) @@ -1,135 +1,149 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "FontManager.h" #include "graphics/Font.h" #include "graphics/TextureManager.h" #include "ps/CLogger.h" #include "ps/CStr.h" #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "renderer/Renderer.h" -#include +#include std::shared_ptr CFontManager::LoadFont(CStrIntern fontName) { FontsMap::iterator it = m_Fonts.find(fontName); if (it != m_Fonts.end()) return it->second; std::shared_ptr font(new CFont()); if (!ReadFont(font.get(), fontName)) { // Fall back to default font (unless this is the default font) if (fontName == str_sans_10) font.reset(); else font = LoadFont(str_sans_10); } m_Fonts[fontName] = font; return font; } bool CFontManager::ReadFont(CFont* font, CStrIntern fontName) { const VfsPath path(L"fonts/"); // Read font definition file into a stringstream - std::shared_ptr buf; + std::shared_ptr buffer; size_t size; const VfsPath fntName(fontName.string() + ".fnt"); - if (g_VFS->LoadFile(path / fntName, buf, size) < 0) + if (g_VFS->LoadFile(path / fntName, buffer, size) < 0) { LOGERROR("Failed to open font file %s", (path / fntName).string8()); return false; } - std::istringstream FNTStream(std::string((const char*)buf.get(), size)); + std::istringstream fontStream( + std::string(reinterpret_cast(buffer.get()), size)); - int Version; - FNTStream >> Version; - if (Version != 101) // Make sure this is from a recent version of the font builder + int version; + fontStream >> version; + // Make sure this is from a recent version of the font builder. + if (version != 101) { LOGERROR("Font %s has invalid version", fontName.c_str()); - return 0; + return false; } - int TextureWidth, TextureHeight; - FNTStream >> TextureWidth >> TextureHeight; + int textureWidth, textureHeight; + fontStream >> textureWidth >> textureHeight; - std::string Format; - FNTStream >> Format; - if (Format == "rgba") + std::string format; + fontStream >> format; + if (format == "rgba") font->m_HasRGB = true; - else if (Format == "a") + else if (format == "a") font->m_HasRGB = false; else - debug_warn(L"Invalid .fnt format string"); + { + LOGWARNING("Invalid .fnt format string"); + return false; + } - int NumGlyphs; - FNTStream >> NumGlyphs; + int mumberOfGlyphs; + fontStream >> mumberOfGlyphs; - FNTStream >> font->m_LineSpacing; - FNTStream >> font->m_Height; + fontStream >> font->m_LineSpacing; + fontStream >> font->m_Height; - font->m_BoundsX0 = FLT_MAX; - font->m_BoundsY0 = FLT_MAX; - font->m_BoundsX1 = -FLT_MAX; - font->m_BoundsY1 = -FLT_MAX; + font->m_BoundsX0 = std::numeric_limits::max(); + font->m_BoundsY0 = std::numeric_limits::max(); + font->m_BoundsX1 = -std::numeric_limits::max(); + font->m_BoundsY1 = -std::numeric_limits::max(); - for (int i = 0; i < NumGlyphs; ++i) + for (int i = 0; i < mumberOfGlyphs; ++i) { - int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance; - FNTStream >> Codepoint>>TextureX>>TextureY>>Width>>Height>>OffsetX>>OffsetY>>Advance; + int codepoint, textureX, textureY, width, height, offsetX, offsetY, advance; + fontStream >> codepoint + >> textureX >> textureY >> width >> height + >> offsetX >> offsetY >> advance; - if (Codepoint < 0 || Codepoint > 0xFFFF) + if (codepoint < 0 || codepoint > 0xFFFF) { - LOGWARNING("Font %s has invalid codepoint 0x%x", fontName.c_str(), Codepoint); + LOGWARNING("Font %s has invalid codepoint 0x%x", fontName.c_str(), codepoint); continue; } - float u = (float)TextureX / (float)TextureWidth; - float v = (float)TextureY / (float)TextureHeight; - float w = (float)Width / (float)TextureWidth; - float h = (float)Height / (float)TextureHeight; - - CFont::GlyphData g = { u, -v, u+w, -v+h, (i16)OffsetX, (i16)-OffsetY, (i16)(OffsetX+Width), (i16)(-OffsetY+Height), (i16)Advance }; - font->m_Glyphs.set((u16)Codepoint, g); - - font->m_BoundsX0 = std::min(font->m_BoundsX0, (float)g.x0); - font->m_BoundsY0 = std::min(font->m_BoundsY0, (float)g.y0); - font->m_BoundsX1 = std::max(font->m_BoundsX1, (float)g.x1); - font->m_BoundsY1 = std::max(font->m_BoundsY1, (float)g.y1); + const float u = static_cast(textureX) / textureWidth; + const float v = static_cast(textureY) / textureHeight; + const float w = static_cast(width) / textureWidth; + const float h = static_cast(height) / textureHeight; + + CFont::GlyphData g = + { + u, -v, u + w, -v + h, + static_cast(offsetX), static_cast(-offsetY), + static_cast(offsetX + width), static_cast(-offsetY + height), + static_cast(advance) + }; + font->m_Glyphs.set(static_cast(codepoint), g); + + font->m_BoundsX0 = std::min(font->m_BoundsX0, static_cast(g.x0)); + font->m_BoundsY0 = std::min(font->m_BoundsY0, static_cast(g.y0)); + font->m_BoundsX1 = std::max(font->m_BoundsX1, static_cast(g.x1)); + font->m_BoundsY1 = std::max(font->m_BoundsY1, static_cast(g.y1)); } - ENSURE(font->m_Height); // Ensure the height has been found (which should always happen if the font includes an 'I') + // Ensure the height has been found (which should always happen if the font includes an 'I'). + ENSURE(font->m_Height); // Load glyph texture - const VfsPath imgName(fontName.string() + ".png"); - CTextureProperties textureProps(path / imgName); + const VfsPath imageName(fontName.string() + ".png"); + CTextureProperties textureProps(path / imageName); textureProps.SetFilter(GL_LINEAR); if (!font->m_HasRGB) textureProps.SetFormatOverride(GL_ALPHA); font->m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); return true; }