首页 > 代码库 > Windows下使用GetGlyphOutline在OpenGL中渲染字体
Windows下使用GetGlyphOutline在OpenGL中渲染字体
欢迎转载,请标明出处:http://blog.csdn.net/tianyu2202/
无图无JB,先上图。使用OpenGL绘制字体,支持多种字体,支持TrueType轮廓字体,支持自选字体纹理大小和输出大小,支持在三维空间内绘制。
关于OpenGL中字体的显示网上其实有很多的教程,不过经常用到的方式有比较简单的Bitmap方式、比较复杂的FreeType方式。而本文介绍的方式虽然只能在Windows下实现,却有着和FreeType一样的显示效果,最重要的是非常简单,仅仅200多行代码即可实现。
首先是字体信息的保存,每个文字都有数个信息需要保存,包括了纹理的宽高、起始位置、字体宽度和所在的纹理序号。本文将每个字体保存为一个纹理,而不是常见的一个纹理保存数十个文字。这是首先是为了简单,二来还有应用上的一些特殊性。有这方面要求的同学可以自行优化。
class CFontData { public: float m_Width, m_Height; float m_OrigX, m_OrigY; float m_FontWidth; GLuint m_TextureID; CFontData() { m_Width = 0.0f; m_Height = 0.0f; m_TextureID = 0; m_FontWidth = 0.0f; m_OrigX = 0.0f; m_OrigY = 0.0f; } ~CFontData() { } };
然后是文字绘制类,非常简单,保存了字体名称、字体大小和一些资源,方法一共两个就是在三维空间内进行绘制和产生纹理字体。
class CFontPrinter { private: int m_FontSize; wchar_t m_FontName[64]; std::map<wchar_t, CFontData*> m_FontMap; HFONT m_Font; public: CFontPrinter(int fontSize, const wchar_t* fontName) { wcscpy_s(m_FontName, 64, fontName); m_FontSize = fontSize; m_Font = NULL; } ~CFontPrinter() { } bool makeChar(wchar_t wChar); void print3DText(float x, float y, float z, float red, float green, float blue, float height, wchar_t* Text); void print3DText(float x, float y, float z, float height, wchar_t* Text) { return print3DText(x, y, z, 1.0f, 1.0f, 1.0f, height, Text); } };
在makeChar中,根据传入的字符产生纹理并存入m_FontMap,在print3DText中进行绘制。直接使用print3DText也可以自动调用makeChar进行文字数据的生成。首先检查m_Font是否已经生成,没有生成则根据字体信息进行生成。然后使用传入的字符获取Buffer的大小,然后建立Buffer并将它传入函数GetGlyphOutlintW以获取生成的字体数据。而这里生成的数据是Gray64的,每个字节代表一个像素,而且是4字节对齐的。这里我为了节省更多的显卡资源,将PixelStore的对齐设为1字节。使用一个SwapBuffer将数据对齐为1字节并传入TexImage2D。
然后计算所需的数据,存入FontMap中等待绘制。
bool CFontPrinter::makeChar(wchar_t wChar) { HDC hdc = CreateCompatibleDC(wglGetCurrentDC()); if(!hdc) return false; HBITMAP hbitmap = CreateCompatibleBitmap(hdc, 1, 1); HBITMAP hbitmapOld = (HBITMAP)SelectObject(hdc, hbitmap); if((DWORD)hbitmapOld == GDI_ERROR) return false; CFontData* fontData = http://www.mamicode.com/new CFontData();>
在Main函数中建立一个OpenGL窗口,并且初始化文字,在渲染循环中调用print3DText即可进行绘制。void Render() { static float FrameID = 0; if (FrameID > 2 * PI) { FrameID = 0.0f; } else { FrameID += PI / 180.0f; } glDrawBuffer(GL_BACK); glViewport(0, 0, m_Width, m_Height); glClearColor(0.3f, 0.4f, 0.5f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); for (int i = 0; i < 20; i++) { fontPrinter->print3DText(sin(FrameID - PI180 * i) * 0.3f - 0.7f, cos(FrameID - PI180 * i), 0.0f, 1.0f, 1.0f, 1.0f, 0.3f, L"中文输出"); fontPrinter->print3DText(cos(FrameID - PI180 * i) * 0.4f - 0.8f, sin(FrameID - PI180 * i) * 0.4f, 0.0f, 0.0f, 1.0f, 0.0f, 0.2f, L"Hello Class"); fontPrinterSong->print3DText(cos(FrameID - PI180 * i) * 0.5f - 0.9f, sin(FrameID - PI180 * i) * 0.6f, 0.0f, 0.0f, 0.0f, 1.0f, 0.4f, L"Font Class"); } fontPrinter->print3DText(-0.7f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.2f, L"Font World"); fontPrinterSong->print3DText(-0.7f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.2f, L"宋体字"); fontPrinter->print3DText(-0.7f, -0.2f, 0.0f, 1.0f, 0.0f, 0.0f, 0.2f, L"微软雅黑"); glFlush(); SwapBuffers(m_hDC); } // 初始化文字 void InitFont() { // 参数1 单个文字纹理的最大大小 // 参数2 字体的文件名称 fontPrinter = new CFontPrinter(96, L"微软雅黑"); fontPrinterSong = new CFontPrinter(96, L"宋体"); } int __stdcall WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd ) { MSG msg; CreateClientWindow(); InitFont(); while (true) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // 有消息在等待吗? { if (msg.message == WM_QUIT) // 收到退出消息? { // 退出程序 break; } else { TranslateMessage(&msg); // 翻译消息 DispatchMessage(&msg); // 发送消息 } } else { Render(); } } if (fontPrinter != NULL) { delete fontPrinter; } return 0; }
工程代码在 http://download.csdn.net/detail/tianyu2202/7797885 ,欢迎下载。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。