Linux下Modern OpenGL显示汉字

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WuNLK/article/details/77529943

Linux下Modern OpenGL显示汉字

前一篇中解码出来的图像已经能够正常颜色格式转换和显示了,现在遇到了新的问题:显示文字
本以为这是一个很简单的东西,因为之前使用SDL时直接应用sdl_ttf库很简单的就实现了文字渲染工作,结果万万没想到OpenGL中实现这个小功能竟然没有现成API,这对于CV码农来说简直是灾难。没办法,看了这么久的GL硬着头皮也要走下去,经过两天不断的查资料和编码调试终于大功告成!老版本的OpenGL直接使用glut加载字符就能完成显示,modern OpenGL则需要使用shader结合vaovbo完成渲染,下面介绍如何实现


FreeType2

freetype2是一个字体库,能够完成加载字体文件,提取字符,生成bitmap等工作
FreeType is a software development library that is able to load fonts, render them to bitmaps and provide support for several font-related operations. It is a popular library used by Mac OS X, Java, PlayStation Consoles, Linux and Android to name a few. What makes FreeType particularly attractive is that it is able to load TrueType fonts.
关键代码
FT_Library ft;
if (FT_Init_FreeType(&ft))
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
FT_Face face;
if (FT_New_Face(ft, "fonts/arial.ttf", 0, &face))
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;

这部分代码完成初始化工作
if (FT_Load_Char(face, 'X', FT_LOAD_RENDER))
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;

完成加载字符工作
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);

完成字符到GL纹理的存储
struct Character
{
GLuint TextureID; // ID handle of the glyph texture
glm::ivec2 Size; // Size of glyph
glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
GLuint Advance; // Horizontal offset to advance to next glyph
};

这是存储字符纹理和大小、偏移等参数的结构体
要显示中文的话需要加载中文字体,可以去网上下载自己喜欢的或者去win里面拷
我使用的是谷歌出品的思源宋体,挺好看的

String转WString

英文字符占一字节,中文字符占两个,所以需要把String转成Wstring
这里我使用C++11的codecvt类完成,话说C++做文字处理真是蛋疼,这活在Python里根本不算事

include <locale>
include <codecvt>
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;
std::wstring wide = converterX.from_bytes(text);

还算简单,五行代码完活

纹理存储

每一个字符都是一张纹理,如果需要显示很多文字的话,那么每次刷新都为文字创建纹理会很耗费资源,所以使用map存储显示过的文字,就第一次使用这个字符时需要创建纹理分配存储,后面可以直接去map中找,节省计算资源。
std::map<wchar_t, Character> Characters;
if(Characters.find(c)==Characters.end())
{
//生成纹理,绑定,存储等等
Characters.insert(std::pair<wchar_t, Character>(c, character));
}
else
{}

效果

这里写图片描述

代码

将文字显示功能整合了一下,实际使用只需要两步
textRender tr(800,600,"/home/wnl/workspace/textRender/SourceHanSerifCN-Bold.otf");

参数是窗口大小和字体路径
渲染循环中
std::string s("WuNL的OpenGL文字显示测试");
tr.RenderText(s,(GLfloat)35.0f,(GLfloat)35.0f,1.0f, glm::vec3(0.5, 0.8f, 0.2f));

rendertext参数为需要渲染的文字,显示位置,大小比例,颜色
实现代码在我的github上,网址为https://github.com/WuNL/textRender
觉得我的代码有些帮助请打颗星,谢谢

展开阅读全文

没有更多推荐了,返回首页