Added support for faux-bold and faux-italic

Former-commit-id: 259429e8d38b0299e30d539253b50e3aab12c76b
This commit is contained in:
Lynix 2015-01-08 14:19:53 +01:00
parent 88af94b987
commit a9ef2f7e36
4 changed files with 100 additions and 51 deletions

View File

@ -87,6 +87,8 @@ class NAZARA_API NzFont : public NzResource, NzNonCopyable
{
NzRecti aabb;
NzRectui atlasRect;
bool requireFauxBold;
bool requireFauxItalic;
bool flipped;
bool valid;
int advance;
@ -105,7 +107,7 @@ class NAZARA_API NzFont : public NzResource, NzNonCopyable
nzUInt64 ComputeKey(unsigned int characterSize, nzUInt32 style) const;
void OnAtlasCleared();
const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, bool bold, char32_t character) const;
const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, nzUInt32 style, char32_t character) const;
std::shared_ptr<NzAbstractFontAtlas> m_atlas;
std::unique_ptr<NzFontData> m_data;

View File

@ -18,7 +18,7 @@ class NAZARA_API NzFontData
NzFontData() = default;
virtual ~NzFontData();
virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, bool bold, NzFontGlyph* dst) = 0;
virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt32 style, NzFontGlyph* dst) = 0;
virtual NzString GetFamilyName() const = 0;
virtual NzString GetStyleName() const = 0;
@ -31,6 +31,8 @@ class NAZARA_API NzFontData
virtual unsigned int QueryLineHeight(unsigned int characterSize) const = 0;
virtual float QueryUnderlinePosition(unsigned int characterSize) const = 0;
virtual float QueryUnderlineThickness(unsigned int characterSize) const = 0;
virtual bool SupportsStyle(nzUInt32 style) const = 0;
};
#endif // NAZARA_FONTDATA_HPP

View File

@ -96,7 +96,7 @@ bool NzFont::ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt
}
#endif
return m_data->ExtractGlyph(characterSize, character, style & nzTextStyle_Bold, glyph);
return m_data->ExtractGlyph(characterSize, character, style, glyph);
}
const NzAbstractFontAtlas* NzFont::GetAtlas() const
@ -284,12 +284,11 @@ nzUInt64 NzFont::ComputeKey(unsigned int characterSize, nzUInt32 style) const
nzUInt64 sizePart = static_cast<nzUInt32>((characterSize/m_minimumSizeStep)*m_minimumSizeStep);
nzUInt64 stylePart = 0;
if (style & nzTextStyle_Bold) // Les caractères gras sont générés différemment
if (style & nzTextStyle_Bold)
stylePart |= nzTextStyle_Bold;
// Les caractères italiques peuvent venir d'une autre police, dans le cas contraire ils sont générés au runtime
//if (style & nzTextStyle_Italic)
// stylePart |= nzTextStyle_Italic;
if (style & nzTextStyle_Italic)
stylePart |= nzTextStyle_Italic;
return (stylePart << 32) | sizePart;
}
@ -302,52 +301,88 @@ void NzFont::OnAtlasCleared()
NotifyModified(ModificationCode_GlyphCacheCleared);
}
const NzFont::Glyph& NzFont::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, bool bold, char32_t character) const
const NzFont::Glyph& NzFont::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, nzUInt32 style, char32_t character) const
{
auto it = glyphMap.find(character);
if (it != glyphMap.end()) // Si le glyphe n'est pas déjà chargé
return it->second;
Glyph& glyph = glyphMap[character]; // Insertion du glyphe
glyph.requireFauxBold = false;
glyph.requireFauxItalic = false;
glyph.valid = false;
// On extrait le glyphe depuis la police
NzFontGlyph fontGlyph;
if (ExtractGlyph(characterSize, character, bold, &fontGlyph))
// On vérifie que le style demandé est supporté par la police (dans le cas contraire il devra être simulé au rendu)
nzUInt32 supportedStyle = style;
if (style & nzTextStyle_Bold && !m_data->SupportsStyle(nzTextStyle_Bold))
{
glyph.atlasRect.width = fontGlyph.image.GetWidth();
glyph.atlasRect.height = fontGlyph.image.GetHeight();
glyph.requireFauxBold = true;
supportedStyle &= ~nzTextStyle_Bold;
}
// Insertion du rectangle dans l'un des atlas
if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose
if (style & nzTextStyle_Italic && !m_data->SupportsStyle(nzTextStyle_Italic))
{
glyph.requireFauxItalic = true;
supportedStyle &= ~nzTextStyle_Italic;
}
// Est-ce que la police supporte le style demandé ?
if (style == supportedStyle)
{
// On extrait le glyphe depuis la police
NzFontGlyph fontGlyph;
if (ExtractGlyph(characterSize, character, style, &fontGlyph))
{
// Padding (pour éviter le débordement lors du filtrage)
const unsigned int padding = 1; // Un pixel de contour
glyph.atlasRect.width = fontGlyph.image.GetWidth();
glyph.atlasRect.height = fontGlyph.image.GetHeight();
glyph.atlasRect.width += padding*2;
glyph.atlasRect.height += padding*2;
// Insertion du rectangle dans l'atlas virtuel
if (!m_atlas->Insert(fontGlyph.image, &glyph.atlasRect, &glyph.flipped, &glyph.layerIndex))
// Insertion du rectangle dans l'un des atlas
if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose
{
NazaraError("Failed to insert glyph into atlas");
return glyph;
// Padding (pour éviter le débordement lors du filtrage)
const unsigned int padding = 1; // Un pixel de contour
glyph.atlasRect.width += padding*2;
glyph.atlasRect.height += padding*2;
// Insertion du rectangle dans l'atlas virtuel
if (!m_atlas->Insert(fontGlyph.image, &glyph.atlasRect, &glyph.flipped, &glyph.layerIndex))
{
NazaraError("Failed to insert glyph into atlas");
return glyph;
}
// Compensation du contour (centrage du glyphe)
glyph.atlasRect.x += padding;
glyph.atlasRect.y += padding;
glyph.atlasRect.width -= padding*2;
glyph.atlasRect.height -= padding*2;
}
// Compensation du contour (centrage du glyphe)
glyph.atlasRect.x += padding;
glyph.atlasRect.y += padding;
glyph.atlasRect.width -= padding*2;
glyph.atlasRect.height -= padding*2;
glyph.aabb = fontGlyph.aabb;
glyph.advance = fontGlyph.advance;
glyph.valid = true;
}
else
{
NazaraWarning("Failed to extract glyph \"" + NzString::Unicode(character) + "\"");
}
glyph.aabb = fontGlyph.aabb;
glyph.advance = fontGlyph.advance;
glyph.valid = true;
}
else
{
NazaraWarning("Failed to extract glyph \"" + NzString::Unicode(character) + "\"");
// La police ne supporte pas le style demandé, nous allons donc précharger le glyphe supportant le style "minimum" supporté
// et copier ses données
nzUInt64 newKey = ComputeKey(characterSize, supportedStyle);
const Glyph& referenceGlyph = PrecacheGlyph(m_glyphes[newKey], characterSize, supportedStyle, character);
if (referenceGlyph.valid)
{
glyph.aabb = referenceGlyph.aabb;
glyph.advance = referenceGlyph.advance;
glyph.atlasRect = referenceGlyph.atlasRect;
glyph.flipped = referenceGlyph.flipped;
glyph.layerIndex = referenceGlyph.layerIndex;
glyph.valid = true;
}
}
return glyph;

View File

@ -75,7 +75,7 @@ namespace
return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0;
}
bool ExtractGlyph(unsigned int characterSize, char32_t character, bool bold, NzFontGlyph* dst)
bool ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt32 style, NzFontGlyph* dst) override
{
#ifdef NAZARA_DEBUG
if (!dst)
@ -97,10 +97,16 @@ namespace
const FT_Pos boldStrength = 2 << 6;
bool outlineFormat = (glyph->format == FT_GLYPH_FORMAT_OUTLINE);
if (outlineFormat && bold)
bool embolden = (style & nzTextStyle_Bold);
dst->advance = (embolden) ? boldStrength >> 6 : 0;
if (embolden && glyph->format == FT_GLYPH_FORMAT_OUTLINE)
{
// http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden
FT_Outline_Embolden(&glyph->outline, boldStrength);
embolden = false;
}
// http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap
// Conversion du glyphe vers le format bitmap
@ -113,18 +119,16 @@ namespace
// Dans le cas où nous voulons des caractères gras mais que nous n'avons pas pu agir plus tôt
// nous demandons à FreeType d'agir directement sur le bitmap généré
if (!outlineFormat && bold)
if (embolden)
{
// http://www.freetype.org/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden
// "If you want to embolden the bitmap owned by a FT_GlyphSlot_Rec, you should call FT_GlyphSlot_Own_Bitmap on the slot first"
FT_GlyphSlot_Own_Bitmap(glyph);
FT_Bitmap_Embolden(s_library, &glyph->bitmap, boldStrength, boldStrength);
embolden = false;
}
dst->advance = glyph->metrics.horiAdvance >> 6;
if (bold)
dst->advance += boldStrength >> 6;
dst->advance += glyph->metrics.horiAdvance >> 6;
dst->aabb.x = glyph->metrics.horiBearingX >> 6;
dst->aabb.y = -(glyph->metrics.horiBearingY >> 6); // Inversion du repère
dst->aabb.width = glyph->metrics.width >> 6;
@ -177,22 +181,22 @@ namespace
return true;
}
NzString GetFamilyName() const
NzString GetFamilyName() const override
{
return m_face->family_name;
}
NzString GetStyleName() const
NzString GetStyleName() const override
{
return m_face->style_name;
}
bool HasKerning() const
bool HasKerning() const override
{
return FT_HAS_KERNING(m_face);
}
bool IsScalable() const
bool IsScalable() const override
{
return FT_IS_SCALABLE(m_face);
}
@ -202,7 +206,7 @@ namespace
return FT_Open_Face(s_library, &m_args, 0, &m_face) == 0;
}
int QueryKerning(unsigned int characterSize, char32_t first, char32_t second) const
int QueryKerning(unsigned int characterSize, char32_t first, char32_t second) const override
{
if (FT_HAS_KERNING(m_face))
{
@ -220,7 +224,7 @@ namespace
return 0;
}
unsigned int QueryLineHeight(unsigned int characterSize) const
unsigned int QueryLineHeight(unsigned int characterSize) const override
{
SetCharacterSize(characterSize);
@ -228,7 +232,7 @@ namespace
return m_face->size->metrics.height >> 6;
}
float QueryUnderlinePosition(unsigned int characterSize) const
float QueryUnderlinePosition(unsigned int characterSize) const override
{
if (FT_IS_SCALABLE(m_face))
{
@ -241,7 +245,7 @@ namespace
return characterSize / 10.f; // Joker ?
}
float QueryUnderlineThickness(unsigned int characterSize) const
float QueryUnderlineThickness(unsigned int characterSize) const override
{
if (FT_IS_SCALABLE(m_face))
{
@ -280,6 +284,12 @@ namespace
m_args.stream = &m_stream;
}
bool SupportsStyle(nzUInt32 style) const override
{
///TODO
return style == nzTextStyle_None || style == nzTextStyle_Bold;
}
private:
void SetCharacterSize(unsigned int characterSize) const
{
@ -299,7 +309,7 @@ namespace
bool IsSupported(const NzString& extension)
{
///FIXME: Je suppose qu'il en manque quelques uns..
///FIXME: Je suppose qu'il en manque quelques unes..
static std::set<NzString> supportedExtensions = {
"afm", "bdf", "cff", "cid", "dfont", "fnt", "pfa", "pfb", "pfm", "pfr", "sfnt", "tte", "ttf"
};