// ---------------------------------------------------------------------------- void FontWithFace::loadGlyphInfo(wchar_t c) { unsigned int font_number = 0; unsigned int glyph_index = 0; while (font_number < m_face_ttf->getTotalFaces()) { glyph_index = FT_Get_Char_Index(m_face_ttf->getFace(font_number), c); if (glyph_index > 0) break; font_number++; } m_character_glyph_info_map[c] = GlyphInfo(font_number, glyph_index); } // loadGlyphInfo
bool ParagraphLayout::_AppendGlyphInfo(uint32 charCode, float width, const CharacterStyle& style) { if (style.Width() >= 0.0f) { // Use the metrics provided by the CharacterStyle and override // the font provided metrics passed in "width" width = style.Width(); } width += style.GlyphSpacing(); return fGlyphInfos.Add(GlyphInfo(charCode, 0.0f, width, 0)); }
GlyphInfo ResourceTrueTypeFont::createFaceGlyphInfo(Char _codePoint, int _fontAscent, FT_GlyphSlot _glyph) { float bearingX = _glyph->metrics.horiBearingX / 64.0f; // The following calculations aren't currently needed but are kept here for future use. // float ascent = _glyph->metrics.horiBearingY / 64.0f; // float descent = (_glyph->metrics.height / 64.0f) - ascent; return GlyphInfo( _codePoint, std::max((float)_glyph->bitmap.width, _glyph->metrics.width / 64.0f), std::max((float)_glyph->bitmap.rows, _glyph->metrics.height / 64.0f), (_glyph->advance.x / 64.0f) - bearingX, bearingX, std::floor(_fontAscent - (_glyph->metrics.horiBearingY / 64.0f) - mOffsetHeight)); }
ComposingStick::ComposingStick(FontRenderer* renderer, PixelSize size, euint32 numChars, xhn::static_string filename) : m_renderer(renderer) , m_pixelSize(size) , m_filename(filename) { int numCharsPerRow = (int)sqrtf((float)numChars + 0.5f); euint32 fontPixelWidth = (euint32)size; euint32 fontPixelHeight = fontPixelWidth; euint32 texPixelWidth = (euint32)(numCharsPerRow + 1) * fontPixelWidth; euint32 texPixelHeight = texPixelWidth; euint32 numHoris = numCharsPerRow; euint32 numVerts = numCharsPerRow; for (euint32 y = 0; y < numVerts; y++) { for (euint32 x = 0; x < numHoris; x++) { GlyphInfo* info = ENEW GlyphInfo(); info->x = x * fontPixelWidth; info->y = y * fontPixelHeight; info->width = fontPixelWidth; info->height = fontPixelHeight; info->usageCount = 0; m_freeGlyphPool.push_back(info); } } /// here create texture m_texture = RenderSystem_new_texture2d(filename.c_str(), "Texture"); m_texture->Create(RGBA8, texPixelWidth, texPixelHeight); EColor color; color.red = 0.0f; color.green = 0.0f; color.blue = 0.0f; color.alpha = 0.0f; m_texture->LoadFromColor(color); }
void ResourceManualFont::deserialization(xml::ElementPtr _node, Version _version) { Base::deserialization(_node, _version); xml::ElementEnumerator node = _node->getElementEnumerator(); while (node.next()) { if (node->getName() == "Property") { const std::string& key = node->findAttribute("key"); const std::string& value = node->findAttribute("value"); if (key == "Source") mSource = value; else if (key == "DefaultHeight") mDefaultHeight = utility::parseInt(value); } } loadTexture(); if (mTexture != nullptr) { int textureWidth = mTexture->getWidth(); int textureHeight = mTexture->getHeight(); node = _node->getElementEnumerator(); while (node.next()) { if (node->getName() == "Codes") { xml::ElementEnumerator element = node->getElementEnumerator(); while (element.next("Code")) { std::string value; // описане глифов if (element->findAttribute("index", value)) { Char id = 0; if (value == "cursor") id = static_cast<Char>(FontCodeType::Cursor); else if (value == "selected") id = static_cast<Char>(FontCodeType::Selected); else if (value == "selected_back") id = static_cast<Char>(FontCodeType::SelectedBack); else if (value == "substitute") id = static_cast<Char>(FontCodeType::NotDefined); else id = utility::parseUInt(value); float advance(utility::parseValue<float>(element->findAttribute("advance"))); FloatPoint bearing(utility::parseValue<FloatPoint>(element->findAttribute("bearing"))); // texture coordinates FloatCoord coord(utility::parseValue<FloatCoord>(element->findAttribute("coord"))); // glyph size, default to texture coordinate size std::string sizeString; FloatSize size(coord.width, coord.height); if (element->findAttribute("size", sizeString)) { size = utility::parseValue<FloatSize>(sizeString); } if (advance == 0.0f) advance = size.width; GlyphInfo& glyphInfo = mCharMap.insert(CharMap::value_type(id, GlyphInfo( id, size.width, size.height, advance, bearing.left, bearing.top, FloatRect( coord.left / textureWidth, coord.top / textureHeight, coord.right() / textureWidth, coord.bottom() / textureHeight) ))).first->second; if (id == FontCodeType::NotDefined) mSubstituteGlyphInfo = &glyphInfo; } } } } } }
void ResourceTrueTypeFont::initialiseFreeType() { //-------------------------------------------------------------------// // Initialise FreeType and load the font. //-------------------------------------------------------------------// FT_Library ftLibrary; if (FT_Init_FreeType(&ftLibrary) != 0) MYGUI_EXCEPT("ResourceTrueTypeFont: Could not init the FreeType library!"); uint8* fontBuffer = nullptr; FT_Face ftFace = loadFace(ftLibrary, fontBuffer); if (ftFace == nullptr) { MYGUI_LOG(Error, "ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!"); return; } //-------------------------------------------------------------------// // Calculate the font metrics. //-------------------------------------------------------------------// // The font's overall ascent and descent are defined in three different places in a TrueType font, and with different // values in each place. The most reliable source for these metrics is usually the "usWinAscent" and "usWinDescent" pair of // values in the OS/2 header; however, some fonts contain inaccurate data there. To be safe, we use the highest of the set // of values contained in the face metrics and the two sets of values contained in the OS/2 header. int fontAscent = ftFace->size->metrics.ascender >> 6; int fontDescent = -ftFace->size->metrics.descender >> 6; TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(ftFace, ft_sfnt_os2); if (os2 != nullptr) { setMax(fontAscent, os2->usWinAscent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM); setMax(fontDescent, os2->usWinDescent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM); setMax(fontAscent, os2->sTypoAscender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM); setMax(fontDescent, -os2->sTypoDescender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM); } // The nominal font height is calculated as the sum of its ascent and descent as specified by the font designer. Previously // it was defined by MyGUI in terms of the maximum ascent and descent of the glyphs currently in use, but this caused the // font's line spacing to change whenever glyphs were added to or removed from the font definition. Doing it this way // instead prevents a lot of layout problems, and it is also more typographically correct and more aesthetically pleasing. mDefaultHeight = fontAscent + fontDescent; // Set the load flags based on the specified type of hinting. FT_Int32 ftLoadFlags; switch (mHinting) { case HintingForceAuto: ftLoadFlags = FT_LOAD_FORCE_AUTOHINT; break; case HintingDisableAuto: ftLoadFlags = FT_LOAD_NO_AUTOHINT; break; case HintingDisableAll: // When hinting is completely disabled, glyphs must always be rendered -- even during layout calculations -- due to // discrepancies between the glyph metrics and the actual rendered bitmap metrics. ftLoadFlags = FT_LOAD_NO_HINTING | FT_LOAD_RENDER; break; case HintingUseNative: ftLoadFlags = FT_LOAD_DEFAULT; break; } //-------------------------------------------------------------------// // Create the glyphs and calculate their metrics. //-------------------------------------------------------------------// GlyphHeightMap glyphHeightMap; int texWidth = 0; // Before creating the glyphs, add the "Space" code point to force that glyph to be created. For historical reasons, MyGUI // users are accustomed to omitting this code point in their font definitions. addCodePoint(FontCodeType::Space); // Create the standard glyphs. for (CharMap::iterator iter = mCharMap.begin(); iter != mCharMap.end(); ) { const Char& codePoint = iter->first; FT_UInt glyphIndex = FT_Get_Char_Index(ftFace, codePoint); texWidth += createFaceGlyph(glyphIndex, codePoint, fontAscent, ftFace, ftLoadFlags, glyphHeightMap); // If the newly created glyph is the "Not Defined" glyph, it means that the code point is not supported by the font. // Remove it from the character map so that we can provide our own substitute instead of letting FreeType do it. if (iter->second != 0) ++iter; else mCharMap.erase(iter++); } // Do some special handling for the "Space" and "Tab" glyphs. GlyphInfo* spaceGlyphInfo = getGlyphInfo(FontCodeType::Space); if (spaceGlyphInfo != nullptr && spaceGlyphInfo->codePoint == FontCodeType::Space) { // Adjust the width of the "Space" glyph if it has been customized. if (mSpaceWidth != 0.0f) { texWidth += (int)std::ceil(mSpaceWidth) - (int)std::ceil(spaceGlyphInfo->width); spaceGlyphInfo->width = mSpaceWidth; spaceGlyphInfo->advance = mSpaceWidth; } // If the width of the "Tab" glyph hasn't been customized, make it eight spaces wide. if (mTabWidth == 0.0f) mTabWidth = mDefaultTabWidth * spaceGlyphInfo->advance; } // Create the special glyphs. They must be created after the standard glyphs so that they take precedence in case of a // collision. To make sure that the indices of the special glyphs don't collide with any glyph indices in the font, we must // use glyph indices higher than the highest glyph index in the font. FT_UInt nextGlyphIndex = (FT_UInt)ftFace->num_glyphs; float height = (float)mDefaultHeight; texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::Tab), 0.0f, 0.0f, mTabWidth, 0.0f, 0.0f), glyphHeightMap); texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::Selected), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap); texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::SelectedBack), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap); texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::Cursor), mCursorWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap); // If a substitute code point has been specified, check to make sure that it exists in the character map. If it doesn't, // revert to the default "Not Defined" code point. This is not a real code point but rather an invalid Unicode value that // is guaranteed to cause the "Not Defined" special glyph to be created. if (mSubstituteCodePoint != FontCodeType::NotDefined && mCharMap.find(mSubstituteCodePoint) == mCharMap.end()) mSubstituteCodePoint = static_cast<Char>(FontCodeType::NotDefined); // Create the "Not Defined" code point (and its corresponding glyph) if it's in use as the substitute code point. if (mSubstituteCodePoint == FontCodeType::NotDefined) texWidth += createFaceGlyph(0, static_cast<Char>(FontCodeType::NotDefined), fontAscent, ftFace, ftLoadFlags, glyphHeightMap); // Cache a pointer to the substitute glyph info for fast lookup. mSubstituteGlyphInfo = &mGlyphMap.find(mSubstituteCodePoint)->second; // Calculate the average height of all of the glyphs that are in use. This value will be used for estimating how large the // texture needs to be. double averageGlyphHeight = 0.0; for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j) averageGlyphHeight += j->first * j->second.size(); averageGlyphHeight /= mGlyphMap.size(); //-------------------------------------------------------------------// // Calculate the final texture size. //-------------------------------------------------------------------// // Round the current texture width and height up to the nearest powers of two. texWidth = Bitwise::firstPO2From(texWidth); int texHeight = Bitwise::firstPO2From((int)ceil(averageGlyphHeight) + mGlyphSpacing); // At this point, the texture is only one glyph high and is probably very wide. For efficiency reasons, we need to make the // texture as square as possible. If the texture cannot be made perfectly square, make it taller than it is wide, because // the height may decrease in the final layout due to height packing. while (texWidth > texHeight) { texWidth /= 2; texHeight *= 2; } // Calculate the final layout of all of the glyphs in the texture, packing them tightly by first arranging them by height. // We assume that the texture width is fixed but that the texture height can be adjusted up or down depending on how much // space is actually needed. // In most cases, the final texture will end up square or almost square. In some rare cases, however, we can end up with a // texture that's more than twice as high as it is wide; when this happens, we double the width and try again. do { if (texHeight > texWidth * 2) texWidth *= 2; int texX = mGlyphSpacing; int texY = mGlyphSpacing; for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j) { for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i) { GlyphInfo& info = *i->second; int glyphWidth = (int)std::ceil(info.width); int glyphHeight = (int)std::ceil(info.height); autoWrapGlyphPos(glyphWidth, texWidth, glyphHeight, texX, texY); if (glyphWidth > 0) texX += mGlyphSpacing + glyphWidth; } } texHeight = Bitwise::firstPO2From(texY + glyphHeightMap.rbegin()->first); } while (texHeight > texWidth * 2); //-------------------------------------------------------------------// // Create the texture and render the glyphs onto it. //-------------------------------------------------------------------// if (mTexture) { RenderManager::getInstance().destroyTexture( mTexture ); mTexture = nullptr; } mTexture = RenderManager::getInstance().createTexture(MyGUI::utility::toString((size_t)this, "_TrueTypeFont")); mTexture->createManual(texWidth, texHeight, TextureUsage::Static | TextureUsage::Write, Pixel<LAMode>::getFormat()); mTexture->setInvalidateListener(this); uint8* texBuffer = static_cast<uint8*>(mTexture->lock(TextureUsage::Write)); if (texBuffer != nullptr) { // Make the texture background transparent white. for (uint8* dest = texBuffer, * endDest = dest + texWidth * texHeight * Pixel<LAMode>::getNumBytes(); dest != endDest; ) Pixel<LAMode, false, false>::set(dest, charMaskWhite, charMaskBlack); renderGlyphs<LAMode, Antialias>(glyphHeightMap, ftLibrary, ftFace, ftLoadFlags, texBuffer, texWidth, texHeight); mTexture->unlock(); MYGUI_LOG(Info, "ResourceTrueTypeFont: Font '" << getResourceName() << "' using texture size " << texWidth << " x " << texHeight << "."); MYGUI_LOG(Info, "ResourceTrueTypeFont: Font '" << getResourceName() << "' using real height " << mDefaultHeight << " pixels."); } else { MYGUI_LOG(Error, "ResourceTrueTypeFont: Error locking texture; pointer is nullptr."); } FT_Done_Face(ftFace); FT_Done_FreeType(ftLibrary); delete [] fontBuffer; }