Basic render of text using freetype

This is a testing version of stk using freetype

It enable better arabic font display with less blurred glyph to all fonts thanks to hinting provide by freetype.

TODO: billboard text
This commit is contained in:
Benau 2015-10-04 11:59:44 +08:00
parent ec33e92ad0
commit 3a5ec83ae9
28 changed files with 1006 additions and 37 deletions

@ -16,6 +16,7 @@ if (NOT CMAKE_BUILD_TYPE)
endif()
option(USE_WIIUSE "Support for wiimote input devices" ON)
option(USE_FREETYPE "Use Freetype to render text" ON)
option(USE_FRIBIDI "Support for right-to-left languages" ON)
option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON)
option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF)
@ -164,6 +165,17 @@ else()
include_directories(${OGGVORBIS_INCLUDE_DIRS})
endif()
# Freetype
if(USE_FREETYPE)
find_package(Freetype)
if(FREETYPE_FOUND)
include_directories(${FREETYPE_INCLUDE_DIRS})
else()
message(FATAL_ERROR "Freetype not found. "
"Either install freetype or disable freetype rendering support with -DUSE_FREETYPE=0 ")
endif()
endif()
# Fribidi
if(USE_FRIBIDI)
find_package(Fribidi)
@ -339,6 +351,7 @@ target_link_libraries(supertuxkart
${OGGVORBIS_LIBRARIES}
${OPENAL_LIBRARY}
${OPENGL_LIBRARIES}
${FREETPYE_LIBRARIES}
)
if(UNIX AND NOT APPLE)
@ -368,6 +381,11 @@ if(USE_FRIBIDI)
add_definitions(-DENABLE_BIDI)
endif()
if(USE_FREETYPE)
target_link_libraries(supertuxkart ${FREETYPE_LIBRARIES})
add_definitions(-DENABLE_FREETYPE)
endif()
# Wiiuse
# ------
if(USE_WIIUSE)

23
cmake/FindFreetype.cmake Normal file

@ -0,0 +1,23 @@
# - Find Freetype
# Find the Freetype includes and libraries
#
# Following variables are provided:
# FREETYPE_FOUND
# True if Freetype has been found
# FREETYPE_INCLUDE_DIRS
# The include directories of Freetype
# FREETYPE_LIBRARIES
# Freetype library list
if(MSVC)
find_path(FREETYPE_INCLUDE_DIRS NAMES freetype/freetype.h PATHS "${PROJECT_SOURCE_DIR}/dependencies/include")
find_library(FREETPYE_LIBRARY NAMES freetype PATHS "${PROJECT_SOURCE_DIR}/dependencies/lib")
set(FREETYPE_FOUND 1)
set(FREETPYE_LIBRARIES ${FREETPYE_LIBRARY})
elseif(UNIX)
include(FindPkgConfig)
pkg_check_modules(FREETYPE freetype2)
else()
set(FREETYPE_FOUND 0)
endif()

BIN
data/ttf/FreeMonoBold.ttf Normal file

Binary file not shown.

BIN
data/ttf/FreeSans.ttf Normal file

Binary file not shown.

BIN
data/ttf/FreeSansBold.ttf Normal file

Binary file not shown.

BIN
data/ttf/Layne_Hansom.ttf Normal file

Binary file not shown.

BIN
data/ttf/amiri-bold.ttf Normal file

Binary file not shown.

BIN
data/ttf/wqy-microhei.ttf Normal file

Binary file not shown.

@ -68,6 +68,8 @@ public:
//! The texture and the corresponding rectangle and sprite will all be added to the end of each array.
//! returns the index of the sprite or -1 on failure
virtual s32 addTextureAsSprite(video::ITexture* texture) = 0;
//! Use for cropping freetype glyph bitmap correctly.
virtual s32 addTextureAsSprite(video::ITexture* texture, s32 width, s32 height) = 0;
//! clears sprites, rectangles and textures
virtual void clear() = 0;

@ -131,6 +131,31 @@ s32 CGUISpriteBank::addTextureAsSprite(video::ITexture* texture)
return Sprites.size() - 1;
}
//! Use for cropping freetype glyph bitmap correctly.
s32 CGUISpriteBank::addTextureAsSprite(video::ITexture* texture, s32 width, s32 height)
{
if ( !texture )
return -1;
addTexture(texture);
u32 textureIndex = getTextureCount() - 1;
u32 rectangleIndex = Rectangles.size();
Rectangles.push_back( core::rect<s32>(0,0, width, height) );
SGUISprite sprite;
sprite.frameTime = 0;
SGUISpriteFrame frame;
frame.textureNumber = textureIndex;
frame.rectNumber = rectangleIndex;
sprite.Frames.push_back( frame );
Sprites.push_back( sprite );
return Sprites.size() - 1;
}
//! draws a sprite in 2d with scale and color
void CGUISpriteBank::draw2DSprite(u32 index, const core::position2di& pos,
const core::rect<s32>* clip, const video::SColor& color,

@ -42,6 +42,8 @@ public:
//! Add the texture and use it for a single non-animated sprite.
virtual s32 addTextureAsSprite(video::ITexture* texture);
//! Use for cropping freetype glyph bitmap correctly.
virtual s32 addTextureAsSprite(video::ITexture* texture, s32 width, s32 height);
//! clears sprites, rectangles and textures
virtual void clear();

@ -167,6 +167,34 @@ s32 STKModifiedSpriteBank::addTextureAsSprite(video::ITexture* texture)
return Sprites.size() - 1;
} // addTextureAsSprite
// ----------------------------------------------------------------------------
/** Use for cropping freetype glyph bitmap correctly.
*/
s32 STKModifiedSpriteBank::addTextureAsSprite(video::ITexture* texture, s32 width, s32 height)
{
assert( m_magic_number == 0xCAFEC001 );
if ( !texture )
return -1;
addTexture(texture);
u32 textureIndex = getTextureCount() - 1;
u32 rectangleIndex = Rectangles.size();
Rectangles.push_back( core::rect<s32>(0,0, width, height) );
SGUISprite sprite;
sprite.frameTime = 0;
SGUISpriteFrame frame;
frame.textureNumber = textureIndex;
frame.rectNumber = rectangleIndex;
sprite.Frames.push_back( frame );
Sprites.push_back( sprite );
return Sprites.size() - 1;
} // addTextureAsSprite
// ----------------------------------------------------------------------------
//! draws a sprite in 2d with scale and color
void STKModifiedSpriteBank::draw2DSprite(u32 index,

@ -45,6 +45,8 @@ public:
//! Add the texture and use it for a single non-animated sprite.
virtual s32 addTextureAsSprite(video::ITexture* texture);
//! Use for cropping freetype glyph bitmap correctly.
virtual s32 addTextureAsSprite(video::ITexture* texture, s32 width, s32 height);
//! clears sprites, rectangles and textures
virtual void clear();

@ -0,0 +1,205 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2010 John Norman
// Copyright (C) 2015 Ben Au
//
// 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.
//
// The image loading function is partially based on CGUITTFont.cpp by John Norman,
// original version is located here:
//
// http://irrlicht.suckerfreegames.com/
#ifdef ENABLE_FREETYPE
#include "io/file_manager.hpp"
#include "guiengine/TTF_handling.hpp"
#include "graphics/irr_driver.hpp"
#include <algorithm>
namespace irr
{
namespace gui
{
TTFfile getTTFAndChar(const std::string &langname, TTFLoadingType type, FontUse& fu)
{
//Borrowed from engine.cpp:
// font size is resolution-dependent.
// normal text will range from 0.8, in 640x* resolutions (won't scale
// below that) to 1.0, in 1024x* resolutions, and linearly up
// normal text will range from 0.2, in 640x* resolutions (won't scale
// below that) to 0.4, in 1024x* resolutions, and linearly up
const int screen_width = irr_driver->getFrameSize().Width;
const int screen_height = irr_driver->getFrameSize().Height;
float scale = std::max(0, screen_width - 640)/564.0f;
// attempt to compensate for small screens
if (screen_width < 1200) scale = std::max(0, screen_width - 640) / 750.0f;
if (screen_width < 900 || screen_height < 700) scale = std::min(scale, 0.05f);
float normal_text_scale = 0.7f + 0.2f*scale;
float title_text_scale = 0.2f + 0.2f*scale;
TTFfile ttf_file;
switch(type)
{
case Normal:
loadChar(langname, &ttf_file, fu, normal_text_scale);
break;
case Digit:
fu = F_DIGIT;
loadNumber(&ttf_file, normal_text_scale);
break;
case Bold:
fu = F_BOLD;
loadBoldChar(&ttf_file, title_text_scale);
break;
}
return ttf_file;
}
void loadChar(const std::string langname, TTFfile* ttf_file, FontUse& fu, float scale)
{
//Determine which ttf file to load first
if (langname.compare("ar") == 0 || langname.compare("fa") == 0)
fu = F_AR;
else if (langname.compare("sq") == 0 || langname.compare("eu") == 0
|| langname.compare("br") == 0 || langname.compare("da") == 0
|| langname.compare("nl") == 0 || langname.compare("en") == 0
|| langname.compare("gd") == 0 || langname.compare("gl") == 0
|| langname.compare("de") == 0 || langname.compare("is") == 0
|| langname.compare("id") == 0 || langname.compare("it") == 0
|| langname.compare("nb") == 0 || langname.compare("nn") == 0
|| langname.compare("pt") == 0 || langname.compare("es") == 0
|| langname.compare("sv") == 0 || langname.compare("uz") == 0)
//They are sorted out by running fc-list :lang="name" |grep Layne
fu = F_LAYNE;
else if (langname.compare("zh") == 0 || langname.compare("ko") == 0
|| langname.compare("ja") == 0)
fu = F_CJK;
else
fu = F_DEFAULT; //Default font file
ttf_file->size = (int)(29*scale); //Set to default size
ttf_file->usedchar = translations->getCurrentAllChar(); //Loading unique characters
for (int i = 33; i < 256; ++i)
ttf_file->usedchar.insert((wchar_t)i); //Include basic Latin too
ttf_file->usedchar.insert((wchar_t)160); //Non-breaking space
ttf_file->usedchar.insert((wchar_t)215); //Used on resolution selection screen (X).
//There's specific handling for some language, we may need more after more translation are added or problems found out.
if (langname.compare("el") == 0)
ttf_file->size = (int)(28*scale); //Set lower size of font for Greek as it uses lots amount of space.
}
void loadNumber(TTFfile* ttf_file, float scale)
{
ttf_file->size = (int)(40*scale); //Set default size for Big Digit Text
for (int i = 46; i < 59; ++i) //Include chars used by timer and laps count only
ttf_file->usedchar.insert((wchar_t)i); //FIXME have to load 46 " . " to make 47 " / " display correctly, why?
}
void loadBoldChar(TTFfile* ttf_file, float scale)
{
ttf_file->size = (int)(120*scale); //Set default size for Bold Text
for (int i = 33; i < 256; ++i)
ttf_file->usedchar.insert((wchar_t)i);
setlocale(LC_ALL, "en_US.UTF8");
std::set<wchar_t>::iterator it = ttf_file->usedchar.begin();
while (it != ttf_file->usedchar.end())
{
if (iswlower((wchar_t)*it))
it = ttf_file->usedchar.erase(it);
else
++it;
}
}
video::IImage* generateTTFImage(FT_Bitmap bits, video::IVideoDriver* Driver)
{
core::dimension2du d(bits.width + 1, bits.rows + 1);
core::dimension2du texture_size;
video::IImage* image = 0;
switch (bits.pixel_mode)
{
case FT_PIXEL_MODE_MONO:
{
// Create a blank image and fill it with transparent pixels.
texture_size = d.getOptimalSize(true, true);
image = Driver->createImage(video::ECF_A1R5G5B5, texture_size);
image->fill(video::SColor(0, 255, 255, 255));
// Load the monochrome data in.
const u32 image_pitch = image->getPitch() / sizeof(u16);
u16* image_data = (u16*)image->lock();
u8* glyph_data = bits.buffer;
for (u32 y = 0; y < bits.rows; ++y)
{
u16* row = image_data;
for (u32 x = 0; x < bits.width; ++x)
{
// Monochrome bitmaps store 8 pixels per byte. The left-most pixel is the bit 0x80.
// So, we go through the data each bit at a time.
if ((glyph_data[y * bits.pitch + (x / 8)] & (0x80 >> (x % 8))) != 0)
*row = 0xFFFF;
++row;
}
image_data += image_pitch;
}
image->unlock();
break;
}
case FT_PIXEL_MODE_GRAY:
{
// Create our blank image.
texture_size = d.getOptimalSize(true, true, true, 0); //Enable force power of 2 texture size to gain performance,
//But may increase vram usage???
image = Driver->createImage(video::ECF_A8R8G8B8, texture_size);
image->fill(video::SColor(0, 255, 255, 255));
// Load the grayscale data in.
const float gray_count = static_cast<float>(bits.num_grays);
const u32 image_pitch = image->getPitch() / sizeof(u32);
u32* image_data = (u32*)image->lock();
u8* glyph_data = bits.buffer;
for (u32 y = 0; y < bits.rows; ++y)
{
u8* row = glyph_data;
for (u32 x = 0; x < bits.width; ++x)
{
image_data[y * image_pitch + x] |= static_cast<u32>(255.0f * (static_cast<float>(*row++) / gray_count)) << 24;
//data[y * image_pitch + x] |= ((u32)(*bitsdata++) << 24);
}
glyph_data += bits.pitch;
}
image->unlock();
break;
}
default:
Log::error("ScalableFont::loadTTF", "Freetype failed to create bitmap!!");
return 0;
}
return image;
}
} // end namespace gui
} // end namespace irr
#endif // ENABLE_FREETYPE

@ -0,0 +1,50 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2015 Ben Au
//
// 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 "utils/translation.hpp"
#include <IVideoDriver.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <cwctype>
#include <clocale>
namespace irr
{
namespace gui
{
enum TTFLoadingType {Normal, Digit, Bold};
enum FontUse {F_DEFAULT, F_CJK, F_AR, F_LAYNE, F_BOLD, F_DIGIT};
typedef struct
{
std::set<wchar_t> usedchar;
unsigned short size;
std::string filename;
}TTFfile;
TTFfile getTTFAndChar(const std::string &langname, TTFLoadingType, FontUse&);
video::IImage* generateTTFImage (FT_Bitmap, video::IVideoDriver*);
void loadChar(const std::string, TTFfile*, FontUse&, float);
void loadNumber(TTFfile*, float);
void loadBoldChar(TTFfile*, float);
} // end namespace gui
} // end namespace irr

@ -688,6 +688,9 @@ namespace GUIEngine
{
IGUIEnvironment* g_env;
Skin* g_skin = NULL;
#ifdef ENABLE_FREETYPE
Ft_Env* g_ft_env = NULL;
#endif // ENABLE_FREETYPE
ScalableFont *g_font;
ScalableFont *g_outline_font;
ScalableFont *g_large_font;
@ -952,6 +955,11 @@ namespace GUIEngine
//if (g_skin != NULL) delete g_skin;
g_skin = NULL;
#ifdef ENABLE_FREETYPE
g_ft_env->~Ft_Env();
g_ft_env = NULL;
#endif // ENABLE_FREETYPE
for (unsigned int i=0; i<g_loaded_screens.size(); i++)
{
g_loaded_screens[i].unload();
@ -982,6 +990,17 @@ namespace GUIEngine
// kill everything along the device
} // cleanUp
// -----------------------------------------------------------------------
void cleanHollowCopyFont()
{
g_small_font->drop();
g_small_font = NULL;
g_large_font->drop();
g_large_font = NULL;
g_outline_font->drop();
g_outline_font = NULL;
} // cleanHollowCopyFont
// -----------------------------------------------------------------------
/**
@ -1009,6 +1028,10 @@ namespace GUIEngine
g_focus_for_player[n] = NULL;
}
#ifdef ENABLE_FREETYPE
g_ft_env = new Ft_Env();
#endif // ENABLE_FREETYPE
/*
To make the g_font a little bit nicer, we load an external g_font
and set it as the new default g_font in the g_skin.
@ -1042,6 +1065,10 @@ namespace GUIEngine
}
}
#ifdef ENABLE_FREETYPE
float normal_text_scale = 1;
float title_text_scale = 1;
#else
// font size is resolution-dependent.
// normal text will range from 0.8, in 640x* resolutions (won't scale
// below that) to 1.0, in 1024x* resolutions, and linearly up
@ -1059,20 +1086,30 @@ namespace GUIEngine
float normal_text_scale = 0.7f + 0.2f*scale;
float title_text_scale = 0.2f + 0.2f*scale;
#endif // ENABLE_FREETYPE
#ifdef ENABLE_FREETYPE
ScalableFont* sfont =new ScalableFont(g_env,Normal);
sfont->setKerningHeight(0);
#else
ScalableFont* sfont =
new ScalableFont(g_env,
file_manager->getAssetChecked(FileManager::FONT,
"StkFont.xml",true) );
sfont->setScale(normal_text_scale);
sfont->setKerningHeight(-5);
#endif // ENABLE_FREETYPE
sfont->setScale(normal_text_scale);
g_font = sfont;
#ifdef ENABLE_FREETYPE
ScalableFont* digit_font =new ScalableFont(g_env,Digit);
#else
ScalableFont* digit_font =
new ScalableFont(g_env,
file_manager->getAssetChecked(FileManager::FONT,
"BigDigitFont.xml",true));
digit_font->lazyLoadTexture(0); // make sure the texture is loaded for this one
#endif // ENABLE_FREETYPE
digit_font->setMonospaceDigits(true);
g_digit_font = digit_font;
@ -1080,7 +1117,11 @@ namespace GUIEngine
ScalableFont* sfont_larger = sfont->getHollowCopy();
sfont_larger->setScale(normal_text_scale*1.4f);
#ifdef ENABLE_FREETYPE
sfont_larger->setKerningHeight(0);
#else
sfont_larger->setKerningHeight(-5);
#endif // ENABLE_FREETYPE
g_large_font = sfont_larger;
g_outline_font = sfont->getHollowCopy();
@ -1090,24 +1131,36 @@ namespace GUIEngine
ScalableFont* sfont_smaller = sfont->getHollowCopy();
sfont_smaller->setScale(normal_text_scale*0.8f);
#ifdef ENABLE_FREETYPE
sfont_smaller->setKerningHeight(0);
#else
sfont_smaller->setKerningHeight(-5);
#endif // ENABLE_FREETYPE
g_small_font = sfont_smaller;
Private::small_font_height =
g_small_font->getDimension( L"X" ).Height;
#ifdef ENABLE_FREETYPE
ScalableFont* sfont2 =new ScalableFont(g_env,Bold);
sfont2->setKerningWidth(0);
// Because the fallback font is much smaller than the title font:
sfont2->m_fallback_font_scale = 2.0f;
sfont2->m_fallback_kerning_width = 5;
#else
ScalableFont* sfont2 =
new ScalableFont(g_env,
file_manager->getAssetChecked(FileManager::FONT,
"title_font.xml",
true) );
sfont2->m_fallback_font = sfont;
sfont2->setKerningWidth(-18);
// Because the fallback font is much smaller than the title font:
sfont2->m_fallback_font_scale = 4.0f;
sfont2->m_fallback_kerning_width = 15;
#endif // ENABLE_FREETYPE
sfont2->m_fallback_font = sfont;
sfont2->setScale(title_text_scale);
sfont2->setKerningWidth(-18);
sfont2->m_black_border = true;
g_title_font = sfont2;
Private::title_font_height =
@ -1125,6 +1178,34 @@ namespace GUIEngine
g_device->getVideoDriver()->endScene();
} // init
// -----------------------------------------------------------------------
void reloadHollowCopyFont(irr::gui::ScalableFont* sfont)
{
//Base on the init function above
float normal_text_scale = 1;
sfont->setScale(normal_text_scale);
sfont->setKerningHeight(-5);
Private::font_height = sfont->getDimension( L"X" ).Height;
ScalableFont* sfont_larger = sfont->getHollowCopy();
sfont_larger->setScale(normal_text_scale*1.4f);
sfont_larger->setKerningHeight(-5);
g_large_font = sfont_larger;
g_outline_font = sfont->getHollowCopy();
g_outline_font->m_black_border = true;
Private::large_font_height = g_large_font->getDimension( L"X" ).Height;
ScalableFont* sfont_smaller = sfont->getHollowCopy();
sfont_smaller->setScale(normal_text_scale*0.8f);
sfont_smaller->setKerningHeight(-5);
g_small_font = sfont_smaller;
Private::small_font_height = g_small_font->getDimension( L"X" ).Height;
} // reloadHollowCopyFont
// -----------------------------------------------------------------------
void reloadSkin()
{

@ -39,6 +39,10 @@ namespace irr
#include "utils/constants.hpp"
#include "utils/ptr_vector.hpp"
#ifdef ENABLE_FREETYPE
#include "guiengine/freetype_environment.hpp"
#endif // ENABLE_FREETYPE
/**
* \ingroup guiengine
* \brief Contains all GUI engine related classes and functions
@ -81,6 +85,9 @@ namespace GUIEngine
{
extern irr::gui::IGUIEnvironment* g_env;
extern Skin* g_skin;
#ifdef ENABLE_FREETYPE
extern irr::gui::Ft_Env* g_ft_env;
#endif // ENABLE_FREETYPE
extern irr::gui::ScalableFont* g_small_font;
extern irr::gui::ScalableFont* g_font;
extern irr::gui::ScalableFont* g_outline_font;
@ -172,6 +179,14 @@ namespace GUIEngine
*/
inline Skin* getSkin() { return Private::g_skin; }
#ifdef ENABLE_FREETYPE
/**
* \pre GUIEngine::init must have been called first
* \return the freetype and library with face
*/
inline irr::gui::Ft_Env* get_Freetype() { return Private::g_ft_env; }
#endif // ENABLE_FREETYPE
Screen* getScreenNamed(const char* name);
/** \return the height of the title font in pixels */
@ -247,6 +262,14 @@ namespace GUIEngine
* \brief call when skin in user config was updated
*/
void reloadSkin();
#ifdef ENABLE_FREETYPE
/**
* \brief call when translation in user config was updated for freetype rendering STK
*/
void cleanHollowCopyFont();
void reloadHollowCopyFont(irr::gui::ScalableFont*);
#endif // ENABLE_FREETYPE
}
#endif

@ -0,0 +1,97 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2015 Ben Au
//
// 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.
#ifdef ENABLE_FREETYPE
#include "guiengine/freetype_environment.hpp"
#include "guiengine/TTF_handling.hpp"
#include "io/file_manager.hpp"
namespace irr
{
namespace gui
{
Ft_Env::Ft_Env()
{
Ft_Env::ft_err += FT_Init_FreeType(&(Ft_Env::ft_lib));
loadFont();
}
Ft_Env::~Ft_Env()
{
for (int i = 0; i < FONTNUM; ++i)
Ft_Env::ft_err += FT_Done_Face((Ft_Env::ft_face[i]));
Ft_Env::ft_err += FT_Done_FreeType(Ft_Env::ft_lib);
if (Ft_Env::ft_err > 0)
Log::error("Freetype Environment", "Can't destroy all fonts.");
else
Log::info("Freetype Environment", "Successfully destroy all fonts.");
}
void Ft_Env::loadFont()
{
Ft_Env::ft_err += FT_New_Face(Ft_Env::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "FreeSans.ttf",true)).c_str(),
0, &(Ft_Env::ft_face[F_DEFAULT]));
Ft_Env::ft_err += FT_New_Face(Ft_Env::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "wqy-microhei.ttf",true)).c_str(),
0, &(Ft_Env::ft_face[F_CJK]));
Ft_Env::ft_err += FT_New_Face(Ft_Env::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "amiri-bold.ttf",true)).c_str(),
0, &(Ft_Env::ft_face[F_AR]));
Ft_Env::ft_err += FT_New_Face(Ft_Env::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "Layne_Hansom.ttf",true)).c_str(),
0, &(Ft_Env::ft_face[F_LAYNE])); //to be removed?
Ft_Env::ft_err += FT_New_Face(Ft_Env::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "FreeSansBold.ttf",true)).c_str(),
0, &(Ft_Env::ft_face[F_BOLD]));
Ft_Env::ft_err += FT_New_Face(Ft_Env::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "FreeMonoBold.ttf",true)).c_str(),
0, &(Ft_Env::ft_face[F_DIGIT]));
//Set charmap
for (int h = 0; h < FONTNUM; ++h)
{
for (int i = 0; i < Ft_Env::ft_face[h]->num_charmaps; ++i)
{
FT_UShort pid = Ft_Env::ft_face[h]->charmaps[i]->platform_id;
FT_UShort eid = Ft_Env::ft_face[h]->charmaps[i]->encoding_id;
if (((pid == 0) && (eid == 3)) || ((pid == 3) && (eid == 1)))
Ft_Env::ft_err += FT_Set_Charmap(Ft_Env::ft_face[h], Ft_Env::ft_face[h]->charmaps[i]);
}
}
if (Ft_Env::ft_err > 0)
Log::error("Freetype Environment", "Can't load all fonts.");
else
Log::info("Freetype Environment", "Successfully loaded all fonts.");
}
FT_Library Ft_Env::ft_lib = NULL;
FT_Error Ft_Env::ft_err = 0;
} // end namespace gui
} // end namespace irr
#endif // ENABLE_FREETYPE

@ -0,0 +1,45 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2015 Ben Au
//
// 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 "io/file_manager.hpp"
#include <ft2build.h>
#include FT_FREETYPE_H
#define FONTNUM 6
namespace irr
{
namespace gui
{
class Ft_Env
{
public:
Ft_Env();
~Ft_Env();
FT_Face ft_face[FONTNUM];
private:
void loadFont();
static FT_Library ft_lib;
static FT_Error ft_err;
};
} // end namespace gui
} // end namespace irr

@ -16,12 +16,83 @@
#include <IVideoDriver.h>
#include <IXMLReader.h>
#include <cmath>
#define cur_face GUIEngine::get_Freetype()->ft_face[fu]
namespace irr
{
namespace gui
{
//! constructor
#ifdef ENABLE_FREETYPE
ScalableFont::ScalableFont(IGUIEnvironment *env, TTFLoadingType type)
: Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
{
#ifdef _DEBUG
setDebugName("ScalableFont");
#endif
m_fallback_font = NULL;
m_fallback_kerning_width = 0;
m_fallback_font_scale = 1.0f;
m_scale = 1.0f;
m_is_hollow_copy = false;
m_black_border = false;
m_isTTF = true;
m_type = type;
m_shadow = false;
m_mono_space_digits = false;
m_rtl = translations->isRTLLanguage();
if (Environment)
{
// don't grab environment, to avoid circular references
Driver = Environment->getVideoDriver();
if (!m_isTTF)
Log::fatal("ScalableFont", "Loading TTF font failed");
else
SpriteBank = Environment->addEmptySpriteBank((std::to_string(type)).c_str());
if (SpriteBank)
SpriteBank->grab();
}
if (Driver)
Driver->grab();
setInvisibleCharacters ( L" " );
if (!loadTTF())
{
Log::fatal("ScalableFont", "Loading TTF font failed");
}
assert(Areas.size() > 0);
}
void ScalableFont::recreateFromLanguage()
{
//Clean previous font data
SpriteBank->clear();
Areas.clear();
CharacterMap.clear();
WrongCharacter = 0;
MaxHeight = 0;
GlobalKerningWidth = 0;
GlobalKerningHeight = 0;
//Set to default scale to reload font
m_scale = 1;
//Reload
if (!loadTTF())
{
Log::fatal("ScalableFont", "Recreation of TTF font failed");
}
}
#else
ScalableFont::ScalableFont(IGUIEnvironment *env, const std::string &filename)
: Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
@ -36,6 +107,7 @@ ScalableFont::ScalableFont(IGUIEnvironment *env, const std::string &filename)
m_scale = 1.0f;
m_is_hollow_copy = false;
m_black_border = false;
m_isTTF = false;
m_shadow = false;
m_mono_space_digits = false;
m_rtl = translations->isRTLLanguage();
@ -65,6 +137,7 @@ ScalableFont::ScalableFont(IGUIEnvironment *env, const std::string &filename)
assert(Areas.size() > 0);
}
#endif // ENABLE_FREETYPE
//! destructor
ScalableFont::~ScalableFont()
@ -87,6 +160,7 @@ void ScalableFont::setShadow(const irr::video::SColor &col)
m_shadow_color = col;
}
#ifndef ENABLE_FREETYPE
void ScalableFont::doReadXmlFile(io::IXMLReader* xml)
{
int trim_top = 0;
@ -281,6 +355,171 @@ bool ScalableFont::load(io::IXMLReader* xml)
m_max_digit_area.overhang = 0;m_max_digit_area.underhang=0;
return true;
}
#endif // ENABLE_FREETYPE
#ifdef ENABLE_FREETYPE
//! loads a font file from a TTF file
bool ScalableFont::loadTTF()
{
if (!SpriteBank)
{
Log::error("ScalableFont::loadTTF", "SpriteBank is NULL!!");
return false;
}
//Initialize glyph slot
FT_GlyphSlot slot;
FT_Error err;
//Determine which font(face) and size to load,
//also get all used char base on current language settings
FontUse fu;
TTFfile TTF_file = getTTFAndChar(translations->getCurrentLanguageNameCode(), m_type, fu);
std::vector <s32> offset;
std::vector <s32> bx;
std::vector <s32> advance;
std::vector <s32> height;
err = FT_Set_Pixel_Sizes(cur_face, 0, TTF_file.size);
if (err)
Log::error("ScalableFont::loadTTF", "Can't set font size.");
slot = cur_face->glyph;
std::set<wchar_t>::iterator it;
s32 current_maxheight = 0;
s32 t;
for (it = TTF_file.usedchar.begin(); it != TTF_file.usedchar.end(); ++it)
{
// Retrieve glyph index from character code, skip useless glyph.
int idx = FT_Get_Char_Index(cur_face, *it);
if (idx == 0) continue;
// Load glyph image into the slot (erase previous one)
err = FT_Load_Glyph(cur_face, idx,
FT_LOAD_DEFAULT | FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
if (err)
Log::error("ScalableFont::loadTTF", "Can't load a single glyph.");
// Store vertical offset on line.
s32 offset_on_line = (cur_face->glyph->metrics.height >> 6) - cur_face->glyph->bitmap_top;
offset.push_back(offset_on_line);
//This is to be used later.
t = cur_face->glyph->metrics.height >> 6;
height.push_back(t);
if (t > current_maxheight)
current_maxheight = t;
// Store horizontal padding (bearingX).
s32 bX = cur_face->glyph->bitmap_left;
bx.push_back(bX);
// Store total width on horizontal line.
s32 width = cur_face->glyph->advance.x >> 6;
advance.push_back(width);
// Convert to an anti-aliased bitmap
FT_Bitmap bits = slot->bitmap;
//Generate image of glyph
video::IImage* image = generateTTFImage(bits, Driver);
if (!image)
return false;
//Add it as texture
SpriteBank->addTextureAsSprite(Driver->addTexture("character",image),
cur_face->glyph->metrics.width >> 6, t);
image->drop();
CharacterMap[*it] = SpriteBank->getSprites().size() - 1;
}
//Fix unused glyphs....
if (m_type == Normal || Bold)
{
CharacterMap[(wchar_t)32] = getAreaIDFromCharacter((wchar_t)160, NULL); //Use non-breaking space glyph to all space/tab characters.
CharacterMap[(wchar_t)9] = getAreaIDFromCharacter((wchar_t)160, NULL);
CharacterMap[(wchar_t)173] = 0; //Don't need a glyph for the soft hypen, as it only print when not having enough space.
//And then it will convert to a "-".
if (m_type == Normal)
{
CharacterMap[(wchar_t)8204] = 0; //They are zero width chars found in Arabic.
CharacterMap[(wchar_t)65279] = 0;
}
}
if (m_type == Bold)
{
setlocale(LC_ALL, "en_US.UTF8");
for (it = TTF_file.usedchar.begin(); it != TTF_file.usedchar.end(); ++it)
{
if (iswupper((wchar_t)*it))
CharacterMap[towlower((wchar_t)*it)] = getAreaIDFromCharacter(*it, NULL);
}
}
for (unsigned int n = 0 ; n < SpriteBank->getSprites().size(); ++n)
{
//Storing now
SFontArea a;
a.spriteno = n;
a.offsety = current_maxheight - height.at(n)
+ offset.at(n); //Compute the correct offset as ttf texture image is cropped against the glyph fully.
if (!n) //Skip soft hypen and space
a.bearingx = 0;
else
a.bearingx = bx.at(n);
if (!n) //Skip soft hypen and space
a.width = 0;
else
a.width = advance.at(n);
// add character to font
Areas.push_back(a);
}
WrongCharacter = getAreaIDFromCharacter(L' ', NULL);
//Add 5 for ttf bitmap to display Chinese better, 40 for digit font to display separately
//Consider fallback font (Bold) too
MaxHeight = (int)((current_maxheight + (m_type == Digit ? 40 : 5) +
(m_type == Bold ? 20 : 0))*m_scale);
if (m_type == Digit)
{
for(wchar_t c='0'; c<='9'; c++)
{
SFontArea a = getAreaFromCharacter(c, NULL);
m_max_digit_area.width = a.width;
m_max_digit_area.offsety = a.offsety;
m_max_digit_area.bearingx = a.bearingx;
}
}
switch (m_type)
{
case Normal:
Log::info("ScalableFont::loadTTF", "Created %d glyphs "
"supporting %d characters for normal font %s at %d dpi."
, Areas.size(), CharacterMap.size(), cur_face->family_name, TTF_file.size);
break;
case Digit:
Log::info("ScalableFont::loadTTF", "Created %d glyphs "
"supporting %d characters for high-res digits font %s at %d dpi."
, Areas.size(), CharacterMap.size(), cur_face->family_name, TTF_file.size);
break;
case Bold:
Log::info("ScalableFont::loadTTF", "Created %d glyphs "
"supporting %d characters for bold title font %s at %d dpi."
, Areas.size(), CharacterMap.size(), cur_face->family_name, TTF_file.size);
break;
}
return true;
}
#endif // ENABLE_FREETYPE
void ScalableFont::setScale(const float scale)
{
m_scale = scale;
@ -304,7 +543,7 @@ void ScalableFont::setMaxHeight()
const TextureInfo& info = (*(m_texture_files.find(texID))).second;
if (info.m_exclude_from_max_height_calculation) continue;
float char_scale = info.m_scale;
float char_scale = (m_isTTF ? 1.0f:info.m_scale);
t = (int)(t*char_scale);
if (t>MaxHeight)
@ -328,6 +567,7 @@ s32 ScalableFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* prev
{
s32 ret = GlobalKerningWidth;
#ifndef ENABLE_FREETYPE
if (thisLetter)
{
ret += Areas[getAreaIDFromCharacter(*thisLetter, NULL)].overhang;
@ -337,7 +577,7 @@ s32 ScalableFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* prev
ret += Areas[getAreaIDFromCharacter(*previousLetter, NULL)].underhang;
}
}
#endif // ENABLE_FREETYPE
return ret;
}
@ -417,6 +657,7 @@ const ScalableFont::SFontArea &ScalableFont::getAreaFromCharacter(const wchar_t
} // getAreaFromCharacter
void ScalableFont::setInvisibleCharacters( const wchar_t *s )
{
Invisible = s;
@ -448,7 +689,9 @@ core::dimension2d<u32> ScalableFont::getDimension(const wchar_t* text) const
bool fallback = false;
const SFontArea &area = getAreaFromCharacter(*p, &fallback);
#ifndef ENABLE_FREETYPE
thisLine.Width += area.underhang;
#endif // ENABLE_FREETYPE
thisLine.Width += getCharWidth(area, fallback);
}
@ -552,8 +795,21 @@ void ScalableFont::doDraw(const core::stringw& text,
bool use_fallback_font = false;
const SFontArea &area = getAreaFromCharacter(c, &use_fallback_font);
fallback[i] = use_fallback_font;
#ifdef ENABLE_FREETYPE
//floor is used to prevent negligible movement when m_scale changes with resolution
int Hpadding = floor((float) area.bearingx*
(fallback[i] ? m_scale*m_fallback_font_scale : m_scale));
int Vpadding = floor((float) area.offsety*
(fallback[i] ? m_scale*m_fallback_font_scale : m_scale));
offset.X += Hpadding;
offset.Y += Vpadding + floor(m_type == Digit ? 20*m_scale : 0); //Additional offset for digit text
offsets.push_back(offset);
offset.X -= Hpadding;
offset.Y -= Vpadding + floor(m_type == Digit ? 20*m_scale : 0);
#else
offset.X += area.underhang;
offsets.push_back(offset);
#endif // ENABLE_FREETYPE
// Invisible character. add something to the array anyway so that
// indices from the various arrays remain in sync
indices.push_back( Invisible.findFirst(c) < 0 ? area.spriteno
@ -595,12 +851,17 @@ void ScalableFont::doDraw(const core::stringw& text,
(*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] :
positions[sprites[spriteID].Frames[0].rectNumber]);
const TextureInfo& info = (fallback[n] ?
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second
);
float char_scale = info.m_scale;
float char_scale;
if (!m_isTTF)
{
const TextureInfo& info = (fallback[n] ?
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second
);
char_scale = info.m_scale;
}
else
char_scale = 1.0f;
core::dimension2d<s32> size = source.getSize();
float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale);
@ -608,9 +869,13 @@ void ScalableFont::doDraw(const core::stringw& text,
size.Height = (int)(size.Height * scale * char_scale);
// align vertically if character is smaller
#ifndef ENABLE_FREETYPE
int y_shift = (size.Height < MaxHeight*m_scale ? (int)((MaxHeight*m_scale - size.Height)/2.0f) : 0);
core::rect<s32> dest(offsets[n] + core::position2di(0, y_shift), size);
#else
core::rect<s32> dest(offsets[n], size);
#endif // ENABLE_FREETYPE
video::ITexture* texture = (fallback[n] ?
m_fallback_font->SpriteBank->getTexture(texID) :
@ -624,8 +889,10 @@ void ScalableFont::doDraw(const core::stringw& text,
source.getWidth(), source.getHeight(), offsets[n].X, offsets[n].Y);
}
*/
if (texture == NULL)
#ifdef FONT_DEBUG
GL32_draw2DRectangle(video::SColor(255, 255,0,0), dest,clip);
#endif
if (texture == NULL && !m_isTTF)
{
// perform lazy loading
@ -666,7 +933,11 @@ void ScalableFont::doDraw(const core::stringw& text,
}
}
#ifdef ENABLE_FREETYPE
if (fallback[n] || m_type == Bold)
#else
if (fallback[n])
#endif // ENABLE_FREETYPE
{
// TODO: don't hardcode colors?
video::SColor orange(color.getAlpha(), 255, 100, 0);
@ -707,21 +978,6 @@ void ScalableFont::doDraw(const core::stringw& text,
clip,
color, true);
}
#ifdef FONT_DEBUG
video::IVideoDriver* driver = GUIEngine::getDriver();
driver->draw2DLine(core::position2d<s32>(dest.UpperLeftCorner.X, dest.UpperLeftCorner.Y),
core::position2d<s32>(dest.UpperLeftCorner.X, dest.LowerRightCorner.Y),
video::SColor(255, 255,0,0));
driver->draw2DLine(core::position2d<s32>(dest.LowerRightCorner.X, dest.LowerRightCorner.Y),
core::position2d<s32>(dest.LowerRightCorner.X, dest.UpperLeftCorner.Y),
video::SColor(255, 255,0,0));
driver->draw2DLine(core::position2d<s32>(dest.LowerRightCorner.X, dest.LowerRightCorner.Y),
core::position2d<s32>(dest.UpperLeftCorner.X, dest.LowerRightCorner.Y),
video::SColor(255, 255,0,0));
driver->draw2DLine(core::position2d<s32>(dest.UpperLeftCorner.X, dest.UpperLeftCorner.Y),
core::position2d<s32>(dest.LowerRightCorner.X, dest.UpperLeftCorner.Y),
video::SColor(255, 255,0,0));
#endif
}
}
}
@ -777,17 +1033,28 @@ int ScalableFont::getCharWidth(const SFontArea& area, const bool fallback) const
(*fallback_sprites)[area.spriteno].Frames[0].textureNumber :
sprites[area.spriteno].Frames[0].textureNumber);
const TextureInfo& info = (fallback ?
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second
);
assert(info.m_file_name.size() > 0);
const float char_scale = info.m_scale;
float char_scale;
if (!m_isTTF)
{
const TextureInfo& info = (fallback ?
(*(m_fallback_font->m_texture_files.find(texID))).second :
(*(m_texture_files.find(texID))).second
);
assert(info.m_file_name.size() > 0);
char_scale = info.m_scale;
}
else
char_scale = 1.0f;
//Log::info("ScalableFont", "area.spriteno = %d, char_scale = %f", area.spriteno, char_scale);
#ifdef ENABLE_FREETYPE
if (fallback) return (int)((area.width*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale);
else return (int)((area.width + GlobalKerningWidth) * m_scale * char_scale);
#else
if (fallback) return (int)(((area.width + area.overhang)*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale);
else return (int)((area.width + area.overhang + GlobalKerningWidth) * m_scale * char_scale);
#endif // ENABLE_FREETYPE
}
@ -802,7 +1069,11 @@ s32 ScalableFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
bool use_fallback_font = false;
const SFontArea &a = getAreaFromCharacter(text[idx], &use_fallback_font);
#ifdef ENABLE_FREETYPE
x += getCharWidth(a, use_fallback_font) + GlobalKerningWidth;
#else
x += getCharWidth(a, use_fallback_font) + a.overhang + a.underhang + GlobalKerningWidth;
#endif // ENABLE_FREETYPE
if (x >= pixel_x)
return idx;

@ -7,6 +7,10 @@
#include "utils/leak_check.hpp"
#ifdef ENABLE_FREETYPE
#include "guiengine/TTF_handling.hpp"
#endif // ENABLE_FREETYPE
#include "IrrCompileConfig.h"
#include "IGUIFontBitmap.h"
#include "irrString.h"
@ -15,7 +19,6 @@
#include "IReadFile.h"
#include "irrArray.h"
#include <map>
#include <string>
@ -77,13 +80,21 @@ public:
LEAK_CHECK()
bool m_black_border;
bool m_isTTF;
#ifdef ENABLE_FREETYPE
TTFLoadingType m_type;
#endif // ENABLE_FREETYPE
ScalableFont* m_fallback_font;
float m_fallback_font_scale;
int m_fallback_kerning_width;
//! constructor
#ifdef ENABLE_FREETYPE
ScalableFont(IGUIEnvironment* env, TTFLoadingType type);
#else
ScalableFont(IGUIEnvironment* env, const std::string &filename);
#endif // ENABLE_FREETYPE
/** Creates a hollow copy of this font; i.e. the underlying font data is the *same* for
* both fonts. The advantage of doing this is that you can change "view" parameters
@ -104,8 +115,13 @@ public:
//! destructor
virtual ~ScalableFont();
#ifdef ENABLE_FREETYPE
//! loads a font from a TTF file
bool loadTTF();
#else
//! loads a font from an XML file
bool load(io::IXMLReader* xml);
#endif // ENABLE_FREETYPE
void lazyLoadTexture(int texID);
@ -159,8 +175,23 @@ public:
void updateRTL();
#ifdef ENABLE_FREETYPE
//! re-create fonts when language is changed
void recreateFromLanguage();
#endif // ENABLE_FREETYPE
private:
#ifdef ENABLE_FREETYPE
struct SFontArea
{
SFontArea() : width(0), spriteno(0), offsety(0), bearingx(0) {}
s32 width;
u32 spriteno;
s32 offsety;
s32 bearingx;
};
#else
struct SFontArea
{
SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
@ -169,6 +200,7 @@ private:
s32 width;
u32 spriteno;
};
#endif // ENABLE_FREETYPE
int getCharWidth(const SFontArea& area, const bool fallback) const;
s32 getAreaIDFromCharacter(const wchar_t c, bool* fallback_font) const;

@ -127,6 +127,7 @@ FileManager::FileManager()
m_subdir_name[SKIN ] = "skins";
m_subdir_name[SHADER ] = "shaders";
m_subdir_name[TEXTURE ] = "textures";
m_subdir_name[TTF ] = "ttf";
m_subdir_name[TRANSLATION] = "po";
#ifdef __APPLE__
// irrLicht's createDevice method has a nasty habit of messing the CWD.

@ -49,7 +49,7 @@ public:
enum AssetType {ASSET_MIN,
CHALLENGE=ASSET_MIN,
FONT, GFX, GRANDPRIX, GUI, LIBRARY, MODEL, MUSIC,
SCRIPT, SFX, SHADER, SKIN, TEXTURE,
SCRIPT, SFX, SHADER, SKIN, TEXTURE, TTF,
TRANSLATION, ASSET_MAX = TRANSLATION,
ASSET_COUNT};
private:

@ -328,6 +328,14 @@ void OptionsScreenUI::eventCallback(Widget* widget, const std::string& name, con
}
translations = new Translations();
#ifdef ENABLE_FREETYPE
//Reload fonts for new translation when using freetype
GUIEngine::cleanHollowCopyFont();
GUIEngine::getFont()->recreateFromLanguage();
GUIEngine::reloadHollowCopyFont(GUIEngine::getFont());
#endif // ENABLE_FREETYPE
GUIEngine::getStateManager()->hardResetAndGoToScreen<MainMenuScreen>();
GUIEngine::getFont()->updateRTL();

@ -19,6 +19,8 @@
#include "dictionary.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
namespace tinygettext {
@ -211,6 +213,36 @@ Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid
}
}
std::set<wchar_t> Dictionary::get_all_used_chars()
{
std::set<wchar_t> UsedChars;
for (Entries::const_iterator i = entries.begin(); i != entries.end(); ++i)
{
const std::vector<std::string>& msgstrs = i->second;
for (unsigned int k = 0; k < msgstrs.size(); k++)
{
irr::core::stringw ws = translations->fribidize((StringUtils::utf8_to_wide(msgstrs[k].c_str())).c_str());
for (unsigned int l = 0; l < ws.size(); ++l)
UsedChars.insert(ws[l]);
}
}
for (CtxtEntries::const_iterator i = ctxt_entries.begin(); i != ctxt_entries.end(); ++i)
{
for (Entries::const_iterator j = i->second.begin(); j != i->second.end(); ++j)
{
const std::vector<std::string>& msgstrs = j->second;
for (unsigned int k = 0; k < msgstrs.size(); k++)
{
irr::core::stringw ws = translations->fribidize((StringUtils::utf8_to_wide(msgstrs[k].c_str())).c_str());
for (unsigned int l = 0; l < ws.size(); ++l)
UsedChars.insert(ws[l]);
}
}
}
return UsedChars;
}
} // namespace tinygettext
/* EOF */

@ -21,6 +21,7 @@
#include <map>
#include <vector>
#include <string>
#include <set>
#include "plural_forms.hpp"
namespace tinygettext {
@ -91,6 +92,10 @@ public:
void add_translation(const std::string& msgid, const std::string& msgstr);
void add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr);
/** Write all unique character from current dictionary using in a c++ set which is useful for
specific character loading. */
std::set<wchar_t> get_all_used_chars();
/** Iterate over all messages, Func is of type:
void func(const std::string& msgid, const std::vector<std::string>& msgstrs) */
template<class Func>

@ -298,6 +298,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
}
m_current_language_name = l.get_name();
m_current_language_name_code = l.get_language();
if (!l)
{
@ -312,11 +313,13 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
Log::warn("Translation", "Unsupported langage '%s'", language.c_str());
UserConfigParams::m_language = "system";
m_current_language_name = "Default language";
m_current_language_name_code = "en";
m_dictionary = m_dictionary_manager.get_dictionary();
}
else
{
m_current_language_name = tgtLang.get_name();
m_current_language_name_code = tgtLang.get_language();
Log::verbose("translation", "Language '%s'.", m_current_language_name.c_str());
m_dictionary = m_dictionary_manager.get_dictionary(tgtLang);
}
@ -325,6 +328,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
else
{
m_current_language_name = "Default language";
m_current_language_name_code = "en";
m_dictionary = m_dictionary_manager.get_dictionary();
}
@ -538,12 +542,22 @@ bool Translations::isRTLLanguage() const
return m_rtl;
}
std::set<wchar_t> Translations::getCurrentAllChar()
{
return m_dictionary.get_all_used_chars();
}
std::string Translations::getCurrentLanguageName()
{
return m_current_language_name;
//return m_dictionary_manager.get_language().get_name();
}
std::string Translations::getCurrentLanguageNameCode()
{
return m_current_language_name_code;
}
core::stringw Translations::fribidizeLine(const core::stringw &str)
{
#if ENABLE_BIDI

@ -54,6 +54,7 @@ private:
bool m_rtl;
std::string m_current_language_name;
std::string m_current_language_name_code;
public:
Translations();
@ -74,7 +75,11 @@ public:
const std::vector<std::string>* getLanguageList() const;
std::string getCurrentLanguageName();
std::set<wchar_t> getCurrentAllChar();
std::string getCurrentLanguageName();
std::string getCurrentLanguageNameCode();
private:
irr::core::stringw fribidizeLine(const irr::core::stringw &str);