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;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue