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:
parent
ec33e92ad0
commit
3a5ec83ae9
CMakeLists.txt
cmake
data/ttf
lib/irrlicht
src
@ -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
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
BIN
data/ttf/FreeMonoBold.ttf
Normal file
Binary file not shown.
BIN
data/ttf/FreeSans.ttf
Normal file
BIN
data/ttf/FreeSans.ttf
Normal file
Binary file not shown.
BIN
data/ttf/FreeSansBold.ttf
Normal file
BIN
data/ttf/FreeSansBold.ttf
Normal file
Binary file not shown.
BIN
data/ttf/Layne_Hansom.ttf
Normal file
BIN
data/ttf/Layne_Hansom.ttf
Normal file
Binary file not shown.
BIN
data/ttf/amiri-bold.ttf
Normal file
BIN
data/ttf/amiri-bold.ttf
Normal file
Binary file not shown.
BIN
data/ttf/wqy-microhei.ttf
Normal file
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();
|
||||
|
205
src/guiengine/TTF_handling.cpp
Normal file
205
src/guiengine/TTF_handling.cpp
Normal file
@ -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
|
50
src/guiengine/TTF_handling.hpp
Normal file
50
src/guiengine/TTF_handling.hpp
Normal file
@ -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
|
||||
|
97
src/guiengine/freetype_environment.cpp
Normal file
97
src/guiengine/freetype_environment.cpp
Normal file
@ -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
|
45
src/guiengine/freetype_environment.hpp
Normal file
45
src/guiengine/freetype_environment.hpp
Normal file
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user