mirror of
https://github.com/minetest/minetest.git
synced 2025-03-06 20:48:40 +01:00
IGUIFont / CGUITTFont code cleanups (#15581)
This commit is contained in:
parent
0bfd9bc09e
commit
c49ff76955
12 changed files with 135 additions and 626 deletions
|
@ -53,7 +53,7 @@ public:
|
||||||
//! Calculates the width and height of a given string of text.
|
//! Calculates the width and height of a given string of text.
|
||||||
/** \return Returns width and height of the area covered by the text if
|
/** \return Returns width and height of the area covered by the text if
|
||||||
it would be drawn. */
|
it would be drawn. */
|
||||||
virtual core::dimension2d<u32> getDimension(const wchar_t *text) const = 0;
|
virtual core::dimension2du getDimension(const wchar_t *text) const = 0;
|
||||||
|
|
||||||
//! Calculates the index of the character in the text which is on a specific position.
|
//! Calculates the index of the character in the text which is on a specific position.
|
||||||
/** \param text: Text string.
|
/** \param text: Text string.
|
||||||
|
@ -82,10 +82,7 @@ public:
|
||||||
which supports kerning pairs a string such as 'Wo' may have the 'o'
|
which supports kerning pairs a string such as 'Wo' may have the 'o'
|
||||||
tucked neatly under the 'W'.
|
tucked neatly under the 'W'.
|
||||||
*/
|
*/
|
||||||
virtual s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const = 0;
|
virtual core::vector2di getKerning(const wchar_t thisLetter = 0, const wchar_t previousLetter = 0) const = 0;
|
||||||
|
|
||||||
//! Returns the distance between letters
|
|
||||||
virtual s32 getKerningHeight() const = 0;
|
|
||||||
|
|
||||||
//! Define which characters should not be drawn by the font.
|
//! Define which characters should not be drawn by the font.
|
||||||
/** For example " " would not draw any space which is usually blank in
|
/** For example " " would not draw any space which is usually blank in
|
||||||
|
|
|
@ -24,17 +24,6 @@ public:
|
||||||
|
|
||||||
//! returns the sprite number from a given character
|
//! returns the sprite number from a given character
|
||||||
virtual u32 getSpriteNoFromChar(const wchar_t *c) const = 0;
|
virtual u32 getSpriteNoFromChar(const wchar_t *c) const = 0;
|
||||||
|
|
||||||
//! Gets kerning values (distance between letters) for the font. If no parameters are provided,
|
|
||||||
/** the global kerning distance is returned.
|
|
||||||
\param thisLetter: If this parameter is provided, the left side kerning for this letter is added
|
|
||||||
to the global kerning value. For example, a space might only be one pixel wide, but it may
|
|
||||||
be displayed as several pixels.
|
|
||||||
\param previousLetter: If provided, kerning is calculated for both letters and added to the global
|
|
||||||
kerning value. For example, EGFT_BITMAP will add the right kerning value of previousLetter to the
|
|
||||||
left side kerning value of thisLetter, then add the global value.
|
|
||||||
*/
|
|
||||||
s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const override = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace gui
|
} // end namespace gui
|
||||||
|
|
|
@ -788,9 +788,9 @@ void CGUIEditBox::draw()
|
||||||
mbegin = font->getDimension(s.c_str()).Width;
|
mbegin = font->getDimension(s.c_str()).Width;
|
||||||
|
|
||||||
// deal with kerning
|
// deal with kerning
|
||||||
mbegin += font->getKerningWidth(
|
mbegin += font->getKerning(
|
||||||
&((*txtLine)[realmbgn - startPos]),
|
(*txtLine)[realmbgn - startPos],
|
||||||
realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0);
|
realmbgn - startPos > 0 ? (*txtLine)[realmbgn - startPos - 1] : 0).X;
|
||||||
|
|
||||||
lineStartPos = realmbgn - startPos;
|
lineStartPos = realmbgn - startPos;
|
||||||
}
|
}
|
||||||
|
@ -832,7 +832,8 @@ void CGUIEditBox::draw()
|
||||||
}
|
}
|
||||||
s = txtLine->subString(0, CursorPos - startPos);
|
s = txtLine->subString(0, CursorPos - startPos);
|
||||||
charcursorpos = font->getDimension(s.c_str()).Width +
|
charcursorpos = font->getDimension(s.c_str()).Width +
|
||||||
font->getKerningWidth(CursorChar.c_str(), CursorPos - startPos > 0 ? &((*txtLine)[CursorPos - startPos - 1]) : 0);
|
font->getKerning(CursorChar[0],
|
||||||
|
CursorPos - startPos > 0 ? (*txtLine)[CursorPos - startPos - 1] : 0).X;
|
||||||
|
|
||||||
if (focus && (CursorBlinkTime == 0 || (os::Timer::getTime() - BlinkStartTime) % (2 * CursorBlinkTime) < CursorBlinkTime)) {
|
if (focus && (CursorBlinkTime == 0 || (os::Timer::getTime() - BlinkStartTime) % (2 * CursorBlinkTime) < CursorBlinkTime)) {
|
||||||
setTextRect(cursorLine);
|
setTextRect(cursorLine);
|
||||||
|
@ -1194,7 +1195,7 @@ void CGUIEditBox::setTextRect(s32 line)
|
||||||
d = font->getDimension(Text.c_str());
|
d = font->getDimension(Text.c_str());
|
||||||
d.Height = AbsoluteRect.getHeight();
|
d.Height = AbsoluteRect.getHeight();
|
||||||
}
|
}
|
||||||
d.Height += font->getKerningHeight();
|
d.Height += font->getKerning(L'A').Y;
|
||||||
|
|
||||||
// justification
|
// justification
|
||||||
switch (HAlign) {
|
switch (HAlign) {
|
||||||
|
@ -1382,7 +1383,7 @@ void CGUIEditBox::calculateScrollPos()
|
||||||
|
|
||||||
// calculate vertical scrolling
|
// calculate vertical scrolling
|
||||||
if (hasBrokenText) {
|
if (hasBrokenText) {
|
||||||
irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerningHeight();
|
irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
// only up to 1 line fits?
|
// only up to 1 line fits?
|
||||||
if (lineHeight >= (irr::u32)FrameRect.getHeight()) {
|
if (lineHeight >= (irr::u32)FrameRect.getHeight()) {
|
||||||
VScrollPos = 0;
|
VScrollPos = 0;
|
||||||
|
|
|
@ -53,141 +53,6 @@ CGUIFont::~CGUIFont()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
//! loads a font file from xml
|
|
||||||
bool CGUIFont::load(io::IXMLReader* xml, const io::path& directory)
|
|
||||||
{
|
|
||||||
if (!SpriteBank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SpriteBank->clear();
|
|
||||||
|
|
||||||
while (xml->read())
|
|
||||||
{
|
|
||||||
if (io::EXN_ELEMENT == xml->getNodeType())
|
|
||||||
{
|
|
||||||
if (core::stringw(L"Texture") == xml->getNodeName())
|
|
||||||
{
|
|
||||||
// add a texture
|
|
||||||
core::stringc fn = xml->getAttributeValue(L"filename");
|
|
||||||
u32 i = (u32)xml->getAttributeValueAsInt(L"index");
|
|
||||||
core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
|
|
||||||
|
|
||||||
while (i+1 > SpriteBank->getTextureCount())
|
|
||||||
SpriteBank->addTexture(0);
|
|
||||||
|
|
||||||
bool flags[3];
|
|
||||||
pushTextureCreationFlags(flags);
|
|
||||||
|
|
||||||
// load texture
|
|
||||||
io::path textureFullName = core::mergeFilename(directory, fn);
|
|
||||||
SpriteBank->setTexture(i, Driver->getTexture(textureFullName));
|
|
||||||
|
|
||||||
popTextureCreationFlags(flags);
|
|
||||||
|
|
||||||
// couldn't load texture, abort.
|
|
||||||
if (!SpriteBank->getTexture(i))
|
|
||||||
{
|
|
||||||
os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// colorkey texture rather than alpha channel?
|
|
||||||
if (alpha == core::stringw("false"))
|
|
||||||
Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (core::stringw(L"c") == xml->getNodeName())
|
|
||||||
{
|
|
||||||
// adding a character to this font
|
|
||||||
SFontArea a;
|
|
||||||
SGUISpriteFrame f;
|
|
||||||
SGUISprite s;
|
|
||||||
core::rect<s32> rectangle;
|
|
||||||
|
|
||||||
a.underhang = xml->getAttributeValueAsInt(L"u");
|
|
||||||
a.overhang = xml->getAttributeValueAsInt(L"o");
|
|
||||||
a.spriteno = SpriteBank->getSprites().size();
|
|
||||||
s32 texno = xml->getAttributeValueAsInt(L"i");
|
|
||||||
|
|
||||||
// parse rectangle
|
|
||||||
core::stringc rectstr = xml->getAttributeValue(L"r");
|
|
||||||
wchar_t ch = xml->getAttributeValue(L"c")[0];
|
|
||||||
|
|
||||||
const c8 *c = rectstr.c_str();
|
|
||||||
s32 val;
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.UpperLeftCorner.X = val;
|
|
||||||
while (*c == L' ' || *c == L',') c++;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.UpperLeftCorner.Y = val;
|
|
||||||
while (*c == L' ' || *c == L',') c++;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.LowerRightCorner.X = val;
|
|
||||||
while (*c == L' ' || *c == L',') c++;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
while (*c >= '0' && *c <= '9')
|
|
||||||
{
|
|
||||||
val *= 10;
|
|
||||||
val += *c - '0';
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
rectangle.LowerRightCorner.Y = val;
|
|
||||||
|
|
||||||
CharacterMap.emplace(ch, Areas.size());
|
|
||||||
|
|
||||||
// make frame
|
|
||||||
f.rectNumber = SpriteBank->getPositions().size();
|
|
||||||
f.textureNumber = texno;
|
|
||||||
|
|
||||||
// add frame to sprite
|
|
||||||
s.Frames.push_back(f);
|
|
||||||
s.frameTime = 0;
|
|
||||||
|
|
||||||
// add rectangle to sprite bank
|
|
||||||
SpriteBank->getPositions().push_back(rectangle);
|
|
||||||
a.width = rectangle.getWidth();
|
|
||||||
|
|
||||||
// add sprite to sprite bank
|
|
||||||
SpriteBank->getSprites().push_back(s);
|
|
||||||
|
|
||||||
// add character to font
|
|
||||||
Areas.push_back(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set bad character
|
|
||||||
WrongCharacter = getAreaFromCharacter(L' ');
|
|
||||||
|
|
||||||
setMaxHeight();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void CGUIFont::setMaxHeight()
|
void CGUIFont::setMaxHeight()
|
||||||
{
|
{
|
||||||
if (!SpriteBank)
|
if (!SpriteBank)
|
||||||
|
@ -365,17 +230,15 @@ void CGUIFont::setKerningWidth(s32 kerning)
|
||||||
GlobalKerningWidth = kerning;
|
GlobalKerningWidth = kerning;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! set an Pixel Offset on Drawing ( scale position on width )
|
core::vector2di CGUIFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
||||||
s32 CGUIFont::getKerningWidth(const wchar_t *thisLetter, const wchar_t *previousLetter) const
|
|
||||||
{
|
{
|
||||||
s32 ret = GlobalKerningWidth;
|
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
|
||||||
|
|
||||||
if (thisLetter) {
|
if (thisLetter) {
|
||||||
ret += Areas[getAreaFromCharacter(*thisLetter)].overhang;
|
ret.X += Areas[getAreaFromCharacter(thisLetter)].overhang;
|
||||||
|
|
||||||
if (previousLetter) {
|
if (previousLetter)
|
||||||
ret += Areas[getAreaFromCharacter(*previousLetter)].underhang;
|
ret.X += Areas[getAreaFromCharacter(previousLetter)].underhang;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -387,12 +250,6 @@ void CGUIFont::setKerningHeight(s32 kerning)
|
||||||
GlobalKerningHeight = kerning;
|
GlobalKerningHeight = kerning;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! set an Pixel Offset on Drawing ( scale position on height )
|
|
||||||
s32 CGUIFont::getKerningHeight() const
|
|
||||||
{
|
|
||||||
return GlobalKerningHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! returns the sprite number from a given character
|
//! returns the sprite number from a given character
|
||||||
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
|
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,8 +58,7 @@ public:
|
||||||
void setKerningHeight(s32 kerning) override;
|
void setKerningHeight(s32 kerning) override;
|
||||||
|
|
||||||
//! set an Pixel Offset on Drawing ( scale position on width )
|
//! set an Pixel Offset on Drawing ( scale position on width )
|
||||||
s32 getKerningWidth(const wchar_t *thisLetter = 0, const wchar_t *previousLetter = 0) const override;
|
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const override;
|
||||||
s32 getKerningHeight() const override;
|
|
||||||
|
|
||||||
//! gets the sprite bank
|
//! gets the sprite bank
|
||||||
IGUISpriteBank *getSpriteBank() const override;
|
IGUISpriteBank *getSpriteBank() const override;
|
||||||
|
|
|
@ -74,10 +74,12 @@ void CGUIStaticText::draw()
|
||||||
IGUIFont *font = getActiveFont();
|
IGUIFont *font = getActiveFont();
|
||||||
|
|
||||||
if (font) {
|
if (font) {
|
||||||
|
s32 kerningHeight = font->getKerning(L'A').Y;
|
||||||
|
|
||||||
if (!WordWrap) {
|
if (!WordWrap) {
|
||||||
if (VAlign == EGUIA_LOWERRIGHT) {
|
if (VAlign == EGUIA_LOWERRIGHT) {
|
||||||
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
|
||||||
font->getDimension(L"A").Height - font->getKerningHeight();
|
font->getDimension(L"A").Height - kerningHeight;
|
||||||
}
|
}
|
||||||
if (HAlign == EGUIA_LOWERRIGHT) {
|
if (HAlign == EGUIA_LOWERRIGHT) {
|
||||||
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
|
||||||
|
@ -92,7 +94,7 @@ void CGUIStaticText::draw()
|
||||||
breakText();
|
breakText();
|
||||||
|
|
||||||
core::rect<s32> r = frameRect;
|
core::rect<s32> r = frameRect;
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + kerningHeight;
|
||||||
s32 totalHeight = height * BrokenText.size();
|
s32 totalHeight = height * BrokenText.size();
|
||||||
if (VAlign == EGUIA_CENTER) {
|
if (VAlign == EGUIA_CENTER) {
|
||||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
||||||
|
@ -471,7 +473,7 @@ s32 CGUIStaticText::getTextHeight() const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (WordWrap) {
|
if (WordWrap) {
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
return height * BrokenText.size();
|
return height * BrokenText.size();
|
||||||
} else {
|
} else {
|
||||||
// TODO: Text can have multiple lines which are not in BrokenText
|
// TODO: Text can have multiple lines which are not in BrokenText
|
||||||
|
|
|
@ -140,7 +140,7 @@ unsigned int FontEngine::getLineHeight(const FontSpec &spec)
|
||||||
gui::IGUIFont *font = getFont(spec);
|
gui::IGUIFont *font = getFont(spec);
|
||||||
|
|
||||||
return font->getDimension(L"Some unimportant example String").Height
|
return font->getDimension(L"Some unimportant example String").Height
|
||||||
+ font->getKerningHeight();
|
+ font->getKerning(L'S').Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -194,9 +194,9 @@ void GUIEditBoxWithScrollBar::draw()
|
||||||
mbegin = font->getDimension(s.c_str()).Width;
|
mbegin = font->getDimension(s.c_str()).Width;
|
||||||
|
|
||||||
// deal with kerning
|
// deal with kerning
|
||||||
mbegin += font->getKerningWidth(
|
mbegin += font->getKerning(
|
||||||
&((*txt_line)[realmbgn - start_pos]),
|
(*txt_line)[realmbgn - start_pos],
|
||||||
realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
|
realmbgn - start_pos > 0 ? (*txt_line)[realmbgn - start_pos - 1] : 0).X;
|
||||||
|
|
||||||
lineStartPos = realmbgn - start_pos;
|
lineStartPos = realmbgn - start_pos;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,8 @@ void GUIEditBoxWithScrollBar::draw()
|
||||||
}
|
}
|
||||||
s = txt_line->subString(0, m_cursor_pos - start_pos);
|
s = txt_line->subString(0, m_cursor_pos - start_pos);
|
||||||
charcursorpos = font->getDimension(s.c_str()).Width +
|
charcursorpos = font->getDimension(s.c_str()).Width +
|
||||||
font->getKerningWidth(L"_", m_cursor_pos - start_pos > 0 ? &((*txt_line)[m_cursor_pos - start_pos - 1]) : 0);
|
font->getKerning(L'_',
|
||||||
|
m_cursor_pos - start_pos > 0 ? (*txt_line)[m_cursor_pos - start_pos - 1] : 0).X;
|
||||||
|
|
||||||
if (focus && (porting::getTimeMs() - m_blink_start_time) % 700 < 350) {
|
if (focus && (porting::getTimeMs() - m_blink_start_time) % 700 < 350) {
|
||||||
setTextRect(cursor_line);
|
setTextRect(cursor_line);
|
||||||
|
@ -431,7 +432,7 @@ void GUIEditBoxWithScrollBar::setTextRect(s32 line)
|
||||||
d = font->getDimension(Text.c_str());
|
d = font->getDimension(Text.c_str());
|
||||||
d.Height = AbsoluteRect.getHeight();
|
d.Height = AbsoluteRect.getHeight();
|
||||||
}
|
}
|
||||||
d.Height += font->getKerningHeight();
|
d.Height += font->getKerning(L'A').Y;
|
||||||
|
|
||||||
// justification
|
// justification
|
||||||
switch (m_halign) {
|
switch (m_halign) {
|
||||||
|
@ -536,7 +537,7 @@ void GUIEditBoxWithScrollBar::calculateScrollPos()
|
||||||
|
|
||||||
// calculate vertical scrolling
|
// calculate vertical scrolling
|
||||||
if (has_broken_text) {
|
if (has_broken_text) {
|
||||||
irr::u32 line_height = font->getDimension(L"A").Height + font->getKerningHeight();
|
irr::u32 line_height = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
// only up to 1 line fits?
|
// only up to 1 line fits?
|
||||||
if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
|
if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
|
||||||
m_vscroll_pos = 0;
|
m_vscroll_pos = 0;
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
*/
|
*/
|
||||||
static unsigned int font_line_height(gui::IGUIFont *font)
|
static unsigned int font_line_height(gui::IGUIFont *font)
|
||||||
{
|
{
|
||||||
return font->getDimension(L"Ay").Height + font->getKerningHeight();
|
return font->getDimension(L"Ay").Height + font->getKerning(L'A').Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 clamp_u8(s32 value)
|
inline u32 clamp_u8(s32 value)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
CGUITTFont FreeType class for Irrlicht
|
CGUITTFont FreeType class for Irrlicht
|
||||||
Copyright (c) 2009-2010 John Norman
|
Copyright (c) 2009-2010 John Norman
|
||||||
|
with changes from Luanti contributors:
|
||||||
Copyright (c) 2016 Nathanaëlle Courant
|
Copyright (c) 2016 Nathanaëlle Courant
|
||||||
Copyright (c) 2023 Caleb Butler
|
Copyright (c) 2023 Caleb Butler
|
||||||
|
|
||||||
|
@ -31,14 +32,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "log.h"
|
||||||
|
#include "filesys.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
#include "CGUITTFont.h"
|
#include "CGUITTFont.h"
|
||||||
#include "CMeshBuffer.h"
|
|
||||||
#include "IFileSystem.h"
|
#include "IFileSystem.h"
|
||||||
#include "IGUIEnvironment.h"
|
#include "IGUIEnvironment.h"
|
||||||
#include "IMeshManipulator.h"
|
|
||||||
#include "IMeshSceneNode.h"
|
|
||||||
#include "ISceneManager.h"
|
|
||||||
#include "ISceneNode.h"
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -46,9 +46,9 @@ namespace gui
|
||||||
{
|
{
|
||||||
|
|
||||||
// Manages the FT_Face cache.
|
// Manages the FT_Face cache.
|
||||||
struct SGUITTFace : public virtual irr::IReferenceCounted
|
struct SGUITTFace : public irr::IReferenceCounted
|
||||||
{
|
{
|
||||||
SGUITTFace() : face_buffer(0), face_buffer_size(0)
|
SGUITTFace()
|
||||||
{
|
{
|
||||||
memset((void*)&face, 0, sizeof(FT_Face));
|
memset((void*)&face, 0, sizeof(FT_Face));
|
||||||
}
|
}
|
||||||
|
@ -56,46 +56,29 @@ struct SGUITTFace : public virtual irr::IReferenceCounted
|
||||||
~SGUITTFace()
|
~SGUITTFace()
|
||||||
{
|
{
|
||||||
FT_Done_Face(face);
|
FT_Done_Face(face);
|
||||||
delete[] face_buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
FT_Byte* face_buffer;
|
std::string face_buffer;
|
||||||
FT_Long face_buffer_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static variables.
|
// Static variables.
|
||||||
FT_Library CGUITTFont::c_library;
|
FT_Library CGUITTFont::c_library;
|
||||||
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
|
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
|
||||||
bool CGUITTFont::c_libraryLoaded = false;
|
bool CGUITTFont::c_libraryLoaded = false;
|
||||||
scene::IMesh* CGUITTFont::shared_plane_ptr_ = 0;
|
|
||||||
scene::SMesh CGUITTFont::shared_plane_;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
/** Checks that no dimension of the FT_BitMap object is negative. If either is
|
|
||||||
* negative, abort execution.
|
|
||||||
*/
|
|
||||||
inline void checkFontBitmapSize(const FT_Bitmap &bits)
|
|
||||||
{
|
|
||||||
if ((s32)bits.rows < 0 || (s32)bits.width < 0) {
|
|
||||||
std::cout << "Insane font glyph size. File: "
|
|
||||||
<< __FILE__ << " Line " << __LINE__
|
|
||||||
<< std::endl;
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
|
video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
|
||||||
{
|
{
|
||||||
// Make sure our casts to s32 in the loops below will not cause problems
|
// Make sure our casts to s32 in the loops below will not cause problems
|
||||||
checkFontBitmapSize(bits);
|
if ((s32)bits.rows < 0 || (s32)bits.width < 0)
|
||||||
|
FATAL_ERROR("Insane font glyph size");
|
||||||
|
|
||||||
// Determine what our texture size should be.
|
// Determine what our texture size should be.
|
||||||
// Add 1 because textures are inclusive-exclusive.
|
// Add 1 because textures are inclusive-exclusive.
|
||||||
core::dimension2du d(bits.width + 1, bits.rows + 1);
|
core::dimension2du d(bits.width + 1, bits.rows + 1);
|
||||||
core::dimension2du texture_size;
|
core::dimension2du texture_size;
|
||||||
//core::dimension2du texture_size(bits.width + 1, bits.rows + 1);
|
|
||||||
|
|
||||||
// Create and load our image now.
|
// Create and load our image now.
|
||||||
video::IImage* image = 0;
|
video::IImage* image = 0;
|
||||||
|
@ -147,36 +130,36 @@ video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVide
|
||||||
for (s32 x = 0; x < (s32)bits.width; ++x)
|
for (s32 x = 0; x < (s32)bits.width; ++x)
|
||||||
{
|
{
|
||||||
image_data[y * image_pitch + x] |= static_cast<u32>(255.0f * (static_cast<float>(*row++) / gray_count)) << 24;
|
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;
|
glyph_data += bits.pitch;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// TODO: error message?
|
errorstream << "CGUITTFont: unknown pixel mode " << (int)bits.pixel_mode << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* driver, u32 font_size, const FT_Int32 loadFlags)
|
void SGUITTGlyph::preload(u32 char_index, FT_Face face, CGUITTFont *parent, u32 font_size, const FT_Int32 loadFlags)
|
||||||
{
|
{
|
||||||
if (isLoaded) return;
|
|
||||||
|
|
||||||
// Set the size of the glyph.
|
// Set the size of the glyph.
|
||||||
FT_Set_Pixel_Sizes(face, 0, font_size);
|
FT_Set_Pixel_Sizes(face, 0, font_size);
|
||||||
|
|
||||||
// Attempt to load the glyph.
|
// Attempt to load the glyph.
|
||||||
if (FT_Load_Glyph(face, char_index, loadFlags) != FT_Err_Ok)
|
auto err = FT_Load_Glyph(face, char_index, loadFlags);
|
||||||
// TODO: error message?
|
if (err != FT_Err_Ok) {
|
||||||
|
warningstream << "SGUITTGlyph: failed to load glyph " << char_index
|
||||||
|
<< " with error: " << (int)err << std::endl;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FT_GlyphSlot glyph = face->glyph;
|
FT_GlyphSlot glyph = face->glyph;
|
||||||
FT_Bitmap bits = glyph->bitmap;
|
const FT_Bitmap &bits = glyph->bitmap;
|
||||||
|
|
||||||
// Setup the glyph information here:
|
// Setup the glyph information here:
|
||||||
advance = glyph->advance;
|
advance = core::vector2di(glyph->advance.x, glyph->advance.y);
|
||||||
offset = core::vector2di(glyph->bitmap_left, glyph->bitmap_top);
|
offset = core::vector2di(glyph->bitmap_left, glyph->bitmap_top);
|
||||||
|
|
||||||
// Try to get the last page with available slots.
|
// Try to get the last page with available slots.
|
||||||
|
@ -187,7 +170,6 @@ void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* dri
|
||||||
{
|
{
|
||||||
page = parent->createGlyphPage(bits.pixel_mode);
|
page = parent->createGlyphPage(bits.pixel_mode);
|
||||||
if (!page)
|
if (!page)
|
||||||
// TODO: add error message?
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,10 +187,7 @@ void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* dri
|
||||||
--page->available_slots;
|
--page->available_slots;
|
||||||
|
|
||||||
// We grab the glyph bitmap here so the data won't be removed when the next glyph is loaded.
|
// We grab the glyph bitmap here so the data won't be removed when the next glyph is loaded.
|
||||||
surface = createGlyphImage(bits, driver);
|
surface = createGlyphImage(bits, parent->getDriver());
|
||||||
|
|
||||||
// Set our glyph as loaded.
|
|
||||||
isLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGUITTGlyph::unload()
|
void SGUITTGlyph::unload()
|
||||||
|
@ -218,7 +197,8 @@ void SGUITTGlyph::unload()
|
||||||
surface->drop();
|
surface->drop();
|
||||||
surface = 0;
|
surface = 0;
|
||||||
}
|
}
|
||||||
isLoaded = false;
|
// reset isLoaded to false
|
||||||
|
source_rect = core::recti();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
|
@ -251,14 +231,13 @@ CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env, const io::path& filen
|
||||||
//! Constructor.
|
//! Constructor.
|
||||||
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
||||||
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
|
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
|
||||||
batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0),
|
batch_load_size(1), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0),
|
||||||
shadow_offset(0), shadow_alpha(0), fallback(0)
|
shadow_offset(0), shadow_alpha(0), fallback(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Environment)
|
if (env) {
|
||||||
{
|
|
||||||
// don't grab environment, to avoid circular references
|
// don't grab environment, to avoid circular references
|
||||||
Driver = Environment->getVideoDriver();
|
Driver = env->getVideoDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Driver)
|
if (Driver)
|
||||||
|
@ -270,13 +249,10 @@ shadow_offset(0), shadow_alpha(0), fallback(0)
|
||||||
bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
|
bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
|
||||||
{
|
{
|
||||||
// Some sanity checks.
|
// Some sanity checks.
|
||||||
if (Environment == 0 || Driver == 0) return false;
|
if (!Driver) return false;
|
||||||
if (size == 0) return false;
|
if (size == 0) return false;
|
||||||
if (filename.size() == 0) return false;
|
if (filename.empty()) return false;
|
||||||
|
|
||||||
io::IFileSystem* filesystem = Environment->getFileSystem();
|
|
||||||
irr::ILogger* logger = (Device != 0 ? Device->getLogger() : 0);
|
|
||||||
// FIXME: this is always null ^
|
|
||||||
this->size = size;
|
this->size = size;
|
||||||
this->filename = filename;
|
this->filename = filename;
|
||||||
|
|
||||||
|
@ -285,62 +261,33 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
|
||||||
this->use_transparency = transparency;
|
this->use_transparency = transparency;
|
||||||
update_load_flags();
|
update_load_flags();
|
||||||
|
|
||||||
// Log.
|
infostream << "CGUITTFont: Creating new font: " << filename.c_str() << " "
|
||||||
if (logger)
|
<< size << "pt " << (antialias ? "+antialias " : "-antialias ")
|
||||||
logger->log("CGUITTFont", (core::stringc(L"Creating new font: ") + filename + " " + core::stringc(size) + "pt " + (antialias ? "+antialias " : "-antialias ") + (transparency ? "+transparency" : "-transparency")).c_str(), irr::ELL_INFORMATION);
|
<< (transparency ? "+transparency" : "-transparency") << std::endl;
|
||||||
|
|
||||||
// Grab the face.
|
// Grab the face.
|
||||||
SGUITTFace* face = 0;
|
SGUITTFace* face = nullptr;
|
||||||
auto node = c_faces.find(filename);
|
auto node = c_faces.find(filename);
|
||||||
if (node == c_faces.end())
|
if (node == c_faces.end()) {
|
||||||
{
|
|
||||||
face = new SGUITTFace();
|
face = new SGUITTFace();
|
||||||
|
|
||||||
|
if (!fs::ReadFile(filename.c_str(), face->face_buffer, true)) {
|
||||||
|
delete face;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the face.
|
||||||
|
if (FT_New_Memory_Face(c_library,
|
||||||
|
reinterpret_cast<const FT_Byte*>(face->face_buffer.data()),
|
||||||
|
face->face_buffer.size(), 0, &face->face))
|
||||||
|
{
|
||||||
|
errorstream << "CGUITTFont: FT_New_Memory_Face failed." << std::endl;
|
||||||
|
delete face;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
c_faces.emplace(filename, face);
|
c_faces.emplace(filename, face);
|
||||||
|
} else {
|
||||||
if (filesystem)
|
|
||||||
{
|
|
||||||
// Read in the file data.
|
|
||||||
io::IReadFile* file = filesystem->createAndOpenFile(filename);
|
|
||||||
if (file == 0)
|
|
||||||
{
|
|
||||||
if (logger) logger->log("CGUITTFont", "Failed to open the file.", irr::ELL_INFORMATION);
|
|
||||||
|
|
||||||
c_faces.erase(filename);
|
|
||||||
delete face;
|
|
||||||
face = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
face->face_buffer = new FT_Byte[file->getSize()];
|
|
||||||
file->read(face->face_buffer, file->getSize());
|
|
||||||
face->face_buffer_size = file->getSize();
|
|
||||||
file->drop();
|
|
||||||
|
|
||||||
// Create the face.
|
|
||||||
if (FT_New_Memory_Face(c_library, face->face_buffer, face->face_buffer_size, 0, &face->face))
|
|
||||||
{
|
|
||||||
if (logger) logger->log("CGUITTFont", "FT_New_Memory_Face failed.", irr::ELL_INFORMATION);
|
|
||||||
|
|
||||||
c_faces.erase(filename);
|
|
||||||
delete face;
|
|
||||||
face = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (FT_New_Face(c_library, reinterpret_cast<const char*>(filename.c_str()), 0, &face->face))
|
|
||||||
{
|
|
||||||
if (logger) logger->log("CGUITTFont", "FT_New_Face failed.", irr::ELL_INFORMATION);
|
|
||||||
|
|
||||||
c_faces.erase(filename);
|
|
||||||
delete face;
|
|
||||||
face = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Using another instance of this face.
|
// Using another instance of this face.
|
||||||
face = node->second;
|
face = node->second;
|
||||||
face->grab();
|
face->grab();
|
||||||
|
@ -353,20 +300,12 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
|
||||||
FT_Set_Pixel_Sizes(tt_face, size, 0);
|
FT_Set_Pixel_Sizes(tt_face, size, 0);
|
||||||
font_metrics = tt_face->size->metrics;
|
font_metrics = tt_face->size->metrics;
|
||||||
|
|
||||||
|
verbosestream << tt_face->num_glyphs << " glyphs, ascender=" << font_metrics.ascender
|
||||||
|
<< " height=" << font_metrics.height << std::endl;
|
||||||
|
|
||||||
// Allocate our glyphs.
|
// Allocate our glyphs.
|
||||||
Glyphs.clear();
|
Glyphs.clear();
|
||||||
Glyphs.reallocate(tt_face->num_glyphs);
|
|
||||||
Glyphs.set_used(tt_face->num_glyphs);
|
Glyphs.set_used(tt_face->num_glyphs);
|
||||||
for (FT_Long i = 0; i < tt_face->num_glyphs; ++i)
|
|
||||||
{
|
|
||||||
Glyphs[i].isLoaded = false;
|
|
||||||
Glyphs[i].glyph_page = 0;
|
|
||||||
Glyphs[i].source_rect = core::recti();
|
|
||||||
Glyphs[i].offset = core::vector2di();
|
|
||||||
Glyphs[i].advance = FT_Vector();
|
|
||||||
Glyphs[i].surface = 0;
|
|
||||||
Glyphs[i].parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the first 127 ascii characters.
|
// Cache the first 127 ascii characters.
|
||||||
u32 old_size = batch_load_size;
|
u32 old_size = batch_load_size;
|
||||||
|
@ -444,7 +383,7 @@ CGUITTGlyphPage* CGUITTFont::getLastGlyphPage() const
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
|
CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8 pixel_mode)
|
||||||
{
|
{
|
||||||
CGUITTGlyphPage* page = 0;
|
CGUITTGlyphPage* page = 0;
|
||||||
|
|
||||||
|
@ -481,7 +420,8 @@ CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
|
||||||
page_texture_size = max_texture_size;
|
page_texture_size = max_texture_size;
|
||||||
|
|
||||||
if (!page->createPageTexture(pixel_mode, page_texture_size)) {
|
if (!page->createPageTexture(pixel_mode, page_texture_size)) {
|
||||||
// TODO: add error message?
|
errorstream << "CGUITTGlyphPage: failed to create texture ("
|
||||||
|
<< page_texture_size.Width << "x" << page_texture_size.Height << ")" << std::endl;
|
||||||
delete page;
|
delete page;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -622,13 +562,12 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
||||||
else if (fallback != 0)
|
else if (fallback != 0)
|
||||||
{
|
{
|
||||||
// Let the fallback font draw it, this isn't super efficient but hopefully that doesn't matter
|
// Let the fallback font draw it, this isn't super efficient but hopefully that doesn't matter
|
||||||
wchar_t l1[] = { (wchar_t) currentChar, 0 }, l2 = (wchar_t) previousChar;
|
wchar_t l1[] = { (wchar_t) currentChar, 0 };
|
||||||
|
|
||||||
if (visible)
|
if (visible)
|
||||||
{
|
{
|
||||||
// Apply kerning.
|
// Apply kerning.
|
||||||
offset.X += fallback->getKerningWidth(l1, &l2);
|
offset += fallback->getKerning(*l1, (wchar_t) previousChar);
|
||||||
offset.Y += fallback->getKerningHeight();
|
|
||||||
|
|
||||||
const u32 current_color = iter - utext.begin();
|
const u32 current_color = iter - utext.begin();
|
||||||
fallback->draw(core::stringw(l1),
|
fallback->draw(core::stringw(l1),
|
||||||
|
@ -688,11 +627,6 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core::dimension2d<u32> CGUITTFont::getCharDimension(const wchar_t ch) const
|
|
||||||
{
|
|
||||||
return core::dimension2d<u32>(getWidthFromCharacter(ch), getHeightFromCharacter(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
|
core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
|
||||||
{
|
{
|
||||||
return getDimension(convertWCharToU32String(text));
|
return getDimension(convertWCharToU32String(text));
|
||||||
|
@ -759,21 +693,12 @@ core::dimension2d<u32> CGUITTFont::getDimension(const std::u32string& text) cons
|
||||||
return text_dimension;
|
return text_dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 CGUITTFont::getWidthFromCharacter(wchar_t c) const
|
|
||||||
{
|
|
||||||
return getWidthFromCharacter((char32_t)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
||||||
{
|
{
|
||||||
// Set the size of the face.
|
|
||||||
// This is because we cache faces and the face may have been set to a different size.
|
|
||||||
//FT_Set_Pixel_Sizes(tt_face, 0, size);
|
|
||||||
|
|
||||||
u32 n = getGlyphIndexByChar(c);
|
u32 n = getGlyphIndexByChar(c);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
int w = Glyphs[n-1].advance.x / 64;
|
int w = Glyphs[n-1].advance.X / 64;
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
if (fallback != 0)
|
if (fallback != 0)
|
||||||
|
@ -787,17 +712,8 @@ inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
|
||||||
else return (font_metrics.ascender / 64) / 2;
|
else return (font_metrics.ascender / 64) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 CGUITTFont::getHeightFromCharacter(wchar_t c) const
|
|
||||||
{
|
|
||||||
return getHeightFromCharacter((char32_t)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
||||||
{
|
{
|
||||||
// Set the size of the face.
|
|
||||||
// This is because we cache faces and the face may have been set to a different size.
|
|
||||||
//FT_Set_Pixel_Sizes(tt_face, 0, size);
|
|
||||||
|
|
||||||
u32 n = getGlyphIndexByChar(c);
|
u32 n = getGlyphIndexByChar(c);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
|
@ -816,11 +732,6 @@ inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
|
||||||
else return (font_metrics.ascender / 64) / 2;
|
else return (font_metrics.ascender / 64) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CGUITTFont::getGlyphIndexByChar(wchar_t c) const
|
|
||||||
{
|
|
||||||
return getGlyphIndexByChar((char32_t)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
||||||
{
|
{
|
||||||
// Get the glyph.
|
// Get the glyph.
|
||||||
|
@ -831,7 +742,7 @@ u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// If our glyph is already loaded, don't bother doing any batch loading code.
|
// If our glyph is already loaded, don't bother doing any batch loading code.
|
||||||
if (glyph != 0 && Glyphs[glyph - 1].isLoaded)
|
if (glyph != 0 && Glyphs[glyph - 1].isLoaded())
|
||||||
return glyph;
|
return glyph;
|
||||||
|
|
||||||
// Determine our batch loading positions.
|
// Determine our batch loading positions.
|
||||||
|
@ -850,9 +761,10 @@ u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
|
||||||
if (char_index)
|
if (char_index)
|
||||||
{
|
{
|
||||||
SGUITTGlyph& glyph = Glyphs[char_index - 1];
|
SGUITTGlyph& glyph = Glyphs[char_index - 1];
|
||||||
if (!glyph.isLoaded)
|
if (!glyph.isLoaded())
|
||||||
{
|
{
|
||||||
glyph.preload(char_index, tt_face, Driver, size, load_flags);
|
auto *this2 = const_cast<CGUITTFont*>(this); // oh well
|
||||||
|
glyph.preload(char_index, tt_face, this2, size, load_flags);
|
||||||
Glyph_Pages[glyph.glyph_page]->pushGlyphToBePaged(&glyph);
|
Glyph_Pages[glyph.glyph_page]->pushGlyphToBePaged(&glyph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,11 +783,10 @@ s32 CGUITTFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
|
||||||
s32 CGUITTFont::getCharacterFromPos(const std::u32string& text, s32 pixel_x) const
|
s32 CGUITTFont::getCharacterFromPos(const std::u32string& text, s32 pixel_x) const
|
||||||
{
|
{
|
||||||
s32 x = 0;
|
s32 x = 0;
|
||||||
//s32 idx = 0;
|
|
||||||
|
|
||||||
u32 character = 0;
|
u32 character = 0;
|
||||||
char32_t previousChar = 0;
|
char32_t previousChar = 0;
|
||||||
std::u32string::const_iterator iter = text.begin();
|
auto iter = text.begin();
|
||||||
while (iter != text.end())
|
while (iter != text.end())
|
||||||
{
|
{
|
||||||
char32_t c = *iter;
|
char32_t c = *iter;
|
||||||
|
@ -906,28 +817,6 @@ void CGUITTFont::setKerningHeight(s32 kerning)
|
||||||
GlobalKerningHeight = 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 getKerningWidth((char32_t)*thisLetter, (char32_t)*previousLetter);
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 CGUITTFont::getKerningWidth(const char32_t thisLetter, const char32_t previousLetter) const
|
|
||||||
{
|
|
||||||
// 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
|
core::vector2di CGUITTFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
|
||||||
{
|
{
|
||||||
return getKerning((char32_t)thisLetter, (char32_t)previousLetter);
|
return getKerning((char32_t)thisLetter, (char32_t)previousLetter);
|
||||||
|
@ -949,11 +838,8 @@ core::vector2di CGUITTFont::getKerning(const char32_t thisLetter, const char32_t
|
||||||
// If we don't have this glyph, ask fallback font
|
// If we don't have this glyph, ask fallback font
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
{
|
{
|
||||||
if (fallback != 0) {
|
if (fallback)
|
||||||
wchar_t l1 = (wchar_t) thisLetter, l2 = (wchar_t) previousLetter;
|
ret = fallback->getKerning((wchar_t) thisLetter, (wchar_t) previousLetter);
|
||||||
ret.X = fallback->getKerningWidth(&l1, &l2);
|
|
||||||
ret.Y = fallback->getKerningHeight();
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,196 +915,6 @@ video::ITexture* CGUITTFont::getPageTextureByIndex(const u32& page_index) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGUITTFont::createSharedPlane()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
2___3
|
|
||||||
| /|
|
|
||||||
| / | <-- plane mesh is like this, point 2 is (0,0), point 0 is (0, -1)
|
|
||||||
|/ | <-- the texture coords of point 2 is (0,0, point 0 is (0, 1)
|
|
||||||
0---1
|
|
||||||
*/
|
|
||||||
|
|
||||||
using namespace core;
|
|
||||||
using namespace video;
|
|
||||||
using namespace scene;
|
|
||||||
S3DVertex vertices[4];
|
|
||||||
u16 indices[6] = {0,2,3,3,1,0};
|
|
||||||
vertices[0] = S3DVertex(vector3df(0,-1,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(0,1));
|
|
||||||
vertices[1] = S3DVertex(vector3df(1,-1,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(1,1));
|
|
||||||
vertices[2] = S3DVertex(vector3df(0, 0,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(0,0));
|
|
||||||
vertices[3] = S3DVertex(vector3df(1, 0,0), vector3df(0,0,-1), SColor(255,255,255,255), vector2df(1,0));
|
|
||||||
|
|
||||||
SMeshBuffer* buf = new SMeshBuffer();
|
|
||||||
buf->append(vertices, 4, indices, 6);
|
|
||||||
|
|
||||||
shared_plane_.addMeshBuffer( buf );
|
|
||||||
shared_plane_.setHardwareMappingHint(EHM_STATIC);
|
|
||||||
|
|
||||||
shared_plane_ptr_ = &shared_plane_;
|
|
||||||
buf->drop(); //the addMeshBuffer method will grab it, so we can drop this ptr.
|
|
||||||
}
|
|
||||||
|
|
||||||
core::dimension2d<u32> CGUITTFont::getDimensionUntilEndOfLine(const wchar_t* p) const
|
|
||||||
{
|
|
||||||
core::stringw s;
|
|
||||||
for (const wchar_t* temp = p; temp && *temp != '\0' && *temp != L'\r' && *temp != L'\n'; ++temp )
|
|
||||||
s.append(*temp);
|
|
||||||
|
|
||||||
return getDimension(s.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text, scene::ISceneManager* smgr, scene::ISceneNode* parent, const video::SColor& color, bool center)
|
|
||||||
{
|
|
||||||
using namespace core;
|
|
||||||
using namespace video;
|
|
||||||
using namespace scene;
|
|
||||||
|
|
||||||
array<scene::ISceneNode*> container;
|
|
||||||
|
|
||||||
if (!Driver || !smgr) return container;
|
|
||||||
if (!parent)
|
|
||||||
parent = smgr->addEmptySceneNode(smgr->getRootSceneNode(), -1);
|
|
||||||
// if you don't specify parent, then we add an empty node attached to the root node
|
|
||||||
// this is generally undesirable.
|
|
||||||
|
|
||||||
if (!shared_plane_ptr_) //this points to a static mesh that contains the plane
|
|
||||||
createSharedPlane(); //if it's not initialized, we create one.
|
|
||||||
|
|
||||||
dimension2d<s32> text_size(getDimension(text)); //convert from unsigned to signed.
|
|
||||||
vector3df start_point(0, 0, 0), offset;
|
|
||||||
|
|
||||||
/** NOTICE:
|
|
||||||
Because we are considering adding texts into 3D world, all Y axis vectors are inverted.
|
|
||||||
**/
|
|
||||||
|
|
||||||
// There's currently no "vertical center" concept when you apply text scene node to the 3D world.
|
|
||||||
if (center)
|
|
||||||
{
|
|
||||||
offset.X = start_point.X = -text_size.Width / 2.f;
|
|
||||||
offset.Y = start_point.Y = +text_size.Height/ 2.f;
|
|
||||||
offset.X += (text_size.Width - getDimensionUntilEndOfLine(text).Width) >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the default font material
|
|
||||||
SMaterial mat;
|
|
||||||
mat.ZWriteEnable = video::EZW_OFF;
|
|
||||||
mat.MaterialType = use_transparency ? video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_SOLID;
|
|
||||||
mat.MaterialTypeParam = 0.01f;
|
|
||||||
|
|
||||||
wchar_t current_char = 0, previous_char = 0;
|
|
||||||
u32 n = 0;
|
|
||||||
|
|
||||||
array<u32> glyph_indices;
|
|
||||||
|
|
||||||
while (*text)
|
|
||||||
{
|
|
||||||
current_char = *text;
|
|
||||||
bool line_break=false;
|
|
||||||
if (current_char == L'\r') // Mac or Windows breaks
|
|
||||||
{
|
|
||||||
line_break = true;
|
|
||||||
if (*(text + 1) == L'\n') // Windows line breaks.
|
|
||||||
current_char = *(++text);
|
|
||||||
}
|
|
||||||
else if (current_char == L'\n') // Unix breaks
|
|
||||||
{
|
|
||||||
line_break = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line_break)
|
|
||||||
{
|
|
||||||
previous_char = 0;
|
|
||||||
offset.Y -= tt_face->size->metrics.ascender / 64;
|
|
||||||
offset.X = start_point.X;
|
|
||||||
if (center)
|
|
||||||
offset.X += (text_size.Width - getDimensionUntilEndOfLine(text+1).Width) >> 1;
|
|
||||||
++text;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = getGlyphIndexByChar(current_char);
|
|
||||||
if (n > 0)
|
|
||||||
{
|
|
||||||
glyph_indices.push_back( n );
|
|
||||||
|
|
||||||
// Store glyph size and offset informations.
|
|
||||||
SGUITTGlyph const& glyph = Glyphs[n-1];
|
|
||||||
u32 texw = glyph.source_rect.getWidth();
|
|
||||||
u32 texh = glyph.source_rect.getHeight();
|
|
||||||
s32 offx = glyph.offset.X;
|
|
||||||
s32 offy = (font_metrics.ascender / 64) - glyph.offset.Y;
|
|
||||||
|
|
||||||
// Apply kerning.
|
|
||||||
vector2di k = getKerning(current_char, previous_char);
|
|
||||||
offset.X += k.X;
|
|
||||||
offset.Y += k.Y;
|
|
||||||
|
|
||||||
vector3df current_pos(offset.X + offx, offset.Y - offy, 0);
|
|
||||||
dimension2d<u32> letter_size = dimension2d<u32>(texw, texh);
|
|
||||||
|
|
||||||
// Now we copy planes corresponding to the letter size.
|
|
||||||
IMeshManipulator* mani = smgr->getMeshManipulator();
|
|
||||||
IMesh* meshcopy = mani->createMeshCopy(shared_plane_ptr_);
|
|
||||||
mani->scale(meshcopy, vector3df((f32)letter_size.Width, (f32)letter_size.Height, 1));
|
|
||||||
|
|
||||||
ISceneNode* current_node = smgr->addMeshSceneNode(meshcopy, parent, -1, current_pos);
|
|
||||||
meshcopy->drop();
|
|
||||||
|
|
||||||
current_node->getMaterial(0) = mat;
|
|
||||||
current_node->setAutomaticCulling(EAC_OFF);
|
|
||||||
current_node->setIsDebugObject(true); //so the picking won't have any effect on individual letter
|
|
||||||
//current_node->setDebugDataVisible(EDS_BBOX); //de-comment this when debugging
|
|
||||||
|
|
||||||
container.push_back(current_node);
|
|
||||||
}
|
|
||||||
offset.X += getWidthFromCharacter(current_char);
|
|
||||||
// Note that fallback font handling is missing here (Minetest never uses this)
|
|
||||||
|
|
||||||
previous_char = current_char;
|
|
||||||
++text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_glyph_pages();
|
|
||||||
//only after we update the textures can we use the glyph page textures.
|
|
||||||
|
|
||||||
for (u32 i = 0; i < glyph_indices.size(); ++i)
|
|
||||||
{
|
|
||||||
u32 n = glyph_indices[i];
|
|
||||||
SGUITTGlyph const& glyph = Glyphs[n-1];
|
|
||||||
ITexture* current_tex = Glyph_Pages[glyph.glyph_page]->texture;
|
|
||||||
f32 page_texture_size = (f32)current_tex->getSize().Width;
|
|
||||||
//Now we calculate the UV position according to the texture size and the source rect.
|
|
||||||
//
|
|
||||||
// 2___3
|
|
||||||
// | /|
|
|
||||||
// | / | <-- plane mesh is like this, point 2 is (0,0), point 0 is (0, -1)
|
|
||||||
// |/ | <-- the texture coords of point 2 is (0,0, point 0 is (0, 1)
|
|
||||||
// 0---1
|
|
||||||
//
|
|
||||||
f32 u1 = glyph.source_rect.UpperLeftCorner.X / page_texture_size;
|
|
||||||
f32 u2 = u1 + (glyph.source_rect.getWidth() / page_texture_size);
|
|
||||||
f32 v1 = glyph.source_rect.UpperLeftCorner.Y / page_texture_size;
|
|
||||||
f32 v2 = v1 + (glyph.source_rect.getHeight() / page_texture_size);
|
|
||||||
|
|
||||||
//we can be quite sure that this is IMeshSceneNode, because we just added them in the above loop.
|
|
||||||
IMeshSceneNode* node = static_cast<IMeshSceneNode*>(container[i]);
|
|
||||||
|
|
||||||
S3DVertex* pv = static_cast<S3DVertex*>(node->getMesh()->getMeshBuffer(0)->getVertices());
|
|
||||||
//pv[0].TCoords.Y = pv[1].TCoords.Y = (letter_size.Height - 1) / static_cast<f32>(letter_size.Height);
|
|
||||||
//pv[1].TCoords.X = pv[3].TCoords.X = (letter_size.Width - 1) / static_cast<f32>(letter_size.Width);
|
|
||||||
pv[0].TCoords = vector2df(u1, v2);
|
|
||||||
pv[1].TCoords = vector2df(u2, v2);
|
|
||||||
pv[2].TCoords = vector2df(u1, v1);
|
|
||||||
pv[3].TCoords = vector2df(u2, v1);
|
|
||||||
|
|
||||||
container[i]->getMaterial(0).setTexture(0, current_tex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::u32string CGUITTFont::convertWCharToU32String(const wchar_t* const charArray) const
|
std::u32string CGUITTFont::convertWCharToU32String(const wchar_t* const charArray) const
|
||||||
{
|
{
|
||||||
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unexpected wchar size");
|
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unexpected wchar size");
|
||||||
|
|
|
@ -32,17 +32,17 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
#include "IGUIEnvironment.h"
|
#include "IGUIEnvironment.h"
|
||||||
#include "IGUIFont.h"
|
#include "IGUIFont.h"
|
||||||
#include "ISceneManager.h"
|
|
||||||
#include "IVideoDriver.h"
|
#include "IVideoDriver.h"
|
||||||
#include "IrrlichtDevice.h"
|
#include "IrrlichtDevice.h"
|
||||||
#include "SMesh.h"
|
#include "SMesh.h"
|
||||||
#include "util/enriched_string.h"
|
#include "util/enriched_string.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
#include FT_FREETYPE_H
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -56,26 +56,22 @@ namespace gui
|
||||||
{
|
{
|
||||||
//! Constructor.
|
//! Constructor.
|
||||||
SGUITTGlyph() :
|
SGUITTGlyph() :
|
||||||
isLoaded(false),
|
|
||||||
glyph_page(0),
|
glyph_page(0),
|
||||||
source_rect(),
|
source_rect(),
|
||||||
offset(),
|
offset(),
|
||||||
advance(),
|
advance(),
|
||||||
surface(0),
|
surface(0)
|
||||||
parent(0)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DISABLE_CLASS_COPY(SGUITTGlyph);
|
DISABLE_CLASS_COPY(SGUITTGlyph);
|
||||||
|
|
||||||
//! This class would be trivially copyable except for the reference count on `surface`.
|
//! This class would be trivially copyable except for the reference count on `surface`.
|
||||||
SGUITTGlyph(SGUITTGlyph &&other) noexcept :
|
SGUITTGlyph(SGUITTGlyph &&other) noexcept :
|
||||||
isLoaded(other.isLoaded),
|
|
||||||
glyph_page(other.glyph_page),
|
glyph_page(other.glyph_page),
|
||||||
source_rect(other.source_rect),
|
source_rect(other.source_rect),
|
||||||
offset(other.offset),
|
offset(other.offset),
|
||||||
advance(other.advance),
|
advance(other.advance),
|
||||||
surface(other.surface),
|
surface(other.surface)
|
||||||
parent(other.parent)
|
|
||||||
{
|
{
|
||||||
other.surface = 0;
|
other.surface = 0;
|
||||||
}
|
}
|
||||||
|
@ -83,12 +79,17 @@ namespace gui
|
||||||
//! Destructor.
|
//! Destructor.
|
||||||
~SGUITTGlyph() { unload(); }
|
~SGUITTGlyph() { unload(); }
|
||||||
|
|
||||||
|
//! If true, the glyph has been loaded.
|
||||||
|
inline bool isLoaded() const {
|
||||||
|
return source_rect != core::recti();
|
||||||
|
}
|
||||||
|
|
||||||
//! Preload the glyph.
|
//! Preload the glyph.
|
||||||
//! The preload process occurs when the program tries to cache the glyph from FT_Library.
|
//! The preload process occurs when the program tries to cache the glyph from FT_Library.
|
||||||
//! However, it simply defines the SGUITTGlyph's properties and will only create the page
|
//! However, it simply defines the SGUITTGlyph's properties and will only create the page
|
||||||
//! textures if necessary. The actual creation of the textures should only occur right
|
//! textures if necessary. The actual creation of the textures should only occur right
|
||||||
//! before the batch draw call.
|
//! before the batch draw call.
|
||||||
void preload(u32 char_index, FT_Face face, video::IVideoDriver* driver, u32 font_size, const FT_Int32 loadFlags);
|
void preload(u32 char_index, FT_Face face, CGUITTFont *parent, u32 font_size, const FT_Int32 loadFlags);
|
||||||
|
|
||||||
//! Unloads the glyph.
|
//! Unloads the glyph.
|
||||||
void unload();
|
void unload();
|
||||||
|
@ -96,9 +97,6 @@ namespace gui
|
||||||
//! Creates the IImage object from the FT_Bitmap.
|
//! Creates the IImage object from the FT_Bitmap.
|
||||||
video::IImage* createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const;
|
video::IImage* createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const;
|
||||||
|
|
||||||
//! If true, the glyph has been loaded.
|
|
||||||
bool isLoaded;
|
|
||||||
|
|
||||||
//! The page the glyph is on.
|
//! The page the glyph is on.
|
||||||
u32 glyph_page;
|
u32 glyph_page;
|
||||||
|
|
||||||
|
@ -109,14 +107,11 @@ namespace gui
|
||||||
core::vector2di offset;
|
core::vector2di offset;
|
||||||
|
|
||||||
//! Glyph advance information.
|
//! Glyph advance information.
|
||||||
FT_Vector advance;
|
core::vector2di advance;
|
||||||
|
|
||||||
//! This is just the temporary image holder. After this glyph is paged,
|
//! This is just the temporary image holder. After this glyph is paged,
|
||||||
//! it will be dropped.
|
//! it will be dropped.
|
||||||
mutable video::IImage* surface;
|
mutable video::IImage* surface;
|
||||||
|
|
||||||
//! The pointer pointing to the parent (CGUITTFont)
|
|
||||||
CGUITTFont* parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Holds a sheet of glyphs.
|
//! Holds a sheet of glyphs.
|
||||||
|
@ -130,7 +125,8 @@ namespace gui
|
||||||
{
|
{
|
||||||
if (driver)
|
if (driver)
|
||||||
driver->removeTexture(texture);
|
driver->removeTexture(texture);
|
||||||
else texture->drop();
|
else
|
||||||
|
texture->drop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,19 +180,11 @@ namespace gui
|
||||||
for (u32 i = 0; i < glyph_to_be_paged.size(); ++i)
|
for (u32 i = 0; i < glyph_to_be_paged.size(); ++i)
|
||||||
{
|
{
|
||||||
const SGUITTGlyph* glyph = glyph_to_be_paged[i];
|
const SGUITTGlyph* glyph = glyph_to_be_paged[i];
|
||||||
if (glyph && glyph->isLoaded)
|
if (glyph && glyph->surface)
|
||||||
{
|
{
|
||||||
if (glyph->surface)
|
glyph->surface->copyTo(pageholder, glyph->source_rect.UpperLeftCorner);
|
||||||
{
|
glyph->surface->drop();
|
||||||
glyph->surface->copyTo(pageholder, glyph->source_rect.UpperLeftCorner);
|
glyph->surface = 0;
|
||||||
glyph->surface->drop();
|
|
||||||
glyph->surface = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
; // TODO: add error message?
|
|
||||||
//currently, if we failed to create the image, just ignore this operation.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,77 +226,70 @@ namespace gui
|
||||||
virtual ~CGUITTFont();
|
virtual ~CGUITTFont();
|
||||||
|
|
||||||
//! Sets the amount of glyphs to batch load.
|
//! Sets the amount of glyphs to batch load.
|
||||||
virtual void setBatchLoadSize(u32 batch_size) { batch_load_size = batch_size; }
|
void setBatchLoadSize(u32 batch_size) { batch_load_size = batch_size; }
|
||||||
|
|
||||||
//! Sets the maximum texture size for a page of glyphs.
|
//! Sets the maximum texture size for a page of glyphs.
|
||||||
virtual void setMaxPageTextureSize(const core::dimension2du& texture_size) { max_page_texture_size = texture_size; }
|
void setMaxPageTextureSize(const core::dimension2du& texture_size) { max_page_texture_size = texture_size; }
|
||||||
|
|
||||||
//! Get the font size.
|
//! Get the font size.
|
||||||
virtual u32 getFontSize() const { return size; }
|
u32 getFontSize() const { return size; }
|
||||||
|
|
||||||
//! Check the font's transparency.
|
//! Check the font's transparency.
|
||||||
virtual bool isTransparent() const { return use_transparency; }
|
bool isTransparent() const { return use_transparency; }
|
||||||
|
|
||||||
//! Check if the font auto-hinting is enabled.
|
//! Check if the font auto-hinting is enabled.
|
||||||
//! Auto-hinting is FreeType's built-in font hinting engine.
|
//! Auto-hinting is FreeType's built-in font hinting engine.
|
||||||
virtual bool useAutoHinting() const { return use_auto_hinting; }
|
bool useAutoHinting() const { return use_auto_hinting; }
|
||||||
|
|
||||||
//! Check if the font hinting is enabled.
|
//! Check if the font hinting is enabled.
|
||||||
virtual bool useHinting() const { return use_hinting; }
|
bool useHinting() const { return use_hinting; }
|
||||||
|
|
||||||
//! Check if the font is being loaded as a monochrome font.
|
//! Check if the font is being loaded as a monochrome font.
|
||||||
//! The font can either be a 256 color grayscale font, or a 2 color monochrome font.
|
//! The font can either be a 256 color grayscale font, or a 2 color monochrome font.
|
||||||
virtual bool useMonochrome() const { return use_monochrome; }
|
bool useMonochrome() const { return use_monochrome; }
|
||||||
|
|
||||||
//! Tells the font to allow transparency when rendering.
|
//! Tells the font to allow transparency when rendering.
|
||||||
//! Default: true.
|
//! Default: true.
|
||||||
//! \param flag If true, the font draws using transparency.
|
//! \param flag If true, the font draws using transparency.
|
||||||
virtual void setTransparency(const bool flag);
|
void setTransparency(const bool flag);
|
||||||
|
|
||||||
//! Tells the font to use monochrome rendering.
|
//! Tells the font to use monochrome rendering.
|
||||||
//! Default: false.
|
//! Default: false.
|
||||||
//! \param flag If true, the font draws using a monochrome image. If false, the font uses a grayscale image.
|
//! \param flag If true, the font draws using a monochrome image. If false, the font uses a grayscale image.
|
||||||
virtual void setMonochrome(const bool flag);
|
void setMonochrome(const bool flag);
|
||||||
|
|
||||||
//! Enables or disables font hinting.
|
//! Enables or disables font hinting.
|
||||||
//! Default: Hinting and auto-hinting true.
|
//! Default: Hinting and auto-hinting true.
|
||||||
//! \param enable If false, font hinting is turned off. If true, font hinting is turned on.
|
//! \param enable If false, font hinting is turned off. If true, font hinting is turned on.
|
||||||
//! \param enable_auto_hinting If true, FreeType uses its own auto-hinting algorithm. If false, it tries to use the algorithm specified by the font.
|
//! \param enable_auto_hinting If true, FreeType uses its own auto-hinting algorithm. If false, it tries to use the algorithm specified by the font.
|
||||||
virtual void setFontHinting(const bool enable, const bool enable_auto_hinting = true);
|
void setFontHinting(const bool enable, const bool enable_auto_hinting = true);
|
||||||
|
|
||||||
//! Draws some text and clips it to the specified rectangle if wanted.
|
//! Draws some text and clips it to the specified rectangle if wanted.
|
||||||
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
virtual void draw(const core::stringw& text, const core::rect<s32>& position,
|
||||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||||
const core::rect<s32>* clip=0);
|
const core::rect<s32>* clip=0) override;
|
||||||
|
|
||||||
void draw(const EnrichedString& text, const core::rect<s32>& position,
|
void draw(const EnrichedString& text, const core::rect<s32>& position,
|
||||||
bool hcenter=false, bool vcenter=false,
|
bool hcenter=false, bool vcenter=false,
|
||||||
const core::rect<s32>* clip=0);
|
const core::rect<s32>* clip=0);
|
||||||
|
|
||||||
//! Returns the dimension of a character produced by this font.
|
|
||||||
virtual core::dimension2d<u32> getCharDimension(const wchar_t ch) const;
|
|
||||||
|
|
||||||
//! Returns the dimension of a text string.
|
//! Returns the dimension of a text string.
|
||||||
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const;
|
virtual core::dimension2du getDimension(const wchar_t* text) const override;
|
||||||
|
|
||||||
//! Calculates the index of the character in the text which is on a specific position.
|
//! 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;
|
virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const override;
|
||||||
|
|
||||||
//! Sets global kerning width for the font.
|
//! Sets global kerning width for the font.
|
||||||
virtual void setKerningWidth(s32 kerning);
|
virtual void setKerningWidth(s32 kerning) override;
|
||||||
|
|
||||||
//! Sets global kerning height for the font.
|
//! Sets global kerning height for the font.
|
||||||
virtual void setKerningHeight(s32 kerning);
|
virtual void setKerningHeight(s32 kerning) override;
|
||||||
|
|
||||||
//! 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;
|
|
||||||
virtual s32 getKerningWidth(const char32_t thisLetter=0, const char32_t previousLetter=0) const;
|
|
||||||
|
|
||||||
//! Returns the distance between letters
|
//! Returns the distance between letters
|
||||||
virtual s32 getKerningHeight() const;
|
virtual core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const override;
|
||||||
|
|
||||||
//! Define which characters should not be drawn by the font.
|
//! Define which characters should not be drawn by the font.
|
||||||
virtual void setInvisibleCharacters(const wchar_t *s);
|
virtual void setInvisibleCharacters(const wchar_t *s) override;
|
||||||
|
|
||||||
//! Get the last glyph page if there's still available slots.
|
//! Get the last glyph page if there's still available slots.
|
||||||
//! If not, it will return zero.
|
//! If not, it will return zero.
|
||||||
|
@ -317,7 +298,7 @@ namespace gui
|
||||||
//! Create a new glyph page texture.
|
//! Create a new glyph page texture.
|
||||||
//! \param pixel_mode the pixel mode defined by FT_Pixel_Mode
|
//! \param pixel_mode the pixel mode defined by FT_Pixel_Mode
|
||||||
//should be better typed. fix later.
|
//should be better typed. fix later.
|
||||||
CGUITTGlyphPage* createGlyphPage(const u8& pixel_mode);
|
CGUITTGlyphPage* createGlyphPage(const u8 pixel_mode);
|
||||||
|
|
||||||
//! Get the last glyph page's index.
|
//! Get the last glyph page's index.
|
||||||
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
|
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
|
||||||
|
@ -328,16 +309,13 @@ namespace gui
|
||||||
//! Create corresponding character's software image copy from the font,
|
//! Create corresponding character's software image copy from the font,
|
||||||
//! so you can use this data just like any ordinary video::IImage.
|
//! so you can use this data just like any ordinary video::IImage.
|
||||||
//! \param ch The character you need
|
//! \param ch The character you need
|
||||||
virtual video::IImage* createTextureFromChar(const char32_t& ch);
|
video::IImage* createTextureFromChar(const char32_t& ch);
|
||||||
|
|
||||||
//! This function is for debugging mostly. If the page doesn't exist it returns zero.
|
//! This function is for debugging mostly. If the page doesn't exist it returns zero.
|
||||||
//! \param page_index Simply return the texture handle of a given page index.
|
//! \param page_index Simply return the texture handle of a given page index.
|
||||||
virtual video::ITexture* getPageTextureByIndex(const u32& page_index) const;
|
video::ITexture* getPageTextureByIndex(const u32& page_index) const;
|
||||||
|
|
||||||
//! Add a list of scene nodes generated by putting font textures on the 3D planes.
|
inline video::IVideoDriver *getDriver() const { return Driver; }
|
||||||
virtual core::array<scene::ISceneNode*> addTextSceneNode
|
|
||||||
(const wchar_t* text, scene::ISceneManager* smgr, scene::ISceneNode* parent = 0,
|
|
||||||
const video::SColor& color = video::SColor(255, 0, 0, 0), bool center = false );
|
|
||||||
|
|
||||||
inline s32 getAscender() const { return font_metrics.ascender; }
|
inline s32 getAscender() const { return font_metrics.ascender; }
|
||||||
|
|
||||||
|
@ -355,8 +333,6 @@ namespace gui
|
||||||
static FT_Library c_library;
|
static FT_Library c_library;
|
||||||
static std::map<io::path, SGUITTFace*> c_faces;
|
static std::map<io::path, SGUITTFace*> c_faces;
|
||||||
static bool c_libraryLoaded;
|
static bool c_libraryLoaded;
|
||||||
static scene::IMesh* shared_plane_ptr_;
|
|
||||||
static scene::SMesh shared_plane_;
|
|
||||||
|
|
||||||
// Helper functions for the same-named public member functions above
|
// Helper functions for the same-named public member functions above
|
||||||
// (Since std::u32string is nicer to work with than wchar_t *)
|
// (Since std::u32string is nicer to work with than wchar_t *)
|
||||||
|
@ -379,20 +355,11 @@ namespace gui
|
||||||
if (useMonochrome()) load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
|
if (useMonochrome()) load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
|
||||||
else load_flags |= FT_LOAD_TARGET_NORMAL;
|
else load_flags |= FT_LOAD_TARGET_NORMAL;
|
||||||
}
|
}
|
||||||
u32 getWidthFromCharacter(wchar_t c) const;
|
|
||||||
u32 getWidthFromCharacter(char32_t c) const;
|
u32 getWidthFromCharacter(char32_t c) const;
|
||||||
u32 getHeightFromCharacter(wchar_t c) const;
|
|
||||||
u32 getHeightFromCharacter(char32_t c) const;
|
u32 getHeightFromCharacter(char32_t c) const;
|
||||||
u32 getGlyphIndexByChar(wchar_t c) const;
|
|
||||||
u32 getGlyphIndexByChar(char32_t c) const;
|
u32 getGlyphIndexByChar(char32_t c) const;
|
||||||
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const;
|
|
||||||
core::vector2di getKerning(const char32_t thisLetter, const char32_t previousLetter) const;
|
core::vector2di getKerning(const char32_t thisLetter, const char32_t previousLetter) const;
|
||||||
core::dimension2d<u32> getDimensionUntilEndOfLine(const wchar_t* p) const;
|
|
||||||
|
|
||||||
void createSharedPlane();
|
|
||||||
|
|
||||||
irr::IrrlichtDevice* Device;
|
|
||||||
gui::IGUIEnvironment* Environment;
|
|
||||||
video::IVideoDriver* Driver;
|
video::IVideoDriver* Driver;
|
||||||
io::path filename;
|
io::path filename;
|
||||||
FT_Face tt_face;
|
FT_Face tt_face;
|
||||||
|
|
|
@ -74,7 +74,7 @@ void StaticText::draw()
|
||||||
updateText();
|
updateText();
|
||||||
|
|
||||||
core::rect<s32> r = frameRect;
|
core::rect<s32> r = frameRect;
|
||||||
s32 height_line = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height_line = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
s32 height_total = height_line * BrokenText.size();
|
s32 height_total = height_line * BrokenText.size();
|
||||||
if (VAlign == EGUIA_CENTER && WordWrap)
|
if (VAlign == EGUIA_CENTER && WordWrap)
|
||||||
{
|
{
|
||||||
|
@ -546,7 +546,7 @@ s32 StaticText::getTextHeight() const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (WordWrap) {
|
if (WordWrap) {
|
||||||
s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
|
s32 height = font->getDimension(L"A").Height + font->getKerning(L'A').Y;
|
||||||
return height * BrokenText.size();
|
return height * BrokenText.size();
|
||||||
}
|
}
|
||||||
// There may be intentional new lines without WordWrap
|
// There may be intentional new lines without WordWrap
|
||||||
|
|
Loading…
Add table
Reference in a new issue