OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)
视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440

OpenGL本身并没有绘制文字的功能,他只是一个三维绘图的API集和,很多东西都要
自己动手才可以实现。OpenGL绘制文字,网络上已经有很多成熟的方式方法,我这里给
大家介绍的是我使用的方式,从绘制的效率上来说,速度上从已经达到我个人水平的最大值。
如果你有更好的方式,请联系我。
首先介绍下网络上的一些绘制方式。
一、将要绘制的文字按照每一个字生成一个小纹理的方式,然后再用将纹理贴到网格
的表面,绘制出来,例如:“博客园-你好”,则会生成6个小纹理,然后生成网格,将纹理
贴到网格的表面。优点:每一个字的大小颜色都可选择。缺点:文字多了以后,频繁的切换
纹理造成效率低下。OSG中使用了这种方式,效率极差,尤其是在文字更新的情况下。
二、直接将随绘制的文本字符串生成一个纹理数据(而不是一个文字一个纹理),这样
做效率上比第一种要好很多,缺点就是更新的时候要重新构建一个新的纹理。速度上有很大
损失。两种方式的原理图如下:

三、将所绘制的文字都放到一个较大的纹理上去,然后再纹理上做索引,当绘制的时候,
去查表。在将纹理贴到网格上绘制出来,这种方式,速度很快,很多游戏引擎都在使用这种
方式,存在的问题绘制的文字多了以后速度会变慢,占用大量的cpu时间,当然对于小的应
用已经足够了,今天我提出的方式也是基于这样方式的,只是我在索引上最了一些改进,改
进之后的算法,将不再进行查表操作,而是直接索引,一定程度上降低了cpu消耗,提搞了
效率。纹理图片如下示意图:

图片存的数据上也很重要,结合OpenGL,采用GL_ALPHA的上存储,这样可以大大
降低图片所占用的显存空间,从而提高效率。
下面定义一个文字所存储的信息,如下所示:
class Character
{
public:
Character()
{
x0 = ;
y0 = ;
x1 = ;
y1 = ;
}
/**
* 存储当前字符在纹理上的坐标位置
*/
unsigned short x0;
unsigned short y0;
unsigned short x1;
unsigned short y1;
};
为了快速索引,减少查找的过程,我么要结合字体本上来做一些处理,我们知道一个汉字要占用2个字节
两个字节所能表示的范围是0-65535,就是6万多个汉字,那么我们就声明一个这么大的数组来存储字符的
信息:
代码如下:
Character g_charMap[<<];
当我们要绘制一个文字的时候,可以直接通过下标就可以直接定位到该字对应的信息了,例如我们绘制'中'
就可以直接获取其在图片上的内容了:
Character getCharacter(wchar_t ch)
{
return g_charMap[ch];
}
然后这样也存在一个问题,即一张多大的纹理才可以容纳这么多的字符呢?如果是一般的应用,我们可以忽略
这个问题,中国常用的汉字只有3000多个,假设是一个汉字占16*16的空间,那么一个1024*1024的纹理
所能容纳的字符有 1024/16 * 1024/16 = 4096个,足够满足正常的需要,如果你是想做一个通用的,没有
瑕疵的应用,我们就要修改我们的设计方式,我能一切从速度优先的方式考虑,我们在上面的Character类中
增加一个字段描述字符所在的纹理句柄,如下:
class Character
{
public:
Character()
{
x0 = ;
y0 = ;
x1 = ;
y1 = ;
texId = ;
}
unsigned short x0;
unsigned short y0;
unsigned short x1;
unsigned short y1;
//! 索引纹理,即当前字符所在的纹理
unsigned texId;
};
这样,就可以拜托之前的限制,实现大规模的绘制文字了。
说完了方案,我们还有说下实现方式,说道文字绘制,不得不提的就是FreeType字体库了
几乎所有的三维绘制文字的方式,都采用这个库。下面以代码的方式来介绍他,我们这里
只用到其中很少的一部分(FreeType)相关内容这里不做介绍,有兴趣的同学可以自行了解。
第一步:初始化字体库
FT_Init_FreeType( &_library );
第二步:加载字体
FT_New_Face(_library,_fontFace,,&_face);
第三步:设置字体大小
FT_Set_Char_Size( _face, fontSize << , fontSize << , , );
第四步:获取字体的信息
FT_Load_Glyph( face, FT_Get_Char_Index( face, code ), FT_LOAD_DEFAULT );
FT_Glyph glyph;
FT_Get_Glyph( face->glyph, &glyph );
//Convert the glyph to a bitmap.
FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, , );
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
//This reference will make accessing the bitmap easier
FT_Bitmap& bitmap = bitmap_glyph->bitmap;
第五步:将bmp数据写到纹理上
glTexSubImage2D(GL_TEXTURE_2D,,x,y,width,height,GL_ALPHA,GL_UNSIGNED_BYTE,data);
第六步:生成网格,贴上纹理绘制文字
RESULT IGraphyDeviceImpl::draw2DText(const wchar_t* text,float x,float y,const Rgba4Byte& color,RectF* pOut)
{ typedef float TextVertex[];
TextVertex vert[ * ]; float texWidth = (float)_fontDefault._textures._width;
float texHeight = (float)_fontDefault._textures._height;
float xStart = x;
float yStart = y;
float zStart = ;
unsigned index = ;
unsigned nSize = wcslen(text);
float fHeight = ; for (unsigned i = ;i < nSize; ++ i )
{
Character* ch = _fontDefault.getCharacter(text[i]); int h = ch->y1 - ch->y0;
int w = ch->x1 - ch->x0;
/**
* 第一个点
*/
vert[index + ][] = xStart;
vert[index + ][] = yStart;
vert[index + ][] = zStart;
vert[index + ][] = ch->x0/texWidth;
vert[index + ][] = ch->y0/texHeight;
/**
* 第二个点
*/
vert[index + ][] = xStart;
vert[index + ][] = yStart + h;
vert[index + ][] = zStart;
vert[index + ][] = ch->x0/texWidth;
vert[index + ][] = ch->y1/texHeight;
/**
* 第二个点
*/
vert[index + ][] = xStart + w;
vert[index + ][] = yStart + h;
vert[index + ][] = zStart;
vert[index + ][] = ch->x1/texWidth;
vert[index + ][] = ch->y1/texHeight; /**
* 第二个三角形
*/
vert[index + ][] = xStart;
vert[index + ][] = yStart;
vert[index + ][] = zStart;
vert[index + ][] = ch->x0/texWidth;
vert[index + ][] = ch->y0/texHeight; /**
* 第二个点
*/
vert[index + ][] = xStart + w;
vert[index + ][] = yStart + h;
vert[index + ][] = zStart;
vert[index + ][] = ch->x1/texWidth;
vert[index + ][] = ch->y1/texHeight; /**
* 第二个点
*/
vert[index + ][] = xStart + w;
vert[index + ][] = yStart;
vert[index + ][] = zStart;
vert[index + ][] = ch->x1/texWidth;
vert[index + ][] = ch->y0/texHeight; index += ;
xStart += w;
}
glColor4ub(color._r,color._g,color._b,color._a);
/**
* 对字体使用到的纹理和定点坐标进行排序
*/
bindTexture2D(_fontDefault._textures._texture); CELL::Graphy::VertexDeclaration fontDesc[] =
{
, CELL::Graphy::TYPE_VERTEX, CELL::Graphy::FORMAT_FLOAT, , , sizeof(TextVertex),
, CELL::Graphy::TYPE_TEXCOORD0,CELL::Graphy::FORMAT_FLOAT, , , sizeof(TextVertex)
}; drawPrimitiveDirect(fontDesc,,PT_TRIANGLELIST,vert,,index);
上面简单的介绍了如何使用FreeType与OpenGL绘制文字,笔者能力所致,说解不到之处,有误之处,敬请谅解,指教。
OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)的更多相关文章
- 使用 highchart 绘制柱状图的通用方法与接口
本文给出使用 highchart 绘制柱状图的通用方法与接口, 只要指定相应的数据结构和配置, 就可以直接拿来使用. 一. 数据结构与基本接口 一般绘制图形, 会涉及到较复杂的数据结构, 比如使 ...
- Word 2010巧妙绘制各种分割线的方法(图文)
引用: 使用Word编辑文档时,可能为了使某些内容醒目显示,或者为了使文档内容显示的更美观.更有层次感,需要为文档添加一些分割线,如添加下框线.插入水平线.使用特殊符号快速绘制分割线等等.在Word ...
- 使用JsPlumb绘制拓扑图的通用方法
转自:http://www.it165.net/pro/html/201311/7616.html 使用JsPlumb绘制拓扑图的通用方法 一. 实现目标 绘制拓扑图, 实际上是个数据结构和算法的问题 ...
- javascript 使用数组+循环+条件实现数字转换为汉字的简单方法。
这几天,博主碰到了几道关于数字转汉字的javascript算法题,在网上找了很多的答案,发现都有点复杂,于是我决定自己写一篇关于这种算法题的简单解法,以下是博主自己的见解,有不足的地方请多指教. 接下 ...
- Python使用plotly绘制数据图表的方法
转载:http://www.jb51.net/article/118936.htm 本篇文章主要介绍了Python使用plotly绘制数据图表的方法,实例分析了plotly绘制的技巧. 导语:使用 p ...
- 使用 JsPlumb 绘制拓扑图的通用方法
摘要: 实现 JsPlumb 绘制拓扑图的通用方法. 只要服务端返回一个符合指定格式的数据结构,就可以绘制相应的拓扑图. 难度: 中级 示例工程见: http://download.csdn.net ...
- 教你如何写出高效整洁的 css 代码——css优化(转载)
css 写起来并不难,但在大型项目中,就变得难以管理,特别是不同的人在 css 书写风格上稍有不同,团队上就更加难以沟通,为此总结了一些如何实现高效整洁的 css 代码原则. css 优化的原则 1. ...
- YbSoftwareFactory 代码生成插件【二十五】:Razor视图中以全局方式调用后台方法输出页面代码的三种方法
上一篇介绍了 MVC中实现动态自定义路由 的实现,本篇将介绍Razor视图中以全局方式调用后台方法输出页面代码的三种方法. 框架最新的升级实现了一个页面部件功能,其实就是通过后台方法查询数据库内容,把 ...
- JQuery 获取json数据$.getJSON方法的实例代码
这篇文章介绍了JQuery 获取json数据$.getJSON方法的实例代码,有需要的朋友可以参考一下 前台: function SelectProject() { var a = new Array ...
随机推荐
- 转换图片为base64
既然有了解析base64图片,那么就一定会有将图片编码格式成base64,其中解码base64用BASE64Decoder,而编码base64用BASE64Encoder, 上代码: //图片转化成b ...
- Java性能调优:利用JFR生成性能日志
Java性能调优作为大型分布式系统提供高性能服务的必修课,其重要性不言而喻. 好的分析工具能起到事半功倍的效果,利用分析利器JMC.JFR,可以实现性能问题的准确定位. 本文主要阐述如何利用JFR生成 ...
- jquery 问题
detach():这个方法不会把匹配的元素从jQuery对象中删除,因而可以在将来再使用这些匹配的元素.与remove()不同的是,所有绑定的事件.附加的数据等都会保留下来. jquery ajax不 ...
- git 在非空文件夹clone新项目
在非空目录下 git clone 项目时会提示错误信息: fatal: destination path '.' already exists and is not an empty director ...
- ASP.NET MVC 使 Controller 的 Action 只接受 Ajax 请求。
首先,ajax 请求跟一般的 web 请求本质是相同的,都是 http 请求.理论上服务器端是无法区分该次请求是不是 ajax 请求的,但是,既然标题都已经说了,那么肯定是有办法做的. 在 ajax ...
- Android Studio 集成 TFS,实现安卓移动开发的持续集成和交付(DevOps)
目录 1 集成TFS系统.... 1.1 概述.... 1.2 安装TFS插件.... 1.2.1 在线安装方式.... 1.2.2 离线安装方案.... 1.3 常见操作.... 1.3.1 新建G ...
- net生成图片验证码--转自Lisliefor
目前,机器识别验证码已经相当强大了,比较常见的避免被机器识别的方法,就是将验证码的字符串连到一起,这样就加大的识别的难度,毕竟机器没有人工智能.我找了很多的.net生成图片验证码的例子,后来经过一些修 ...
- C博客作业03—函数
1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量学习体会 1.2.1 学习体会 知道了程序的模块化设计可使程序结构清晰,简化复杂问题,解决代码重复问题 学会使用自定义函数简化主函数,使代码 ...
- 《Python黑帽子:黑客与渗透测试编程之道》 扩展Burp代理
下载jython,在Burpsuite的扩展中配置jython路径: Burp模糊测试: #!/usr/bin/python #coding=utf-8 # 导入三个类,其中IBurpExtender ...
- FastAdmin 前端页面传参
如果我们需要自己在控制器中透传数据到JS中去,则可以使用控制器的assignconfig方法来透传,使用如下 $this->assignconfig('demo', ['name'=>'名 ...