Auto embolden glyph of bold face, without fallback font

This commit is contained in:
Benau 2016-07-21 12:26:19 +08:00
parent a72f67015c
commit 744a4705b6
19 changed files with 201 additions and 97 deletions

View File

@ -411,8 +411,7 @@
which leads to crash with STK), but the fonts are to blame, what's the point of not
using industry standard nowadays...
-->
<fonts-list regular-faces="Cantarell-Regular.otf FreeSans.ttf wqy-microhei.ttf NotoNaskhArabicUI-Bold.ttf"
bold-faces="Cantarell-Bold.otf FreeSansBold.ttf"
digit-faces="SigmarOne.otf" />
<fonts-list normal-ttf="Cantarell-Regular.otf FreeSans.ttf wqy-microhei.ttf NotoNaskhArabicUI-Bold.ttf"
digit-ttf="SigmarOne.otf" />
</config>

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,4 @@
GNU FreeFont (FreeSans, FreeSansBold) is released under the GPLv3
GNU FreeFont (FreeSans) is released under the GPLv3
wqyMicroHei is released under the GPLv3 with font embedding exception and Apache-2.0 licenses
By Qianqian Fang and The WenQuanYi Project Contributors

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -182,9 +182,8 @@ void STKConfig::init_defaults()
m_score_increase.clear();
m_leader_intervals.clear();
m_switch_items.clear();
m_regular_faces.clear();
m_bold_faces.clear();
m_digit_faces.clear();
m_normal_ttf.clear();
m_digit_ttf.clear();
} // init_defaults
//-----------------------------------------------------------------------------
@ -368,9 +367,8 @@ void STKConfig::getAllData(const XMLNode * root)
if (const XMLNode *fonts_list = root->getNode("fonts-list"))
{
fonts_list->get("regular-faces", &m_regular_faces);
fonts_list->get("bold-faces", &m_bold_faces );
fonts_list->get("digit-faces", &m_digit_faces );
fonts_list->get("normal-ttf", &m_normal_ttf);
fonts_list->get("digit-ttf", &m_digit_ttf );
}
// Get the default KartProperties

View File

@ -154,9 +154,8 @@ public:
std::string m_font_bold_fallback;
std::string m_font_digit;
/** Lists of TTF files used in STK. */
std::vector<std::string> m_regular_faces;
std::vector<std::string> m_bold_faces;
std::vector<std::string> m_digit_faces;
std::vector<std::string> m_normal_ttf;
std::vector<std::string> m_digit_ttf;
private:
/** True if stk_config has been loaded. This is necessary if the

View File

@ -18,11 +18,10 @@
#include "font/bold_face.hpp"
#include "config/stk_config.hpp"
#include "font/regular_face.hpp"
#include "font/face_ttf.hpp"
// ----------------------------------------------------------------------------
BoldFace::BoldFace() : FontWithFace("BoldFace")
BoldFace::BoldFace(FaceTTF* ttf) : FontWithFace("BoldFace", ttf)
{
} // BoldFace
@ -32,8 +31,10 @@ void BoldFace::init()
FontWithFace::init();
// Reserve some space for characters added later
m_font_max_height = m_glyph_max_height + 20;
/* Use FT_Outline_Embolden for now, no more fallback font
setFallbackFont(font_manager->getFont<RegularFace>());
setFallbackFontScale(2.0f);
setFallbackFontScale(2.0f);*/
} // init
// ----------------------------------------------------------------------------
@ -51,9 +52,3 @@ void BoldFace::reset()
insertCharacters(preload_chars.c_str());
updateCharactersList();
} // reset
// ----------------------------------------------------------------------------
std::vector<std::string> BoldFace::getFacesList() const
{
return stk_config->m_bold_faces;
} // getFacesList

View File

@ -21,11 +21,11 @@
#include "font/font_with_face.hpp"
class FaceTTF;
class BoldFace : public FontWithFace
{
private:
virtual std::vector<std::string> getFacesList() const OVERRIDE;
// ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const OVERRIDE { return true; }
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 1024; }
@ -37,7 +37,7 @@ private:
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
BoldFace();
BoldFace(FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~BoldFace() {}
// ------------------------------------------------------------------------

View File

@ -18,10 +18,10 @@
#include "font/digit_face.hpp"
#include "config/stk_config.hpp"
#include "font/face_ttf.hpp"
// ----------------------------------------------------------------------------
DigitFace::DigitFace() : FontWithFace("DigitFace")
DigitFace::DigitFace(FaceTTF* ttf) : FontWithFace("DigitFace", ttf)
{
} // DigitFace
@ -50,9 +50,3 @@ void DigitFace::reset()
insertCharacters(preload_chars.c_str(), true/*first_load*/);
updateCharactersList();
} // reset
// ----------------------------------------------------------------------------
std::vector<std::string> DigitFace::getFacesList() const
{
return stk_config->m_digit_faces;
} // getFacesList

View File

@ -21,11 +21,11 @@
#include "font/font_with_face.hpp"
class FaceTTF;
class DigitFace : public FontWithFace
{
private:
virtual std::vector<std::string> getFacesList() const OVERRIDE;
// ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const OVERRIDE { return false; }
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 256; }
@ -37,7 +37,7 @@ private:
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
DigitFace();
DigitFace(FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~DigitFace() {}
// ------------------------------------------------------------------------

49
src/font/face_ttf.cpp Normal file
View File

@ -0,0 +1,49 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program 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 3
// of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "font/face_ttf.hpp"
#include "io/file_manager.hpp"
// ----------------------------------------------------------------------------
FaceTTF::FaceTTF(const std::vector<std::string>& ttf_list)
{
for (const std::string& font : ttf_list)
{
FT_Face face = NULL;
font_manager->checkFTError(FT_New_Face(font_manager->getFTLibrary(),
(file_manager->getAssetChecked(FileManager::TTF,
font.c_str(), true)).c_str(), 0, &face), "loading fonts");
m_faces.push_back(face);
}
} // FaceTTF
// ----------------------------------------------------------------------------
FaceTTF::~FaceTTF()
{
for (unsigned int i = 0; i < m_faces.size(); i++)
{
font_manager->checkFTError(FT_Done_Face(m_faces[i]), "removing face");
}
} // ~FaceTTF
// ----------------------------------------------------------------------------
FT_Face FaceTTF::getFace(unsigned int i) const
{
assert(i < m_faces.size());
return m_faces[i];
} // getFace

43
src/font/face_ttf.hpp Normal file
View File

@ -0,0 +1,43 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program 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 3
// of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_FACE_TTF_HPP
#define HEADER_FACE_TTF_HPP
#include "font/font_manager.hpp"
class FaceTTF : public NoCopy
{
private:
std::vector<FT_Face> m_faces;
public:
LEAK_CHECK();
// ------------------------------------------------------------------------
FaceTTF(const std::vector<std::string>& ttf_list);
// ------------------------------------------------------------------------
~FaceTTF();
// ------------------------------------------------------------------------
FT_Face getFace(unsigned int i) const;
// ------------------------------------------------------------------------
unsigned int getTotalFaces() const { return m_faces.size(); }
}; // FaceTTF
#endif
/* EOF */

View File

@ -18,8 +18,10 @@
#include "font/font_manager.hpp"
#include "config/stk_config.hpp"
#include "font/bold_face.hpp"
#include "font/digit_face.hpp"
#include "font/face_ttf.hpp"
#include "font/regular_face.hpp"
FontManager *font_manager = NULL;
@ -33,6 +35,11 @@ FontManager::FontManager()
FontManager::~FontManager()
{
m_fonts.clearAndDeleteAll();
delete m_normal_ttf;
m_normal_ttf = NULL;
delete m_digit_ttf;
m_digit_ttf = NULL;
checkFTError(FT_Done_FreeType(m_ft_library), "removing freetype library");
m_ft_library = NULL;
} // ~FontManager
@ -40,13 +47,20 @@ FontManager::~FontManager()
// ----------------------------------------------------------------------------
void FontManager::loadFonts()
{
RegularFace* regular = new RegularFace();
// First load the TTF files required by each font
m_normal_ttf = new FaceTTF(stk_config->m_normal_ttf);
m_digit_ttf = new FaceTTF(stk_config->m_digit_ttf);
// Now load fonts with settings of ttf file
RegularFace* regular = new RegularFace(m_normal_ttf);
regular->init();
m_fonts.push_back(regular);
BoldFace* bold = new BoldFace();
BoldFace* bold = new BoldFace(m_normal_ttf);
bold->init();
m_fonts.push_back(bold);
DigitFace* digit = new DigitFace();
DigitFace* digit = new DigitFace(m_digit_ttf);
digit->init();
m_fonts.push_back(digit);
} // loadFonts

View File

@ -29,6 +29,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
class FaceTTF;
class FontWithFace;
class FontManager : public NoCopy
@ -38,6 +39,10 @@ private:
FT_Library m_ft_library;
FaceTTF* m_normal_ttf;
FaceTTF* m_digit_ttf;
public:
LEAK_CHECK()
// ------------------------------------------------------------------------

View File

@ -19,14 +19,17 @@
#include "font/font_with_face.hpp"
#include "font/bold_face.hpp"
#include "font/face_ttf.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/skin.hpp"
#include "utils/string_utils.hpp"
#include <freetype/ftoutln.h>
// ----------------------------------------------------------------------------
FontWithFace::FontWithFace(const std::string& name)
FontWithFace::FontWithFace(const std::string& name, FaceTTF* ttf)
{
m_spritebank = irr_driver->getGUI()->addEmptySpriteBank(name.c_str());
@ -36,6 +39,7 @@ FontWithFace::FontWithFace(const std::string& name)
m_fallback_font = NULL;
m_fallback_font_scale = 1.0f;
m_glyph_max_height = 0;
m_face_ttf = ttf;
} // FontWithFace
// ----------------------------------------------------------------------------
@ -46,33 +50,24 @@ FontWithFace::~FontWithFace()
m_spritebank->drop();
m_spritebank = NULL;
for (unsigned int i = 0; i < m_faces.size(); i++)
{
font_manager->checkFTError(FT_Done_Face(m_faces[i]), "removing face");
}
// To be deleted by font_manager
m_face_ttf = NULL;
} // ~FontWithFace
// ----------------------------------------------------------------------------
void FontWithFace::init()
{
setDPI();
m_page = irr_driver->getVideoDriver()->createImage(video::ECF_A8R8G8B8,
core::dimension2du(getGlyphPageSize(), getGlyphPageSize()));
for (const std::string& font : getFacesList())
{
FT_Face face = NULL;
font_manager->checkFTError(FT_New_Face(font_manager->getFTLibrary(),
(file_manager->getAssetChecked(FileManager::TTF,
font.c_str(), true)).c_str(), 0, &face), "loading fonts");
font_manager->checkFTError(FT_Set_Pixel_Sizes(face, 0, getDPI()),
"setting DPI");
m_faces.push_back(face);
}
// Get the max height for this face
assert(m_faces.size() > 0);
FT_Face cur_face = m_faces[0];
assert(m_face_ttf->getTotalFaces() > 0);
FT_Face cur_face = m_face_ttf->getFace(0);
font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
"setting DPI");
for (int i = 32; i < 128; i++)
{
// Test all basic latin characters
@ -98,6 +93,20 @@ void FontWithFace::reset()
createNewGlyphPage();
} // reset
// ----------------------------------------------------------------------------
void FontWithFace::loadGlyphInfo(wchar_t c)
{
unsigned int font_number = 0;
unsigned int glyph_index = 0;
while (font_number < m_face_ttf->getTotalFaces())
{
glyph_index = FT_Get_Char_Index(m_face_ttf->getFace(font_number), c);
if (glyph_index > 0) break;
font_number++;
}
m_character_glyph_info_map[c] = GlyphInfo(font_number, glyph_index);
} // loadGlyphInfo
// ----------------------------------------------------------------------------
void FontWithFace::createNewGlyphPage()
{
@ -124,13 +133,26 @@ void FontWithFace::createNewGlyphPage()
void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
{
assert(gi.glyph_index > 0);
assert(gi.font_number < m_faces.size());
FT_Face cur_face = m_faces[gi.font_number];
assert(gi.font_number < m_face_ttf->getTotalFaces());
FT_Face cur_face = m_face_ttf->getFace(gi.font_number);
FT_GlyphSlot slot = cur_face->glyph;
// Faces may be shared across regular and bold,
// so reset dpi each time
font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
"setting DPI");
font_manager->checkFTError(FT_Load_Glyph(cur_face, gi.glyph_index,
FT_LOAD_DEFAULT | FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL),
"loading a glyph");
FT_LOAD_DEFAULT), "loading a glyph");
if (dynamic_cast<BoldFace*>(this))
{
// Embolden the outline of the glyph
FT_Outline_Embolden(&(slot->outline), getDPI() * 2);
}
font_manager->checkFTError(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL),
"render a glyph to bitmap");
// Convert to an anti-aliased bitmap
FT_Bitmap bits = slot->bitmap;
@ -297,7 +319,7 @@ void FontWithFace::dumpGlyphPage()
} // dumpGlyphPage
// ----------------------------------------------------------------------------
unsigned int FontWithFace::getDPI() const
void FontWithFace::setDPI()
{
// Get face dpi:
// Font size is resolution-dependent.
@ -315,10 +337,10 @@ unsigned int FontWithFace::getDPI() const
if (screen_width < 900 || screen_height < 700)
scale = std::min(scale, 0.05f);
return unsigned((getScalingFactorOne() + 0.2f * scale) *
m_face_dpi = unsigned((getScalingFactorOne() + 0.2f * scale) *
getScalingFactorTwo());
} // getDPI
} // setDPI
// ----------------------------------------------------------------------------
const FontWithFace::FontArea&

View File

@ -29,6 +29,8 @@
const int BEARING = 64;
class FaceTTF;
class FontWithFace : public NoCopy
{
public:
@ -53,8 +55,6 @@ public:
};
protected:
std::vector<FT_Face> m_faces;
int m_font_max_height;
int m_glyph_max_height;
@ -104,6 +104,8 @@ private:
}
};
FaceTTF* m_face_ttf;
FontWithFace* m_fallback_font;
float m_fallback_font_scale;
@ -120,6 +122,7 @@ private:
unsigned int m_temp_height;
unsigned int m_used_width;
unsigned int m_used_height;
unsigned int m_face_dpi;
std::map<wchar_t, FontArea> m_character_area_map;
std::map<wchar_t, GlyphInfo> m_character_glyph_info_map;
@ -162,27 +165,16 @@ private:
return false;
}
// ------------------------------------------------------------------------
void loadGlyphInfo(wchar_t c)
{
unsigned int font_number = 0;
unsigned int glyph_index = 0;
while (font_number < m_faces.size())
{
glyph_index = FT_Get_Char_Index(m_faces[font_number], c);
if (glyph_index > 0) break;
font_number++;
}
m_character_glyph_info_map[c] = GlyphInfo(font_number, glyph_index);
}
void loadGlyphInfo(wchar_t c);
// ------------------------------------------------------------------------
void createNewGlyphPage();
// ------------------------------------------------------------------------
unsigned int getDPI() const;
// ------------------------------------------------------------------------
void addLazyLoadChar(wchar_t c) { m_new_char_holder.insert(c); }
// ------------------------------------------------------------------------
void insertGlyph(wchar_t c, const GlyphInfo& gi);
// ------------------------------------------------------------------------
void setDPI();
// ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const = 0;
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const = 0;
@ -190,13 +182,11 @@ private:
virtual float getScalingFactorOne() const = 0;
// ------------------------------------------------------------------------
virtual unsigned int getScalingFactorTwo() const = 0;
// ------------------------------------------------------------------------
virtual std::vector<std::string> getFacesList() const = 0;
public:
LEAK_CHECK();
// ------------------------------------------------------------------------
FontWithFace(const std::string& name);
FontWithFace(const std::string& name, FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~FontWithFace();
// ------------------------------------------------------------------------
@ -231,6 +221,8 @@ public:
// ------------------------------------------------------------------------
const FontArea& getAreaFromCharacter(const wchar_t c,
bool* fallback_font) const;
// ------------------------------------------------------------------------
unsigned int getDPI() const { return m_face_dpi; }
}; // FontWithFace

View File

@ -16,12 +16,12 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "font/face_ttf.hpp"
#include "font/regular_face.hpp"
#include "config/stk_config.hpp"
// ----------------------------------------------------------------------------
RegularFace::RegularFace() : FontWithFace("RegularFace")
RegularFace::RegularFace(FaceTTF* ttf) : FontWithFace("RegularFace", ttf)
{
} // RegularFace
@ -48,9 +48,3 @@ void RegularFace::reset()
insertCharacters(preload_chars.c_str());
updateCharactersList();
} // reset
// ----------------------------------------------------------------------------
std::vector<std::string> RegularFace::getFacesList() const
{
return stk_config->m_regular_faces;
} // getFacesList

View File

@ -21,11 +21,11 @@
#include "font/font_with_face.hpp"
class FaceTTF;
class RegularFace : public FontWithFace
{
private:
virtual std::vector<std::string> getFacesList() const OVERRIDE;
// ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const OVERRIDE { return true; }
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 512; }
@ -37,7 +37,7 @@ private:
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
RegularFace();
RegularFace(FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~RegularFace() {}
// ------------------------------------------------------------------------