mirror of https://github.com/Poikilos/b3view
Switched to Truetype font rendering in entire app
parent
1b8831cbc9
commit
76818f5586
10
B3View.pro
10
B3View.pro
|
@ -7,13 +7,15 @@ SOURCES += main.cpp \
|
|||
UserInterface.cpp \
|
||||
Debug.cpp \
|
||||
View.cpp \
|
||||
Utils.cpp
|
||||
Utils.cpp \
|
||||
extlib/CGUITTFont.cpp
|
||||
HEADERS += Engine.h \
|
||||
EventHandler.h \
|
||||
UserInterface.h \
|
||||
Debug.h \
|
||||
View.h \
|
||||
Utils.h
|
||||
Utils.h \
|
||||
extlib/CGUITTFont.h
|
||||
CONFIG += warn_off
|
||||
|
||||
# Irrlicht
|
||||
|
@ -24,3 +26,7 @@ LIBS += -L$$IRRLICHTBASE/source/Irrlicht \
|
|||
-lX11 \
|
||||
-lGL \
|
||||
-lXxf86vm
|
||||
|
||||
# Freetype
|
||||
INCLUDEPATH += /usr/include/freetype2
|
||||
LIBS += -lfreetype
|
||||
|
|
|
@ -137,7 +137,11 @@ Engine::Engine()
|
|||
m_EventHandler->addEventReceiver( ERT_3DVIEW, m_View );
|
||||
|
||||
// Load font for displaying Axis names
|
||||
m_AxisFont = m_Device->getGUIEnvironment()->getFont( "arial.xml" );
|
||||
m_AxisFontFace = new CGUITTFace();
|
||||
m_AxisFontFace->load( "arial.ttf" );
|
||||
m_AxisFont = new CGUITTFont( m_UserInterface->getGUIEnvironment() );
|
||||
m_AxisFont->attach( m_AxisFontFace, 14 );
|
||||
m_AxisFont->AntiAlias = false;
|
||||
|
||||
// Set Engine enabled
|
||||
m_RunEngine = true;
|
||||
|
@ -153,6 +157,8 @@ Engine::~Engine()
|
|||
{
|
||||
m_Device->drop();
|
||||
delete m_WindowSize;
|
||||
delete m_AxisFont;
|
||||
delete m_AxisFontFace;
|
||||
}
|
||||
|
||||
void Engine::loadMesh( const wstring &fileName )
|
||||
|
|
6
Engine.h
6
Engine.h
|
@ -14,6 +14,8 @@ class View;
|
|||
#include "UserInterface.h"
|
||||
#include "View.h"
|
||||
|
||||
#include "extlib/CGUITTFont.h"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::wstring;
|
||||
|
@ -42,7 +44,9 @@ private:
|
|||
IVideoDriver *m_Driver;
|
||||
ISceneManager *m_Scene;
|
||||
IAnimatedMeshSceneNode *m_LoadedMesh;
|
||||
IGUIFont *m_AxisFont;
|
||||
CGUITTFont *m_AxisFont;
|
||||
CGUITTFace *m_AxisFontFace;
|
||||
|
||||
dimension2d<u32> *m_WindowSize;
|
||||
|
||||
bool m_RunEngine;
|
||||
|
|
15
Makefile
15
Makefile
|
@ -1,6 +1,6 @@
|
|||
#############################################################################
|
||||
# Makefile for building: build/B3View
|
||||
# Generated by qmake (2.01a) (Qt 4.7.0) on: Thu Apr 22 14:20:08 2010
|
||||
# Generated by qmake (2.01a) (Qt 4.7.0) on: Fri Apr 23 09:51:28 2010
|
||||
# Project: B3View.pro
|
||||
# Template: app
|
||||
# Command: /opt/qt47/bin/qmake -spec /opt/qt47/mkspecs/linux-g++ CONFIG+=debug -o Makefile B3View.pro
|
||||
|
@ -13,10 +13,10 @@ CXX = g++
|
|||
DEFINES =
|
||||
CFLAGS = -pipe -g -w $(DEFINES)
|
||||
CXXFLAGS = -pipe -g -w $(DEFINES)
|
||||
INCPATH = -I/opt/qt47/mkspecs/linux-g++ -I. -I../irrlicht/trunk/include
|
||||
INCPATH = -I/opt/qt47/mkspecs/linux-g++ -I. -I../irrlicht/trunk/include -I/usr/include/freetype2
|
||||
LINK = g++
|
||||
LFLAGS = -Wl,-rpath,/opt/qt47/lib
|
||||
LIBS = $(SUBLIBS) -L/home/er/tmp/irrlicht/trunk/source/Irrlicht -lIrrlicht -lX11 -lGL -lXxf86vm
|
||||
LIBS = $(SUBLIBS) -L/home/er/tmp/irrlicht/trunk/source/Irrlicht -lIrrlicht -lX11 -lGL -lXxf86vm -lfreetype
|
||||
AR = ar cqs
|
||||
RANLIB =
|
||||
QMAKE = /opt/qt47/bin/qmake
|
||||
|
@ -49,14 +49,16 @@ SOURCES = main.cpp \
|
|||
UserInterface.cpp \
|
||||
Debug.cpp \
|
||||
View.cpp \
|
||||
Utils.cpp
|
||||
Utils.cpp \
|
||||
extlib/CGUITTFont.cpp
|
||||
OBJECTS = tmp/main.o \
|
||||
tmp/Engine.o \
|
||||
tmp/EventHandler.o \
|
||||
tmp/UserInterface.o \
|
||||
tmp/Debug.o \
|
||||
tmp/View.o \
|
||||
tmp/Utils.o
|
||||
tmp/Utils.o \
|
||||
tmp/CGUITTFont.o
|
||||
DIST = /opt/qt47/mkspecs/common/g++.conf \
|
||||
/opt/qt47/mkspecs/common/unix.conf \
|
||||
/opt/qt47/mkspecs/common/linux.conf \
|
||||
|
@ -221,6 +223,9 @@ tmp/Utils.o: Utils.cpp Utils.h \
|
|||
Debug.h
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o tmp/Utils.o Utils.cpp
|
||||
|
||||
tmp/CGUITTFont.o: extlib/CGUITTFont.cpp extlib/CGUITTFont.h
|
||||
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o tmp/CGUITTFont.o extlib/CGUITTFont.cpp
|
||||
|
||||
####### Install
|
||||
|
||||
install: FORCE
|
||||
|
|
|
@ -12,8 +12,16 @@ void UserInterface::setupUserInterface()
|
|||
fileMenu->addItem( L"Load", UIC_FILE_LOAD );
|
||||
fileMenu->addItem( L"Quit", UIC_FILE_QUIT );
|
||||
|
||||
// Playback Control Window
|
||||
IGUIWindow *playbackWindow = m_Gui->addWindow( rect<s32>( vector2d<s32>( 20, 60 ), dimension2d<s32>( 160, 300 )), false, L"Playback", 0, UIE_PLAYBACKWINDOW );
|
||||
playbackWindow->getCloseButton()->setVisible( false );
|
||||
|
||||
// Set Font for UI Elements
|
||||
m_GuiFont = m_Gui->getFont( "arial.xml" );
|
||||
m_GuiFontFace = new CGUITTFace();
|
||||
m_GuiFontFace->load( "arial.ttf" );
|
||||
m_GuiFont = new CGUITTFont( m_Gui );
|
||||
m_GuiFont->attach( m_GuiFontFace, 14 );
|
||||
|
||||
m_Gui->getSkin()->setFont( m_GuiFont );
|
||||
}
|
||||
|
||||
|
@ -50,6 +58,7 @@ UserInterface::UserInterface( Engine *engine )
|
|||
UserInterface::~UserInterface()
|
||||
{
|
||||
delete m_GuiFont;
|
||||
delete m_GuiFontFace;
|
||||
}
|
||||
|
||||
IGUIEnvironment * UserInterface::getGUIEnvironment() const
|
||||
|
|
|
@ -11,6 +11,8 @@ class Engine;
|
|||
#include "Debug.h"
|
||||
#include "Engine.h"
|
||||
|
||||
#include "extlib/CGUITTFont.h"
|
||||
|
||||
using namespace irr;
|
||||
using namespace irr::core;
|
||||
using namespace irr::gui;
|
||||
|
@ -20,7 +22,7 @@ using std::wstring;
|
|||
|
||||
enum UserInterfaceElements
|
||||
{
|
||||
UIE_MAINWINDOW = 1000,
|
||||
UIE_PLAYBACKWINDOW = 1000,
|
||||
UIE_LOADBUTTON = 1001,
|
||||
UIE_LOADFILEDIALOG = 1002,
|
||||
UIE_FILEMENU = 1003,
|
||||
|
@ -37,7 +39,8 @@ class UserInterface : public IEventReceiver
|
|||
private:
|
||||
Engine *m_Engine;
|
||||
IGUIEnvironment *m_Gui;
|
||||
IGUIFont *m_GuiFont;
|
||||
CGUITTFont *m_GuiFont;
|
||||
CGUITTFace *m_GuiFontFace;
|
||||
|
||||
void setupUserInterface();
|
||||
void displayLoadFileDialog();
|
||||
|
|
BIN
build/arial.bmp
BIN
build/arial.bmp
Binary file not shown.
Before Width: | Height: | Size: 768 KiB |
Binary file not shown.
BIN
build/arial.xml
BIN
build/arial.xml
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
|
@ -0,0 +1,628 @@
|
|||
// Kudus to Nalin for this wonderful piece of code!
|
||||
// See: http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=3995
|
||||
#include <irrlicht.h>
|
||||
using namespace irr;
|
||||
#include "CGUITTFont.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace gui
|
||||
{
|
||||
|
||||
FT_Library library;
|
||||
bool CGUITTFace::libraryLoaded = false;
|
||||
s32 facesCount = 0;
|
||||
|
||||
//////////////////////
|
||||
|
||||
CGUITTFace::CGUITTFace()
|
||||
: faceLoaded(false), font_buffer(0), font_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
CGUITTFace::~CGUITTFace()
|
||||
{
|
||||
if (faceLoaded)
|
||||
{
|
||||
FT_Done_Face(face);
|
||||
if (font_buffer)
|
||||
{
|
||||
delete[] font_buffer;
|
||||
font_buffer = 0;
|
||||
}
|
||||
if (--facesCount == 0)
|
||||
{
|
||||
FT_Done_FreeType(library);
|
||||
CGUITTFace::libraryLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CGUITTFace::load(const io::path& filename, io::IFileSystem* filesystem)
|
||||
{
|
||||
if (!libraryLoaded)
|
||||
{
|
||||
if (FT_Init_FreeType(&library))
|
||||
return false;
|
||||
CGUITTFace::libraryLoaded = true;
|
||||
}
|
||||
|
||||
if (filesystem)
|
||||
{
|
||||
// Read in the file data.
|
||||
io::IReadFile* file = filesystem->createAndOpenFile(filename);
|
||||
font_buffer = new FT_Byte[file->getSize()];
|
||||
file->read(font_buffer, file->getSize());
|
||||
font_size = file->getSize();
|
||||
file->drop();
|
||||
|
||||
// Create the face.
|
||||
if (FT_New_Memory_Face(library, font_buffer, font_size, 0, &face))
|
||||
{
|
||||
delete[] font_buffer;
|
||||
font_buffer = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FT_New_Face(library, core::stringc(filename).c_str(), 0, &face))
|
||||
return false;
|
||||
}
|
||||
|
||||
++facesCount;
|
||||
faceLoaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
CGUITTGlyph::CGUITTGlyph()
|
||||
: cached(false), face(0), image(0), texture(0), texture_mono(0),
|
||||
size(0), size_is_pixels(false), hasDefault(false), hasMonochrome(false)
|
||||
{
|
||||
}
|
||||
|
||||
CGUITTGlyph::~CGUITTGlyph()
|
||||
{
|
||||
if (image) delete[] image;
|
||||
if (texture) Driver->removeTexture(texture);
|
||||
if (texture_mono) Driver->removeTexture(texture_mono);
|
||||
}
|
||||
|
||||
void CGUITTGlyph::cache(u32 idx, bool fontHinting, bool autoHinting)
|
||||
{
|
||||
// Set the size of the glyph.
|
||||
if (size_is_pixels)
|
||||
FT_Set_Pixel_Sizes(*face, 0, size);
|
||||
else
|
||||
FT_Set_Char_Size(*face, size * 64, size * 64, 0, 0);
|
||||
|
||||
FT_Int32 loadFlags = FT_LOAD_DEFAULT;
|
||||
if (!fontHinting) loadFlags |= FT_LOAD_NO_HINTING;
|
||||
if (!autoHinting) loadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||
if (!FT_Load_Glyph(*face, idx, loadFlags))
|
||||
{
|
||||
hasDefault = true;
|
||||
FT_GlyphSlot glyph = (*face)->glyph;
|
||||
FT_Bitmap bits;
|
||||
FT_Error err = 0;
|
||||
if (glyph->format != FT_GLYPH_FORMAT_BITMAP)
|
||||
err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
// Generate the image.
|
||||
bits = glyph->bitmap;
|
||||
u8 *pt = bits.buffer;
|
||||
image = new u8[bits.width * bits.rows];
|
||||
memcpy(image, pt, bits.width * bits.rows);
|
||||
|
||||
// Bitmap information.
|
||||
bitmap.top = glyph->bitmap_top;
|
||||
bitmap.left = glyph->bitmap_left;
|
||||
bitmap.width = bits.width;
|
||||
bitmap.height = bits.rows;
|
||||
|
||||
// Initialize the texture information.
|
||||
texture_size.set(1, 1);
|
||||
|
||||
// Determine what our texture size should be.
|
||||
// Keep multiplying by 2 until we get it.
|
||||
while (texture_size.Width <= bitmap.width)
|
||||
texture_size.Width <<= 1;
|
||||
while (texture_size.Height <= bitmap.height)
|
||||
texture_size.Height <<= 1;
|
||||
|
||||
// Square our texture.
|
||||
if (texture_size.Height < texture_size.Width)
|
||||
texture_size.Height = texture_size.Width;
|
||||
else texture_size.Width = texture_size.Height;
|
||||
|
||||
// Create our texture data.
|
||||
u32 *texture_data = new u32[texture_size.Width * texture_size.Height];
|
||||
memset(texture_data, 0, texture_size.Width * texture_size.Height * sizeof(u32));
|
||||
u32 *texp = texture_data;
|
||||
bool cflag = (Driver->getDriverType() == video::EDT_DIRECT3D8);
|
||||
for (int i = 0; i < bits.rows; i++)
|
||||
{
|
||||
u32 *rowp = texp;
|
||||
for (int j = 0; j < bits.width; j++)
|
||||
{
|
||||
if (*pt)
|
||||
{
|
||||
if (cflag)
|
||||
{
|
||||
*rowp = *pt;
|
||||
*rowp *= 0x01010101;
|
||||
}
|
||||
else
|
||||
{
|
||||
*rowp = *pt << 24;
|
||||
*rowp |= 0x00ffffff;
|
||||
}
|
||||
}
|
||||
else *rowp = 0;
|
||||
pt++;
|
||||
rowp++;
|
||||
}
|
||||
texp += texture_size.Width;
|
||||
}
|
||||
|
||||
// Name our texture.
|
||||
c8 name[128];
|
||||
sprintf(name, "TTFontGlyph%d", idx);
|
||||
|
||||
// Create our texture.
|
||||
video::IImage *img = Driver->createImageFromData(video::ECF_A8R8G8B8, core::dimension2d<u32>(texture_size.Width, texture_size.Height), texture_data);
|
||||
bool flg16 = Driver->getTextureCreationFlag(video::ETCF_ALWAYS_16_BIT);
|
||||
bool flg32 = Driver->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT);
|
||||
bool flgmip = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT, false);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
|
||||
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
|
||||
if (texture) Driver->removeTexture(texture);
|
||||
texture = Driver->addTexture(name, img);
|
||||
img->drop();
|
||||
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, flgmip);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, flg32);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT, flg16);
|
||||
delete[] texture_data;
|
||||
|
||||
// Set our glyph as "cached".
|
||||
cached = true;
|
||||
}
|
||||
}
|
||||
|
||||
loadFlags = FT_LOAD_RENDER | FT_LOAD_MONOCHROME;
|
||||
if (!fontHinting) loadFlags |= FT_LOAD_NO_HINTING;
|
||||
if (!autoHinting) loadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||
if (fontHinting || autoHinting) loadFlags |= FT_LOAD_TARGET_MONO;
|
||||
if (!FT_Load_Glyph(*face, idx, loadFlags))
|
||||
{
|
||||
hasMonochrome = true;
|
||||
FT_GlyphSlot glyph = (*face)->glyph;
|
||||
FT_Bitmap bits = glyph->bitmap;
|
||||
u8 *pt = bits.buffer;
|
||||
|
||||
// Bitmap information.
|
||||
bitmap_mono.top = glyph->bitmap_top;
|
||||
bitmap_mono.left = glyph->bitmap_left;
|
||||
bitmap_mono.width = bits.width;
|
||||
bitmap_mono.height = bits.rows;
|
||||
|
||||
// Initialize the texture information.
|
||||
texture_mono_size.set(1, 1);
|
||||
|
||||
// Determine what our texture size should be.
|
||||
// Keep multiplying by 2 until we get it.
|
||||
while (texture_mono_size.Width <= bitmap_mono.width)
|
||||
texture_mono_size.Width <<= 1;
|
||||
while (texture_mono_size.Height <= bitmap_mono.height)
|
||||
texture_mono_size.Height <<= 1;
|
||||
|
||||
// Square our texture.
|
||||
if (texture_mono_size.Height < texture_mono_size.Width)
|
||||
texture_mono_size.Height = texture_mono_size.Width;
|
||||
else texture_mono_size.Width = texture_mono_size.Height;
|
||||
|
||||
// Create our texture data.
|
||||
u16 *texture_mono_data = new u16[texture_mono_size.Width * texture_mono_size.Height];
|
||||
memset(texture_mono_data, 0, texture_mono_size.Width * texture_mono_size.Height * sizeof(u16));
|
||||
u16 *texpm = texture_mono_data;
|
||||
for (int y = 0; y < bits.rows; y++)
|
||||
{
|
||||
u16 *rowp = texpm;
|
||||
for (int x = 0; x < bits.width; x++)
|
||||
{
|
||||
if (pt[y * bits.pitch + (x / 8)] & (0x80 >> (x % 8)))
|
||||
*rowp = 0xffff;
|
||||
rowp++;
|
||||
}
|
||||
texpm += texture_mono_size.Width;
|
||||
}
|
||||
|
||||
// Name our texture.
|
||||
c8 name[128];
|
||||
sprintf(name, "TTFontGlyph%d_mono", idx);
|
||||
|
||||
// Create our texture.
|
||||
video::IImage *img = Driver->createImageFromData(video::ECF_A1R5G5B5, core::dimension2d<u32>(texture_mono_size.Width, texture_mono_size.Height), texture_mono_data);
|
||||
bool flg16 = Driver->getTextureCreationFlag(video::ETCF_ALWAYS_16_BIT);
|
||||
bool flg32 = Driver->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT);
|
||||
bool flgmip = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT,true);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,false);
|
||||
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,false);
|
||||
if (texture_mono) Driver->removeTexture(texture_mono);
|
||||
texture_mono = Driver->addTexture(name, img);
|
||||
img->drop();
|
||||
Driver->makeColorKeyTexture(texture_mono, video::SColor(0,0,0,0));
|
||||
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,flgmip);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,flg32);
|
||||
Driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT,flg16);
|
||||
delete[] texture_mono_data;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
//! constructor
|
||||
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
||||
: AntiAlias(true), Transparency(true), FontHinting(true), AutoHinting(true),
|
||||
Environment(env), Driver(0), tt_face(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUITTFont");
|
||||
#endif
|
||||
|
||||
if (Environment)
|
||||
{
|
||||
// don't grab environment, to avoid circular references
|
||||
Driver = Environment->getVideoDriver();
|
||||
}
|
||||
|
||||
if (Driver)
|
||||
Driver->grab();
|
||||
|
||||
setInvisibleCharacters ( L" " );
|
||||
|
||||
// Glyphs isn't reference counted, so don't try to delete when we free the array.
|
||||
Glyphs.set_free_when_destroyed(false);
|
||||
}
|
||||
|
||||
//! destructor
|
||||
CGUITTFont::~CGUITTFont()
|
||||
{
|
||||
Glyphs.clear();
|
||||
if (Driver)
|
||||
Driver->drop();
|
||||
}
|
||||
|
||||
bool CGUITTFont::attach(CGUITTFace *face, u32 size, bool size_is_pixels)
|
||||
{
|
||||
if (!Driver)
|
||||
return false;
|
||||
|
||||
tt_face = face;
|
||||
|
||||
Glyphs.reallocate(tt_face->face->num_glyphs);
|
||||
Glyphs.set_used(tt_face->face->num_glyphs);
|
||||
for (int i = 0; i < tt_face->face->num_glyphs; i++)
|
||||
{
|
||||
Glyphs[i].Driver = Driver;
|
||||
Glyphs[i].size = size;
|
||||
Glyphs[i].size_is_pixels = size_is_pixels;
|
||||
Glyphs[i].face = &(tt_face->face);
|
||||
Glyphs[i].cached = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
|
||||
{
|
||||
if (!Driver)
|
||||
return;
|
||||
|
||||
core::dimension2d<s32> textDimension;
|
||||
core::position2d<s32> offset = position.UpperLeftCorner;
|
||||
video::SColor colors[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
colors[i] = color;
|
||||
|
||||
if (hcenter || vcenter)
|
||||
{
|
||||
textDimension = getDimension(text.c_str());
|
||||
|
||||
if (hcenter)
|
||||
offset.X = ((position.getWidth() - textDimension.Width) >> 1) + offset.X;
|
||||
|
||||
if (vcenter)
|
||||
offset.Y = ((position.getHeight() - textDimension.Height) >> 1) + offset.Y;
|
||||
}
|
||||
|
||||
u32 n;
|
||||
|
||||
wchar_t previousChar = 0;
|
||||
const wchar_t* ptext = text.c_str();
|
||||
while (*ptext)
|
||||
{
|
||||
wchar_t currentChar = *ptext;
|
||||
n = getGlyphByChar(currentChar);
|
||||
bool visible = (Invisible.findFirst(currentChar) == -1);
|
||||
if (n > 0 && visible)
|
||||
{
|
||||
bool lineBreak=false;
|
||||
if (currentChar == L'\r') // Mac or Windows breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
if (*(ptext + 1) == L'\n') // Windows breaks
|
||||
currentChar = *(++ptext);
|
||||
}
|
||||
else if (currentChar == L'\n') // Unix breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
}
|
||||
|
||||
if (lineBreak)
|
||||
{
|
||||
offset.Y += Glyphs[0].size;
|
||||
offset.X = position.UpperLeftCorner.X;
|
||||
|
||||
if (hcenter)
|
||||
{
|
||||
core::dimension2d<u32> lineDim = getDimension(text.c_str());
|
||||
offset.X += (position.getWidth() - lineDim.Width) >> 1;
|
||||
}
|
||||
++ptext;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only use the 256-color font if we are anti-aliasing, or if there was no monochrome font.
|
||||
if (AntiAlias || !Glyphs[n-1].hasMonochrome)
|
||||
{
|
||||
u32 texw = Glyphs[n-1].texture_size.Width;
|
||||
u32 texh = Glyphs[n-1].texture_size.Height;
|
||||
u32 bmpw = Glyphs[n-1].bitmap.width;
|
||||
u32 bmph = Glyphs[n-1].bitmap.height;
|
||||
s32 offx = Glyphs[n-1].bitmap.left;
|
||||
s32 offy = Glyphs[n-1].size - Glyphs[n-1].bitmap.top;
|
||||
|
||||
// Apply kerning.
|
||||
core::vector2di k = getKerning(currentChar, previousChar);
|
||||
offset.X += k.X;
|
||||
offset.Y += k.Y;
|
||||
|
||||
if (Driver->getDriverType() != video::EDT_SOFTWARE)
|
||||
{
|
||||
if (!Transparency) color.color |= 0xff000000;
|
||||
Driver->draw2DImage(Glyphs[n-1].texture, core::position2d<s32>(offset.X + offx, offset.Y + offy), core::rect<s32>(0, 0, texw-1, texh-1), clip, color, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Software driver doesn't do transparency correctly, so if we are using the driver,
|
||||
// we must manually apply the transparency.
|
||||
u32 a = color.getAlpha();
|
||||
u32 r = color.getRed();
|
||||
u32 g = color.getGreen();
|
||||
u32 b = color.getBlue();
|
||||
u8 *pt = Glyphs[n-1].image;
|
||||
if (!Transparency) a = 255;
|
||||
for (u32 y = 0; y < bmph; y++)
|
||||
{
|
||||
for (u32 x = 0; x < bmpw; x++)
|
||||
{
|
||||
if (!clip || clip->isPointInside(core::position2d<s32>(offset.X + x + offx, offset.Y + y + offy)))
|
||||
{
|
||||
if (*pt)
|
||||
{
|
||||
Driver->draw2DRectangle(video::SColor((a * (*pt)) / 255, r, g, b), core::rect<s32>(offset.X + x + offx, offset.Y + y + offy, offset.X + x + offx + 1, offset.Y + y + offy + 1));
|
||||
}
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Glyphs[n-1].hasMonochrome)
|
||||
{
|
||||
u32 texw = Glyphs[n-1].texture_mono_size.Width;
|
||||
u32 texh = Glyphs[n-1].texture_mono_size.Height;
|
||||
s32 offx = Glyphs[n-1].bitmap_mono.left;
|
||||
s32 offy = Glyphs[n-1].size - Glyphs[n-1].bitmap_mono.top;
|
||||
|
||||
// Apply kerning.
|
||||
core::vector2di k = getKerning(currentChar, previousChar);
|
||||
offset.X += k.X;
|
||||
offset.Y += k.Y;
|
||||
|
||||
if (!Transparency) color.color |= 0xff000000;
|
||||
Driver->draw2DImage(Glyphs[n-1].texture_mono, core::position2d<s32>(offset.X + offx, offset.Y + offy), core::rect<s32>(0, 0, texw - 1, texh - 1), clip, color, true);
|
||||
}
|
||||
offset.X += getWidthFromCharacter(currentChar);
|
||||
}
|
||||
else offset.X += getWidthFromCharacter(currentChar);
|
||||
|
||||
previousChar = currentChar;
|
||||
++ptext;
|
||||
}
|
||||
}
|
||||
|
||||
core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
|
||||
{
|
||||
// Get the maximum font height. Unfortunately, we have to do this hack as
|
||||
// Irrlicht will draw things wrong. In FreeType, the font size is the
|
||||
// maximum size for a single glyph, but that glyph may hang "under" the
|
||||
// draw line, increasing the total font height to beyond the set size.
|
||||
// Irrlicht does not understand this concept when drawing fonts. Also, I
|
||||
// add +1 to give it a 1 pixel blank border. This makes things like
|
||||
// tooltips look nicer.
|
||||
s32 test1 = getHeightFromCharacter(L'g') + 1;
|
||||
s32 test2 = getHeightFromCharacter(L'j') + 1;
|
||||
s32 test3 = getHeightFromCharacter(L'_') + 1;
|
||||
s32 max_font_height = core::max_(test1, core::max_(test2, test3));
|
||||
|
||||
core::dimension2d<u32> dim(0, max_font_height);
|
||||
core::dimension2d<u32> thisLine(0, max_font_height);
|
||||
|
||||
wchar_t previousChar = 0;
|
||||
for (const wchar_t* p = text; *p; ++p)
|
||||
{
|
||||
bool lineBreak=false;
|
||||
if (*p == L'\r') // Mac or Windows breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
if (p[1] == L'\n') // Windows breaks
|
||||
++p;
|
||||
}
|
||||
else if (*p == L'\n') // Unix breaks
|
||||
{
|
||||
lineBreak = true;
|
||||
}
|
||||
|
||||
// Kerning.
|
||||
core::vector2di k = getKerning(*p, previousChar);
|
||||
thisLine.Width += k.X;
|
||||
previousChar = *p;
|
||||
|
||||
// Check for linebreak.
|
||||
if (lineBreak)
|
||||
{
|
||||
previousChar = 0;
|
||||
dim.Height += thisLine.Height;
|
||||
if (dim.Width < thisLine.Width)
|
||||
dim.Width = thisLine.Width;
|
||||
thisLine.Width = 0;
|
||||
thisLine.Height = max_font_height;
|
||||
continue;
|
||||
}
|
||||
thisLine.Width += getWidthFromCharacter(*p);
|
||||
}
|
||||
if (dim.Width < thisLine.Width)
|
||||
dim.Width = thisLine.Width;
|
||||
|
||||
return dim;
|
||||
}
|
||||
|
||||
inline u32 CGUITTFont::getWidthFromCharacter(wchar_t c) const
|
||||
{
|
||||
u32 n = getGlyphByChar(c);
|
||||
if (n > 0)
|
||||
{
|
||||
int w = Glyphs[n - 1].bitmap.width;
|
||||
s32 left = Glyphs[n - 1].bitmap.left;
|
||||
if (w + left > 0) return w + left;
|
||||
}
|
||||
if (c >= 0x2000)
|
||||
return Glyphs[0].size;
|
||||
else return Glyphs[0].size / 2;
|
||||
}
|
||||
|
||||
inline u32 CGUITTFont::getHeightFromCharacter(wchar_t c) const
|
||||
{
|
||||
u32 n = getGlyphByChar(c);
|
||||
if (n > 0)
|
||||
{
|
||||
// Grab the true height of the character, taking into account underhanging glyphs.
|
||||
s32 height = Glyphs[n-1].size - Glyphs[n-1].bitmap.top + Glyphs[n-1].bitmap.height;
|
||||
return height;
|
||||
}
|
||||
if (c >= 0x2000)
|
||||
return Glyphs[0].size;
|
||||
else return Glyphs[0].size / 2;
|
||||
}
|
||||
|
||||
u32 CGUITTFont::getGlyphByChar(wchar_t c) const
|
||||
{
|
||||
u32 idx = FT_Get_Char_Index(tt_face->face, c);
|
||||
|
||||
// If the glyph hasn't been loaded yet, do it now.
|
||||
if (idx && !Glyphs[idx - 1].cached)
|
||||
Glyphs[idx - 1].cache(idx, FontHinting, AutoHinting);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
s32 CGUITTFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
|
||||
{
|
||||
s32 x = 0;
|
||||
s32 idx = 0;
|
||||
|
||||
while (text[idx])
|
||||
{
|
||||
x += getWidthFromCharacter(text[idx]);
|
||||
|
||||
if (x >= pixel_x)
|
||||
return idx;
|
||||
|
||||
++idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CGUITTFont::setKerningWidth(s32 kerning)
|
||||
{
|
||||
GlobalKerningWidth = kerning;
|
||||
}
|
||||
|
||||
void CGUITTFont::setKerningHeight(s32 kerning)
|
||||
{
|
||||
GlobalKerningHeight = kerning;
|
||||
}
|
||||
|
||||
s32 CGUITTFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const
|
||||
{
|
||||
if (tt_face == 0)
|
||||
return GlobalKerningWidth;
|
||||
if (thisLetter == 0 || previousLetter == 0)
|
||||
return 0;
|
||||
|
||||
// Return only the kerning width.
|
||||
return getKerning(*thisLetter, *previousLetter).X;
|
||||
}
|
||||
|
||||
s32 CGUITTFont::getKerningHeight() const
|
||||
{
|
||||
// FreeType 2 currently doesn't return any height kerning information.
|
||||
return GlobalKerningHeight;
|
||||
}
|
||||
|
||||
core::vector2di CGUITTFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
||||
{
|
||||
if (tt_face == 0 || thisLetter == 0 || previousLetter == 0)
|
||||
return core::vector2di();
|
||||
|
||||
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
|
||||
|
||||
// Grab the face's flags to determine if the font is scalable or not.
|
||||
FT_Long flags = tt_face->face->face_flags;
|
||||
bool scalable = ((flags & FT_FACE_FLAG_SCALABLE) != 0);
|
||||
|
||||
// Get the kerning information.
|
||||
FT_Vector v;
|
||||
FT_Get_Kerning(tt_face->face, getGlyphByChar(previousLetter), getGlyphByChar(thisLetter), FT_KERNING_DEFAULT, &v);
|
||||
|
||||
// If we have a scalable font, the return value will be in font points.
|
||||
if (scalable)
|
||||
{
|
||||
// Font points, so divide by 64.
|
||||
ret.X += (v.x / 64);
|
||||
ret.Y += (v.y / 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pixel units.
|
||||
ret.X += v.x;
|
||||
ret.Y += v.y;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CGUITTFont::setInvisibleCharacters( const wchar_t *s )
|
||||
{
|
||||
Invisible = s;
|
||||
}
|
||||
|
||||
} // end namespace gui
|
||||
} // end namespace irr
|
|
@ -0,0 +1,169 @@
|
|||
#ifndef __C_GUI_TTFONT_H_INCLUDED__
|
||||
#define __C_GUI_TTFONT_H_INCLUDED__
|
||||
|
||||
#include <irrlicht.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace gui
|
||||
{
|
||||
//! Represents a font face.
|
||||
class CGUITTFace : public virtual IReferenceCounted
|
||||
{
|
||||
public:
|
||||
CGUITTFace();
|
||||
virtual ~CGUITTFace();
|
||||
|
||||
//! Loads a font face.
|
||||
//! \param filename Path to the font face.
|
||||
//! \param filesystem The Irrlicht filesystem to use. If 0, fonts will be loaded into memory by FreeType instead of by Irrlicht.
|
||||
//! \return Returns true if the font face loaded, false if it failed to load.
|
||||
bool load(const io::path& filename, io::IFileSystem* filesystem = 0);
|
||||
|
||||
//! The font face.
|
||||
FT_Face face;
|
||||
|
||||
private:
|
||||
//! Flag to load the library.
|
||||
static bool libraryLoaded;
|
||||
bool faceLoaded;
|
||||
FT_Byte* font_buffer;
|
||||
FT_Long font_size;
|
||||
};
|
||||
|
||||
//! Represents a glyph's bitmap info.
|
||||
struct CGUITTBitmapInfo
|
||||
{
|
||||
u32 top;
|
||||
u32 left;
|
||||
u32 width;
|
||||
u32 height;
|
||||
};
|
||||
|
||||
//! Class representing a single glyph.
|
||||
class CGUITTGlyph
|
||||
{
|
||||
public:
|
||||
CGUITTGlyph();
|
||||
virtual ~CGUITTGlyph();
|
||||
|
||||
//! Loads the glyph.
|
||||
void cache(u32 idx, bool fontHinting, bool autoHinting);
|
||||
|
||||
//! Informs if the glyph was loaded.
|
||||
bool cached;
|
||||
|
||||
//! Video driver.
|
||||
video::IVideoDriver* Driver;
|
||||
|
||||
//! The face.
|
||||
FT_Face *face;
|
||||
|
||||
//! The image data.
|
||||
//! Used for rendering with the software engine.
|
||||
u8* image;
|
||||
|
||||
// Texture/image data.
|
||||
video::ITexture *texture;
|
||||
video::ITexture *texture_mono;
|
||||
|
||||
// Size of the glyph.
|
||||
u32 size;
|
||||
|
||||
// The size of the glyph is expressed in pixels.
|
||||
bool size_is_pixels;
|
||||
|
||||
// Info.
|
||||
bool hasDefault;
|
||||
bool hasMonochrome;
|
||||
|
||||
// Bitmap information.
|
||||
CGUITTBitmapInfo bitmap;
|
||||
CGUITTBitmapInfo bitmap_mono;
|
||||
|
||||
// Texture information.
|
||||
core::dimension2du texture_size;
|
||||
core::dimension2du texture_mono_size;
|
||||
};
|
||||
|
||||
//! Class representing a font.
|
||||
class CGUITTFont : public IGUIFont
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
CGUITTFont(IGUIEnvironment *env);
|
||||
|
||||
//! Destructor
|
||||
virtual ~CGUITTFont();
|
||||
|
||||
//! Binds a font face to the class.
|
||||
//! \param face The font face to attach.
|
||||
//! \param size The size you want to load the font at.
|
||||
//! \param size_is_pixels If true, size is represented as pixels instead of points.
|
||||
bool attach(CGUITTFace *face, u32 size, bool size_is_pixels = false);
|
||||
|
||||
//! Draws some text and clips it to the specified rectangle if wanted.
|
||||
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
//! Returns the dimension of a text string.
|
||||
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const;
|
||||
|
||||
//! Calculates the index of the character in the text which is on a specific position.
|
||||
virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const;
|
||||
|
||||
//! Sets global kerning width for the font.
|
||||
virtual void setKerningWidth(s32 kerning);
|
||||
|
||||
//! Sets global kerning height for the font.
|
||||
virtual void setKerningHeight(s32 kerning);
|
||||
|
||||
//! Gets kerning values (distance between letters) for the font. If no parameters are provided,
|
||||
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const;
|
||||
|
||||
//! Returns the distance between letters
|
||||
virtual s32 getKerningHeight() const;
|
||||
|
||||
//! Define which characters should not be drawn by the font.
|
||||
virtual void setInvisibleCharacters(const wchar_t *s);
|
||||
|
||||
//! Determines if the font will be loaded with antialiasing.
|
||||
//! Defaults true.
|
||||
bool AntiAlias;
|
||||
|
||||
//! Determines if the font will be drawn with transparency.
|
||||
//! Defaults true.
|
||||
bool Transparency;
|
||||
|
||||
//! Turns font hinting on or off. If a font looks odd, try toggling this option.
|
||||
//! This setting controls whether or not FreeType uses a font's built-in hinting.
|
||||
//! Defaults true.
|
||||
bool FontHinting;
|
||||
|
||||
//! Turns FreeType auto-hinting on or off. If a font looks odd, try toggling this option.
|
||||
//! This setting controls whether or not FreeType uses its built-in auto hinting.
|
||||
//! Defaults to true.
|
||||
bool AutoHinting;
|
||||
|
||||
private:
|
||||
u32 getWidthFromCharacter(wchar_t c) const;
|
||||
u32 getHeightFromCharacter(wchar_t c) const;
|
||||
u32 getGlyphByChar(wchar_t c) const;
|
||||
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const;
|
||||
|
||||
gui::IGUIEnvironment* Environment;
|
||||
video::IVideoDriver* Driver;
|
||||
mutable core::array< CGUITTGlyph > Glyphs;
|
||||
CGUITTFace *tt_face;
|
||||
s32 GlobalKerningWidth;
|
||||
s32 GlobalKerningHeight;
|
||||
core::stringw Invisible;
|
||||
};
|
||||
|
||||
} // end namespace gui
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue