This commit is contained in:
hiker 2015-10-20 22:44:26 +11:00
commit 10c612a0f6
75 changed files with 1709 additions and 3129 deletions

View File

@ -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)
@ -416,9 +434,6 @@ if(MINGW)
endif()
endif()
# Optional tools
add_subdirectory(tools/font_tool)
# ==== Checking if data folder exists ====
if(NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data)

29
cmake/FindFreetype.cmake Normal file
View File

@ -0,0 +1,29 @@
# - 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(WIN32)
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(APPLE)
find_path(FREETYPE_INCLUDE_DIRS NAMES freetype/freetype.h PATHS "/Library/Frameworks/FreeType.Framework/Versions/2.4/unix/include")
find_library(FREETPYE_LIBRARY NAMES freetype PATHS "/Library/Frameworks/FreeType.Framework/Versions/2.4/")
include_directories(/Library/Frameworks/FreeType.Framework/Versions/2.4/unix/include)
set(FREETYPE_FOUND 1)
set(FREETPYE_LIBRARIES ${FREETPYE_LIBRARY})
elseif(UNIX)
include(FindPkgConfig)
pkg_check_modules(FREETYPE freetype2)
else()
set(FREETYPE_FOUND 0)
endif()

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -1,22 +0,0 @@
<?xml version="1.0"?>
<materials>
<!-- Fonts -->
<material name="title_font.png" shader="unlit" dont-load="Y"/>
<material name="title_font_2.png" shader="unlit" dont-load="Y"/>
<material name="sigmar0.png" shader="unlit" dont-load="Y"/>
<material name="comix.png" shader="unlit" dont-load="Y"/>
<material name="LayneHansom0.png" shader="unlit" dont-load="Y"/>
<material name="Mplus2p_JP0.png" shader="unlit" dont-load="Y"/>
<material name="rasheeq0.png" shader="unlit" dont-load="Y"/>
<material name="rasheeq3.png" shader="unlit" dont-load="Y"/>
<material name="rasheeq4.png" shader="unlit" dont-load="Y"/>
<material name="wqyMicroHei0.png" shader="unlit" dont-load="Y"/>
<material name="wqyMicroHei1.png" shader="unlit" dont-load="Y"/>
<material name="wqyMicroHei2.png" shader="unlit" dont-load="Y"/>
<material name="wqyMicroHei3.png" shader="unlit" dont-load="Y"/>
<material name="wqyMicroHei4.png" shader="unlit" dont-load="Y"/>
<material name="wqyMicroHei5.png" shader="unlit" dont-load="Y"/>
<material name="AR_PL_SungtiL_GB0.png" shader="unlit" dont-load="Y"/>
<material name="LayneHansomBigDigits.png" shader="unlit" dont-load="Y"/>
</materials>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

BIN
data/ttf/FreeSans.ttf Normal file

Binary file not shown.

BIN
data/ttf/FreeSansBold.ttf Normal file

Binary file not shown.

12
data/ttf/LICENSE Normal file
View File

@ -0,0 +1,12 @@
GNU FreeFont (FreeSans, FreeSansBold) is released under the GPLv3
wqyMicroHei is released under the GPLv3 with font embedding exception and Apache-2.0 licenses
By Qianqian Fang and The WenQuanYi Project Contributors
Copyright (C) 2008-2009 The WenQuanYi Project Board of Trustees
Copyright (C) 2007 Google Corporation
Noto Naskh Arabic UI is released under Apache-2.0 license
Ubuntu font is released under the ubuntu font license (http://font.ubuntu.com/licence/)
SigmarOne is released under the SIL open font license 1.1 ( https://www.google.com/fonts/specimen/Sigmar+One )

Binary file not shown.

View File

@ -0,0 +1,44 @@
Copyright (c) 2011, Vernon Adams (vern@newtypography.co.uk),
with Reserved Font Name Sigmar One.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.

BIN
data/ttf/SigmarOne.otf Normal file

Binary file not shown.

BIN
data/ttf/Ubuntu-B.ttf Normal file

Binary file not shown.

BIN
data/ttf/Ubuntu-R.ttf Normal file

Binary file not shown.

View File

@ -0,0 +1,96 @@
-------------------------------
UBUNTU FONT LICENCE Version 1.0
-------------------------------
PREAMBLE
This licence allows the licensed fonts to be used, studied, modified and
redistributed freely. The fonts, including any derivative works, can be
bundled, embedded, and redistributed provided the terms of this licence
are met. The fonts and derivatives, however, cannot be released under
any other licence. The requirement for fonts to remain under this
licence does not require any document created using the fonts or their
derivatives to be published under this licence, as long as the primary
purpose of the document is not to be a vehicle for the distribution of
the fonts.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this licence and clearly marked as such. This may
include source files, build scripts and documentation.
"Original Version" refers to the collection of Font Software components
as received under this licence.
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to
a new environment.
"Copyright Holder(s)" refers to all individuals and companies who have a
copyright ownership of the Font Software.
"Substantially Changed" refers to Modified Versions which can be easily
identified as dissimilar to the Font Software by users of the Font
Software comparing the Original Version with the Modified Version.
To "Propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification and with or without charging
a redistribution fee), making available to the public, and in some
countries other activities as well.
PERMISSION & CONDITIONS
This licence does not grant any rights under trademark law and all such
rights are reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to propagate the Font Software, subject to
the below conditions:
1) Each copy of the Font Software must contain the above copyright
notice and this licence. These can be included either as stand-alone
text files, human-readable headers or in the appropriate machine-
readable metadata fields within text or binary files as long as those
fields can be easily viewed by the user.
2) The font name complies with the following:
(a) The Original Version must retain its name, unmodified.
(b) Modified Versions which are Substantially Changed must be renamed to
avoid use of the name of the Original Version or similar names entirely.
(c) Modified Versions which are not Substantially Changed must be
renamed to both (i) retain the name of the Original Version and (ii) add
additional naming elements to distinguish the Modified Version from the
Original Version. The name of such Modified Versions must be the name of
the Original Version, with "derivative X" where X represents the name of
the new work, appended to that name.
3) The name(s) of the Copyright Holder(s) and any contributor to the
Font Software shall not be used to promote, endorse or advertise any
Modified Version, except (i) as required by this licence, (ii) to
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
their explicit written permission.
4) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this licence, and must not be distributed
under any other licence. The requirement for fonts to remain under this
licence does not affect any document created using the Font Software,
except any version of the Font Software extracted from a document
created using the Font Software may only be distributed under this
licence.
TERMINATION
This licence becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.

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

Binary file not shown.

View File

@ -501,7 +501,7 @@ if(APPLE)
set_source_files_properties(source/Irrlicht/MacOSX/OSXClipboard.mm PROPERTIES LANGUAGE C)
endif()
add_library(stkirrlicht ${IRRLICHT_SOURCES})
add_library(stkirrlicht STATIC ${IRRLICHT_SOURCES})
target_link_libraries(stkirrlicht ${PNG_LIBRARY} ${JPEG_LIBRARY} ${ZLIB_LIBRARY})

View File

@ -377,6 +377,7 @@ public:
float getZipperMinSpeed() const { return m_zipper_min_speed; }
// ------------------------------------------------------------------------
ShaderType getShaderType() const { return m_shader_type; }
void setShaderType(ShaderType st) { m_shader_type = st; }
// ------------------------------------------------------------------------
/** True if this texture should have the U coordinates mirrored. */
char getMirrorAxisInReverse() const { return m_mirror_axis_when_reverse; }

View File

@ -24,6 +24,7 @@
#include "config/user_config.hpp"
#include "graphics/material.hpp"
#include "graphics/shaders.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "modes/world.hpp"
@ -40,7 +41,6 @@ MaterialManager::MaterialManager()
{
/* Create list - and default material zero */
m_default_material = NULL;
m_materials.reserve(256);
// We can't call init/loadMaterial here, since the global variable
// material_manager has not yet been initialised, and
@ -67,7 +67,7 @@ Material* MaterialManager::getMaterialFor(video::ITexture* t,
scene::IMeshBuffer *mb)
{
if (t == NULL)
return m_default_material;
return getDefaultMaterial(mb->getMaterial().MaterialType);
core::stringc img_path = core::stringc(t->getName());
const std::string image = StringUtils::getBasename(img_path.c_str());
@ -92,7 +92,8 @@ Material* MaterialManager::getMaterialFor(video::ITexture* t,
}
} // for i
}
return m_default_material;
return getDefaultMaterial(mb->getMaterial().MaterialType);
}
//-----------------------------------------------------------------------------
@ -111,53 +112,41 @@ void MaterialManager::setAllMaterialFlags(video::ITexture* t,
return;
}
if (m_default_material == NULL)
m_default_material = new Material("", false, false, false);
m_default_material->setMaterialProperties(&(mb->getMaterial()), mb);
/*
// This material does not appear in materials.xml. Set some common flags...
if (UserConfigParams::m_anisotropic > 0)
{
for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
{
mb->getMaterial().TextureLayer[i].AnisotropicFilter =
UserConfigParams::m_anisotropic;
}
}
else if (UserConfigParams::m_trilinear)
{
mb->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, true);
}
mb->getMaterial().ColorMaterial = video::ECM_DIFFUSE_AND_AMBIENT;
if (World::getWorld() != NULL)
{
mb->getMaterial().FogEnable = World::getWorld()->isFogEnabled();
}
// Modify lightmap materials so that vertex colors are taken into account.
// But disable lighting because we assume all lighting is already part
// of the lightmap
if (mb->getMaterial().MaterialType == video::EMT_LIGHTMAP)
{
mb->getMaterial().MaterialType = video::EMT_LIGHTMAP_LIGHTING;
mb->getMaterial().AmbientColor = video::SColor(255, 255, 255, 255);
mb->getMaterial().DiffuseColor = video::SColor(255, 255, 255, 255);
mb->getMaterial().EmissiveColor = video::SColor(255, 255, 255, 255);
mb->getMaterial().SpecularColor = video::SColor(255, 255, 255, 255);
}
//if (UserConfigParams::m_fullscreen_antialiasing)
// mb->getMaterial().AntiAliasing = video::EAAM_LINE_SMOOTH;
*/
Material* default_material = getDefaultMaterial(mb->getMaterial().MaterialType);
default_material->setMaterialProperties(&(mb->getMaterial()), mb);
} // setAllMaterialFlags
//-----------------------------------------------------------------------------
Material* MaterialManager::getDefaultMaterial(video::E_MATERIAL_TYPE shader_type)
{
auto it = m_default_materials.find(shader_type);
if (it == m_default_materials.end())
{
Material* default_material = new Material("", false, false, false);
// TODO: workaround, should not hardcode these material types here?
// Try to find a cleaner way
if (shader_type == Shaders::getShader(ShaderType::ES_OBJECT_UNLIT))
default_material->setShaderType(Material::SHADERTYPE_SOLID_UNLIT);
else if (shader_type == Shaders::getShader(ShaderType::ES_OBJECTPASS_REF))
default_material->setShaderType(Material::SHADERTYPE_ALPHA_TEST);
//else if (shader_type == Shaders::getShader(ShaderType::ES_OBJECTPASS))
// default_material->setShaderType(Material::SHADERTYPE_ALPHA_BLEND);
else
default_material->setShaderType(Material::SHADERTYPE_SOLID);
m_default_materials[shader_type] = default_material;
return default_material;
}
else
{
return it->second;
}
}
//-----------------------------------------------------------------------------
void MaterialManager::adjustForFog(video::ITexture* t,
scene::IMeshBuffer *mb,
scene::ISceneNode* parent,
@ -191,9 +180,8 @@ void MaterialManager::setAllUntexturedMaterialFlags(scene::IMeshBuffer *mb)
material.MaterialType = irr::video::EMT_SOLID;
}
if (m_default_material == NULL)
m_default_material = new Material("", false, false, false);
m_default_material->setMaterialProperties(&(mb->getMaterial()), mb);
Material* default_material = getDefaultMaterial(mb->getMaterial().MaterialType);
default_material->setMaterialProperties(&(mb->getMaterial()), mb);
}
//-----------------------------------------------------------------------------
int MaterialManager::addEntity(Material *m)

View File

@ -29,8 +29,10 @@ namespace irr
}
using namespace irr;
#include <irrlicht.h>
#include <string>
#include <vector>
#include <map>
class Material;
class XMLReader;
@ -48,7 +50,8 @@ private:
std::vector<Material*> m_materials;
Material* m_default_material;
std::map<video::E_MATERIAL_TYPE, Material*> m_default_materials;
Material* getDefaultMaterial(video::E_MATERIAL_TYPE material_type);
public:
MaterialManager();

View File

@ -67,7 +67,11 @@ scene::IMesh* STKTextBillboard::getTextMesh(core::stringw text, gui::ScalableFon
font->doDraw(text, core::rect<s32>(0, 0, size.Width, size.Height), video::SColor(255,255,255,255),
false, false, NULL, this);
#ifdef ENABLE_FREETYPE
const float scale = 0.03f; //Larger for ttf font as they are less bold
#else
const float scale = 0.018f;
#endif // ENABLE_FREETYPE
//scene::SMesh* mesh = new scene::SMesh();
std::map<video::ITexture*, scene::SMeshBuffer*> buffers;

View File

@ -688,6 +688,10 @@ namespace GUIEngine
{
IGUIEnvironment* g_env;
Skin* g_skin = NULL;
#ifdef ENABLE_FREETYPE
FTEnvironment* g_ft_env = NULL;
GlyphPageCreator* g_gp_creator = NULL;
#endif // ENABLE_FREETYPE
ScalableFont *g_font;
ScalableFont *g_outline_font;
ScalableFont *g_large_font;
@ -952,6 +956,13 @@ namespace GUIEngine
//if (g_skin != NULL) delete g_skin;
g_skin = NULL;
#ifdef ENABLE_FREETYPE
g_ft_env->~FTEnvironment();
g_ft_env = NULL;
g_gp_creator->~GlyphPageCreator();
g_gp_creator = NULL;
#endif // ENABLE_FREETYPE
for (unsigned int i=0; i<g_loaded_screens.size(); i++)
{
g_loaded_screens[i].unload();
@ -982,6 +993,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 +1031,11 @@ namespace GUIEngine
g_focus_for_player[n] = NULL;
}
#ifdef ENABLE_FREETYPE
g_ft_env = new FTEnvironment();
g_gp_creator = new GlyphPageCreator();
#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 +1069,51 @@ namespace GUIEngine
}
}
#ifdef ENABLE_FREETYPE
float normal_text_scale = 1;
float title_text_scale = 1;
ScalableFont* digit_font =new ScalableFont(g_env,T_DIGIT);
digit_font->setMonospaceDigits(true);
g_digit_font = digit_font;
ScalableFont* sfont2 =new ScalableFont(g_env,T_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;
ScalableFont* sfont =new ScalableFont(g_env,T_NORMAL);
sfont->setKerningHeight(0);
sfont->setScale(normal_text_scale);
g_font = sfont;
Private::font_height = g_font->getDimension( L"X" ).Height;
ScalableFont* sfont_larger = sfont->getHollowCopy();
sfont_larger->setScale(normal_text_scale*1.4f);
sfont_larger->setKerningHeight(0);
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(0);
g_small_font = sfont_smaller;
Private::small_font_height =
g_small_font->getDimension( L"X" ).Height;
sfont2->m_fallback_font = sfont;
sfont2->setScale(title_text_scale);
sfont2->m_black_border = true;
g_title_font = sfont2;
Private::title_font_height =
g_title_font->getDimension( L"X" ).Height;
#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
@ -1112,6 +1184,7 @@ namespace GUIEngine
g_title_font = sfont2;
Private::title_font_height =
g_title_font->getDimension( L"X" ).Height;
#endif // ENABLE_FREETYPE
if (g_font != NULL) g_skin->setFont(g_font);
@ -1125,6 +1198,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()
{

View File

@ -39,6 +39,11 @@ namespace irr
#include "utils/constants.hpp"
#include "utils/ptr_vector.hpp"
#ifdef ENABLE_FREETYPE
#include "guiengine/ft_environment.hpp"
#include "guiengine/glyph_page_creator.hpp"
#endif // ENABLE_FREETYPE
/**
* \ingroup guiengine
* \brief Contains all GUI engine related classes and functions
@ -81,6 +86,10 @@ namespace GUIEngine
{
extern irr::gui::IGUIEnvironment* g_env;
extern Skin* g_skin;
#ifdef ENABLE_FREETYPE
extern FTEnvironment* g_ft_env;
extern GlyphPageCreator* g_gp_creator;
#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 +181,20 @@ 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 FTEnvironment* getFreetype() { return Private::g_ft_env; }
/**
* \pre GUIEngine::init must have been called first
* \return the glyph page creator, useful to create a glyph page from individual char
*/
inline GlyphPageCreator* getGlyphPageCreator() { return Private::g_gp_creator; }
#endif // ENABLE_FREETYPE
Screen* getScreenNamed(const char* name);
/** \return the height of the title font in pixels */
@ -247,6 +270,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

View File

@ -0,0 +1,101 @@
// 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/ft_environment.hpp"
#include "guiengine/get_font_properties.hpp"
#include "io/file_manager.hpp"
#include "utils/log.hpp"
using namespace gui;
namespace GUIEngine
{
FTEnvironment::FTEnvironment()
{
FTEnvironment::ft_err += FT_Init_FreeType(&(FTEnvironment::ft_lib));
loadFont();
}
FTEnvironment::~FTEnvironment()
{
for (int i = 0; i < F_COUNT; ++i)
FTEnvironment::ft_err += FT_Done_Face((FTEnvironment::ft_face[i]));
FTEnvironment::ft_err += FT_Done_FreeType(FTEnvironment::ft_lib);
if (FTEnvironment::ft_err > 0)
Log::error("Freetype Environment", "Can't destroy all fonts.");
else
Log::info("Freetype Environment", "Successfully destroy all fonts.");
}
void FTEnvironment::loadFont()
{
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "Ubuntu-R.ttf", true)).c_str(),
0, &(FTEnvironment::ft_face[F_DEFAULT]));
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "FreeSans.ttf",true)).c_str(),
0, &(FTEnvironment::ft_face[F_DEFAULT_FALLBACK]));
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "wqy-microhei.ttf",true)).c_str(),
0, &(FTEnvironment::ft_face[F_CJK]));
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "NotoNaskhArabicUI-Bold.ttf",true)).c_str(),
0, &(FTEnvironment::ft_face[F_AR]));
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "Ubuntu-B.ttf", true)).c_str(),
0, &(FTEnvironment::ft_face[F_BOLD]));
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "FreeSansBold.ttf", true)).c_str(),
0, &(FTEnvironment::ft_face[F_BOLD_FALLBACK]));
FTEnvironment::ft_err += FT_New_Face(FTEnvironment::ft_lib, (file_manager->getAssetChecked
(FileManager::TTF, "SigmarOne.otf",true)).c_str(),
0, &(FTEnvironment::ft_face[F_DIGIT]));
//Set charmap
for (int h = 0; h < F_COUNT; ++h)
{
for (int i = 0; i < FTEnvironment::ft_face[h]->num_charmaps; ++i)
{
FT_UShort pid = FTEnvironment::ft_face[h]->charmaps[i]->platform_id;
FT_UShort eid = FTEnvironment::ft_face[h]->charmaps[i]->encoding_id;
if (((pid == 0) && (eid == 3)) || ((pid == 3) && (eid == 1)))
FTEnvironment::ft_err += FT_Set_Charmap(FTEnvironment::ft_face[h], FTEnvironment::ft_face[h]->charmaps[i]);
}
}
if (FTEnvironment::ft_err > 0)
Log::error("Freetype Environment", "Can't load all fonts.");
else
Log::info("Freetype Environment", "Successfully loaded all fonts.");
}
FT_Library FTEnvironment::ft_lib = NULL;
FT_Error FTEnvironment::ft_err = 0;
} // guiengine
#endif // ENABLE_FREETYPE

View File

@ -0,0 +1,46 @@
// 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 <ft2build.h>
#include "guiengine/get_font_properties.hpp"
#include FT_FREETYPE_H
/**
* \ingroup guiengine
*/
namespace GUIEngine
{
/**
* \brief Initialize a freetype environment with a single freetype library.
*/
class FTEnvironment
{
public:
FTEnvironment();
~FTEnvironment();
FT_Face ft_face[irr::gui::F_COUNT];
private:
/** Load font face into memory, but don't create glyph yet.
*/
void loadFont();
static FT_Library ft_lib;
static FT_Error ft_err;
};
} // guiengine

View File

@ -0,0 +1,127 @@
// 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 "graphics/irr_driver.hpp"
#include "guiengine/get_font_properties.hpp"
#include "utils/translation.hpp"
#include <algorithm>
#include <clocale>
#include <cwctype>
namespace irr
{
namespace gui
{
getFontProperties::getFontProperties (const core::stringc &langname, TTFLoadingType type, FontUse &fu)
{
findScale();
switch(type)
{
case T_NORMAL:
loadChar(langname, fu, normal_text_scale);
break;
case T_DIGIT:
fu = F_DIGIT;
loadNumber(normal_text_scale);
break;
case T_BOLD:
fu = F_BOLD;
loadBoldChar(title_text_scale);
break;
}
}
void getFontProperties::findScale()
{
//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);
normal_text_scale = 0.7f + 0.2f*scale;
title_text_scale = 0.2f + 0.2f*scale;
}
void getFontProperties::loadChar(const core::stringc langname, FontUse& fu, float scale)
{
fu = F_DEFAULT; //Default font file
for (int i = 32; i < 128; ++i)
usedchar.insert((wchar_t)i); //Include basic Latin too
usedchar.insert((wchar_t)160); //Non-breaking space
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 == "el" || langname == "fr" || langname == "gd")
size = (int)(27*scale); //Lower scale for them as they're space-consuming.
//else
// size = (int)(29*scale); //Set to default size
}
void getFontProperties::loadNumber(float scale)
{
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
usedchar.insert((wchar_t)i); //FIXME have to load 46 " . " to make 47 " / " display correctly, why?
}
void getFontProperties::loadBoldChar(float scale)
{
size = (int)(120*scale); //Set default size for Bold Text
usedchar = translations->getCurrentAllChar(); //Loading unique characters
for (int i = 65; i < 256; ++i)
usedchar.insert((wchar_t)i); //Include basic Latin too, starting from A (char code 65)
setlocale(LC_ALL, "en_US.UTF8");
std::set<wchar_t>::iterator it = usedchar.begin();
while (it != usedchar.end())
{
//Only use all capital letter for bold char with latin (<640 of char code).
//Remove all characters (>char code 8191) not used by the title
if (((iswlower((wchar_t)*it) || !iswalpha((wchar_t)*it)) && *it < 640) || *it > 8191)
it = usedchar.erase(it);
else
++it;
}
//Final hack to make stk display title properly
for (int i = 32; i < 65; ++i)
usedchar.insert((wchar_t)i); //Include basic symbol (from space (char code 32) to @(char code 64))
usedchar.insert((wchar_t)160); //Non-breaking space
//Remove Ordinal indicator (char code 170 and 186)
usedchar.erase((wchar_t)170);
usedchar.erase((wchar_t)186);
usedchar.erase((wchar_t)304); //Remove Capital I-dotted (char code 304) with using "I" altogether.
}
} // end namespace gui
} // end namespace irr

View File

@ -0,0 +1,76 @@
// 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.
#ifndef HEADER_GET_FONT_PROPERTIES_HPP
#define HEADER_GET_FONT_PROPERTIES_HPP
#include <irrlicht.h>
#include <set>
namespace irr
{
namespace gui
{
enum FontUse
{
F_DEFAULT = 0,
F_DEFAULT_FALLBACK = 1,
F_CJK = 2,
F_AR = 3,
F_LAST_REGULAR_FONT = F_AR,
F_BOLD = 4,
F_BOLD_FALLBACK = 5,
F_DIGIT = 6,
F_COUNT = 7
};
enum TTFLoadingType {T_NORMAL, T_DIGIT, T_BOLD};
class getFontProperties
{
public:
/** Get properties used for load characters with ttf.
* \param langname The current gui language.
* \param type Current loaded font type (normal, bold or digit font).
* \param fu Give a suitable font file.
* \return Font dpi and characters required to preload for current gui language.
*/
getFontProperties (const core::stringc &langname, TTFLoadingType type, FontUse &fu);
unsigned short size;
std::set<wchar_t> usedchar;
private:
void loadChar(core::stringc, FontUse&, float);
void loadNumber(float);
void loadBoldChar(float);
/** Find a suitable font scale base on current resolution
*/
void findScale();
float normal_text_scale;
float title_text_scale;
};
} // end namespace gui
} // end namespace irr
#endif

View File

@ -0,0 +1,159 @@
// 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 <irrlicht.h>
#include "guiengine/engine.hpp"
namespace GUIEngine
{
GlyphPageCreator::GlyphPageCreator()
{
page = GUIEngine::getDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2du(512, 512));
image = 0;
newchar.clear();
}
GlyphPageCreator::~GlyphPageCreator()
{
clearGlyphPage();
page->drop();
page = 0;
}
void GlyphPageCreator::dumpGlyphPage(const core::stringc fn)
{
GUIEngine::getDriver()->writeImageToFile(page, fn + ".png");
}
bool GlyphPageCreator::checkEnoughSpace(FT_Bitmap bits)
{
core::dimension2du d(bits.width + 1, bits.rows + 1);
core::dimension2du texture_size;
texture_size = d.getOptimalSize(!(GUIEngine::getDriver()->queryFeature(video::EVDF_TEXTURE_NPOT)),
!(GUIEngine::getDriver()->queryFeature(video::EVDF_TEXTURE_NSQUARE)), true, 0);
if ((used_width + texture_size.Width > 512 && used_height + temp_height + texture_size.Height > 512)
|| used_height + texture_size.Height > 512)
return false;
return true;
}
void GlyphPageCreator::clearGlyphPage()
{
used_width = 0;
temp_height = 0;
used_height = 0;
}
void GlyphPageCreator::createNewGlyphPage()
{
//Clean the current glyph page by filling it with transparent content
page->fill(video::SColor(0, 255, 255, 255));
}
video::IImage* GlyphPageCreator::getPage()
{
return page;
}
core::stringw GlyphPageCreator::getNewChar()
{
core::stringw c;
for (std::set<wchar_t>::iterator it = newchar.begin(); it != newchar.end(); ++it)
c += *it;
return c;
}
bool GlyphPageCreator::insertGlyph(FT_Bitmap bits, core::rect<s32>& rect)
{
core::dimension2du d(bits.width + 1, bits.rows + 1);
core::dimension2du texture_size;
switch (bits.pixel_mode)
{
case FT_PIXEL_MODE_GRAY:
{
// Create our blank image.
texture_size = d.getOptimalSize(!(GUIEngine::getDriver()->queryFeature(video::EVDF_TEXTURE_NPOT)),
!(GUIEngine::getDriver()->queryFeature(video::EVDF_TEXTURE_NSQUARE)), true, 0);
image = GUIEngine::getDriver()->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 < (unsigned)bits.rows; ++y)
{
u8* row = glyph_data;
for (u32 x = 0; x < (unsigned)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:
return false;
}
if (!image)
return false;
//Done creating a single glyph, now copy to the glyph page...
//Determine the linebreak location
if (used_width + texture_size.Width > 512)
{
used_width = 0;
used_height += temp_height;
temp_height = 0;
}
//Copy now
image->copyTo(page, core::position2di(used_width, used_height));
//Store the rectangle of current glyph
rect = core::rect<s32> (used_width, used_height, used_width + bits.width, used_height + bits.rows);
image->drop();
image = 0;
//Store used area
used_width += texture_size.Width;
if (temp_height < texture_size.Height)
temp_height = texture_size.Height;
return true;
}
u32 GlyphPageCreator::used_width = 0;
u32 GlyphPageCreator::used_height = 0;
u32 GlyphPageCreator::temp_height = 0;
} // guiengine
#endif // ENABLE_FREETYPE

View File

@ -0,0 +1,95 @@
// 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 <IVideoDriver.h>
#include <irrlicht.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <set>
using namespace irr;
/**
* \ingroup guiengine
*/
namespace GUIEngine
{
/**
* \brief Create glyph pages for different fonts.
*/
class GlyphPageCreator
{
public:
GlyphPageCreator();
~GlyphPageCreator();
/** Write the current glyph page into png on current running directory.
* Mainly for debug use.
* \param fn The file name.
*/
void dumpGlyphPage(const core::stringc fn);
/** Check whether it is ok the fit the inputted glyph into the current glyph page.
* \param bits The Glyph bitmap inputted.
* \return True if there is enough space.
*/
bool checkEnoughSpace(FT_Bitmap bits);
/** Reset position of glyph on the current glyph page.
*/
static void clearGlyphPage();
/** Clear (fill it with transparent content) the current glyph page.
*/
void createNewGlyphPage();
/** Used to get a glyph page which is loaded later for texture
* \return Glyph page image.
*/
video::IImage* getPage();
/** Used to get the string of new characters inside set newchar. (Mainly for debug)
* \return string of wild-character.
*/
core::stringw getNewChar();
/** Used to insert a single glyph bitmap into the glyph page
* \param bits The Glyph bitmap inputted.
* \param rect Give the rectangle of the glyph on the page.
* \return True if a glyph is loaded.
*/
bool insertGlyph(FT_Bitmap bits, core::rect<s32>& rect);
/** A temporary holder stored new char to be inserted.
*/
std::set<wchar_t> newchar;
private:
/** A temporary storage for a single glyph.
*/
video::IImage* image;
/** A full glyph page.
*/
video::IImage* page;
static u32 temp_height;
static u32 used_width;
static u32 used_height;
};
} // guiengine

View File

@ -16,12 +16,81 @@
#include <IVideoDriver.h>
#include <IXMLReader.h>
#include <clocale>
#include <cmath>
#include <cwctype>
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_type = type;
m_font_use = (FontUse)0;
m_dpi = 0;
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();
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)
@ -65,6 +134,7 @@ ScalableFont::ScalableFont(IGUIEnvironment *env, const std::string &filename)
assert(Areas.size() > 0);
}
#endif // ENABLE_FREETYPE
//! destructor
ScalableFont::~ScalableFont()
@ -87,6 +157,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,11 +352,391 @@ 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 from a TTF file
bool ScalableFont::loadTTF()
{
if (!SpriteBank)
{
Log::error("ScalableFont::loadTTF", "SpriteBank is NULL!!");
return false;
}
GUIEngine::GlyphPageCreator* gp_creator = GUIEngine::getGlyphPageCreator();
//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
getFontProperties cur_prop(translations->getCurrentLanguageNameCode().c_str(), m_type, m_font_use);
m_dpi = cur_prop.size;
std::vector <s32> offset;
std::vector <s32> bx;
std::vector <s32> advance;
std::vector <s32> height;
std::set<wchar_t>::iterator it;
s32 current_maxheight = 0;
s32 t;
u32 texno = 0;
SpriteBank->addTexture(NULL);
gp_creator->clearGlyphPage();
gp_creator->createNewGlyphPage();
GUIEngine::FTEnvironment* ft_env = GUIEngine::getFreetype();
it = cur_prop.usedchar.begin();
while (it != cur_prop.usedchar.end())
{
SGUISpriteFrame f;
SGUISprite s;
core::rect<s32> rectangle;
int idx;
if (m_type == T_BOLD) //Lite-Fontconfig for stk, this one is specifically for bold title
{
int count = F_BOLD;
while (count < irr::gui::F_COUNT)
{
m_font_use = (FontUse)count;
FT_Face curr_face = ft_env->ft_face[m_font_use];
err = FT_Set_Pixel_Sizes(curr_face, 0, m_dpi);
if (err)
Log::error("ScalableFont::loadTTF", "Can't set font size.");
idx = FT_Get_Char_Index(curr_face, *it);
if (idx > 0) break;
count++;
}
}
else
{
FT_Face curr_face = ft_env->ft_face[m_font_use];
err = FT_Set_Pixel_Sizes(curr_face, 0, m_dpi);
if (err)
Log::error("ScalableFont::loadTTF", "Can't set font size.");
idx = FT_Get_Char_Index(curr_face, *it);
}
FT_Face curr_face = ft_env->ft_face[m_font_use];
slot = curr_face->glyph;
if (idx)
{
// Load glyph image into the slot (erase previous one)
err = FT_Load_Glyph(curr_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 = (curr_face->glyph->metrics.height >> 6) - curr_face->glyph->bitmap_top;
offset.push_back(offset_on_line);
// This is to be used later.
t = curr_face->glyph->metrics.height >> 6;
height.push_back(t);
if (t > current_maxheight)
current_maxheight = t;
// Store horizontal padding (bearingX).
s32 bX = curr_face->glyph->bitmap_left;
bx.push_back(bX);
// Store total width on horizontal line.
s32 width = curr_face->glyph->advance.x >> 6;
advance.push_back(width);
// Convert to an anti-aliased bitmap
FT_Bitmap bits = slot->bitmap;
CharacterMap[*it] = SpriteBank->getSprites().size();
if (!gp_creator->checkEnoughSpace(bits))
// Glyph page is full, save current one and reset the current page
{
#ifdef FONT_DEBUG
gp_creator->dumpGlyphPage(((std::to_string(m_type)) + "_" + (std::to_string(texno))).c_str());
#endif
SpriteBank->setTexture(texno, Driver->addTexture("Glyph_page", gp_creator->getPage()));
gp_creator->clearGlyphPage();
SpriteBank->addTexture(NULL);
gp_creator->createNewGlyphPage();
texno++;
}
// Inserting now
if (gp_creator->insertGlyph(bits, rectangle))
{
f.rectNumber = SpriteBank->getPositions().size();
f.textureNumber = texno;
// add frame to sprite
s.Frames.push_back(f);
s.frameTime = 0;
SpriteBank->getPositions().push_back(rectangle);
SpriteBank->getSprites().push_back(s);
}
else
return false;
}
// Check for glyph page which can fit all characters
if (it == --cur_prop.usedchar.end())
{
#ifdef FONT_DEBUG
gp_creator->dumpGlyphPage(((std::to_string(m_type)) + "_" + (std::to_string(texno))).c_str());
#endif
if (m_type == T_NORMAL)
{
LastNormalPage = Driver->addTexture("Glyph_page", gp_creator->getPage());
SpriteBank->setTexture(texno, LastNormalPage);
}
else
SpriteBank->setTexture(texno, Driver->addTexture("Glyph_page", gp_creator->getPage()));
}
if (*it == (wchar_t)32 && SpriteBank->getPositions().size() == 1)
continue; //Preventing getAreaIDFromCharacter of whitespace == 0, which make space disappear
else ++it;
}
//Fix unused glyphs....
if (m_type == T_NORMAL || T_BOLD)
{
CharacterMap[(wchar_t)9] = getAreaIDFromCharacter((wchar_t)160, NULL); //Use non-breaking space glyph to tab.
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 == T_NORMAL)
{
CharacterMap[(wchar_t)8204] = 0; //They are zero width chars found in Arabic.
CharacterMap[(wchar_t)65279] = 0;
}
}
if (m_type == T_BOLD)
{
setlocale(LC_ALL, "en_US.UTF8");
for (it = cur_prop.usedchar.begin(); it != cur_prop.usedchar.end(); ++it)
{
if (iswupper((wchar_t)*it) && *it < 640)
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.
a.offsety_bt = -offset.at(n); //FIXME
//Specific offset for billboard text as billboard text seems to be drawn bottom-up,
//as the offset in calculated based on the fact that the characters are drawn all
//at the bottom line, so no addition is required, but if we can make draw2dimage draw
//characters close to the bottom line too, than only one offsety is needed.
if (!n) //Skip width-less characters
a.bearingx = 0;
else
a.bearingx = bx.at(n);
if (!n) //Skip width-less characters
a.width = 0;
else
a.width = advance.at(n);
// add character to font
Areas.push_back(a);
}
WrongCharacter = getAreaIDFromCharacter(L' ', NULL);
//Reserve 10 for normal font new characters added, 40 for digit font to display separately
//Consider fallback font (bold) too
MaxHeight = (int)((current_maxheight + (m_type == T_DIGIT ? 40 : 10) +
(m_type == T_BOLD ? 20 : 0))*m_scale);
GlyphMaxHeight = current_maxheight;
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 T_NORMAL:
Log::info("ScalableFont::loadTTF", "Created %d glyphs "
"supporting %d characters for normal font %s at %d dpi using %d glyph page(s)."
, Areas.size(), CharacterMap.size(), GUIEngine::getFreetype()->ft_face[m_font_use]->family_name, m_dpi, SpriteBank->getTextureCount());
break;
case T_DIGIT:
Log::info("ScalableFont::loadTTF", "Created %d glyphs "
"supporting %d characters for high-res digits font %s at %d dpi using %d glyph page(s)."
, Areas.size(), CharacterMap.size(), GUIEngine::getFreetype()->ft_face[m_font_use]->family_name, m_dpi, SpriteBank->getTextureCount());
break;
case T_BOLD:
Log::info("ScalableFont::loadTTF", "Created %d glyphs "
"supporting %d characters for bold title font %s at %d dpi using %d glyph page(s)."
, Areas.size(), CharacterMap.size(), GUIEngine::getFreetype()->ft_face[m_font_use]->family_name, m_dpi, SpriteBank->getTextureCount());
break;
}
return true;
}
//! lazy load new characters discovered in normal font
bool ScalableFont::lazyLoadChar()
{
//Mainly copy from loadTTF(), so removing unnecessary comments
if (m_type != T_NORMAL) return false; //Make sure only insert char inside normal font
FT_GlyphSlot slot;
FT_Error err;
GUIEngine::FTEnvironment* ft_env = GUIEngine::getFreetype();
GUIEngine::GlyphPageCreator* gp_creator = GUIEngine::getGlyphPageCreator();
s32 height;
s32 bX;
s32 offset_on_line;
s32 width;
u32 texno = SpriteBank->getTextureCount() - 1;
std::set<wchar_t>::iterator it;
it = gp_creator->newchar.begin();
while (it != gp_creator->newchar.end())
{
SGUISpriteFrame f;
SGUISprite s;
core::rect<s32> rectangle;
//Lite-Fontconfig for stk
int idx;
int font = irr::gui::F_DEFAULT;
while (font <= irr::gui::F_LAST_REGULAR_FONT)
{
m_font_use = (FontUse)font;
FT_Face face = ft_env->ft_face[font];
err = FT_Set_Pixel_Sizes(face, 0, m_dpi);
if (err)
Log::error("ScalableFont::loadTTF", "Can't set font size.");
idx = FT_Get_Char_Index(face, *it);
if (idx > 0) break;
font++;
}
FT_Face curr_face = ft_env->ft_face[m_font_use];
slot = curr_face->glyph;
if (idx)
{
err = FT_Load_Glyph(curr_face, idx,
FT_LOAD_DEFAULT | FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
if (err)
Log::error("ScalableFont::loadTTF", "Can't load a single glyph.");
offset_on_line = (curr_face->glyph->metrics.height >> 6) - curr_face->glyph->bitmap_top;
height = curr_face->glyph->metrics.height >> 6;
bX = curr_face->glyph->bitmap_left;
width = curr_face->glyph->advance.x >> 6;
FT_Bitmap bits = slot->bitmap;
CharacterMap[*it] = SpriteBank->getSprites().size();
if (!gp_creator->checkEnoughSpace(bits))
{
#ifdef FONT_DEBUG
gp_creator->dumpGlyphPage(((std::to_string(m_type)) + "_" + (std::to_string(texno))).c_str());
#endif
SpriteBank->setTexture(texno, Driver->addTexture("Glyph_page", gp_creator->getPage()));
gp_creator->clearGlyphPage();
SpriteBank->addTexture(NULL);
gp_creator->createNewGlyphPage();
texno++;
}
if (gp_creator->insertGlyph(bits, rectangle))
{
f.rectNumber = SpriteBank->getPositions().size();
f.textureNumber = texno;
s.Frames.push_back(f);
s.frameTime = 0;
SpriteBank->getPositions().push_back(rectangle);
SpriteBank->getSprites().push_back(s);
}
else
return false;
SFontArea a;
a.spriteno = SpriteBank->getSprites().size() - 1;
a.offsety = GlyphMaxHeight - height + offset_on_line;
a.offsety_bt = -offset_on_line;
a.bearingx = bX;
a.width = width;
Areas.push_back(a);
}
else
CharacterMap[*it] = 2; //Set wrong character to !, preventing it from loading again
++it;
}
#ifdef FONT_DEBUG
gp_creator->dumpGlyphPage(((std::to_string(m_type)) + "_" + (std::to_string(texno))).c_str());
#endif
gp_creator->newchar.clear(); //Clear the Newly characters in creator after they are loaded
Driver->removeTexture(LastNormalPage); //Remove old texture
LastNormalPage = Driver->addTexture("Glyph_page", gp_creator->getPage());
SpriteBank->setTexture(texno, LastNormalPage);
if (!m_is_hollow_copy)
{
GUIEngine::cleanHollowCopyFont();
GUIEngine::reloadHollowCopyFont(GUIEngine::getFont());
}
Log::debug("ScalableFont::lazyLoadChar", "New characters drawn by %s inserted, there are %d glyphs "
"supporting %d characters for normal font at %d dpi using %d glyph page(s) now."
, GUIEngine::getFreetype()->ft_face[m_font_use]->family_name, Areas.size(), CharacterMap.size(), m_dpi, SpriteBank->getTextureCount());
return true;
}
//! force create a new texture (glyph) page in a font
void ScalableFont::forceNewPage()
{
GUIEngine::GlyphPageCreator* gp_creator = GUIEngine::getGlyphPageCreator();
SpriteBank->setTexture(SpriteBank->getTextureCount() - 1, Driver->addTexture("Glyph_page", gp_creator->getPage()));
gp_creator->clearGlyphPage();
SpriteBank->addTexture(NULL);
gp_creator->createNewGlyphPage();
}
#endif // ENABLE_FREETYPE
void ScalableFont::setScale(const float scale)
{
m_scale = scale;
}
#ifndef ENABLE_FREETYPE
void ScalableFont::setMaxHeight()
{
MaxHeight = 0;
@ -313,6 +764,7 @@ void ScalableFont::setMaxHeight()
MaxHeight = (int)(MaxHeight*m_scale);
}
#endif // ENABLE_FREETYPE
@ -328,6 +780,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,6 +790,7 @@ s32 ScalableFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* prev
ret += Areas[getAreaIDFromCharacter(*previousLetter, NULL)].underhang;
}
}
#endif // ENABLE_FREETYPE
return ret;
}
@ -426,6 +880,29 @@ void ScalableFont::setInvisibleCharacters( const wchar_t *s )
//! returns the dimension of text
core::dimension2d<u32> ScalableFont::getDimension(const wchar_t* text) const
{
#ifdef ENABLE_FREETYPE
GUIEngine::GlyphPageCreator* gp_creator = GUIEngine::getGlyphPageCreator();
if (m_type == T_NORMAL || T_BOLD) //lazy load char
{
for (const wchar_t* p = text; *p; ++p)
{
if (*p == L'\r' || *p == L'\n' || *p == L' ' || *p < 32) continue;
if (GUIEngine::getFont()->getSpriteNoFromChar(p) == WrongCharacter)
gp_creator->newchar.insert(*p);
}
if (gp_creator->newchar.size() > 0 && !m_is_hollow_copy && m_scale == 1)
{
Log::debug("ScalableFont::getDimension", "New character(s) %s discoverd, perform lazy loading",
StringUtils::wide_to_utf8(gp_creator->getNewChar().c_str()).c_str());
if (!GUIEngine::getFont()->lazyLoadChar())
Log::error("ScalableFont::lazyLoadChar", "Can't insert new char into glyph pages.");
}
}
#endif // ENABLE_FREETYPE
assert(Areas.size() > 0);
core::dimension2d<u32> dim(0, 0);
@ -448,7 +925,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);
}
@ -496,6 +975,8 @@ void ScalableFont::doDraw(const core::stringw& text,
{
if (!Driver) return;
GUIEngine::GlyphPageCreator* gp_creator = GUIEngine::getGlyphPageCreator();
if (m_shadow)
{
m_shadow = false; // avoid infinite recursion
@ -534,6 +1015,37 @@ void ScalableFont::doDraw(const core::stringw& text,
core::array<core::position2di> offsets(text_size);
std::vector<bool> fallback(text_size);
#ifdef ENABLE_FREETYPE
if (m_type == T_NORMAL || T_BOLD) //lazy load char, have to do this again
{ //because some text isn't drawn with getDimension
for (u32 i = 0; i<text_size; i++)
{
wchar_t c = text[i];
if (c == L'\r' || c == L'\n' || c == L' ' || c < 32) continue;
if (GUIEngine::getFont()->getSpriteNoFromChar(&c) == WrongCharacter)
gp_creator->newchar.insert(c);
if (charCollector != NULL && m_type == T_NORMAL && SpriteBank->getSprites()
[GUIEngine::getFont()->getSpriteNoFromChar(&c)].Frames[0].textureNumber
== SpriteBank->getTextureCount() - 1) //Prevent overwriting texture used by billboard text
{
Log::debug("ScalableFont::doDraw", "Character used by billboard text is in the last glyph page of normal font."
" Create a new glyph page for new characters inserted later to prevent it from being removed.");
GUIEngine::getFont()->forceNewPage();
}
}
if (gp_creator->newchar.size() > 0 && !m_is_hollow_copy && m_scale == 1)
{
Log::debug("ScalableFont::doDraw", "New character(s) %s discoverd, perform lazy loading",
StringUtils::wide_to_utf8(gp_creator->getNewChar().c_str()).c_str());
if (!GUIEngine::getFont()->lazyLoadChar())
Log::error("ScalableFont::lazyLoadChar", "Can't insert new char into glyph pages.");
}
}
#endif // ENABLE_FREETYPE
for (u32 i = 0; i<text_size; i++)
{
wchar_t c = text[i];
@ -552,8 +1064,36 @@ 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
if (charCollector == NULL)
{
//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 == T_DIGIT ? 20*m_scale : 0); //Additional offset for digit text
offsets.push_back(offset);
offset.X -= Hpadding;
offset.Y -= Vpadding + floor(m_type == T_DIGIT ? 20*m_scale : 0);
}
else //Billboard text specific
{
int Hpadding = floor((float) area.bearingx*
(fallback[i] ? m_scale*m_fallback_font_scale : m_scale));
int Vpadding = floor((float) area.offsety_bt*
(fallback[i] ? m_scale*m_fallback_font_scale : m_scale));
offset.X += Hpadding;
offset.Y += Vpadding + floor(m_type == T_DIGIT ? 20*m_scale : 0); //Additional offset for digit text
offsets.push_back(offset);
offset.X -= Hpadding;
offset.Y -= Vpadding + floor(m_type == T_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,11 +1135,15 @@ void ScalableFont::doDraw(const core::stringw& text,
(*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] :
positions[sprites[spriteID].Frames[0].rectNumber]);
#ifdef ENABLE_FREETYPE
float char_scale = 1.0f;
#else
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;
#endif // ENABLE_FREETYPE
core::dimension2d<s32> size = source.getSize();
@ -608,9 +1152,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,7 +1172,11 @@ void ScalableFont::doDraw(const core::stringw& text,
source.getWidth(), source.getHeight(), offsets[n].X, offsets[n].Y);
}
*/
#ifdef FONT_DEBUG
GL32_draw2DRectangle(video::SColor(255, 255,0,0), dest,clip);
#endif
#ifndef ENABLE_FREETYPE
if (texture == NULL)
{
// perform lazy loading
@ -646,6 +1198,7 @@ void ScalableFont::doDraw(const core::stringw& text,
continue; // no such character
}
}
#endif // ENABLE_FREETYPE
if (m_black_border && charCollector == NULL)
{
@ -666,7 +1219,11 @@ void ScalableFont::doDraw(const core::stringw& text,
}
}
#ifdef ENABLE_FREETYPE
if (fallback[n] || m_type == T_BOLD)
#else
if (fallback[n])
#endif // ENABLE_FREETYPE
{
// TODO: don't hardcode colors?
video::SColor orange(color.getAlpha(), 255, 100, 0);
@ -707,26 +1264,12 @@ 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
}
}
}
#ifndef ENABLE_FREETYPE
void ScalableFont::lazyLoadTexture(int texID)
{
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
@ -765,9 +1308,13 @@ void ScalableFont::lazyLoadTexture(int texID)
}
}
}
#endif // ENABLE_FREETYPE
int ScalableFont::getCharWidth(const SFontArea& area, const bool fallback) const
{
#ifdef ENABLE_FREETYPE
const float char_scale = 1.0f;
#else
core::array< SGUISprite >& sprites = SpriteBank->getSprites();
core::array< SGUISprite >* fallback_sprites = (m_fallback_font != NULL ?
&m_fallback_font->SpriteBank->getSprites() :
@ -783,11 +1330,17 @@ int ScalableFont::getCharWidth(const SFontArea& area, const bool fallback) const
);
assert(info.m_file_name.size() > 0);
const float char_scale = info.m_scale;
#endif // ENABLE_FREETYPE
//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 +1355,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;

View File

@ -7,6 +7,10 @@
#include "utils/leak_check.hpp"
#ifdef ENABLE_FREETYPE
#include "guiengine/get_font_properties.hpp"
#endif // ENABLE_FREETYPE
#include "IrrCompileConfig.h"
#include "IGUIFontBitmap.h"
#include "irrString.h"
@ -51,6 +55,7 @@ class ScalableFont : public IGUIFontBitmap
bool m_mono_space_digits;
irr::video::SColor m_shadow_color;
#ifndef ENABLE_FREETYPE
struct TextureInfo
{
irr::core::stringc m_file_name;
@ -68,6 +73,7 @@ class ScalableFont : public IGUIFontBitmap
std::map<int /* texture file ID */, TextureInfo> m_texture_files;
void doReadXmlFile(io::IXMLReader* xml);
#endif // ENABLE_FREETYPE
bool m_is_hollow_copy;
bool m_rtl;
@ -78,12 +84,22 @@ public:
bool m_black_border;
#ifdef ENABLE_FREETYPE
TTFLoadingType m_type;
FontUse m_font_use;
u32 m_dpi;
#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,10 +120,15 @@ 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);
void lazyLoadTexture(int texID);
#endif // ENABLE_FREETYPE
//! draws an text and clips it to the specified rectangle if wanted
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
@ -159,8 +180,30 @@ public:
void updateRTL();
#ifdef ENABLE_FREETYPE
//! re-create fonts when language is changed
void recreateFromLanguage();
//! lazy load new characters discovered in normal font
bool lazyLoadChar();
//! force create a new texture (glyph) page in a font
void forceNewPage();
#endif // ENABLE_FREETYPE
private:
#ifdef ENABLE_FREETYPE
struct SFontArea
{
SFontArea() : width(0), spriteno(0), offsety(0), offsety_bt(0), bearingx(0) {}
s32 width;
u32 spriteno;
s32 offsety;
s32 offsety_bt;
s32 bearingx;
};
#else
struct SFontArea
{
SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
@ -169,6 +212,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;
@ -185,6 +229,10 @@ private:
u32 WrongCharacter;
s32 MaxHeight;
s32 GlobalKerningWidth, GlobalKerningHeight;
#ifdef ENABLE_FREETYPE
s32 GlyphMaxHeight;
video::ITexture* LastNormalPage;
#endif // ENABLE_FREETYPE
core::stringw Invisible;
};

View File

@ -13,6 +13,7 @@
#include "Keycodes.h"
#include "graphics/2dutils.hpp"
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
#include "utils/time.hpp"
@ -279,9 +280,9 @@ bool CGUIEditBox::processKey(const SEvent& event)
const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
core::stringc s;
core::stringw s;
s = Text.subString(realmbgn, realmend - realmbgn).c_str();
Operator->copyToClipboard(s.c_str());
Operator->copyToClipboard(StringUtils::wide_to_utf8(s.c_str()).c_str());
}
break;
case KEY_KEY_X:
@ -292,9 +293,9 @@ bool CGUIEditBox::processKey(const SEvent& event)
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
// copy
core::stringc sc;
core::stringw sc;
sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
Operator->copyToClipboard(sc.c_str());
Operator->copyToClipboard(StringUtils::wide_to_utf8(sc.c_str()).c_str());
if (isEnabled())
{
@ -330,13 +331,13 @@ bool CGUIEditBox::processKey(const SEvent& event)
{
// insert text
core::stringw s = Text.subString(0, CursorPos);
s.append(p);
s.append(StringUtils::utf8_to_wide(p));
s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
if (!Max || s.size()<=Max) // thx to Fish FH for fix
{
Text = s;
s = p;
s = StringUtils::utf8_to_wide(p);
CursorPos += s.size();
}
}
@ -345,13 +346,13 @@ bool CGUIEditBox::processKey(const SEvent& event)
// replace text
core::stringw s = Text.subString(0, realmbgn);
s.append(p);
s.append(StringUtils::utf8_to_wide(p));
s.append( Text.subString(realmend, Text.size()-realmend) );
if (!Max || s.size()<=Max) // thx to Fish FH for fix
{
Text = s;
s = p;
s = StringUtils::utf8_to_wide(p);
CursorPos = realmbgn + s.size();
}
}

View File

@ -56,7 +56,6 @@ DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row)
m_item_count_hint = 0;
m_font = GUIEngine::getFont()->getHollowCopy();
m_max_label_width = 0;
}
// -----------------------------------------------------------------------------
@ -385,6 +384,8 @@ void DynamicRibbonWidget::buildInternalStructure()
ribbon->m_properties[PROP_ID] = name.str();
ribbon->m_event_handler = this;
m_font = GUIEngine::getFont()->getHollowCopy();
// calculate font size
if (m_col_amount > 0)
{

View File

@ -145,8 +145,8 @@ void SpinnerWidget::add()
else
{
rect<s32> subsize_label = rect<s32>(m_h, 0, m_w - m_h, m_h);
const wchar_t *text = stringw(m_value).c_str();
IGUIStaticText* label = GUIEngine::getGUIEnv()->addStaticText(text, subsize_label,
stringw text = stringw(m_value);
IGUIStaticText* label = GUIEngine::getGUIEnv()->addStaticText(text.c_str(), subsize_label,
false /* border */, true /* word wrap */,
btn, getNewNoFocusID());
m_children[1].m_element = label;

View File

@ -115,7 +115,6 @@ FileManager::FileManager()
{
m_subdir_name.resize(ASSET_COUNT);
m_subdir_name[CHALLENGE ] = "challenges";
m_subdir_name[FONT ] = "fonts";
m_subdir_name[GFX ] = "gfx";
m_subdir_name[GRANDPRIX ] = "grandprix";
m_subdir_name[GUI ] = "gui";
@ -127,6 +126,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.

View File

@ -48,8 +48,8 @@ public:
* The last entry ASSET_COUNT specifies the number of entries. */
enum AssetType {ASSET_MIN,
CHALLENGE=ASSET_MIN,
FONT, GFX, GRANDPRIX, GUI, LIBRARY, MODEL, MUSIC,
SCRIPT, SFX, SHADER, SKIN, TEXTURE,
GFX, GRANDPRIX, GUI, LIBRARY, MODEL, MUSIC,
SCRIPT, SFX, SHADER, SKIN, TEXTURE, TTF,
TRANSLATION, ASSET_MAX = TRANSLATION,
ASSET_COUNT};
private:

View File

@ -1289,14 +1289,6 @@ int main(int argc, char *argv[] )
main_loop = new MainLoop();
material_manager->loadMaterial();
// Load the font textures - they are all lazily loaded
// so no need to push a texture search path. They will actually
// be loaded from ScalableFont.
file_manager->pushTextureSearchPath(file_manager->getAsset(FileManager::FONT, ""));
material_manager->addSharedMaterial(
file_manager->getAsset(FileManager::FONT,"materials.xml"));
file_manager->popTextureSearchPath();
GUIEngine::addLoadingIcon( irr_driver->getTexture(FileManager::GUI,
"options_video.png"));
kart_properties_manager -> loadAllKarts ();

View File

@ -192,12 +192,13 @@ void OptionsScreenUI::init()
// The names need to be sorted alphabetically. Store the 2-letter
// language names in a mapping, to be able to get them from the
// user visible full name.
std::vector<std::string> nice_lang_list;
std::map<std::string, std::string> nice_name_2_id;
std::vector<core::stringw> nice_lang_list;
std::map<core::stringw, std::string> nice_name_2_id;
for (int n=0; n<amount; n++)
{
std::string code_name = (*lang_list)[n];
std::string nice_name = tinygettext::Language::from_name(code_name).get_name();
std::string s_name = tinygettext::Language::from_name(code_name).get_name();
core::stringw nice_name = StringUtils::utf8_to_wide(s_name.c_str());
nice_lang_list.push_back(nice_name);
nice_name_2_id[nice_name] = code_name;
}
@ -205,7 +206,7 @@ void OptionsScreenUI::init()
for(unsigned int i=0; i<nice_lang_list.size(); i++)
{
list_widget->addItem(nice_name_2_id[nice_lang_list[i]],
nice_lang_list[i].c_str());
nice_lang_list[i]);
}
list_widget->setSelectionID( list_widget->getItemID(UserConfigParams::m_language) );
@ -328,6 +329,15 @@ 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::getTitleFont()->recreateFromLanguage();
GUIEngine::getFont()->recreateFromLanguage();
GUIEngine::reloadHollowCopyFont(GUIEngine::getFont());
#endif // ENABLE_FREETYPE
GUIEngine::getStateManager()->hardResetAndGoToScreen<MainMenuScreen>();
GUIEngine::getFont()->updateRTL();

View File

@ -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 */

View File

@ -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>

View File

@ -19,6 +19,7 @@
#include "utils/time.hpp"
#include "graphics/irr_driver.hpp"
#include "utils/translation.hpp"
#include <ctime>
@ -38,6 +39,22 @@ void StkTime::init()
m_timer->grab();
} // init
// ----------------------------------------------------------------------------
/** Converts the time in this object to a human readable string. */
std::string StkTime::toString(const TimeType &tt)
{
const struct tm *t = gmtime(&tt);
//I18N: Format for dates (%d = day, %m = month, %Y = year). See http://www.cplusplus.com/reference/ctime/strftime/ for more info about date formats.
core::stringw w_date_format = translations->w_gettext(N_("%d/%m/%Y"));
core::stringc c_date_format(w_date_format.c_str());
char s[64];
strftime(s, 64, c_date_format.c_str(), t);
return s;
} // toString
// ----------------------------------------------------------------------------
/** Returns a time based on an arbitrary 'epoch' (e.g. could be start
* time of the application, 1.1.1970, ...).

View File

@ -52,13 +52,7 @@ public:
static void getDate(int *day=NULL, int *month=NULL, int *year=NULL);
/** Converts the time in this object to a human readable string. */
static std::string toString(const TimeType &tt)
{
const struct tm *t = gmtime(&tt);
char s[16];
strftime(s, 16, "%x", t);
return s;
} // toString
static std::string toString(const TimeType &tt);
// ------------------------------------------------------------------------
/** Returns the number of seconds since 1.1.1970. This function is used
* to compare access times of files, e.g. news, addons data etc.

View File

@ -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

View File

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

View File

@ -1,861 +0,0 @@
#include "CFontTool.h"
#include "IXMLWriter.h"
#include <iostream>
#include <fstream>
using namespace irr;
const int fontsizes[] = {4,6,8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,56,68,72,0};
char bUsed[0x10000]={0};
/** True if pot files where given, which indicates that Asian fonts
* are to be created, and an offset needs to be used for the index. */
bool has_pot_files = false;
inline u32 getTextureSizeFromSurfaceSize(u32 size)
{
u32 ts = 0x01;
while(ts < size)
ts <<= 1;
return ts;
}
bool LoadPoFiles(const char* sListFileName){
has_pot_files = true;
char s[1024];
std::ifstream fin(sListFileName);
if(!fin){
std::cout<<"Error: Can't open "<<sListFileName<<std::endl;
return false;
}
std::cout<<"Opened list file "<<sListFileName<<std::endl;
for(;;){
fin.getline(s,1024);
if(fin.eof()) break;
std::ifstream fin2(s);
if(!fin2){
std::cout<<"Error: Can't open "<<s<<std::endl;
}else{
std::cout<<"Opened "<<s<<std::endl;
//buggy code that convert UTF-8 to UCS-2
for(;;){
unsigned char c1=(unsigned char)fin2.get();
unsigned short out=0;
if(fin2.eof()) break;
if(c1>=0xF0) continue;
else if(c1>=0xE0){
out=((c1&0xF)<<12)
|((((unsigned char)fin2.get())&0x3F)<<6)
|(((unsigned char)fin2.get())&0x3F);
}else if(c1>=0xC0){
out=((c1&0x1F)<<6)
|(((unsigned char)fin2.get())&0x3F);
}else{
out=c1;
}
bUsed[out]=1;
}
}
}
return true;
}
// ----------------------------------------------------------------------------
/** Set all characters in the given character string to be used. */
bool setUsedCharacters(const char* characters)
{
int n = strlen(characters);
for(int i=0; i<n; i++)
bUsed[short(characters[i])] = true;
return true;
} // setUsedCharacters
// ----------------------------------------------------------------------------
// windows specific
#ifdef _IRR_WINDOWS_
const DWORD charsets[] = { ANSI_CHARSET, DEFAULT_CHARSET, OEM_CHARSET, BALTIC_CHARSET, GB2312_CHARSET, CHINESEBIG5_CHARSET,
EASTEUROPE_CHARSET, GREEK_CHARSET, HANGUL_CHARSET, MAC_CHARSET, RUSSIAN_CHARSET,
SHIFTJIS_CHARSET, SYMBOL_CHARSET, TURKISH_CHARSET, VIETNAMESE_CHARSET, JOHAB_CHARSET,
ARABIC_CHARSET, HEBREW_CHARSET, THAI_CHARSET, 0};
const wchar_t *setnames[] = {L"ANSI", L"All Available", L"OEM", L"Baltic", L"Chinese Simplified", L"Chinese Traditional",
L"Eastern European", L"Greek", L"Hangul", L"Macintosh", L"Russian",
L"Japanese", L"Symbol", L"Turkish", L"Vietnamese", L"Johab",
L"Arabic", L"Hebrew", L"Thai", 0};
// callback for adding font names
int CALLBACK EnumFontFamExProc( ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme,
DWORD FontType, LPARAM lParam)
{
CFontTool* t = (CFontTool*) lParam;
t->FontNames.push_back( core::stringw(lpelfe->elfFullName));
return 1;
}
//
// Constructor
//
CFontTool::CFontTool(IrrlichtDevice* device) : FontSizes(fontsizes),
Device(device), UseAlphaChannel(false),
// win specific
dc(0)
{
// init display context
dc = CreateDC(L"DISPLAY", L"DISPLAY", 0 ,0 );
// populate list of available character set names
for (int i=0; setnames[i] != 0; ++i)
CharSets.push_back( core::stringw(setnames[i]));
selectCharSet(0);
}
void CFontTool::selectCharSet(u32 currentCharSet)
{
if ( currentCharSet >= CharSets.size() )
return;
LOGFONTW lf;
lf.lfFaceName[0] = L'\0';
lf.lfCharSet = (BYTE) charsets[currentCharSet];
// HRESULT hr; // no error checking(!)
// clear font list
FontNames.clear();
// create list of available fonts
EnumFontFamiliesExW( dc, (LPLOGFONTW) &lf, (FONTENUMPROCW) EnumFontFamExProc, (LPARAM) this, 0);
}
bool CFontTool::makeBitmapFont(u32 fontIndex, u32 charsetIndex, s32 fontSize, u32 textureWidth, u32 textureHeight, bool bold, bool italic, bool aa, bool alpha,bool usedOnly,bool excludeLatin)
{
if (fontIndex >= FontNames.size() || charsetIndex >= CharSets.size() )
return false;
UseAlphaChannel = alpha;
u32 currentImage = 0;
// create the font
HFONT font = CreateFontW(
-MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSY), 72), 0,
0,0,
bold ? FW_BOLD : 0,
italic, 0,0, charsets[charsetIndex], 0,0,
aa ? ANTIALIASED_QUALITY : 0,
0, FontNames[fontIndex].c_str() );
if (!font)
return false;
SelectObject(dc, font);
SetTextAlign (dc,TA_LEFT | TA_TOP | TA_NOUPDATECP);
// get rid of the current textures/images
for (u32 i=0; i<currentTextures.size(); ++i)
currentTextures[i]->drop();
currentTextures.clear();
for (u32 i=0; i<currentImages.size(); ++i)
currentImages[i]->drop();
currentImages.clear();
// clear current image mappings
CharMap.clear();
// clear array
Areas.clear();
// get information about this font's unicode ranges.
s32 size = GetFontUnicodeRanges( dc, 0);
c8 *buf = new c8[size];
LPGLYPHSET glyphs = (LPGLYPHSET)buf;
GetFontUnicodeRanges( dc, glyphs);
// s32 TotalCharCount = glyphs->cGlyphsSupported;
s32 currentx=0, currenty=0, maxy=0;
for (u32 range=0; range < glyphs->cRanges; range++)
{
WCRANGE* current = &glyphs->ranges[range];
//maxy=0;
// loop through each glyph and write its size and position
for (s32 ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++)
{
wchar_t currentchar = ch;
/* if ( IsDBCSLeadByte((BYTE) ch))
continue; // surragate pairs unsupported */
if(excludeLatin && ch>=0 && ch<0x100) continue;
if(usedOnly && !bUsed[(unsigned short)ch]) continue;
// get the dimensions
SIZE size;
ABC abc;
GetTextExtentPoint32W(dc, &currentchar, 1, &size);
SFontArea fa;
fa.underhang = 0;
fa.overhang = 0;
if (GetCharABCWidthsW(dc, currentchar, currentchar, &abc)) // for unicode fonts, get overhang, underhang, width
{
size.cx = abc.abcB;
fa.underhang = abc.abcA;
fa.overhang = abc.abcC;
}
if (size.cy < 1)
continue;
//GetGlyphOutline(dc, currentchar, GGO_METRICS, &gm, 0, 0, 0);
//size.cx++; size.cy++;
// wrap around?
if (currentx + size.cx > (s32) textureWidth)
{
currenty += maxy;
currentx = 0;
if ((u32)(currenty + maxy) > textureHeight)
{
currentImage++; // increase Image count
currenty=0;
}
maxy = 0;
}
// add this char dimension to the current map
fa.rectangle = core::rect<s32>(currentx, currenty, currentx + size.cx, currenty + size.cy);
fa.sourceimage = currentImage;
CharMap.insert(currentchar, Areas.size());
Areas.push_back( fa );
currentx += size.cx +1;
if (size.cy+1 > maxy)
maxy = size.cy+1;
}
}
currenty += maxy;
u32 lastTextureHeight = getTextureSizeFromSurfaceSize(currenty);
// delete the glyph set
delete [] buf;
currentImages.set_used(currentImage+1);
currentTextures.set_used(currentImage+1);
for (currentImage=0; currentImage < currentImages.size(); ++currentImage)
{
core::stringc logmsg = "Creating image ";
logmsg += (s32) (currentImage+1);
logmsg += " of ";
logmsg += (s32) currentImages.size();
Device->getLogger()->log(logmsg.c_str());
// no need for a huge final texture
u32 texHeight = textureHeight;
if (currentImage == currentImages.size()-1 )
texHeight = lastTextureHeight;
// make a new bitmap
HBITMAP bmp = CreateCompatibleBitmap(dc, textureWidth, texHeight);
HDC bmpdc = CreateCompatibleDC(dc);
LOGBRUSH lbrush;
lbrush.lbColor = RGB(0,0,0);
lbrush.lbHatch = 0;
lbrush.lbStyle = BS_SOLID;
HBRUSH brush = CreateBrushIndirect(&lbrush);
HPEN pen = CreatePen(PS_NULL, 0, 0);
HGDIOBJ oldbmp = SelectObject(bmpdc, bmp);
HGDIOBJ oldbmppen = SelectObject(bmpdc, pen);
HGDIOBJ oldbmpbrush = SelectObject(bmpdc, brush);
HGDIOBJ oldbmpfont = SelectObject(bmpdc, font);
SetTextColor(bmpdc, RGB(255,255,255));
Rectangle(bmpdc, 0,0,textureWidth,texHeight);
SetBkMode(bmpdc, TRANSPARENT);
// draw the letters...
// iterate through the tree
core::map<wchar_t, u32>::Iterator it = CharMap.getIterator();
while (!it.atEnd())
{
s32 currentArea = (*it).getValue();
wchar_t wch = (*it).getKey();
// sloppy but I couldnt be bothered rewriting it
if (Areas[currentArea].sourceimage == currentImage)
{
// draw letter
s32 sx = Areas[currentArea].rectangle.UpperLeftCorner.X - Areas[currentArea].underhang;
TextOutW(bmpdc, sx, Areas[currentArea].rectangle.UpperLeftCorner.Y, &wch, 1);
// if ascii font...
//SetPixel(bmpdc, Areas[currentArea].rectangle.UpperLeftCorner.X, Areas[currentArea].rectangle.UpperLeftCorner.Y, RGB(255,255,0));// left upper corner mark
}
it++;
}
// copy the font bitmap into a new irrlicht image
BITMAP b;
PBITMAPINFO pbmi;
WORD cClrBits;
u32 cformat;
// Retrieve the bitmap color format, width, and height.
GetObject(bmp, sizeof(BITMAP), (LPSTR)&b);
// Convert the color format to a count of bits.
cClrBits = (WORD)(b.bmPlanes * b.bmBitsPixel);
if (cClrBits <= 8) // we're not supporting these
cformat = -1;
else if (cClrBits <= 16)
cformat = video::ECF_A1R5G5B5;
else if (cClrBits <= 24)
cformat = video::ECF_R8G8B8;
else
cformat = video::ECF_A8R8G8B8;
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER));
// Initialize the fields in the BITMAPINFO structure.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = b.bmWidth;
pbmi->bmiHeader.biHeight = b.bmHeight;
pbmi->bmiHeader.biPlanes = b.bmPlanes;
pbmi->bmiHeader.biBitCount = b.bmBitsPixel;
// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;
// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
* pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
pbmi->bmiHeader.biClrImportant = 0;
LPBYTE lpBits; // memory pointer
PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) pbmi;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
GetDIBits(dc, bmp, 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS);
// DEBUG- copy to clipboard
//OpenClipboard(hWnd);
//EmptyClipboard();
//SetClipboardData(CF_BITMAP, bmp);
//CloseClipboard();
// flip bitmap
s32 rowsize = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8;
c8 *row = new c8[rowsize];
for (s32 i=0; i < (pbih->biHeight/2); ++i)
{
// grab a row
memcpy(row, lpBits + (rowsize * i), rowsize);
// swap row
memcpy(lpBits + (rowsize * i), lpBits + ((pbih->biHeight-1 -i) * rowsize ) , rowsize);
memcpy(lpBits + ((pbih->biHeight-1 -i) * rowsize ), row , rowsize);
}
bool ret = false;
if (cformat == video::ECF_A8R8G8B8)
{
// in this case the font should have an alpha channel, but since windows doesn't draw one
// we have to set one manually by going through all the pixels.. *sigh*
u8* m;
for (m = lpBits; m < lpBits + pbih->biSizeImage; m+=4)
{
if (UseAlphaChannel)
{
if (m[0] > 0) // pixel has colour
{
m[3]=m[0]; // set alpha
m[0]=m[1]=m[2] = 255; // everything else is full
}
}
else
m[3]=255; // all pixels are full alpha
}
}
else if (cformat == video::ECF_A1R5G5B5)
{
u8* m;
for (m = lpBits; m < lpBits + pbih->biSizeImage; m+=2)
{
WORD *p = (WORD*)m;
if (m[0] > 0 || !UseAlphaChannel) // alpha should be set
*p |= 0x8000; // set alpha bit
}
}
else
{
cformat = -1;
}
// make a texture from the image
if (cformat != -1)
{
// turn mip-mapping off
bool b = Device->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
currentImages[currentImage] = Device->getVideoDriver()->createImageFromData((video::ECOLOR_FORMAT)cformat, core::dimension2d<u32>(textureWidth,texHeight), (void*)lpBits);
Device->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,b);
}
else
{
Device->getLogger()->log("Couldn't create font, your pixel format is unsupported.");
}
// free memory and windows resources
// sloppy I know, but I only intended to create one image at first.
delete [] row;
LocalFree(pbmi);
GlobalFree(lpBits);
DeleteDC(bmpdc);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(bmp);
if (currentImages[currentImage])
{
// add texture
currentTextures[currentImage] = Device->getVideoDriver()->addTexture("GUIFontImage",currentImages[currentImage]);
currentTextures[currentImage]->grab();
}
else
{
Device->getLogger()->log("Something went wrong, aborting.");
// drop all images
DeleteObject(font);
return false;
}
} // looping through each texture
DeleteObject(font);
return true;
}
#else
CFontTool::CFontTool(IrrlichtDevice *device) : FontSizes(fontsizes), Device(device), UseAlphaChannel(false)
{
if (!XftInitFtLibrary())
{
core::stringc logmsg = "XFT not found\n";
Device->getLogger()->log(logmsg.c_str());
exit(EXIT_FAILURE);
}
/* Get a list of the font foundries, storing them in a set to sort */
std::set<core::stringw> foundries;
Display* display = (Display*)Device->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display;
XftFontSet* fonts = XftListFonts(display, DefaultScreen(display), 0, XFT_FOUNDRY, NULL);
for (int i = 0; i < fonts->nfont; i++)
{
char *foundry;
XftPatternGetString(fonts->fonts[i], XFT_FOUNDRY, 0, &foundry);
core::stringw tmp(foundry);
foundries.insert(tmp);
}
XftFontSetDestroy(fonts);
/* Copy the sorted list into the array */
CharSets.clear();
for (std::set<core::stringw>::iterator i = foundries.begin(); i != foundries.end(); i++)
CharSets.push_back((*i).c_str());
selectCharSet(0);
}
/* Note: There must be some trick for using strings as pattern parameters to XftListFonts because
no matter how I specify a string, I end up with an intermittent segfault. Since XftFontList is
just calling FcFontList, that's what I'll do too since that works OK */
void CFontTool::selectCharSet(u32 currentCharSet)
{
/* Get a list of the font families, storing them in a set to sort */
char foundry[256];
sprintf(&foundry[0],"%ls",CharSets[currentCharSet].c_str());
std::set<core::stringw> families;
XftPattern *pattern = FcPatternCreate();
XftPatternAddString(pattern, FC_FOUNDRY, &foundry[0]);
XftObjectSet *objectset = FcObjectSetCreate();
XftObjectSetAdd(objectset, XFT_FOUNDRY);
XftObjectSetAdd(objectset, XFT_FAMILY);
FcFontSet *fonts = FcFontList(NULL, pattern, objectset);
for (int i = 0; i < fonts->nfont; i++)
{
char* ptr;
XftPatternGetString(fonts->fonts[i], XFT_FAMILY, 0, &ptr);
core::stringw family(ptr);
families.insert(family);
}
XftPatternDestroy(pattern);
FcObjectSetDestroy(objectset);
/* Copy the sorted list into the array */
FontNames.clear();
for (std::set<core::stringw>::iterator i = families.begin(); i != families.end(); i++)
FontNames.push_back((*i).c_str());
}
bool CFontTool::makeBitmapFont(u32 fontIndex, u32 charsetIndex, s32 fontSize, u32 textureWidth, u32 textureHeight, bool bold, bool italic, bool aa, bool alpha,bool usedOnly,bool excludeLatin)
{
if (fontIndex >= FontNames.size() || charsetIndex >= CharSets.size() )
return false;
Display *display = (Display*) Device->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display;
u32 screen = DefaultScreen(display);
Window win = RootWindow(display, screen);
Visual *visual = DefaultVisual(display, screen);
UseAlphaChannel = alpha;
u32 currentImage = 0;
XftResult result;
XftPattern *request = XftPatternCreate();
char foundry[256], family[256];
sprintf(&foundry[0],"%ls",CharSets[charsetIndex].c_str());
sprintf(&family[0],"%ls",FontNames[fontIndex].c_str());
XftPatternAddString(request, XFT_FOUNDRY, &foundry[0]);
XftPatternAddString(request, XFT_FAMILY, &family[0]);
XftPatternAddInteger(request, XFT_PIXEL_SIZE, fontSize);
XftPatternAddInteger(request, XFT_WEIGHT, bold ? XFT_WEIGHT_BLACK : XFT_WEIGHT_LIGHT);
XftPatternAddInteger(request, XFT_SLANT, italic ? XFT_SLANT_ITALIC : XFT_SLANT_ROMAN);
XftPatternAddBool(request, XFT_ANTIALIAS, aa);
/* Find the closest font that matches the user choices and open it and check if the returned
font has anti aliasing enabled by default, even if it wasn't requested */
FcBool aaEnabled;
XftPattern *found = XftFontMatch(display, DefaultScreen(display), request, &result);
XftPatternGetBool(found, XFT_ANTIALIAS, 0, &aaEnabled);
aa = aaEnabled;
XftFont *font = XftFontOpenPattern(display, found);
// get rid of the current textures/images
for (u32 i=0; i<currentTextures.size(); ++i)
currentTextures[i]->drop();
currentTextures.clear();
for (u32 i=0; i<currentImages.size(); ++i)
currentImages[i]->drop();
currentImages.clear();
CharMap.clear();
Areas.clear();
/* Calculate the max height of the font. Annoyingly, it seems that the height property of the font
is the maximum height of any single character, but a string of characters, aligned along their
baselines, can exceed this figure. Because I don't know any better way of doing it, I'm going to
have to use the brute force method.
Note: There will be a certain number of charters in a font, however they may not be grouped
consecutively, and could in fact be spread out with many gaps */
u32 maxY = 0;
u32 charsFound = 0;
for (FT_UInt charCode = 0; charsFound < FcCharSetCount(font->charset); charCode++)
{
if (!XftCharExists(display, font, charCode))
continue;
charsFound++;
XGlyphInfo extents;
XftTextExtents32(display, font, &charCode, 1, &extents);
if ((extents.xOff <= 0) && (extents.height <= 0))
continue;
/* Calculate the width and height, adding 1 extra pixel if anti aliasing is enabled */
u32 chWidth = extents.xOff + (aa ? 1 : 0);
u32 chHeight = (font->ascent - extents.y + extents.height) + (aa ? 1 : 0);
if (chHeight > maxY)
maxY = chHeight;
/* Store the character details here */
SFontArea fontArea;
fontArea.rectangle = core::rect<s32>(0, 0, chWidth, chHeight);
CharMap.insert(charCode, Areas.size());
Areas.push_back(fontArea);
}
core::stringc logmsg = "Found ";
logmsg += (s32) (CharMap.size() + 1);
logmsg += " characters";
Device->getLogger()->log(logmsg.c_str());
/* Get the size of the chars and allocate them a position on a texture. If the next character that
is added would be outside the width or height of the texture, then a new texture is added */
u32 currentX = 0, currentY = 0, rowY = 0;
for (core::map<wchar_t, u32>::Iterator it = CharMap.getIterator(); !it.atEnd(); it++)
{
s32 currentArea = (*it).getValue();
SFontArea *fontArea = &Areas[currentArea];
u32 chWidth = fontArea->rectangle.LowerRightCorner.X;
u32 chHeight = fontArea->rectangle.LowerRightCorner.Y;
/* If the width of this char will exceed the textureWidth then start a new row */
if ((currentX + chWidth) > textureWidth)
{
currentY += rowY;
currentX = 0;
/* If the new row added to the texture exceeds the textureHeight then start a new texture */
if ((currentY + rowY) > textureHeight)
{
currentImage++;
currentY = 0;
}
rowY = 0;
}
/* Update the area with the current x and y and texture */
fontArea->rectangle = core::rect<s32>(currentX, currentY, currentX + chWidth, currentY + chHeight);
fontArea->sourceimage = currentImage;
currentX += chWidth + 1;
if (chHeight + 1 > rowY)
rowY = chHeight + 1;
}
/* The last row of chars and the last texture weren't accounted for in the loop, so add them here */
currentY += rowY;
u32 lastTextureHeight = getTextureSizeFromSurfaceSize(currentY);
currentImages.set_used(currentImage + 1);
currentTextures.set_used(currentImage + 1);
/* Initialise colours */
XftColor colFore, colBack;
XRenderColor xFore = {0xffff, 0xffff, 0xffff, 0xffff};
XRenderColor xBack = {0x0000, 0x0000, 0x0000, 0xffff};
XftColorAllocValue(display, DefaultVisual(display, screen), DefaultColormap(display, screen), &xFore, &colFore);
XftColorAllocValue(display, DefaultVisual(display, screen), DefaultColormap(display, screen), &xBack, &colBack);
/* Create a pixmap that is large enough to hold any character in the font */
Pixmap pixmap = XCreatePixmap(display, win, textureWidth, maxY, DefaultDepth(display, screen));
XftDraw *draw = XftDrawCreate(display, pixmap, visual, DefaultColormap(display, screen));
/* Render the chars */
for (currentImage = 0; currentImage < currentImages.size(); ++currentImage)
{
core::stringc logmsg = "Creating image ";
logmsg += (s32) (currentImage+1);
logmsg += " of ";
logmsg += (s32) currentImages.size();
Device->getLogger()->log(logmsg.c_str());
/* The last texture that is saved is vertically shrunk to fit the characters drawn on it */
u32 texHeight = textureHeight;
if (currentImage == currentImages.size() - 1)
texHeight = lastTextureHeight;
/* The texture that holds this "page" of characters */
currentImages[currentImage] = Device->getVideoDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2du(textureWidth, texHeight));
currentImages[currentImage]->fill(video::SColor(alpha ? 0 : 255,0,0,0));
for (core::map<wchar_t, u32>::Iterator it = CharMap.getIterator(); !it.atEnd(); it++)
{
FcChar32 wch = (*it).getKey();
s32 currentArea = (*it).getValue();
if (Areas[currentArea].sourceimage == currentImage)
{
SFontArea *fontArea = &Areas[currentArea];
u32 chWidth = fontArea->rectangle.LowerRightCorner.X - fontArea->rectangle.UpperLeftCorner.X;
u32 chHeight = fontArea->rectangle.LowerRightCorner.Y - fontArea->rectangle.UpperLeftCorner.Y;
/* Draw the glyph onto the pixmap */
XGlyphInfo extents;
XftDrawRect(draw, &colBack, 0, 0, chWidth, chHeight);
XftTextExtents32(display, font, &wch, 1, &extents);
XftDrawString32(draw, &colFore, font, extents.x, extents.y, &wch, 1);
/* Convert the pixmap into an image, then copy it onto the Irrlicht texture, pixel by pixel.
There's bound to be a faster way, but this is adequate */
u32 xDest = fontArea->rectangle.UpperLeftCorner.X;
u32 yDest = fontArea->rectangle.UpperLeftCorner.Y + font->ascent - extents.y;
XImage *image = XGetImage(display, pixmap, 0, 0, chWidth, chHeight, 0xffffff, XYPixmap);
if (image)
{
for (u32 ySrc = 0; ySrc < chHeight; ySrc++)
for (u32 xSrc = 0; xSrc < chWidth; xSrc++)
{
/* Get the pixel colour and break it down into rgb components */
u32 col = XGetPixel(image, xSrc, ySrc);
u32 a = 255;
u32 r = col & visual->red_mask;
u32 g = col & visual->green_mask;
u32 b = col & visual->blue_mask;
while (r > 0xff) r >>= 8;
while (g > 0xff) g >>= 8;
while (b > 0xff) b >>= 8;
/* To make the background transparent, set the colour to 100% white and the alpha to
the average of the three rgb colour components to maintain the anti-aliasing */
if (alpha)
{
a = (r + g + b) / 3;
r = 255;
g = 255;
b = 255;
}
currentImages[currentImage]->setPixel(xDest + xSrc,yDest + ySrc,video::SColor(a,r,g,b));
}
image->f.destroy_image(image);
}
}
}
/* Add the texture to the list */
currentTextures[currentImage] = Device->getVideoDriver()->addTexture("GUIFontImage",currentImages[currentImage]);
currentTextures[currentImage]->grab();
}
XftColorFree (display, visual, DefaultColormap(display, screen), &colFore);
XftColorFree (display, visual, DefaultColormap(display, screen), &colBack);
XftFontClose(display,font);
XftPatternDestroy(request);
XftDrawDestroy(draw);
XFreePixmap(display, pixmap);
return true;
}
#endif
CFontTool::~CFontTool()
{
#ifdef _IRR_WINDOWS_
// destroy display context
if (dc)
DeleteDC(dc);
#endif
// drop textures+images
for (u32 i=0; i<currentTextures.size(); ++i)
currentTextures[i]->drop();
currentTextures.clear();
for (u32 i=0; i<currentImages.size(); ++i)
currentImages[i]->drop();
currentImages.clear();
}
bool CFontTool::saveBitmapFont(const c8 *filename, const c8* format)
{
if (currentImages.size() == 0)
{
Device->getLogger()->log("No image data to write, aborting.");
return false;
}
core::stringc fn = filename;
core::stringc imagename = filename;
fn += ".xml";
io::IXMLWriter *writer = Device->getFileSystem()->createXMLWriter(fn.c_str());
// header and line breaks
writer->writeXMLHeader();
writer->writeLineBreak();
// write information
writer->writeElement(L"font", false, L"type", L"bitmap");
writer->writeLineBreak();
writer->writeLineBreak();
// write images and link to them
// Only use the offset if Asian fonts are created.
u32 offset_for_asian_fonts=has_pot_files ? 100 : 0;
for (u32 i=0; i<currentImages.size(); ++i)
{
imagename = filename;
imagename += (s32)i;
imagename += ".";
imagename += format;
Device->getVideoDriver()->writeImageToFile(currentImages[i],imagename.c_str());
writer->writeElement(L"Texture", true,
L"index", core::stringw(i+offset_for_asian_fonts).c_str(),
L"filename", core::stringw(imagename.c_str()).c_str(),
L"hasAlpha", UseAlphaChannel ? L"true" : L"false");
writer->writeLineBreak();
}
writer->writeLineBreak();
// write each character
core::map<wchar_t, u32>::Iterator it = CharMap.getIterator();
while (!it.atEnd())
{
SFontArea &fa = Areas[(*it).getValue()];
wchar_t c[2];
c[0] = (*it).getKey();
c[1] = L'\0';
core::stringw area, under, over, image;
area = core::stringw(fa.rectangle.UpperLeftCorner.X);
area += L", ";
area += fa.rectangle.UpperLeftCorner.Y;
area += L", ";
area += fa.rectangle.LowerRightCorner.X;
area += L", ";
area += fa.rectangle.LowerRightCorner.Y;
core::array<core::stringw> names;
core::array<core::stringw> values;
names.clear();
values.clear();
// char
names.push_back(core::stringw(L"c"));
values.push_back(core::stringw(c));
// image number
if (fa.sourceimage+offset_for_asian_fonts != 0)
{
image = core::stringw(fa.sourceimage+offset_for_asian_fonts);
names.push_back(core::stringw(L"i"));
values.push_back(image);
}
// rectangle
names.push_back(core::stringw(L"r"));
values.push_back(area);
if (fa.underhang != 0)
{
under = core::stringw(fa.underhang);
names.push_back(core::stringw(L"u"));
values.push_back(under);
}
if (fa.overhang != 0)
{
over = core::stringw(fa.overhang);
names.push_back(core::stringw(L"o"));
values.push_back(over);
}
writer->writeElement(L"c", true, names, values);
writer->writeLineBreak();
it++;
}
writer->writeClosingTag(L"font");
writer->drop();
Device->getLogger()->log("Bitmap font saved.");
return true;
}

View File

@ -1,79 +0,0 @@
#ifndef __IRR_FONT_TOOL_INCLUDED__
#define __IRR_FONT_TOOL_INCLUDED__
#include "irrlicht.h"
#if defined(_IRR_WINDOWS_)
#ifdef _MBCS
#undef _MBCS
#endif
#define UNICODE
#define _WIN32_WINNT 0x0500
#include "windows.h"
#else
#ifdef _IRR_COMPILE_WITH_X11_
#include <X11/Xlib.h>
#endif
#include <X11/Xft/Xft.h>
#include <set>
#endif
bool LoadPoFiles(const char* sListFileName);
bool setUsedCharacters(const char* characters);
namespace irr {
class CFontTool : public irr::IReferenceCounted
{
public:
CFontTool(irr::IrrlichtDevice* device);
~CFontTool();
virtual bool makeBitmapFont(u32 fontIndex, u32 charsetIndex,
s32 fontSize, u32 texturewidth, u32 textureHeight,
bool bold, bool italic, bool aa, bool alpha,
bool usedOnly=false,bool exclideLatin=false);
virtual bool saveBitmapFont(const c8* filename, const c8* format);
virtual void selectCharSet(u32 currentCharSet);
struct SFontArea
{
SFontArea() : rectangle(), underhang(0), overhang(0), sourceimage(0) {}
core::rect<s32> rectangle;
s32 underhang;
s32 overhang;
u32 sourceimage;
};
/* struct SFontMap
{
SFontMap() : areas(), start(0), count(0) {}
core::array< SFontArea > areas;
s32 start;
s32 count;
};*/
core::array<core::stringw> FontNames;
core::array<core::stringw> CharSets;
//core::array<SFontMap> Mappings;
core::array<SFontArea> Areas;
core::map<wchar_t, u32> CharMap;
core::array<video::ITexture*> currentTextures;
core::array<video::IImage*> currentImages;
const int *FontSizes;
IrrlichtDevice *Device;
bool UseAlphaChannel;
// windows
#ifdef _IRR_WINDOWS_
HDC dc;
#endif
};
}
#endif // __IRR_FONT_TOOL_INCLUDED__

View File

@ -1,39 +0,0 @@
option(FONT_TOOL "Compile font tool (only useful for developers)" OFF)
mark_as_advanced(FONT_TOOL)
if(FONT_TOOL)
if(MSVC)
add_executable(font_tool CFontTool.cpp main.cpp)
target_link_libraries(font_tool stkirrlicht)
else()
find_package(Freetype)
find_library(FONTCONFIG_LIBRARY fontconfig)
if(UNIX AND NOT APPLE)
find_package(Xrandr REQUIRED)
find_package(X11 REQUIRED)
include_directories(${X11_INCLUDE_DIR})
if(NOT XRANDR_FOUND)
message(STATUS "XRANDR not found.")
endif()
endif()
if(FREETYPE_FOUND)
include_directories(${FREETYPE_INCLUDE_DIRS})
add_executable(font_tool CFontTool.cpp main.cpp)
target_link_libraries(font_tool stkirrlicht)
target_link_libraries(font_tool ${FREETYPE_LIBRARIES})
target_link_libraries(font_tool ${OPENGL_LIBRARIES})
target_link_libraries(font_tool ${FONTCONFIG_LIBRARY})
if(UNIX AND NOT APPLE)
target_link_libraries(font_tool ${XRANDR_LIBRARIES})
target_link_libraries(font_tool ${X11_Xft_LIB} Xxf86vm)
target_link_libraries(font_tool ${X11_LIBRARIES})
endif()
else()
message(STATUS "Freetype was not found, the font tool won't be built (only useful for developers)")
endif()
endif()
else()
message(STATUS "Font tool deactivated, the font tool won't be built (only useful for developers)")
endif()

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Font Tool", "irrFontTool_v9.vcproj", "{4D53E40F-37E3-42B1-8848-F4C6F8313A17}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.ActiveCfg = Debug|Win32
{4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.Build.0 = Debug|Win32
{4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.ActiveCfg = Release|Win32
{4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,204 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="Font Tool"
ProjectGUID="{4D53E40F-37E3-42B1-8848-F4C6F8313A17}"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../lib/irrlicht/include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_IRR_STATIC_LIB_"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions=" kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib"
AdditionalDependencies="Irrlicht.lib"
OutputFile="../../font_tool.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="../../lib/irrlicht/lib/Win32-visualstudio"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/TestProject.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
WholeProgramOptimization="false"
AdditionalIncludeDirectories="../../lib/irrlicht/include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_IRR_STATIC_LIB_"
MinimalRebuild="true"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions=" kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib"
AdditionalDependencies="Irrlicht.lib"
OutputFile="../../FontTool.exe"
LinkIncremental="0"
AdditionalLibraryDirectories="../../lib/irrlicht/lib/Win32-visualstudio"
GenerateDebugInformation="false"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\CFontTool.cpp"
>
</File>
<File
RelativePath=".\CFontTool.h"
>
</File>
<File
RelativePath=".\CVectorFontTool.h"
>
</File>
<File
RelativePath=".\main.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -1,592 +0,0 @@
/*
Tool for creating Irrlicht bitmap+vector fonts,
started by Gaz Davidson in December 2006
Due to my laziness and Microsoft's unituitive API, surragate pairs and
nonspacing diacritical marks are not supported!
Linux bitmap font support added by Neil Burlock Oct 2008
Note: Xft/Freetype2 is used to render the fonts under X11. Anti-aliasing
is controlled by the system and cannot be overriden by an application,
so fonts that are rendered will be aliased or anti-aliased depending
on the system that they are created on.
acme_pjz modified the original irrlicht font tool to only write the
characters needed in a list of .po files - which saves huge amount
of space for Asian fonts.
*/
#include <irrlicht.h>
#include <iostream>
#include "CFontTool.h"
#include "CVectorFontTool.h"
#include "ITexture.h"
using namespace irr;
using namespace gui;
#if DEBUG
bool GLContextDebugBit = true;
#else
bool GLContextDebugBit = false;
#endif
const int WIDTH = 1024;
const int HEIGHT = 768;
const s32 texturesizes[] = {128, 256, 512, 1024, 2048, 4096, 0};
const wchar_t *fileformats[] = { L"bmp", L"ppm", 0 }; // bitmap font formats
const wchar_t *alphafileformats[] = { L"png", L"tga", 0 }; // bitmap font formats which support alpha channels
const wchar_t *vectorfileformats[] = { L"xml", L"bin", 0 }; // file formats for vector fonts
const wchar_t *warntext = L"Legal Notice\n"
L"------------\n\n"
L"When making bitmap and vector fonts, you should consider the potential legal "
L"issues with redistributing the fonts with your software; this tool basically "
L"copies font data and some authors might not like this!\n"
L"If you purchased fonts or they came with an application or your OS, you'll have"
L"to check the license to see what restrictions are placed on making derivative works.\n\n"
L"PD and the OFL\n"
L"--------------\n\n"
L"You'll find lots of fonts on the web listed as Public Domain, you can do what you like "
L"with these.\n"
L"Many fonts are released under the Open Font License, which is a 'viral' open source "
L"license like the GPL. It's worth reading the license here: http://scripts.sil.org/OFL\n"
L"The most important restrictions are- you must include the original font's license, you "
L"can't stop your users from using or distributing the font, the font must have a "
L"different name the original.\n\n"
L"Some free fonts can be found here- www.openfontlibrary.org\n"
L"http://savannah.nongnu.org/projects/freefont/";
const wchar_t *helptext = L"This tool creates bitmap fonts for the Irrlicht Engine\n\n"
L"First select a character encoding from the list, then choose the font, "
L"size, and whether you'd like bold, italic, antialiasing and an alpha channel. "
L"In Windows, antialiasing will be ignored for small fonts\n\n"
L"Then select a texture width and height. If the output exceeds this then more than "
L"one image will be created. You can use the scrollbar at the top of the screen to "
L"preview them. Most modern graphics cards will support up to 2048x2048, "
L"keep in mind that more images means worse performance when drawing text!\n\n"
L"If you want a vector font rather than a bitmap font, check the vector box. "
L"Vector fonts are stored in system memory while bitmap fonts are in video ram\n\n"
L"Click create to preview your font, this may take lots of time and memory "
L"when making a font with a lot of characters, please be patient!\n\n"
L"Now you're ready to give your font a name, select a format and click save.\n\n"
L"To load your font in Irrlicht, simply use env->getFont(\"Myfont.xml\");\n\n"
L"That's all, have fun :-)";
#ifdef _IRR_WINDOWS
const wchar_t *completeText = L"Font created"
#else
const wchar_t *completeText = L"Font created\n\n"
L"Please note that anti-aliasing under X11 is controlled by the system "
L"configuration, so if your system is set to use anti-aliasing, then so "
L"will any fonts you create with FontTool";
#endif
enum MYGUI
{
MYGUI_CHARSET = 100,
MYGUI_FONTNAME,
MYGUI_SIZE,
MYGUI_TEXWIDTH,
MYGUI_TEXHEIGHT,
MYGUI_BOLD,
MYGUI_ITALIC,
MYGUI_ANTIALIAS,
MYGUI_ALPHA,
MYGUI_VECTOR,
MYGUI_FILENAME,
MYGUI_FORMAT,
MYGUI_CREATE,
MYGUI_SAVE,
MYGUI_IMAGE,
MYGUI_CURRENTIMAGE,
MYGUI_HELPBUTTON
};
// event reciever
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(IrrlichtDevice* device, CFontTool*& fonttool, CVectorFontTool* &vectool) :
Device(device), FontTool(fonttool), VecTool(vectool)
{
}
virtual bool OnEvent(const SEvent &event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
IGUIEnvironment* env = Device->getGUIEnvironment();
switch(event.GUIEvent.EventType)
{
case EGET_SCROLL_BAR_CHANGED:
if (id == MYGUI_CURRENTIMAGE)
{
IGUIImage* img = (IGUIImage*)env->getRootGUIElement()->getElementFromId(MYGUI_IMAGE,true);
s32 i = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
img->setImage(FontTool->currentTextures[i]);
return true;
}
break;
case EGET_COMBO_BOX_CHANGED:
if (id == MYGUI_CHARSET)
{
IGUIComboBox* cbo = (IGUIComboBox*)event.GUIEvent.Caller;
IGUIComboBox* cbo_1 = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FONTNAME,true);
core::stringw str=FontTool->FontNames[cbo_1->getSelected()];
u32 j=0;
FontTool->selectCharSet(cbo->getSelected());
// rebuild font list
cbo = cbo_1;
cbo->clear();
for (u32 i=0; i < FontTool->FontNames.size(); ++i){
cbo->addItem(FontTool->FontNames[i].c_str());
if(FontTool->FontNames[i]==str) j=i;
}
cbo->setSelected(j);
return true;
}
else if(id==MYGUI_FONTNAME){
IGUIComboBox* cbo = (IGUIComboBox*)event.GUIEvent.Caller;
std::cout << FontTool->FontNames[cbo->getSelected()].c_str() << std::endl;
}
break;
case EGET_CHECKBOX_CHANGED:
if (id == MYGUI_VECTOR)
{
IGUICheckBox* chk = (IGUICheckBox*)event.GUIEvent.Caller;
IGUIComboBox *cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true);
cbo->clear();
if (chk->isChecked() && VecTool)
{
// vector formats
for (s32 i=0; fileformats[i] != 0; ++i)
cbo->addItem( core::stringw(vectorfileformats[i]).c_str());
}
else
{
// bitmap formats
if (!FontTool->UseAlphaChannel)
{
// add non-alpha formats
for (s32 i=0; fileformats[i] != 0; ++i)
cbo->addItem( core::stringw(fileformats[i]).c_str());
}
// add formats which support alpha
for (s32 i=0; alphafileformats[i] != 0; ++i)
cbo->addItem( core::stringw(alphafileformats[i]).c_str());
}
}
break;
case EGET_BUTTON_CLICKED:
if (id == MYGUI_CREATE)
{
// create the font with the params
IGUIComboBox* cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_CHARSET, true);
int charset = cbo->getSelected();
cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FONTNAME,true);
int fontname = cbo->getSelected();
/*
cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_SIZE,true);
int fontsize = cbo->getSelected();
*/
int fontsize=wcstol(((IGUIEditBox*)env->getRootGUIElement()->getElementFromId(MYGUI_SIZE,true))->getText(),NULL,10);
cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_TEXWIDTH,true);
int texwidth = cbo->getSelected();
cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_TEXHEIGHT,true);
int texheight = cbo->getSelected();
IGUICheckBox* chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_BOLD,true);
bool bold = chk->isChecked();
chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ITALIC,true);
bool italic = chk->isChecked();
chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ALPHA,true);
bool alpha = chk->isChecked();
chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ANTIALIAS,true);
bool aa = chk->isChecked();
chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(201,true);
bool usedOnly = chk->isChecked();
chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(202,true);
bool excludeLatin = chk->isChecked();
// vector fonts disabled
//chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_VECTOR,true);
bool vec = false;//chk->isChecked();
FontTool->makeBitmapFont(fontname, charset, /*FontTool->FontSizes[fontsize]*/ fontsize, texturesizes[texwidth], texturesizes[texheight], bold, italic, aa, alpha, usedOnly, excludeLatin);
IGUIScrollBar* scrl = (IGUIScrollBar*)env->getRootGUIElement()->getElementFromId(MYGUI_CURRENTIMAGE,true);
scrl->setMax(FontTool->currentTextures.size() == 0 ? 0 : FontTool->currentTextures.size()-1);
if (FontTool->currentTextures.size() > 0)
{
IGUIImage* img = (IGUIImage*)env->getRootGUIElement()->getElementFromId(MYGUI_IMAGE,true);
img->setImage(FontTool->currentTextures[0]);
scrl->setPos(0);
}
// make sure users pick a file format that supports alpha channel
cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true);
cbo->clear();
if (vec)
{
// add vector formats
for (s32 i=0; fileformats[i] != 0; ++i)
cbo->addItem( core::stringw(vectorfileformats[i]).c_str());
}
else
{
if (!alpha)
{
// add non-alpha formats
for (s32 i=0; fileformats[i] != 0; ++i)
cbo->addItem( core::stringw(fileformats[i]).c_str());
}
// add formats which support alpha
for (s32 i=0; alphafileformats[i] != 0; ++i)
cbo->addItem( core::stringw(alphafileformats[i]).c_str());
}
if (VecTool)
{
delete VecTool;
VecTool = 0;
}
if (vec)
{
VecTool = new CVectorFontTool(FontTool);
}
/* Message box letting the user know the process is complete */
env->addMessageBox(L"Create", completeText);
return true;
}
if (id == MYGUI_SAVE)
{
IGUIEditBox *edt = (IGUIEditBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FILENAME,true);
core::stringc name = edt->getText();
IGUIComboBox *fmt = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true);
core::stringc format = fmt->getItem(fmt->getSelected());
// vector fonts disabled
// IGUICheckBox *chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_VECTOR,true);
// bool vec = chk->isChecked();
bool vec = false;
if (vec && VecTool)
VecTool->saveVectorFont(name.c_str(), format.c_str());
else
FontTool->saveBitmapFont(name.c_str(), format.c_str());
return true;
}
if (id == MYGUI_HELPBUTTON)
{
env->addMessageBox(L"Irrlicht Unicode Font Tool", helptext);
return true;
}
break;
default:
break;
}
}
return false;
}
IrrlichtDevice* Device;
CFontTool* FontTool;
CVectorFontTool* VecTool;
};
void createGUI(IrrlichtDevice* device, CFontTool* fc)
{
// Scaling factor to allow a larger font to be used
float scale = 2.0f;
io::path previous_cwd = device->getFileSystem()->getWorkingDirectory();
gui::IGUIEnvironment *env = device->getGUIEnvironment();
gui::IGUIFont *font = env->getFont(io::path("../../../data/fonts/StkFont.xml"));
device->getGUIEnvironment()->getSkin()->setFont(font);
//env->getSkin()->setSize((gui::EGUI_DEFAULT_SIZE, 24);
// change transparency of skin
for (s32 i=0; i<gui::EGDC_COUNT ; ++i)
{
video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
col.setAlpha(255);
env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
}
IGUIWindow *win = env->addWindow( core::rect<s32>(10,HEIGHT/30,int(scale*WIDTH)/4,HEIGHT-100), false, L"Font Creator");
win->getCloseButton()->setVisible(false);
s32 xs=10,xp=xs, yp=HEIGHT/20, h=HEIGHT/20;
env->addStaticText(L"Charset", core::rect<s32>(int(scale*xp),yp,int(scale*90),yp+h),false,false, win);
xp+=60;
// charset combo
gui::IGUIComboBox* cbo = env->addComboBox( core::rect<s32>(int(scale*xp),yp,int(scale*180),yp+h),win, MYGUI_CHARSET);
for (u32 i=0; i < fc->CharSets.size(); ++i)
cbo->addItem(fc->CharSets[i].c_str());
yp += (s32)(h*1.5f);
xp = xs;
env->addStaticText(L"Font", core::rect<s32>(int(scale*xp),yp,int(scale*50),yp+h),false,false, win);
xp+=60;
// font name combo
cbo = env->addComboBox( core::rect<s32>(int(scale*xp),yp,int(scale*180),yp+h),win, MYGUI_FONTNAME);
for (u32 i=0; i < fc->FontNames.size(); ++i){
cbo->addItem(fc->FontNames[i].c_str());
if(fc->FontNames[i] == L"\u6587\u6CC9\u9A7F\u5FAE\u7C73\u9ED1") cbo->setSelected(i); //auto select wqy-microhei
}
yp += (s32)(h*1.5f);
xp = xs;
env->addStaticText(L"Size", core::rect<s32>(int(scale*xp),yp,int(scale*(50+xp)),yp+h),false,false, win);
xp += 60;
/*
// font size combo
cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_SIZE);
for (s32 i=0; fc->FontSizes[i] != 0; ++i)
cbo->addItem( ((core::stringw(fc->FontSizes[i])) + L"pt").c_str()); */
env->addEditBox(L"24",core::rect<s32>(int(scale*xp),yp,int(scale*(xp+70)),yp+h), true, win, MYGUI_SIZE);
xp += int(scale*80);
env->addStaticText(L"pt", core::rect<s32>(xp,yp,xp+50,yp+h),false,false,win);
xp = xs;
yp += (s32)(h*1.5f);
// bold checkbox
env->addCheckBox(false, core::rect<s32>(xp,yp,int(scale*(xp+50)),yp+h),win, MYGUI_BOLD, L"Bold");
xp += int(45*scale);
// italic checkbox
env->addCheckBox(false, core::rect<s32>(xp,yp,int(scale*(xp+50)),yp+h),win, MYGUI_ITALIC, L"Italic");
xp += int(55*scale);
// AA checkbox
env->addCheckBox(false, core::rect<s32>(xp,yp,int(scale*(xp+50)),yp+h),win, MYGUI_ANTIALIAS, L"AA");
xp += int(scale * 40);
// Alpha checkbox
env->addCheckBox(false, core::rect<s32>(xp,yp,int(scale*(xp+50)),yp+h),win, MYGUI_ALPHA, L"Alpha");
xp = xs;
yp += (s32)(h*1.5f);
//new
env->addCheckBox(false, core::rect<s32>(xp,yp,int(scale*(xp+200)),yp+h),win, 201, L"Only used characters")->setChecked(false);
yp += (s32)(h*1.5f);
env->addCheckBox(false, core::rect<s32>(xp,yp,int(scale*(xp+200)),yp+h),win, 202, L"Exclude basic latin");
yp += (s32)(h*1.5f);
/*
// vector fonts can't be loaded yet
env->addCheckBox(false, core::rect<s32>(xp,yp,xp+200,yp+h),win, MYGUI_VECTOR, L"Vector Font");
yp += (s32)(h*1.5f);
*/
env->addStaticText(L"Max Width:", core::rect<s32>(xp,yp,int(scale*100),yp+h),false,false, win);
xp += int(scale*90);
// texture widths
cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+int(scale*80),yp+h),win, MYGUI_TEXWIDTH);
for (s32 i=0; texturesizes[i] != 0; ++i)
cbo->addItem( ((core::stringw(texturesizes[i])) + L" wide").c_str());
cbo->setSelected(2); // 128, 256, 512 --> make 512 the default
xp=xs;
yp += (s32)(h*1.5f);
env->addStaticText(L"Max Height:", core::rect<s32>(xp,yp,int(scale*100),yp+h),false,false, win);
xp += int(scale*90);
// texture height
cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+int(scale*80),yp+h),win, MYGUI_TEXHEIGHT);
for (s32 i=0; texturesizes[i] != 0; ++i)
cbo->addItem( ((core::stringw(texturesizes[i])) + L" tall").c_str());
cbo->setSelected(2); // 512 as default
// file name
xp = xs;
yp += (s32)(h*1.5f);
env->addStaticText(L"Filename", core::rect<s32>(xp,yp,int(scale*100),yp+h),false,false, win);
xp += int(scale*90);
env->addEditBox(L"wqyMicroHei",core::rect<s32>(xp,yp,xp+int(scale*80),yp+h), true, win, MYGUI_FILENAME);
// file format
xp = xs;
yp += (s32)(h*1.5f);
env->addStaticText(L"File Format", core::rect<s32>(xp,yp,int(scale*100),yp+h),false,false, win);
xp += int(scale*90);
cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+int(scale*80),yp+h),win, MYGUI_FORMAT);
for (s32 i=0; fileformats[i] != 0; ++i)
cbo->addItem( core::stringw(fileformats[i]).c_str());
for (s32 i=0; alphafileformats[i] != 0; ++i)
cbo->addItem( core::stringw(alphafileformats[i]).c_str());
cbo->setSelected(2); // bmp, ppm, png, ... --> select pn
xp = xs;
yp += h*2;
// create button
env->addButton( core::rect<s32>(xp,yp,int(scale*(xp+50)),yp+h),win, MYGUI_CREATE, L"Create");
xp += int(scale*60);
// save button
env->addButton( core::rect<s32>(xp,yp,xp+int(scale*50),yp+h),win, MYGUI_SAVE, L"Save");
xp += int(scale*60);
// help button
env->addButton( core::rect<s32>(xp,yp,xp+int(scale*50),yp+h),win, MYGUI_HELPBUTTON, L"Help");
// font image
gui::IGUIImage *img = env->addImage(0, core::position2d<s32>(0,0), true,0, MYGUI_IMAGE);
img->setRelativePosition(core::rect<s32>(0,HEIGHT/30,WIDTH,HEIGHT));
// font scrollbar
IGUIScrollBar *scrl= env->addScrollBar(true,core::rect<s32>(0,0,WIDTH,HEIGHT/30),0, MYGUI_CURRENTIMAGE);
scrl->setMax(0);
scrl->setSmallStep(1);
yp += h*3;
env->getRootGUIElement()->bringToFront(win);
win->setRelativePosition( core::rect<s32>(0,HEIGHT/30,int(scale*200),yp));
}
int main(int argc,char **argv)
{
SIrrlichtCreationParameters p;
p.DriverType = video::EDT_OPENGL;
p.WindowSize = core::dimension2du(WIDTH, HEIGHT);
p.Bits = 16;
p.Fullscreen = false;
p.Stencilbuffer = false;
p.Vsync = false;
p.EventReceiver = NULL;
p.FileSystem = NULL;
p.ForceLegacyDevice = true;
IrrlichtDevice *device = createDeviceEx(p);
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment *env = device->getGUIEnvironment();
// create font tool
CFontTool *fc = new CFontTool(device);
CVectorFontTool *vc = 0;
MyEventReceiver events(device,fc,vc);
device->setEventReceiver(&events);
createGUI(device, fc);
for(int i=1; i<argc; i++)
{
if(!strcmp(argv[i],"-c") && i<argc-1)
{
i++;
if(setUsedCharacters(argv[i]))
{
IGUICheckBox *box =
dynamic_cast<IGUICheckBox*>(device->getGUIEnvironment()
->getRootGUIElement()
->getElementFromId(201, true));
box->setChecked(true);
}
}
else
{
// Old style: just a single parameter, assume it's a file name with pot files in it
if(LoadPoFiles(argv[i]))
{
IGUICheckBox *box =
dynamic_cast<IGUICheckBox*>(device->getGUIEnvironment()
->getRootGUIElement()
->getElementFromId(201, true));
box->setChecked(true);
}
}
} // for i <argc
while(device->run())
{
device->sleep(50);
if (device->isWindowActive())
{
driver->beginScene(true, true, video::SColor(0,200,200,200));
smgr->drawAll();
env->drawAll();
driver->endScene();
}
}
// drop the font tool and resources
fc->drop();
device->drop();
return 0;
}

View File

@ -1,6 +0,0 @@
data/po/ko.po
data/po/vi.po
data/po/zh_CN.po
data/po/zh_TW.po
data/po/uk.po
data/po/ky.po