From 5778484a77b0f01d53f4d915d8af71ea272501d0 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Fri, 18 Oct 2013 15:53:07 +0000 Subject: [PATCH] Refactor text renderer Replace unifont with CFont and CFontManager, since the h_mgr interface was needlessly inconvenient. Load the font textures through CTextureManager, to support dynamic reloading (e.g. when resetting GL state - see #741). Add CFontMetrics as a convenient wrapper for code that just wants to measure text. Fixes #1117. This was SVN commit r14016. --- binaries/data/mods/public/fonts/textures.xml | 5 + source/graphics/Font.cpp | 57 ++++ source/graphics/Font.h | 61 ++++ source/graphics/FontManager.cpp | 122 +++++++ source/{ps/Font.h => graphics/FontManager.h} | 36 +-- source/graphics/FontMetrics.cpp | 61 ++++ source/graphics/FontMetrics.h | 43 +++ source/graphics/TextRenderer.cpp | 19 +- source/graphics/TextRenderer.h | 2 - source/gui/CCheckBox.cpp | 4 +- source/gui/CGUI.cpp | 2 +- source/gui/CInput.cpp | 10 +- source/gui/GUItext.cpp | 5 +- source/lib/res/graphics/unifont.cpp | 299 ------------------ source/lib/res/graphics/unifont.h | 105 ------ source/ps/ArchiveBuilder.cpp | 4 +- source/ps/CConsole.cpp | 2 +- source/ps/CLogger.cpp | 4 +- source/ps/Font.cpp | 83 ----- source/ps/GameSetup/GameSetup.cpp | 4 +- source/ps/ProfileViewer.cpp | 4 +- source/renderer/Renderer.cpp | 10 +- source/renderer/Renderer.h | 3 + source/renderer/TerrainRenderer.cpp | 1 - .../tools/atlas/GameInterface/ActorViewer.cpp | 1 - 25 files changed, 406 insertions(+), 541 deletions(-) create mode 100644 binaries/data/mods/public/fonts/textures.xml create mode 100644 source/graphics/Font.cpp create mode 100644 source/graphics/Font.h create mode 100644 source/graphics/FontManager.cpp rename source/{ps/Font.h => graphics/FontManager.h} (60%) create mode 100644 source/graphics/FontMetrics.cpp create mode 100644 source/graphics/FontMetrics.h delete mode 100644 source/lib/res/graphics/unifont.cpp delete mode 100644 source/lib/res/graphics/unifont.h delete mode 100644 source/ps/Font.cpp diff --git a/binaries/data/mods/public/fonts/textures.xml b/binaries/data/mods/public/fonts/textures.xml new file mode 100644 index 0000000000..9d37323713 --- /dev/null +++ b/binaries/data/mods/public/fonts/textures.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/source/graphics/Font.cpp b/source/graphics/Font.cpp new file mode 100644 index 0000000000..ee0fbd1acf --- /dev/null +++ b/source/graphics/Font.cpp @@ -0,0 +1,57 @@ +/* Copyright (C) 2013 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 "Font.h" + +#include "graphics/FontManager.h" +#include "ps/Filesystem.h" +#include "ps/CLogger.h" +#include "renderer/Renderer.h" + +#include +#include + +int CFont::GetCharacterWidth(wchar_t c) const +{ + GlyphMap::const_iterator it = m_Glyphs.find(c); + + if (it == m_Glyphs.end()) + it = m_Glyphs.find(0xFFFD); // Use the missing glyph symbol + + if (it == m_Glyphs.end()) + return 0; + + return it->second.xadvance; +} + +void CFont::CalculateStringSize(const wchar_t* string, int& width, int& height) const +{ + width = 0; + height = m_Height; + + for (const wchar_t* c = string; *c != '\0'; c++) + { + GlyphMap::const_iterator it = m_Glyphs.find(*c); + + if (it == m_Glyphs.end()) + it = m_Glyphs.find(0xFFFD); // Use the missing glyph symbol + + if (it != m_Glyphs.end()) + width += it->second.xadvance; // Add the character's advance distance + } +} diff --git a/source/graphics/Font.h b/source/graphics/Font.h new file mode 100644 index 0000000000..58b44f6be0 --- /dev/null +++ b/source/graphics/Font.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2013 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" + +#include + +class CStrW; +struct UnifontGlyphData; + +class CFont +{ + friend class CFontManager; +public: + struct GlyphData + { + float u0, v0, u1, v1; + i16 x0, y0, x1, y1; + i16 xadvance; + }; + + typedef std::map GlyphMap; + + 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; + const GlyphMap& GetGlyphs() const { return m_Glyphs; } + CTexturePtr GetTexture() const { return m_Texture; } + +private: + 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 +}; + +#endif // INCLUDED_FONT diff --git a/source/graphics/FontManager.cpp b/source/graphics/FontManager.cpp new file mode 100644 index 0000000000..a2fa26f1cd --- /dev/null +++ b/source/graphics/FontManager.cpp @@ -0,0 +1,122 @@ +/* Copyright (C) 2013 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/Filesystem.h" +#include "renderer/Renderer.h" + +shared_ptr CFontManager::LoadFont(const CStrW& fontName) +{ + FontsMap::iterator it = m_Fonts.find(fontName); + if (it != m_Fonts.end()) + return it->second; + + shared_ptr font(new CFont()); + + if (!ReadFont(font.get(), fontName)) + { + // Fall back to default font (unless this is the default font) + if (fontName == L"sans-10") + font.reset(); + else + font = LoadFont(L"sans-10"); + } + + m_Fonts[fontName] = font; + return font; +} + +bool CFontManager::ReadFont(CFont* font, const CStrW& fontName) +{ + const VfsPath path(L"fonts/"); + + // Read font definition file into a stringstream + shared_ptr buf; + size_t size; + const VfsPath fntName(fontName + L".fnt"); + if (g_VFS->LoadFile(path / fntName, buf, size) < 0) + { + LOGERROR(L"Failed to open font file %ls", (path / fntName).string().c_str()); + return false; + } + std::istringstream FNTStream(std::string((const char*)buf.get(), size)); + + int Version; + FNTStream >> Version; + if (Version != 101) // Make sure this is from a recent version of the font builder + { + LOGERROR(L"Font %ls has invalid version", fontName.c_str()); + return 0; + } + + int TextureWidth, TextureHeight; + FNTStream >> TextureWidth >> TextureHeight; + + std::string Format; + FNTStream >> Format; + if (Format == "rgba") + font->m_HasRGB = true; + else if (Format == "a") + font->m_HasRGB = false; + else + debug_warn(L"Invalid .fnt format string"); + + int NumGlyphs; + FNTStream >> NumGlyphs; + + FNTStream >> font->m_LineSpacing; + FNTStream >> font->m_Height; + + for (int i = 0; i < NumGlyphs; ++i) + { + int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance; + FNTStream >> Codepoint>>TextureX>>TextureY>>Width>>Height>>OffsetX>>OffsetY>>Advance; + + if (Codepoint < 0 || Codepoint > 0xFFFF) + { + LOGWARNING(L"Font %ls 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[(u16)Codepoint] = g; + } + + ENSURE(font->m_Height); // Ensure the height has been found (which should always happen if the font includes an 'I') + + // Load glyph texture + const VfsPath imgName(fontName + L".png"); + CTextureProperties textureProps(path / imgName); + textureProps.SetFilter(GL_NEAREST); + if (!font->m_HasRGB) + textureProps.SetFormatOverride(GL_ALPHA); + font->m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); + + return true; +} diff --git a/source/ps/Font.h b/source/graphics/FontManager.h similarity index 60% rename from source/ps/Font.h rename to source/graphics/FontManager.h index 8c71f78e04..9275c10755 100644 --- a/source/ps/Font.h +++ b/source/graphics/FontManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2013 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,33 +15,27 @@ * along with 0 A.D. If not, see . */ -#ifndef INCLUDED_FONT -#define INCLUDED_FONT +#ifndef INCLUDED_FONTMANAGER +#define INCLUDED_FONTMANAGER -#include "lib/res/handle.h" - -#include +#include +class CFont; class CStrW; -struct UnifontGlyphData; -class CFont +/** + * Font manager: loads and caches bitmap fonts. + */ +class CFontManager { public: - CFont(const CStrW& name); - ~CFont(); - - bool HasRGB(); - int GetLineSpacing(); - int GetHeight(); - int GetCharacterWidth(wchar_t c); - void CalculateStringSize(const wchar_t* string, int& w, int& h); - const std::map& GetGlyphs(); - Handle GetTexture(); + shared_ptr LoadFont(const CStrW& fontName); private: - Handle h; + bool ReadFont(CFont* font, const CStrW& fontName); + + typedef boost::unordered_map > FontsMap; + FontsMap m_Fonts; }; - -#endif // INCLUDED_FONT +#endif // INCLUDED_FONTMANAGER diff --git a/source/graphics/FontMetrics.cpp b/source/graphics/FontMetrics.cpp new file mode 100644 index 0000000000..49f84dee0b --- /dev/null +++ b/source/graphics/FontMetrics.cpp @@ -0,0 +1,61 @@ +/* Copyright (C) 2013 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 "FontMetrics.h" + +#include "graphics/Font.h" +#include "graphics/FontManager.h" +#include "ps/Filesystem.h" +#include "ps/CLogger.h" +#include "renderer/Renderer.h" + +CFontMetrics::CFontMetrics(const CStrW& font) +{ + m_Font = g_Renderer.GetFontManager().LoadFont(font); +} + +int CFontMetrics::GetLineSpacing() const +{ + // Return some arbitrary default if the font failed to load, so that the + // user of CFontMetrics doesn't have to care about failures + if (!m_Font) + return 12; + return m_Font->GetLineSpacing(); +} + +int CFontMetrics::GetHeight() const +{ + if (!m_Font) + return 6; + return m_Font->GetHeight(); +} + +int CFontMetrics::GetCharacterWidth(wchar_t c) const +{ + if (!m_Font) + return 6; + return m_Font->GetCharacterWidth(c); +} + +void CFontMetrics::CalculateStringSize(const wchar_t* string, int& w, int& h) const +{ + if (!m_Font) + w = h = 0; + else + m_Font->CalculateStringSize(string, w, h); +} diff --git a/source/graphics/FontMetrics.h b/source/graphics/FontMetrics.h new file mode 100644 index 0000000000..1024a0cf01 --- /dev/null +++ b/source/graphics/FontMetrics.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2013 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_FONTMETRICS +#define INCLUDED_FONTMETRICS + +class CFont; +class CStrW; + +/** + * Helper class for measuring sizes of text. + * This will load the font when necessary, and will return plausible values + * if loading fails (since misrendering is better than crashing). + */ +class CFontMetrics +{ +public: + CFontMetrics(const CStrW& font); + + int GetLineSpacing() const; + int GetHeight() const; + int GetCharacterWidth(wchar_t c) const; + void CalculateStringSize(const wchar_t* string, int& w, int& h) const; + +private: + shared_ptr m_Font; +}; + +#endif // INCLUDED_FONTMETRICS diff --git a/source/graphics/TextRenderer.cpp b/source/graphics/TextRenderer.cpp index dfdb8a3a0f..bba379fd5e 100644 --- a/source/graphics/TextRenderer.cpp +++ b/source/graphics/TextRenderer.cpp @@ -19,10 +19,11 @@ #include "TextRenderer.h" +#include "graphics/Font.h" +#include "graphics/FontManager.h" #include "lib/ogl.h" -#include "lib/res/graphics/unifont.h" #include "ps/CStrIntern.h" -#include "ps/Font.h" +#include "renderer/Renderer.h" extern int g_xres, g_yres; @@ -74,10 +75,7 @@ void CTextRenderer::Color(float r, float g, float b, float a) void CTextRenderer::Font(const CStrW& font) { - if (!m_Fonts[font]) - m_Fonts[font] = shared_ptr(new CFont(font)); - - m_Font = m_Fonts[font]; + m_Font = g_Renderer.GetFontManager().LoadFont(font); } void CTextRenderer::PrintfAdvance(const wchar_t* fmt, ...) @@ -125,6 +123,9 @@ void CTextRenderer::Put(float x, float y, const wchar_t* buf) if (buf[0] == 0) return; // empty string; don't bother storing + if (!m_Font) + return; // invalid font; can't render + CMatrix3D translate; translate.SetTranslation(x, y, 0.0f); @@ -155,7 +156,7 @@ void CTextRenderer::Render() if (batch.text.empty()) // avoid zero-length arrays continue; - const std::map& glyphs = batch.font->GetGlyphs(); + const CFont::GlyphMap& glyphs = batch.font->GetGlyphs(); m_Shader->BindTexture(str_tex, batch.font->GetTexture()); @@ -179,7 +180,7 @@ void CTextRenderer::Render() i16 x = 0; for (size_t i = 0; i < batch.text.size(); ++i) { - std::map::const_iterator it = glyphs.find(batch.text[i]); + CFont::GlyphMap::const_iterator it = glyphs.find(batch.text[i]); if (it == glyphs.end()) it = glyphs.find(0xFFFD); // Use the missing glyph symbol @@ -187,7 +188,7 @@ void CTextRenderer::Render() if (it == glyphs.end()) // Missing the missing glyph symbol - give up continue; - const UnifontGlyphData& g = it->second; + const CFont::GlyphData& g = it->second; vertexes[i*4].u = g.u1; vertexes[i*4].v = g.v0; diff --git a/source/graphics/TextRenderer.h b/source/graphics/TextRenderer.h index f45bc7a55c..54d66c2c1f 100644 --- a/source/graphics/TextRenderer.h +++ b/source/graphics/TextRenderer.h @@ -101,8 +101,6 @@ private: CColor m_Color; shared_ptr m_Font; - std::map > m_Fonts; - std::vector m_Batches; }; diff --git a/source/gui/CCheckBox.cpp b/source/gui/CCheckBox.cpp index 0347a4c03d..c5d7486333 100644 --- a/source/gui/CCheckBox.cpp +++ b/source/gui/CCheckBox.cpp @@ -24,7 +24,7 @@ CCheckBox #include "CCheckBox.h" #include "ps/CLogger.h" -#include "ps/Font.h" +#include "graphics/FontMetrics.h" //------------------------------------------------------------------- @@ -130,7 +130,7 @@ void CCheckBox::Draw() GUI::GetSetting(this, "cell_id", cell_id); // Get line height - CFont font (font_name); + CFontMetrics font (font_name); float line_height = (float)font.GetHeight(); float bz = GetBufferedZ(); diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index e6bfdecd12..c06178672f 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -41,6 +41,7 @@ CGUI #include "MiniMap.h" #include "scripting/JSInterface_GUITypes.h" +#include "graphics/FontMetrics.h" #include "graphics/ShaderManager.h" #include "graphics/TextRenderer.h" #include "lib/input.h" @@ -49,7 +50,6 @@ CGUI #include "lib/sysdep/sysdep.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" -#include "ps/Font.h" #include "ps/Hotkey.h" #include "ps/Globals.h" #include "ps/Overlay.h" diff --git a/source/gui/CInput.cpp b/source/gui/CInput.cpp index 07ccf21213..e679f98fce 100644 --- a/source/gui/CInput.cpp +++ b/source/gui/CInput.cpp @@ -24,6 +24,7 @@ CInput #include "CInput.h" #include "CGUIScrollBarVertical.h" +#include "graphics/FontMetrics.h" #include "graphics/ShaderManager.h" #include "graphics/TextRenderer.h" #include "lib/ogl.h" @@ -31,7 +32,6 @@ CInput #include "lib/timer.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" -#include "ps/Font.h" #include "ps/Globals.h" #include "ps/Hotkey.h" #include "renderer/Renderer.h" @@ -1057,7 +1057,7 @@ void CInput::Draw() scroll = GetScrollBar(0).GetPos(); } - CFont font(font_name); + CFontMetrics font(font_name); // We'll have to setup clipping manually, since we're doing the rendering manually. CRect cliparea(m_CachedActualSize); @@ -1406,7 +1406,7 @@ void CInput::UpdateText(int from, int to_before, int to_after) if (to_before == -1) to = (int)caption.length(); - CFont font(font_name); + CFontMetrics font(font_name); std::list::iterator current_line; @@ -1782,7 +1782,7 @@ int CInput::GetMouseHoveringTextPosition() // Now get the height of the font. // TODO: Get the real font - CFont font(font_name); + CFontMetrics font(font_name); float spacing = (float)font.GetLineSpacing(); //float height = (float)font.GetHeight(); // unused @@ -1930,7 +1930,7 @@ void CInput::UpdateAutoScroll() // Now get the height of the font. // TODO: Get the real font - CFont font(font_name); + CFontMetrics font(font_name); float spacing = (float)font.GetLineSpacing(); //float height = font.GetHeight(); diff --git a/source/gui/GUItext.cpp b/source/gui/GUItext.cpp index cadd56681f..d1b7d958a5 100644 --- a/source/gui/GUItext.cpp +++ b/source/gui/GUItext.cpp @@ -23,12 +23,11 @@ GUI text #include "GUI.h" #include "GUIManager.h" +#include "graphics/FontMetrics.h" #include "ps/CLogger.h" #include "ps/Parser.h" #include -#include "ps/Font.h" - static const wchar_t TagStart = '['; static const wchar_t TagEnd = ']'; @@ -232,7 +231,7 @@ void CGUIString::GenerateTextCall(SFeedback &Feedback, // Calculate the size of the font CSize size; int cx, cy; - CFont font (TextCall.m_Font); + CFontMetrics font (TextCall.m_Font); font.CalculateStringSize(TextCall.m_String.c_str(), cx, cy); // For anything other than the first line, the line spacing // needs to be considered rather than just the height of the text diff --git a/source/lib/res/graphics/unifont.cpp b/source/lib/res/graphics/unifont.cpp deleted file mode 100644 index addbcda85e..0000000000 --- a/source/lib/res/graphics/unifont.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* Copyright (c) 2012 Wildfire Games - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Unicode OpenGL texture font. - */ - -#include "precompiled.h" -#include "unifont.h" - -#include -#include -#include -#include - -#include "ogl_tex.h" -#include "lib/res/h_mgr.h" - -typedef std::map glyphmap; - -struct UniFont -{ - Handle ht; // Handle to font texture - - bool HasRGB; // true if RGBA, false if ALPHA - - glyphmap* glyphs; - - int LineSpacing; - int Height; // of a capital letter, roughly -}; - -H_TYPE_DEFINE(UniFont); - -static void UniFont_init(UniFont* UNUSED(f), va_list UNUSED(args)) -{ -} - -static void UniFont_dtor(UniFont* f) -{ - // these are all safe, no is_valid flags needed - (void)ogl_tex_free(f->ht); - - SAFE_DELETE(f->glyphs); -} - -// basename is e.g. "console"; the files are "fonts/console.fnt" and "fonts/console.png" -// [10..70ms] -static Status UniFont_reload(UniFont* f, const PIVFS& vfs, const VfsPath& basename, Handle UNUSED(h)) -{ - // already loaded - if(f->ht > 0) - return INFO::OK; - - f->glyphs = new glyphmap(); - - const VfsPath path(L"fonts/"); - - // Read font definition file into a stringstream - shared_ptr buf; size_t size; - const VfsPath fntName(basename.ChangeExtension(L".fnt")); - RETURN_STATUS_IF_ERR(vfs->LoadFile(path / fntName, buf, size)); // [cumulative for 12: 36ms] - std::istringstream FNTStream(std::string((const char*)buf.get(), size)); - - int Version; - FNTStream >> Version; - if (Version < 100 || Version > 101) // Make sure this is from a recent version of the font builder - WARN_RETURN(ERR::FAIL); - - int TextureWidth, TextureHeight; - FNTStream >> TextureWidth >> TextureHeight; - - if (Version >= 101) - { - std::string Format; - FNTStream >> Format; - if (Format == "rgba") - f->HasRGB = true; - else if (Format == "a") - f->HasRGB = false; - else - debug_warn(L"Invalid .fnt format string"); - } - - int NumGlyphs; - FNTStream >> NumGlyphs; - - FNTStream >> f->LineSpacing; - - if (Version >= 101) - FNTStream >> f->Height; - else - f->Height = 0; - - // [cumulative for 12: 256ms] - for (int i = 0; i < NumGlyphs; ++i) - { - int Codepoint, TextureX, TextureY, Width, Height, OffsetX, OffsetY, Advance; - FNTStream >> Codepoint>>TextureX>>TextureY>>Width>>Height>>OffsetX>>OffsetY>>Advance; - - if (Codepoint < 0 || Codepoint > 0xFFFF) - { - DEBUG_WARN_ERR(ERR::LOGIC); // Invalid codepoint - continue; - } - - if (Version < 101 && Codepoint == 'I') - { - f->Height = Height; - } - - GLfloat u = (GLfloat)TextureX / (GLfloat)TextureWidth; - GLfloat v = (GLfloat)TextureY / (GLfloat)TextureHeight; - GLfloat w = (GLfloat)Width / (GLfloat)TextureWidth; - GLfloat h = (GLfloat)Height / (GLfloat)TextureHeight; - - UnifontGlyphData g = { u, -v, u+w, -v+h, (i16)OffsetX, (i16)-OffsetY, (i16)(OffsetX+Width), (i16)(-OffsetY+Height), (i16)Advance }; - (*f->glyphs)[(u16)Codepoint] = g; - } - - ENSURE(f->Height); // Ensure the height has been found (which should always happen if the font includes an 'I') - - // Load glyph texture - // [cumulative for 12: 20ms] - const VfsPath imgName(basename.ChangeExtension(L".png")); - Handle ht = ogl_tex_load(vfs, path / imgName); - RETURN_STATUS_IF_ERR(ht); - (void)ogl_tex_set_filter(ht, GL_NEAREST); - - Status err; - if (f->HasRGB) - { - // use format auto-detection - err = ogl_tex_upload(ht); - } - else - { - // override is necessary because the GL format is chosen as LUMINANCE, - // but we want ALPHA. there is no way of knowing what format - // 8bpp textures are in - we could adopt a naming convention and - // add some TEX_ flags, but that's overkill. - err = ogl_tex_upload(ht, GL_ALPHA); - } - - if(err < 0) - { - (void)ogl_tex_free(ht); - return err; - } - - f->ht = ht; - - return INFO::OK; -} - -static Status UniFont_validate(const UniFont* f) -{ - if(f->ht < 0) - WARN_RETURN(ERR::_1); - if(debug_IsPointerBogus(f->glyphs)) - WARN_RETURN(ERR::_2); - // and are read directly from font file. - // negative values don't make sense, but that's all we can check. - if(f->LineSpacing < 0 || f->Height < 0) - WARN_RETURN(ERR::_3); - return INFO::OK; -} - -static Status UniFont_to_string(const UniFont* f, wchar_t* buf) -{ - if (f->ht) // not true if this is called after dtor (which it is) - { - const VfsPath& path = h_filename(f->ht); - swprintf_s(buf, H_STRING_LEN, L"Font %ls", path.string().c_str()); - } - else - swprintf_s(buf, H_STRING_LEN, L"Font"); - return INFO::OK; -} - - -Handle unifont_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags) -{ - return h_alloc(H_UniFont, vfs, pathname, flags); -} - - -Status unifont_unload(Handle& h) -{ - H_DEREF(h, UniFont, f); - return h_free(h, H_UniFont); -} - - -int unifont_linespacing(const Handle h) -{ - H_DEREF(h, UniFont, f); - return f->LineSpacing; -} - - -int unifont_height(const Handle h) -{ - H_DEREF(h, UniFont, f); - return f->Height; -} - - -bool unifont_has_rgb(const Handle h) -{ - UniFont* const f = H_USER_DATA(h, UniFont); - if(!f) - return false; - return f->HasRGB; -} - - -int unifont_character_width(const Handle h, wchar_t c) -{ - H_DEREF(h, UniFont, f); - glyphmap::iterator it = f->glyphs->find(c); - - if (it == f->glyphs->end()) - it = f->glyphs->find(0xFFFD); // Use the missing glyph symbol - - return it->second.xadvance; -} - -Status unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height) -{ - H_DEREF(h, UniFont, f); - - width = 0; - height = f->Height; - - size_t len = wcslen(text); - - for (size_t i = 0; i < len; ++i) - { - glyphmap::iterator it = f->glyphs->find(text[i]); - - if (it == f->glyphs->end()) - it = f->glyphs->find(0xFFFD); // Use the missing glyph symbol - - if (it == f->glyphs->end()) // Missing the missing glyph symbol - give up - { - DEBUG_WARN_ERR(ERR::LOGIC); // Missing the missing glyph in a unifont! - return INFO::OK; - } - - width += it->second.xadvance; // Add the character's advance distance - } - - return INFO::OK; -} - -const glyphmap& unifont_get_glyphs(const Handle h) -{ - UniFont* const f = H_USER_DATA(h, UniFont); - if(!f) - { - DEBUG_WARN_ERR(ERR::INVALID_HANDLE); - static glyphmap dummy; - return dummy; - } - - return *f->glyphs; -} - -Handle unifont_get_texture(const Handle h) -{ - UniFont* const f = H_USER_DATA(h, UniFont); - if(!f) - { - DEBUG_WARN_ERR(ERR::INVALID_HANDLE); - return 0; - } - - return f->ht; -} diff --git a/source/lib/res/graphics/unifont.h b/source/lib/res/graphics/unifont.h deleted file mode 100644 index e82744a598..0000000000 --- a/source/lib/res/graphics/unifont.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (c) 2012 Wildfire Games - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Unicode OpenGL texture font. - */ - -#ifndef INCLUDED_UNIFONT -#define INCLUDED_UNIFONT - -#include // va_list -#include - -#include "lib/res/handle.h" -#include "lib/file/vfs/vfs.h" - -/** - * Load a font. - * - * @param vfs - * @param pathname path and basename of the font definition file - * (.fnt) and its texture (.png) - * @param flags - **/ -extern Handle unifont_load(const PIVFS& vfs, const VfsPath& pathname, size_t flags = 0); - -/** - * Release a handle to a previously loaded font - * (subject to reference counting). - **/ -extern Status unifont_unload(Handle& h); - -/** - * Determine pixel extents of a string. - * - * @param h - * @param text string in question. - * @param width - * @param height is roughly the pixel height of a capital letter, for use - * when aligning text in an aesthetically pleasing way. - * - * note: This is intended for the GUI (hence Unicode). - **/ -Status unifont_stringsize(const Handle h, const wchar_t* text, int& width, int& height); - -/** - * @return whether the font is an RGBA texture, not an ALPHA texture. - **/ -bool unifont_has_rgb(const Handle h); - -/** - * @return height [pixels] of the font. - **/ -int unifont_height(const Handle h); - -/** - * @return width [pixels] of a certain character. - **/ -int unifont_character_width(const Handle h, wchar_t c); - -/** - * @return spacing in pixels from one line of text to the next. - **/ -int unifont_linespacing(const Handle h); - -// Raw access to font data (since it's convenient to move as much of the -// processing as possible to outside lib/): - -struct UnifontGlyphData -{ - float u0, v0, u1, v1; - i16 x0, y0, x1, y1; - i16 xadvance; -}; - -/** - * @return glyph data for all glyphs in this font. - */ -const std::map& unifont_get_glyphs(const Handle h); - -/** - * @return texture handle for this font. - */ -Handle unifont_get_texture(const Handle h); - -#endif // INCLUDED_UNIFONT diff --git a/source/ps/ArchiveBuilder.cpp b/source/ps/ArchiveBuilder.cpp index 4d3137fcc8..31c7a65e28 100644 --- a/source/ps/ArchiveBuilder.cpp +++ b/source/ps/ArchiveBuilder.cpp @@ -93,7 +93,9 @@ void CArchiveBuilder::Build(const OsPath& archive, bool compress) ENSURE(ret == INFO::OK); // Compress textures and store the new cached version instead of the original - if (boost::algorithm::starts_with(path.string(), L"art/textures/") && + if ((boost::algorithm::starts_with(path.string(), L"art/textures/") || + boost::algorithm::starts_with(path.string(), L"fonts/") + ) && tex_is_known_extension(path) && // Skip some subdirectories where the engine doesn't use CTextureManager yet: !boost::algorithm::starts_with(path.string(), L"art/textures/cursors/") && diff --git a/source/ps/CConsole.cpp b/source/ps/CConsole.cpp index a41d9fae87..fae7961c40 100644 --- a/source/ps/CConsole.cpp +++ b/source/ps/CConsole.cpp @@ -24,6 +24,7 @@ #include "CConsole.h" +#include "graphics/FontMetrics.h" #include "graphics/ShaderManager.h" #include "graphics/TextRenderer.h" #include "gui/GUIutil.h" @@ -35,7 +36,6 @@ #include "network/NetServer.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" -#include "ps/Font.h" #include "ps/Globals.h" #include "ps/Hotkey.h" #include "ps/Pyrogenesis.h" diff --git a/source/ps/CLogger.cpp b/source/ps/CLogger.cpp index f7919242b9..8c85159dcf 100644 --- a/source/ps/CLogger.cpp +++ b/source/ps/CLogger.cpp @@ -19,13 +19,13 @@ #include "CLogger.h" #include "CConsole.h" +#include "graphics/FontMetrics.h" #include "graphics/ShaderManager.h" #include "graphics/TextRenderer.h" #include "lib/ogl.h" #include "lib/timer.h" #include "lib/utf8.h" #include "lib/sysdep/sysdep.h" -#include "ps/Font.h" #include "ps/Profile.h" #include "renderer/Renderer.h" @@ -281,7 +281,7 @@ void CLogger::Render() CleanupRenderQueue(); CStrW font_name(L"mono-stroke-10"); - CFont font(font_name); + CFontMetrics font(font_name); int lineSpacing = font.GetLineSpacing(); CShaderTechniquePtr textTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); diff --git a/source/ps/Font.cpp b/source/ps/Font.cpp deleted file mode 100644 index 46f2130ee8..0000000000 --- a/source/ps/Font.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (C) 2009 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 "Font.h" - -#include "lib/res/graphics/unifont.h" - -#include "ps/Filesystem.h" -#include "ps/CLogger.h" - -#include -#include - -const wchar_t* DefaultFont = L"sans-10"; - -CFont::CFont(const CStrW& name) -{ - h = unifont_load(g_VFS, name); - - // Found it - if (h > 0) - return; - - // Not found as a font -- give up and use the default. - LOGERROR(L"Failed to find font '%ls'", name.c_str()); - h = unifont_load(g_VFS, DefaultFont); - // Assume this worked -} - -CFont::~CFont() -{ - unifont_unload(h); -} - -bool CFont::HasRGB() -{ - return unifont_has_rgb(h); -} - -int CFont::GetLineSpacing() -{ - return unifont_linespacing(h); -} - -int CFont::GetHeight() -{ - return unifont_height(h); -} - -int CFont::GetCharacterWidth(wchar_t c) -{ - return unifont_character_width(h, c); -} - -void CFont::CalculateStringSize(const wchar_t* string, int& width, int& height) -{ - unifont_stringsize(h, string, width, height); -} - -const std::map& CFont::GetGlyphs() -{ - return unifont_get_glyphs(h); -} - -Handle CFont::GetTexture() -{ - return unifont_get_texture(h); -} diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index b675343747..05c66b578c 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -36,6 +36,7 @@ #endif #include "graphics/CinemaTrack.h" +#include "graphics/FontMetrics.h" #include "graphics/GameView.h" #include "graphics/LightEnv.h" #include "graphics/MapReader.h" @@ -55,7 +56,6 @@ #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/Filesystem.h" -#include "ps/Font.h" #include "ps/Game.h" #include "ps/GameSetup/Atlas.h" #include "ps/GameSetup/GameSetup.h" @@ -507,7 +507,7 @@ static void InitPs(bool setup_gui, const CStrW& gui_page, CScriptVal initData) g_Console->UpdateScreenSize(g_xres, g_yres); // Calculate and store the line spacing - CFont font(CONSOLE_FONT); + CFontMetrics font(CONSOLE_FONT); g_Console->m_iFontHeight = font.GetLineSpacing(); g_Console->m_iFontWidth = font.GetCharacterWidth(L'C'); g_Console->m_charsPerPage = (size_t)(g_xres / g_Console->m_iFontWidth); diff --git a/source/ps/ProfileViewer.cpp b/source/ps/ProfileViewer.cpp index 240dc3c87a..8641739c29 100644 --- a/source/ps/ProfileViewer.cpp +++ b/source/ps/ProfileViewer.cpp @@ -27,12 +27,12 @@ #include "ProfileViewer.h" +#include "graphics/FontMetrics.h" #include "gui/GUIutil.h" #include "graphics/ShaderManager.h" #include "graphics/TextRenderer.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" -#include "ps/Font.h" #include "ps/Hotkey.h" #include "ps/Profile.h" #include "lib/external_libraries/libsdl.h" @@ -171,7 +171,7 @@ void CProfileViewer::RenderProfile() size_t numrows = table->GetNumberRows(); CStrW font_name = L"mono-stroke-10"; - CFont font(font_name); + CFontMetrics font(font_name); int lineSpacing = font.GetLineSpacing(); // Render background diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 2e54332ba3..43833198fc 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -44,6 +44,7 @@ #include "ps/Loader.h" #include "ps/ProfileViewer.h" #include "graphics/Camera.h" +#include "graphics/FontManager.h" #include "graphics/GameView.h" #include "graphics/LightEnv.h" #include "graphics/LOSTexture.h" @@ -281,6 +282,8 @@ public: /// Postprocessing effect manager CPostprocManager postprocManager; + CFontManager fontManager; + /// Various model renderers struct Models { @@ -2007,4 +2010,9 @@ CMaterialManager& CRenderer::GetMaterialManager() CPostprocManager& CRenderer::GetPostprocManager() { return m->postprocManager; -} \ No newline at end of file +} + +CFontManager& CRenderer::GetFontManager() +{ + return m->fontManager; +} diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index f874ff6a6f..8bd0667386 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -36,6 +36,7 @@ #include "scriptinterface/ScriptInterface.h" // necessary declarations +class CFontManager; class CLightEnv; class CMaterial; class CMaterialManager; @@ -304,6 +305,8 @@ public: CMaterialManager& GetMaterialManager(); + CFontManager& GetFontManager(); + CShaderDefines GetSystemShaderDefines() { return m_SystemShaderDefines; } CTimeManager& GetTimeManager(); diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 4fd89a1a39..a1c599ff92 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -39,7 +39,6 @@ #include "ps/Filesystem.h" #include "ps/CLogger.h" -#include "ps/Font.h" #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index 072f9385d4..c8c171b7ed 100644 --- a/source/tools/atlas/GameInterface/ActorViewer.cpp +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -38,7 +38,6 @@ #include "graphics/Overlay.h" #include "maths/MathUtil.h" #include "ps/Filesystem.h" -#include "ps/Font.h" #include "ps/CLogger.h" #include "ps/GameSetup/Config.h" #include "ps/ProfileViewer.h"