CEGUI Font资源加载流程

  • Font(字体),主要两个类型的字体:位图字体、矢量字体。
  • 位图字体:PixmapFont,相当于每个字形(glyph)对应一个图片元素。有时候也称为光栅字体。
  • 矢量字体:FreetypeFont,动态字体。每个字形(glyph)由数学矢量组成,支持任意缩放。
  • 本文以CEGUI 0.8.7为例子

Font加载流程

  • CEGUI种可以通过Scheme文件加载,也可以使用下面的代码显式加载。
FontManager::getSingleton().createFromFile("DejaVuSans-12.font");
  • DejaVuSans-12.font 文件内容。
<?xml version="1.0" ?>
<Font version="3" name="DejaVuSans-12" filename="DejaVuSans.ttf" type="FreeType" size="12" nativeHorzRes="1280" nativeVertRes="720" autoScaled="vertical"/>
  • createFromFile会调用到其父类NamedXMLResourceManager的定义。
//----------------------------------------------------------------------------//
template<typename T, typename U>
T& NamedXMLResourceManager<T, U>::createFromFile(const String& xml_filename,const String& resource_group,XMLResourceExistsAction action)
{U xml_loader;xml_loader.handleFile(xml_filename, resource_group);return doExistingObjectAction(xml_loader.getObjectName(),&xml_loader.getObject(), action);
}
  • 这里 U为 Font_xmlHandler 类型,T为 Font类型。Font_xmlHandler为重载handleFile,调用到其父类XMLHandler中的定义。
    void XMLHandler::handleFile(const String& fileName, const String& resourceGroup){System::getSingleton().getXMLParser()->parseXMLFile(*this, fileName, getSchemaName(),resourceGroup.empty() ? getDefaultResourceGroup() :resourceGroup);}
  • 调用到XMLParser中的parseXMLFile函数。FileName就是字体资源文件名,shcemaName为“Font.xsd”,resourceGroup为CEGUI中资源组的概念(可以理解为资源路径),接下来开始解析 .Font文件。这里注意一点,对于Font加载,传入的this,为Font_xmlHandler这个类型。
    void XMLParser::parseXMLFile(XMLHandler& handler, const String& filename, const String& schemaName, const String& resourceGroup){// 省略// Acquire resource using CEGUI ResourceProvider// 这里会把.font文件内容,读入内存RawDataContainer rawXMLData;System::getSingleton().getResourceProvider()->loadRawDataContainer(filename, rawXMLData, resourceGroup);CEGUI_TRY{// The actual parsing action (this is overridden and depends on the specific parser)// 这里开始解析.Font文件中的元素parseXML(handler, rawXMLData, schemaName);}CEGUI_CATCH (const Exception&){// 省略,这里是一些异常的处理}// Release resource// 释放资源System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);}
  • 接下来调用具体xml解析模块的parseXML函数,这里handler(Font_xmlHandler)传入。例如走的是LibxmlParser
void LibxmlParser::parseXML(XMLHandler& handler,const RawDataContainer& source,const String& /*schemaName*/)
{// 从内存中解析,因为之前已经将.font文件内容,加载到内存中了。xmlDocPtr doc = xmlParseMemory(reinterpret_cast<const char*>(source.getDataPtr()),source.getSize());if (!doc){xmlError* err = xmlGetLastError();CEGUI_THROW(GenericException(String("xmlParseMemory failed in file: '") +err->file + "' at line number" +PropertyHelper<uint>::toString(err->line) + ".  Error is:" +err->message));}// get root elementxmlNode* root = xmlDocGetRootElement(doc);// 这里这里开始解析xml元素。processXMLElement(handler, root);// release the xmlDoc xmlFreeDoc(doc);
}
  • processXMLElement的入参为Handler(Font_xmlHandler)和XML的RootElement。
// internal helper function to process elements
void processXMLElement(XMLHandler& handler, xmlNode* node)
{// build attributes block for the element// 省略// element start processing// Font_xmlHandler在这里发挥了这种。element的信息,在这里传给对应的handler。handler.elementStart(reinterpret_cast<const encoded_char*>(node->name), attrs);// 遍历for (xmlNode* cur_node = node->children; cur_node; cur_node = cur_node->next){switch(cur_node->type){case XML_ELEMENT_NODE:// 迭代processXMLElement(handler, cur_node);break;case XML_TEXT_NODE:if (cur_node->content != 0 && *cur_node->content!= '\0')handler.text(reinterpret_cast<const encoded_char*>(cur_node->content));break;default:break;}}// element end processing// 结束解析handler.elementEnd(reinterpret_cast<const encoded_char*>(node->name));
}
  • 这里最重要的是,调用了Font_xmlHandler的elementStart,这里面会真正加载.ttf字体。
//----------------------------------------------------------------------------//
void Font_xmlHandler::elementStart(const String& element,const XMLAttributes& attributes)
{// handle root Font elementif (element == FontElement) // 解析 <Font />中的内容。elementFontStart(attributes);   // handle a Mapping elementelse if (element == MappingElement)elementMappingStart(attributes);// anything else is a non-fatal error.elseLogger::getSingleton().logEvent("Font_xmlHandler::elementStart: ""Unknown element encountered: <" + element + ">", Errors);
}
  • 这个函数里,根据Element Name,做不同的处理。elementFontStart函数中,会根据 Font元素中的内容,加载字体文件。
void Font_xmlHandler::elementFontStart(const XMLAttributes& attributes)
{validateFontFileVersion(attributes);// get type of font being created// 获取字体类型 // 最上面的.font文件中,写明了 type="FreeType"const String font_type(attributes.getValueAsString(FontTypeAttribute));// log the start of font creation.CEGUI_LOGINSANE("Started creation of Font from XML specification:");if (font_type == FontTypeFreeType)  // 矢量字体createFreeTypeFont(attributes);else if (font_type == FontTypePixmap)  // 位图字体createPixmapFont(attributes);elseCEGUI_THROW(InvalidRequestException("Encountered unknown font type of '" + font_type + "'"));
}
  • 接下来调用 createFreeTypeFont,加载矢量字体。
void Font_xmlHandler::createFreeTypeFont(const XMLAttributes& attributes)
{// name="DejaVuSans-12"const String name(attributes.getValueAsString(FontNameAttribute));// filename="DejaVuSans.ttf"const String filename(attributes.getValueAsString(FontFilenameAttribute));const String resource_group(attributes.getValueAsString(FontResourceGroupAttribute));#ifdef CEGUI_HAS_FREETYPE// 创建FreeTypeFont对象,FreeTypeFont在创建过程中,会加载ttf字体文件// 并,构建 字形索引 和字符映射表d_font = CEGUI_NEW_AO FreeTypeFont(name,attributes.getValueAsFloat(FontSizeAttribute, 12.0f),attributes.getValueAsBool(FontAntiAliasedAttribute, true),filename, resource_group,PropertyHelper<AutoScaledMode>::fromString(attributes.getValueAsString(FontAutoScaledAttribute)),Sizef(attributes.getValueAsFloat(FontNativeHorzResAttribute, 640.0f),attributes.getValueAsFloat(FontNativeVertResAttribute, 480.0f)),attributes.getValueAsFloat(FontLineSpacingAttribute, 0.0f));
#elseCEGUI_THROW(InvalidRequestException("CEGUI was compiled without freetype support."));
#endif
}
  • 创建FreeTypeFont对象
FreeTypeFont::FreeTypeFont(const String& font_name, const float point_size,const bool anti_aliased, const String& font_filename,const String& resource_group,const AutoScaledMode auto_scaled,const Sizef& native_res,const float specific_line_spacing) :Font(font_name, Font_xmlHandler::FontTypeFreeType, font_filename,resource_group, auto_scaled, native_res),d_specificLineSpacing(specific_line_spacing),d_ptSize(point_size),d_antiAliased(anti_aliased),d_fontFace(0)
{if (!ft_usage_count++)FT_Init_FreeType(&ft_lib);  // 初始化 FreeTypeaddFreeTypeFontProperties();updateFont(); // 这里会使用 freetype字体引擎处理字体文件char tmp[50];snprintf(tmp, sizeof(tmp), "Successfully loaded %d glyphs",static_cast<int>(d_cp_map.size()));Logger::getSingleton().logEvent(tmp, Informative);
}
  • freetype是一个开源的字体引擎库,关于其概念和使用可以字形百度。接下来updateFont,会使用freetype加载ttf字体文件,进行相关的初始化。
void FreeTypeFont::updateFont()
{free();// 将.ttf 读入到内存中System::getSingleton().getResourceProvider()->loadRawDataContainer(d_filename, d_fontData, d_resourceGroup.empty() ?getDefaultResourceGroup() : d_resourceGroup);FT_Error error;// 使用FreeType创建FontFace对象// create face using input fontif ((error = FT_New_Memory_Face(ft_lib, d_fontData.getDataPtr(),static_cast<FT_Long>(d_fontData.getSize()), 0,&d_fontFace)) != 0)CEGUI_THROW(GenericException("Failed to create face from font file '" +d_filename + "' error was: " +((error < FT_Err_Max) ? ft_errors[error] : "unknown error")));// check that default Unicode character map is availableif (!d_fontFace->charmap){FT_Done_Face(d_fontFace);d_fontFace = 0;CEGUI_THROW(GenericException("The font '" + d_name + "' does not have a Unicode charmap, and ""cannot be used."));}uint horzdpi = static_cast<uint>(System::getSingleton().getRenderer()->getDisplayDPI().d_x);uint vertdpi = static_cast<uint>(System::getSingleton().getRenderer()->getDisplayDPI().d_y);float hps = d_ptSize * 64;float vps = d_ptSize * 64;if (d_autoScaled != ASM_Disabled){hps *= d_horzScaling;vps *= d_vertScaling;}// 设置像素尺寸,其实就是根据字号,进行设定if (FT_Set_Char_Size(d_fontFace, FT_F26Dot6(hps), FT_F26Dot6(vps), horzdpi, vertdpi)){// For bitmap fonts we can render only at specific point sizes.// Try to find nearest point size and use it, if that is possiblefloat ptSize_72 = (d_ptSize * 72.0f) / vertdpi;float best_delta = 99999;float best_size = 0;for (int i = 0; i < d_fontFace->num_fixed_sizes; i++){float size = d_fontFace->available_sizes [i].size * float(FT_POS_COEF);float delta = fabs(size - ptSize_72);if (delta < best_delta){best_delta = delta;best_size = size;}}if ((best_size <= 0) ||FT_Set_Char_Size(d_fontFace, 0, FT_F26Dot6(best_size * 64), 0, 0)){char size [20];snprintf(size, sizeof(size), "%g", d_ptSize);CEGUI_THROW(GenericException("The font '" + d_name + "' cannot be ""rasterised at a size of " + size + " points, and cannot be ""used."));}}if (d_fontFace->face_flags & FT_FACE_FLAG_SCALABLE){//float x_scale = d_fontFace->size->metrics.x_scale * FT_POS_COEF * (1.0/65536.0);float y_scale = d_fontFace->size->metrics.y_scale * float(FT_POS_COEF) * (1.0f / 65536.0f);d_ascender = d_fontFace->ascender * y_scale;d_descender = d_fontFace->descender * y_scale;d_height = d_fontFace->height * y_scale;}else{d_ascender = d_fontFace->size->metrics.ascender * float(FT_POS_COEF);d_descender = d_fontFace->size->metrics.descender * float(FT_POS_COEF);d_height = d_fontFace->size->metrics.height * float(FT_POS_COEF);}if (d_specificLineSpacing > 0.0f){d_height = d_specificLineSpacing;}// 构建字符映像initialiseGlyphMap();
}
  • 字符映像其实是 字符码与字形索引的映射关系。字符码,就是某个字符在某种编码下得值,比如C的ASCII码为83。字形索引,就是字体文件中用来查找某个字形的索引。通过字体文件提供的字符映射表,来查找某个字符码对应的字形索引。
void FreeTypeFont::initialiseGlyphMap()
{FT_UInt gindex;FT_ULong codepoint = FT_Get_First_Char(d_fontFace, &gindex);FT_ULong max_codepoint = codepoint;while (gindex){if (max_codepoint < codepoint)max_codepoint = codepoint;// 这里将字体中,所有的字符码,存储到map中。d_cp_map[codepoint] = FontGlyph();codepoint = FT_Get_Next_Char(d_fontFace, codepoint, &gindex);}setMaxCodepoint(max_codepoint);
}
  • 到这里完成了字体加载的主要部分。字体渲染时,会根据传入的字符码,使用FT_Load_Char函数,将对应的字符码渲染出位图,并进行OpenGL的相应纹理(CEGUI的Render为OPENGL类型时)进行渲染。

【CEGUI】Font资源加载流程相关推荐

  1. 【CEGUI】资源加载流程

    CEGUI资源加载流程 CEGUI版本 0.8.7 主要资源类型 Scheme scheme资源(包括图像集.字体资源.窗口外观信息.类型映射)等.可以通过".scheme"&qu ...

  2. Cocos Creator 资源加载流程剖析【二】——Download部分

    Download流程的处理由Downloader这个pipe负责(downloader.js),Downloader提供了各种资源的"下载"方式--即如何获取文件内容,有从网络获取 ...

  3. android资源加载流程6,FrameWork源码解析(6)-AssetManager加载资源过程

    之前一段时间项目比较忙所以一直没有更新,接下来准备把插件化系列的文章写完,今天我们就先跳过ContentProvider源码解析来讲资源加载相关的知识,资源加载可以说是插件化非常重要的一环,我们很有必 ...

  4. 【CEGUI】字体加载优化

    CEGUI 字体加载优化 CEGUI字体加载流程详见[CEGUI]Font资源加载流程 CEGUI对于字体加载,例如Freetype类型字体,会通过libfreetype遍历字体文件的所有字形索引,并 ...

  5. UE4 资源加载与资源缓存

    前一段时间其实就做完了这个资源预加载的功能,仅仅是根据以往的经验完成的这项功能.最近稍微有一点时间,就把UE4资源加载和缓存的整体流程进行了分析,这样可以对整个UE4资源管理流程有更深入的了解,同时也 ...

  6. 【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  7. 浏览器页面资源加载过程与优化

    评价页面性能好坏的核心之一就是页面的加载速度,而页面加载速度的关键就是页面资源的加载.本文将从浏览器浏览器页面资源加载过程展开分析,来引出页面关键请求路径的概念,并给出如何优化该关键请求路径的一些方法 ...

  8. Cocos Creator2.4.8 资源加载源码阅读

    最近用到资源加载的问题:加载的资源进度条倒退问题,现在只是用临时的解决方案 - 加载进度如果出现会倒退的问题还是用原来的数值.抽时间看了下cocos creator 资源加载的源码,整理了一下脑图 一 ...

  9. QT程序启动加载流程简介

    1. QT应用程序启动加载流程简介 1.1      QWS与QPA启动客户端程序区别 1.1.1   QWS(Qt Window System)介绍 QWS(Qt Windows System)是Q ...

最新文章

  1. 随着加密货币市场稳定 比特币价格不可避免的会下降
  2. POJ - 3070 Fibonacci
  3. 使用SVCUtil.exe生成客户端代理类和配置文件
  4. 微软嵌入式WEC2013产品研讨会(深圳站---2013.10.16)
  5. python之钉钉机器人编程
  6. 如何在.NET上处理二维码
  7. 项目管理工具篇(一、Maven)
  8. 服务器压力测试_魔兽世界怀旧服:美服18日开放安其拉开门测试,P5阶段即将来临...
  9. ubuntu如何杀死进程
  10. vba上传指定文件ftp服务器
  11. insert into select from 部分字段插入_MySQL的故障分析,Insert 加锁与死锁分析-爱可生
  12. 考英语四级误用六级题 千余考生困教室4个小时
  13. sas rename重命名_如何使用sp_rename命令在SQL Server中重命名表
  14. c bool 类型检查_第3篇:C/C++ 检查数字类型的最高有效位(MSB)
  15. 数据同步工具:Canal
  16. MSN天气不显示数据、打不开、微软商店打不开报错0x80131500
  17. 周易六十四卦——地风升卦
  18. BZOJ 1002 1003 1007 被屠记录
  19. 视频号带货优势有哪些?普通人为什么要做视频号:国仁楠哥
  20. 三个选择框,当前框选过之后的数据其他两个不能选择

热门文章

  1. 物联网的安全问题引起争论,这些威胁有待解决...
  2. 【设计模式】JAVA 枚举实现策略模式
  3. WinDebug 常用命令表【摘】
  4. cadence ORCAD因为不正常关闭导致opj文件打不开的解决办法
  5. [TopCoder 12984] TorusSailing(高斯消元主元法优化)
  6. Maching Learning 学习资料
  7. Java 高并发,什么方式解决?高并发和大流量解决方案
  8. JS伪3D 图形透视效果
  9. 在PPT中插入并嵌入SWF文件图文教程
  10. AI会抢走我们的饭碗?现在报告破解谜失