mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-27 17:28:41 +00:00
Replace fallback font nonsense with automatic per-glyph fallback (#11084)
This commit is contained in:
parent
5f4c78a77d
commit
8d89f5f0cc
8 changed files with 119 additions and 88 deletions
|
@ -275,7 +275,8 @@ CGUITTFont* CGUITTFont::create(IrrlichtDevice *device, const io::path& filename,
|
|||
//! Constructor.
|
||||
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
|
||||
: 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), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0),
|
||||
shadow_offset(0), shadow_alpha(0), fallback(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUITTFont");
|
||||
|
@ -640,7 +641,30 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
|||
if (current_color < colors.size())
|
||||
applied_colors.push_back(colors[current_color]);
|
||||
}
|
||||
offset.X += getWidthFromCharacter(currentChar);
|
||||
if (n > 0)
|
||||
{
|
||||
offset.X += getWidthFromCharacter(currentChar);
|
||||
}
|
||||
else if (fallback != 0)
|
||||
{
|
||||
// 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;
|
||||
|
||||
if (visible)
|
||||
{
|
||||
// Apply kerning.
|
||||
offset.X += fallback->getKerningWidth(l1, &l2);
|
||||
offset.Y += fallback->getKerningHeight();
|
||||
|
||||
u32 current_color = iter.getPos();
|
||||
fallback->draw(core::stringw(l1),
|
||||
core::rect<s32>({offset.X-1, offset.Y-1}, position.LowerRightCorner), // ???
|
||||
current_color < colors.size() ? colors[current_color] : video::SColor(255, 255, 255, 255),
|
||||
false, false, clip);
|
||||
}
|
||||
|
||||
offset.X += fallback->getDimension(l1).Width;
|
||||
}
|
||||
|
||||
previousChar = currentChar;
|
||||
++iter;
|
||||
|
@ -766,6 +790,12 @@ inline u32 CGUITTFont::getWidthFromCharacter(uchar32_t c) const
|
|||
int w = Glyphs[n-1].advance.x / 64;
|
||||
return w;
|
||||
}
|
||||
if (fallback != 0)
|
||||
{
|
||||
wchar_t s[] = { (wchar_t) c, 0 };
|
||||
return fallback->getDimension(s).Width;
|
||||
}
|
||||
|
||||
if (c >= 0x2000)
|
||||
return (font_metrics.ascender / 64);
|
||||
else return (font_metrics.ascender / 64) / 2;
|
||||
|
@ -789,6 +819,12 @@ inline u32 CGUITTFont::getHeightFromCharacter(uchar32_t c) const
|
|||
s32 height = (font_metrics.ascender / 64) - Glyphs[n-1].offset.Y + Glyphs[n-1].source_rect.getHeight();
|
||||
return height;
|
||||
}
|
||||
if (fallback != 0)
|
||||
{
|
||||
wchar_t s[] = { (wchar_t) c, 0 };
|
||||
return fallback->getDimension(s).Height;
|
||||
}
|
||||
|
||||
if (c >= 0x2000)
|
||||
return (font_metrics.ascender / 64);
|
||||
else return (font_metrics.ascender / 64) / 2;
|
||||
|
@ -804,9 +840,9 @@ u32 CGUITTFont::getGlyphIndexByChar(uchar32_t c) const
|
|||
// Get the glyph.
|
||||
u32 glyph = FT_Get_Char_Index(tt_face, c);
|
||||
|
||||
// Check for a valid glyph. If it is invalid, attempt to use the replacement character.
|
||||
// Check for a valid glyph.
|
||||
if (glyph == 0)
|
||||
glyph = FT_Get_Char_Index(tt_face, core::unicode::UTF_REPLACEMENT_CHARACTER);
|
||||
return 0;
|
||||
|
||||
// If our glyph is already loaded, don't bother doing any batch loading code.
|
||||
if (glyph != 0 && Glyphs[glyph - 1].isLoaded)
|
||||
|
@ -922,13 +958,26 @@ core::vector2di CGUITTFont::getKerning(const uchar32_t thisLetter, const uchar32
|
|||
|
||||
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
|
||||
|
||||
u32 n = getGlyphIndexByChar(thisLetter);
|
||||
|
||||
// If we don't have this glyph, ask fallback font
|
||||
if (n == 0)
|
||||
{
|
||||
if (fallback != 0) {
|
||||
wchar_t l1 = (wchar_t) thisLetter, l2 = (wchar_t) previousLetter;
|
||||
ret.X = fallback->getKerningWidth(&l1, &l2);
|
||||
ret.Y = fallback->getKerningHeight();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If we don't have kerning, no point in continuing.
|
||||
if (!FT_HAS_KERNING(tt_face))
|
||||
return ret;
|
||||
|
||||
// Get the kerning information.
|
||||
FT_Vector v;
|
||||
FT_Get_Kerning(tt_face, getGlyphIndexByChar(previousLetter), getGlyphIndexByChar(thisLetter), FT_KERNING_DEFAULT, &v);
|
||||
FT_Get_Kerning(tt_face, getGlyphIndexByChar(previousLetter), n, FT_KERNING_DEFAULT, &v);
|
||||
|
||||
// If we have a scalable font, the return value will be in font points.
|
||||
if (FT_IS_SCALABLE(tt_face))
|
||||
|
@ -960,6 +1009,9 @@ void CGUITTFont::setInvisibleCharacters(const core::ustring& s)
|
|||
video::IImage* CGUITTFont::createTextureFromChar(const uchar32_t& ch)
|
||||
{
|
||||
u32 n = getGlyphIndexByChar(ch);
|
||||
if (n == 0)
|
||||
n = getGlyphIndexByChar((uchar32_t) core::unicode::UTF_REPLACEMENT_CHARACTER);
|
||||
|
||||
const SGUITTGlyph& glyph = Glyphs[n-1];
|
||||
CGUITTGlyphPage* page = Glyph_Pages[glyph.glyph_page];
|
||||
|
||||
|
@ -1147,6 +1199,8 @@ core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -269,7 +269,7 @@ namespace gui
|
|||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
virtual void draw(const EnrichedString& text, const core::rect<s32>& position,
|
||||
void draw(const EnrichedString& text, const core::rect<s32>& position,
|
||||
video::SColor color, bool hcenter=false, bool vcenter=false,
|
||||
const core::rect<s32>* clip=0);
|
||||
|
||||
|
@ -313,6 +313,9 @@ namespace gui
|
|||
//! Get the last glyph page's index.
|
||||
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
|
||||
|
||||
//! Set font that should be used for glyphs not present in ours
|
||||
void setFallback(gui::IGUIFont* font) { fallback = font; }
|
||||
|
||||
//! Create corresponding character's software image copy from the font,
|
||||
//! so you can use this data just like any ordinary video::IImage.
|
||||
//! \param ch The character you need
|
||||
|
@ -387,6 +390,8 @@ namespace gui
|
|||
core::ustring Invisible;
|
||||
u32 shadow_offset;
|
||||
u32 shadow_alpha;
|
||||
|
||||
gui::IGUIFont* fallback;
|
||||
};
|
||||
|
||||
} // end namespace gui
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue