博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux OpenGL 实践篇-16 文本绘制
阅读量:5263 次
发布时间:2019-06-14

本文共 4647 字,大约阅读时间需要 15 分钟。

文本绘制

  本文主要射击Freetype的入门理解和在OpenGL中实现文字的渲染。

freetype

  freetype的官网,本文大部分内容参考

library

  FreeType中的library其类型是FT_Library,定义如下:

typedef struct FT_LibraryRec_  *FT_Library;

 

  所以可以简单的理解为一个FT_LibraryRec_的对象,虽然FreeType用c写的,但这个地方不妨碍我们使用对象来理解它。因为_LibraryRec_我并没有看到源代码,具体包含哪些内容我并不清楚。但根据其用法,可以推测其应该是一些字体上下文的内容,比如缓存、内存管理等。

FT_Error = FT_Init_Freetype(&library);

 

face

  一个face可以理解为字体的描述或者说字形的集合,比如“Times New Roman Regular"表示正常的新罗马字体,而"Times New Roman Italic"表示新罗马字体的斜体表示。一个字体文件中可以嵌入多个face,我们可以通过下面的API加载特定的face:

  

FT_Error FT_New_Face(FT_Library library,const char* filepathname,FT_Long face_index,FT_Face *aface);

 

  其中face_index就表示要加载字体文件中的哪个face,一般情况下,0总是可用的。如果face_index设置为-1,则可以通过face->num_faces获取字体文件中有多少个face。

error = FT_New_Face(library,"./arial.ttf",0,&face);

字体大小

error = FT_Set_Char_Size(          face,    /* handle to face object           */          0,       /* char_width in 1/64th of points  */          16*64,   /* char_height in 1/64th of points */          300,     /* horizontal device resolution    */          300 );   /* vertical device resolution      */

  在这里有两个概念需要注意:pt和dpi。pt是point的缩写,可以立即为一个点,一个点的大小使用物理距离来描述的,通常是1/72英寸。dpi的意思是dot per inch,表示每英寸有多少个点,这个点表示的是显示设备最小输出单元,可以理解为我们常说的像素,主流显示设备的标准值是72dpi和96dpi,这个可以在显示器配置中查到。所以在这个方法中通过同时指定pt大小和设备的dpi,根据换算关系可以计算字符的像素大小。

  下面的代码直接设置字形的像素大小。注意这两个方法中,width的值设置为0,表示width与height一样,height设置为0同理。

error = FT_Set_Pixel_Sizes(          face,   /* handle to face object */          0,      /* pixel_width           */          16 );   /* pixel_height          */

glyph

  字形,其实就是某个字符具体的形状描述。字形的描述有两种,一种是位图,一种是矢量图。位图又叫点阵图,简单理解就是图像是由一个一个像素点组成,每个像素点可以有自己的颜色;矢量图则记录的是一个一个的对象,这些对象是一种形状,形状由数学公式来描述的,简单的理解就是矢量图记录的是图像的画法。这两种描述最大的区别就是,缩放的时候矢量图不会失真。

  使用FreeType的时候,我们不需要关心这些底层的实现,直接使用FT_Load_Glyph即可加载。

FT_UInt FT_Get_Char_Index( FT_Face   face,                     FT_ULong  charcode );FT_Error FT_Load_Glyph( FT_Face   face,                 FT_UInt   glyph_index, //The index of the glyph in the font file.                  FT_Int32  load_flags );  //A flag indicating what to load for this glyph
FT_Error FT_Render_Glyph( face->glyph,   /* glyph slot  */                         render_mode ); /* render mode */
 

   字形的数据结构:

typedef struct  FT_GlyphSlotRec_  {    FT_Library        library;    FT_Face           face;    FT_GlyphSlot      next;    FT_UInt           reserved;       /* retained for binary compatibility */    FT_Generic        generic;    FT_Glyph_Metrics  metrics;    FT_Fixed          linearHoriAdvance;    FT_Fixed          linearVertAdvance;    FT_Vector         advance;    FT_Glyph_Format   format;    FT_Bitmap         bitmap;    FT_Int            bitmap_left;    FT_Int            bitmap_top;    FT_Outline        outline;    FT_UInt           num_subglyphs;    FT_SubGlyph       subglyphs;    void*             control_data;    long              control_len;    FT_Pos            lsb_delta;    FT_Pos            rsb_delta;    void*             other;    FT_Slot_Internal  internal;  } FT_GlyphSlotRec;

 

  在字形数据结构中,几个比较重要的数据是bitmap,bitmap_left,bitmap_top。其中bitmap其实可以理解为字形的位图数据,定义如下:

typedef struct  FT_Bitmap_  {    unsigned int    rows;    unsigned int    width;    int             pitch;    unsigned char*  buffer;    unsigned short  num_grays;    unsigned char   pixel_mode;    unsigned char   palette_mode;    void*           palette;  } FT_Bitmap;

  其中buffer像素数据,rows,width表示图像的宽和高,我们在OpenGL中绘制时主要用到的三个数据。

   除了bitmap,还有几个重要的数据,这写数据主要影响多个文本之间的布局,因为不是每个字形的大小都是一样的,比如bitmap_left,bitmap_right等。让我们以下图为例说明一下FreeType对于字形的描述:

  每一个字形都放在一个水平的基准线(Baseline)上(即上图中水平箭头指示的那条线)。一些字形恰好位于基准线上(如’X’),而另一些则会稍微越过基准线以下(如’g’或’p’)(译注:即这些带有下伸部的字母,可以见)。这些度量值精确定义了摆放字形所需的每个字形距离基准线的偏移量,每个字形的大小,以及需要预留多少空间来渲染下一个字形。下面这个表列出了我们需要的所有属性。

 

在OpenGL中绘制文字 

  FreeType 官网有些例子给我们参考,点击查看。其中一个简单的是在终端中以字符的形式输出字形,这个例子可以帮助我们理解bitmap中的数据形式。

  获取到字形的bitmap后,在OpenGL绘制文字的思路就很简单了:根据字形数据生成二维纹理,然后把这个纹理绘制到一个四方形中,以下是绘制的主要代码,完整代码见:。

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //禁用字节对齐限制     unsigned int textureID;    glGenTextures(1,&textureID);    glBindTexture(GL_TEXTURE_2D,textureID);    glTexImage2D(GL_TEXTURE_2D,0,format,width,height,0,format,GL_UNSIGNED_BYTE,data);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);

  在这里需要注意字节对齐的问题,OpenGL默认要求纹理4字节对齐,即纹理的大小是4的倍数,这通常不会有什么问题,因为绝大多数的纹理大小都是4的倍数并/或每个橡树4字节大小,但现在我们一个像素是一个字节(GL_RED),它可以是任意的宽度,所以需要需求这个限制,将对齐参数设置为1,不然的话可能会造成段错误。

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);//禁用字节对齐限制

 

效果:

 

demo参考网址:。

 

转载于:https://www.cnblogs.com/xin-lover/p/10083201.html

你可能感兴趣的文章
A Tour of C++(Chapter 2 of The C++ Programming Language)
查看>>
规定元素宽高,内容超出则显示滚动条,内容不超出则隐藏滚动条。
查看>>
ADO.NET Entity Framework 学习(1)
查看>>
函数的传参.命名空间及关键字global和nonlocal
查看>>
模板方法(template pattern)
查看>>
js的基础知识
查看>>
python selenium实现文件、图片上传
查看>>
Junit4入门
查看>>
必须掌握的八个【cmd 命令行】
查看>>
hdu1010 dfs+路径剪枝
查看>>
hdu 2037 这个夏天不AC
查看>>
2.环境变量,内存管理,错误处理
查看>>
多项式回归(Polynomial Regression)
查看>>
PHP基础知识之字符串运算符
查看>>
@Autowired 基本介绍,有待丰富
查看>>
第十一周作业(补)
查看>>
C#创建服务及使用程序自动安装服务,.NET创建一个即是可执行程序又是Windows服务的exe...
查看>>
jscex 原理探析
查看>>
jQuery (选择器,属性,筛选,文档处理)
查看>>
从头学起-继承本质论
查看>>