Added support for faux-bold and faux-italic
Former-commit-id: 259429e8d38b0299e30d539253b50e3aab12c76b
This commit is contained in:
parent
88af94b987
commit
a9ef2f7e36
|
|
@ -87,6 +87,8 @@ class NAZARA_API NzFont : public NzResource, NzNonCopyable
|
||||||
{
|
{
|
||||||
NzRecti aabb;
|
NzRecti aabb;
|
||||||
NzRectui atlasRect;
|
NzRectui atlasRect;
|
||||||
|
bool requireFauxBold;
|
||||||
|
bool requireFauxItalic;
|
||||||
bool flipped;
|
bool flipped;
|
||||||
bool valid;
|
bool valid;
|
||||||
int advance;
|
int advance;
|
||||||
|
|
@ -105,7 +107,7 @@ class NAZARA_API NzFont : public NzResource, NzNonCopyable
|
||||||
|
|
||||||
nzUInt64 ComputeKey(unsigned int characterSize, nzUInt32 style) const;
|
nzUInt64 ComputeKey(unsigned int characterSize, nzUInt32 style) const;
|
||||||
void OnAtlasCleared();
|
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::shared_ptr<NzAbstractFontAtlas> m_atlas;
|
||||||
std::unique_ptr<NzFontData> m_data;
|
std::unique_ptr<NzFontData> m_data;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class NAZARA_API NzFontData
|
||||||
NzFontData() = default;
|
NzFontData() = default;
|
||||||
virtual ~NzFontData();
|
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 GetFamilyName() const = 0;
|
||||||
virtual NzString GetStyleName() 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 unsigned int QueryLineHeight(unsigned int characterSize) const = 0;
|
||||||
virtual float QueryUnderlinePosition(unsigned int characterSize) const = 0;
|
virtual float QueryUnderlinePosition(unsigned int characterSize) const = 0;
|
||||||
virtual float QueryUnderlineThickness(unsigned int characterSize) const = 0;
|
virtual float QueryUnderlineThickness(unsigned int characterSize) const = 0;
|
||||||
|
|
||||||
|
virtual bool SupportsStyle(nzUInt32 style) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAZARA_FONTDATA_HPP
|
#endif // NAZARA_FONTDATA_HPP
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ bool NzFont::ExtractGlyph(unsigned int characterSize, char32_t character, nzUInt
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return m_data->ExtractGlyph(characterSize, character, style & nzTextStyle_Bold, glyph);
|
return m_data->ExtractGlyph(characterSize, character, style, glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NzAbstractFontAtlas* NzFont::GetAtlas() const
|
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 sizePart = static_cast<nzUInt32>((characterSize/m_minimumSizeStep)*m_minimumSizeStep);
|
||||||
nzUInt64 stylePart = 0;
|
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;
|
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)
|
||||||
//if (style & nzTextStyle_Italic)
|
stylePart |= nzTextStyle_Italic;
|
||||||
// stylePart |= nzTextStyle_Italic;
|
|
||||||
|
|
||||||
return (stylePart << 32) | sizePart;
|
return (stylePart << 32) | sizePart;
|
||||||
}
|
}
|
||||||
|
|
@ -302,52 +301,88 @@ void NzFont::OnAtlasCleared()
|
||||||
NotifyModified(ModificationCode_GlyphCacheCleared);
|
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);
|
auto it = glyphMap.find(character);
|
||||||
if (it != glyphMap.end()) // Si le glyphe n'est pas déjà chargé
|
if (it != glyphMap.end()) // Si le glyphe n'est pas déjà chargé
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
Glyph& glyph = glyphMap[character]; // Insertion du glyphe
|
Glyph& glyph = glyphMap[character]; // Insertion du glyphe
|
||||||
|
glyph.requireFauxBold = false;
|
||||||
|
glyph.requireFauxItalic = false;
|
||||||
glyph.valid = false;
|
glyph.valid = false;
|
||||||
|
|
||||||
// On extrait le glyphe depuis la police
|
// On vérifie que le style demandé est supporté par la police (dans le cas contraire il devra être simulé au rendu)
|
||||||
NzFontGlyph fontGlyph;
|
nzUInt32 supportedStyle = style;
|
||||||
if (ExtractGlyph(characterSize, character, bold, &fontGlyph))
|
if (style & nzTextStyle_Bold && !m_data->SupportsStyle(nzTextStyle_Bold))
|
||||||
{
|
{
|
||||||
glyph.atlasRect.width = fontGlyph.image.GetWidth();
|
glyph.requireFauxBold = true;
|
||||||
glyph.atlasRect.height = fontGlyph.image.GetHeight();
|
supportedStyle &= ~nzTextStyle_Bold;
|
||||||
|
}
|
||||||
|
|
||||||
// Insertion du rectangle dans l'un des atlas
|
if (style & nzTextStyle_Italic && !m_data->SupportsStyle(nzTextStyle_Italic))
|
||||||
if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose
|
{
|
||||||
|
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)
|
glyph.atlasRect.width = fontGlyph.image.GetWidth();
|
||||||
const unsigned int padding = 1; // Un pixel de contour
|
glyph.atlasRect.height = fontGlyph.image.GetHeight();
|
||||||
|
|
||||||
glyph.atlasRect.width += padding*2;
|
// Insertion du rectangle dans l'un des atlas
|
||||||
glyph.atlasRect.height += padding*2;
|
if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose
|
||||||
|
|
||||||
// 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");
|
// Padding (pour éviter le débordement lors du filtrage)
|
||||||
return glyph;
|
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.aabb = fontGlyph.aabb;
|
||||||
glyph.atlasRect.x += padding;
|
glyph.advance = fontGlyph.advance;
|
||||||
glyph.atlasRect.y += padding;
|
glyph.valid = true;
|
||||||
glyph.atlasRect.width -= padding*2;
|
}
|
||||||
glyph.atlasRect.height -= padding*2;
|
else
|
||||||
|
{
|
||||||
|
NazaraWarning("Failed to extract glyph \"" + NzString::Unicode(character) + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph.aabb = fontGlyph.aabb;
|
|
||||||
glyph.advance = fontGlyph.advance;
|
|
||||||
glyph.valid = true;
|
|
||||||
}
|
}
|
||||||
else
|
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;
|
return glyph;
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ namespace
|
||||||
return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0;
|
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
|
#ifdef NAZARA_DEBUG
|
||||||
if (!dst)
|
if (!dst)
|
||||||
|
|
@ -97,10 +97,16 @@ namespace
|
||||||
|
|
||||||
const FT_Pos boldStrength = 2 << 6;
|
const FT_Pos boldStrength = 2 << 6;
|
||||||
|
|
||||||
bool outlineFormat = (glyph->format == FT_GLYPH_FORMAT_OUTLINE);
|
bool embolden = (style & nzTextStyle_Bold);
|
||||||
if (outlineFormat && 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
|
// http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden
|
||||||
FT_Outline_Embolden(&glyph->outline, boldStrength);
|
FT_Outline_Embolden(&glyph->outline, boldStrength);
|
||||||
|
embolden = false;
|
||||||
|
}
|
||||||
|
|
||||||
// http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap
|
// http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap
|
||||||
// Conversion du glyphe vers le format 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
|
// 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é
|
// 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
|
// 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"
|
// "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_GlyphSlot_Own_Bitmap(glyph);
|
||||||
FT_Bitmap_Embolden(s_library, &glyph->bitmap, boldStrength, boldStrength);
|
FT_Bitmap_Embolden(s_library, &glyph->bitmap, boldStrength, boldStrength);
|
||||||
|
embolden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dst->advance = glyph->metrics.horiAdvance >> 6;
|
dst->advance += glyph->metrics.horiAdvance >> 6;
|
||||||
if (bold)
|
|
||||||
dst->advance += boldStrength >> 6;
|
|
||||||
|
|
||||||
dst->aabb.x = glyph->metrics.horiBearingX >> 6;
|
dst->aabb.x = glyph->metrics.horiBearingX >> 6;
|
||||||
dst->aabb.y = -(glyph->metrics.horiBearingY >> 6); // Inversion du repère
|
dst->aabb.y = -(glyph->metrics.horiBearingY >> 6); // Inversion du repère
|
||||||
dst->aabb.width = glyph->metrics.width >> 6;
|
dst->aabb.width = glyph->metrics.width >> 6;
|
||||||
|
|
@ -177,22 +181,22 @@ namespace
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NzString GetFamilyName() const
|
NzString GetFamilyName() const override
|
||||||
{
|
{
|
||||||
return m_face->family_name;
|
return m_face->family_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
NzString GetStyleName() const
|
NzString GetStyleName() const override
|
||||||
{
|
{
|
||||||
return m_face->style_name;
|
return m_face->style_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasKerning() const
|
bool HasKerning() const override
|
||||||
{
|
{
|
||||||
return FT_HAS_KERNING(m_face);
|
return FT_HAS_KERNING(m_face);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsScalable() const
|
bool IsScalable() const override
|
||||||
{
|
{
|
||||||
return FT_IS_SCALABLE(m_face);
|
return FT_IS_SCALABLE(m_face);
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +206,7 @@ namespace
|
||||||
return FT_Open_Face(s_library, &m_args, 0, &m_face) == 0;
|
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))
|
if (FT_HAS_KERNING(m_face))
|
||||||
{
|
{
|
||||||
|
|
@ -220,7 +224,7 @@ namespace
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int QueryLineHeight(unsigned int characterSize) const
|
unsigned int QueryLineHeight(unsigned int characterSize) const override
|
||||||
{
|
{
|
||||||
SetCharacterSize(characterSize);
|
SetCharacterSize(characterSize);
|
||||||
|
|
||||||
|
|
@ -228,7 +232,7 @@ namespace
|
||||||
return m_face->size->metrics.height >> 6;
|
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))
|
if (FT_IS_SCALABLE(m_face))
|
||||||
{
|
{
|
||||||
|
|
@ -241,7 +245,7 @@ namespace
|
||||||
return characterSize / 10.f; // Joker ?
|
return characterSize / 10.f; // Joker ?
|
||||||
}
|
}
|
||||||
|
|
||||||
float QueryUnderlineThickness(unsigned int characterSize) const
|
float QueryUnderlineThickness(unsigned int characterSize) const override
|
||||||
{
|
{
|
||||||
if (FT_IS_SCALABLE(m_face))
|
if (FT_IS_SCALABLE(m_face))
|
||||||
{
|
{
|
||||||
|
|
@ -280,6 +284,12 @@ namespace
|
||||||
m_args.stream = &m_stream;
|
m_args.stream = &m_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SupportsStyle(nzUInt32 style) const override
|
||||||
|
{
|
||||||
|
///TODO
|
||||||
|
return style == nzTextStyle_None || style == nzTextStyle_Bold;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetCharacterSize(unsigned int characterSize) const
|
void SetCharacterSize(unsigned int characterSize) const
|
||||||
{
|
{
|
||||||
|
|
@ -299,7 +309,7 @@ namespace
|
||||||
|
|
||||||
bool IsSupported(const NzString& extension)
|
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 = {
|
static std::set<NzString> supportedExtensions = {
|
||||||
"afm", "bdf", "cff", "cid", "dfont", "fnt", "pfa", "pfb", "pfm", "pfr", "sfnt", "tte", "ttf"
|
"afm", "bdf", "cff", "cid", "dfont", "fnt", "pfa", "pfb", "pfm", "pfr", "sfnt", "tte", "ttf"
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue