Is there a good way for displaying unicode text in opengl under Windows? For example, when you have to deal with different languages. The most common approach like
是否有一种好的方法可以在Windows下的opengl中显示unicode文本?例如,当你必须处理不同的语言时。最常见的方法是
#define FONTLISTRANGE 128
GLuint list;
list = glGenLists(FONTLISTRANGE);
wglUseFontBitmapsW(hDC, 0, FONTLISTRANGE, list);
just won't do because you can't create enough lists for all unicode characters.
因为不能为所有unicode字符创建足够的列表,所以不能这样做。
7 个解决方案
#1
0
You could also group the characters by language. Load each language table as needed, and when you need to switch languages, unload the previous language table and load the new one.
您还可以按语言对字符进行分组。根据需要加载每个语言表,当需要切换语言时,卸载前一个语言表并加载新的语言表。
#2
16
You should also check out the FTGL library.
您还应该检查FTGL库。
FTGL is a free cross-platform Open Source C++ library that uses Freetype2 to simplify rendering fonts in OpenGL applications. FTGL supports bitmaps, pixmaps, texture maps, outlines, polygon mesh, and extruded polygon rendering modes.
FTGL是一个免费的跨平台开放源码c++库,它使用Freetype2来简化OpenGL应用程序中的呈现字体。FTGL支持位图、像素图、纹理图、轮廓、多边形网格和挤压多边形渲染模式。
This project was dormant for awhile, but is recently back under development. I haven't updated my project to use the latest version, but you should check it out.
这个项目休眠了一段时间,但最近又重新开始开发。我还没有更新我的项目来使用最新的版本,但是你应该去看看。
It allows for using any True Type Font via the FreeType font library.
它允许通过*字体库使用任何真正的字体类型。
#3
6
I recommend reading this OpenGL font tutorial. It's for the D programming language but it's a nice introduction to various issues involved in implementing a glyph caching system for rendering text with OpenGL. The tutorial covers Unicode compliance, antialiasing, and kerning techniques.
我推荐阅读OpenGL字体教程。它是用于D编程语言的,但是它很好地介绍了实现使用OpenGL呈现文本的字形缓存系统所涉及的各种问题。本教程涵盖了Unicode遵从性、抗锯齿和字距技术。
D is pretty comprehensible to anyone who knows C++ and most of the article is about the general techniques, not the implementation language.
对于任何了解c++的人来说,D都是可以理解的,本文的大部分内容都是关于一般的技术,而不是实现语言。
#4
3
Id recommend FTGL as already recommended above, however I have implemented a freetype/OpenGL renderer myself and thought you might find the code handy if you want reinvent this wheel yourself. I'd really recommend FTGL though, its a lot less hassle to use. :)
我已经按照上面的建议推荐了FTGL,但是我自己已经实现了一个freetype/OpenGL渲染器,如果您想要自己重新创建这个*,您可能会觉得代码很方便。不过我还是推荐FTGL,它使用起来不会那么麻烦。:)
* glTextRender class by Semi Essessi
*
* FreeType2 empowered text renderer
*
*/
#include "glTextRender.h"
#include "jEngine.h"
#include "glSystem.h"
#include "jMath.h"
#include "jProfiler.h"
#include "log.h"
#include <windows.h>
FT_Library glTextRender::ftLib = 0;
//TODO::maybe fix this so it use wchar_t for the filename
glTextRender::glTextRender(jEngine* j, const char* fontName, int size = 12)
{
#ifdef _DEBUG
jProfiler profiler = jProfiler(L"glTextRender::glTextRender");
#endif
char fontName2[1024];
memset(fontName2,0,sizeof(char)*1024);
sprintf(fontName2,"fonts\\%s",fontName);
if(!ftLib)
{
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Font: %s was requested before FreeType was initialised", fn);
#endif
return;
}
// constructor code for glTextRender
e=j;
gl = j->gl;
red=green=blue=alpha=1.0f;
face = 0;
// remember that for some weird reason below font size 7 everything gets scrambled up
height = max(6,(int)floorf((float)size*((float)gl->getHeight())*0.001666667f));
aHeight = ((float)height)/((float)gl->getHeight());
setPosition(0.0f,0.0f);
// look in base fonts dir
if(FT_New_Face(ftLib, fontName2, 0, &face ))
{
// if we dont have it look in windows fonts dir
char buf[1024];
GetWindowsDirectoryA(buf,1024);
strcat(buf, "\\fonts\\");
strcat(buf, fontName);
if(FT_New_Face(ftLib, buf, 0, &face ))
{
//TODO::check in mod fonts directory
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Request for font: %s has failed", fn);
#endif
face = 0;
return;
}
}
// FreeType uses 64x size and 72dpi for default
// doubling size for ms
FT_Set_Char_Size(face, mulPow2(height,7), mulPow2(height,7), 96, 96);
// set up cache table and then generate the first 256 chars and the console prompt character
for(int i=0;i<65536;i++)
{
cached[i]=false;
width[i]=0.0f;
}
for(unsigned short i = 0; i < 256; i++) getChar((wchar_t)i);
getChar(CHAR_PROMPT);
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Font: %s loaded OK", fn);
#endif
}
glTextRender::~glTextRender()
{
// destructor code for glTextRender
for(int i=0;i<65536;i++)
{
if(cached[i])
{
glDeleteLists(listID[i],1);
glDeleteTextures(1,&(texID[i]));
}
}
// TODO:: work out stupid freetype crashz0rs
try
{
static int foo = 0;
if(face && foo < 1)
{
foo++;
FT_Done_Face(face);
face = 0;
}
}
catch(...)
{
face = 0;
}
}
// return true if init works, or if already initialised
bool glTextRender::initFreeType()
{
if(!ftLib)
{
if(!FT_Init_FreeType(&ftLib)) return true;
else return false;
} else return true;
}
void glTextRender::shutdownFreeType()
{
if(ftLib)
{
FT_Done_FreeType(ftLib);
ftLib = 0;
}
}
void glTextRender::print(const wchar_t* str)
{
// store old stuff to set start position
glPushAttrib(GL_TRANSFORM_BIT);
// get viewport size
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
glPopAttrib();
float color[4];
glGetFloatv(GL_CURRENT_COLOR, color);
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
//glDisable(GL_DEPTH_TEST);
// set blending for AA
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTranslatef(xPos,yPos,0.0f);
glColor4f(red,green,blue,alpha);
// call display lists to render text
glListBase(0u);
for(unsigned int i=0;i<wcslen(str);i++) glCallList(getChar(str[i]));
// restore old states
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
glColor4fv(color);
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
void glTextRender::printf(const wchar_t* str, ...)
{
if(!str) return;
wchar_t* buf = 0;
va_list parg;
va_start(parg, str);
// allocate buffer
int len = (_vscwprintf(str, parg)+1);
buf = new wchar_t[len];
if(!buf) return;
vswprintf(buf, str, parg);
va_end(parg);
print(buf);
delete[] buf;
}
GLuint glTextRender::getChar(const wchar_t c)
{
int i = (int)c;
if(cached[i]) return listID[i];
// load glyph and get bitmap
if(FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT )) return 0;
FT_Glyph glyph;
if(FT_Get_Glyph(face->glyph, &glyph)) return 0;
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
int w = roundPow2(bitmap.width);
int h = roundPow2(bitmap.rows);
// convert to texture in memory
GLubyte* texture = new GLubyte[2*w*h];
for(int j=0;j<h;j++)
{
bool cond = j>=bitmap.rows;
for(int k=0;k<w;k++)
{
texture[2*(k+j*w)] = 0xFFu;
texture[2*(k+j*w)+1] = ((k>=bitmap.width)||cond) ? 0x0u : bitmap.buffer[k+bitmap.width*j];
}
}
// store char width and adjust max height
// note .5f
float ih = 1.0f/((float)gl->getHeight());
width[i] = ((float)divPow2(face->glyph->advance.x, 7))*ih;
aHeight = max(aHeight,(.5f*(float)bitmap.rows)*ih);
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
// create gl texture
glGenTextures(1, &(texID[i]));
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texture);
glPopAttrib();
delete[] texture;
// create display list
listID[i] = glGenLists(1);
glNewList(listID[i], GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, texID[i]);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// adjust position to account for texture padding
glTranslatef(.5f*(float)bitmapGlyph->left, 0.0f, 0.0f);
glTranslatef(0.0f, .5f*(float)(bitmapGlyph->top-bitmap.rows), 0.0f);
// work out texcoords
float tx=((float)bitmap.width)/((float)w);
float ty=((float)bitmap.rows)/((float)h);
// render
// note .5f
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, .5f*(float)bitmap.rows);
glTexCoord2f(0.0f, ty);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(tx, ty);
glVertex2f(.5f*(float)bitmap.width, 0.0f);
glTexCoord2f(tx, 0.0f);
glVertex2f(.5f*(float)bitmap.width, .5f*(float)bitmap.rows);
glEnd();
glPopMatrix();
// move position for the next character
// note extra div 2
glTranslatef((float)divPow2(face->glyph->advance.x, 7), 0.0f, 0.0f);
glEndList();
// char is succesfully cached for next time
cached[i] = true;
return listID[i];
}
void glTextRender::setPosition(float x, float y)
{
float fac = ((float)gl->getHeight());
xPos = fac*x+FONT_BORDER_PIXELS; yPos = fac*(1-y)-(float)height-FONT_BORDER_PIXELS;
}
float glTextRender::getAdjustedWidth(const wchar_t* str)
{
float w = 0.0f;
for(unsigned int i=0;i<wcslen(str);i++)
{
if(cached[str[i]]) w+=width[str[i]];
else
{
getChar(str[i]);
w+=width[str[i]];
}
}
return w;
}
#5
2
You may have to generate you own "glyph cache" in texture memory as you go, potentially with some sort of LRU policy to avoid destroying all of the texture memory. Not nearly as easy as your current method, but may be the only way given the number of unicode chars
您可能需要在纹理内存中生成自己的“字形缓存”,可能需要使用某种LRU策略,以避免破坏所有的纹理内存。虽然没有当前方法那么简单,但是考虑到unicode字符的数量,这可能是惟一的方法
#6
2
You should consider using an Unicode rendering library (eg. Pango) to render the stuff into a bitmap and put that bitmap on the screen or into a texture.
您应该考虑使用Unicode呈现库(如。将内容渲染成位图,并将位图放到屏幕上或纹理中。
Rendering unicode text is not simple. So you cannot simply load 64K rectangular glyphs and use it.
呈现unicode文本并不简单。因此,不能简单地加载64K矩形符号并使用它。
Characters may overlap. Eg in this smiley:
字符可能重叠。在这个笑脸如:
( ͡° ͜ʖ ͡°)
(͡°͜ʖ͡°)
Some code points stack accents on the previous character. Consider this excerpt from this notable post:
一些代码点在前一个字符上的堆栈重音。考虑一下这篇著名文章的节选:
...he com̡e̶s, ̕h̵is un̨ho͞ly radiańcé destro҉ying all enli̍̈́̂̈́ghtenment, HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo͟ur eye͢s̸ ̛l̕ik͏e liquid pain, the song of re̸gular expression parsing will extinguish the voices of mortal man from the sphere I can see it can you see ̲͚̖͔̙î̩́t̲͎̩̱͔́̋̀ it is beautiful the final snuffing of the lies of Man ALL IS LOŚ͖̩͇̗̪̏̈́T ALL IS LOST the pon̷y he comes he c̶̮omes he comes the ichor permeates all MY FACE MY FACE ᵒh god no NO NOO̼OO NΘ stop the an*̶͑̾̾̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅s ͎a̧͈͖r̽̾̈́͒͑e not rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ
…他com̡e̶s,̕h̵is联合国̨ho͞ly弧度́cédestro҉应所有enli̍̈́̂̈́ghtenment,HTML标记lea͠ki̧n͘g fr̶ǫm̡͟哟你的眼睛͢s̸̛l̕反向͏e液体uid疼痛,再保险之歌̸喉部的exp ression解析将exti nguish铁道部塔尔人的声音从sp在这里,我可以看到它你能看见̲͚̖͔̙我̩̂́t̲͎̩̱͔́̋̀美丽t他撒谎的最后出现的人都是洛杉矶͖̩͇̗̪́̏̈́t我s失去了彩球̷y他是c̶̮化为他来我或渗透我的脸我的脸ᵒh上帝不不知道了̼O O NΘ停止一个*̶͑̾̾̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅年代̧͎͈͖r̽̾̈́͒͑e n ot再保险̀̑ͧ̌ͨl̘̝̙̃ͤ͂̾̆咱̡͊͠͝LGΌ是ͮ̂҉̯͈͕̹̘̱TO͇̹̺ͅƝ̴ȳ̳TH ë̘͖́̉͠P̯͍̭O̚n̐y̡h̸̡̪̯ͨ͊̽̅̾̎ȩ̶̧̨̬̩̱̹̭̯̾͛ͪ̈́̀́ͧ̾ͬ͘C̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝年代̨̥̫͎̭ͯ̿̔̀ͅ
If you truly want to render Unicode correctly you should be able to render this one correctly too.
如果您确实希望正确地呈现Unicode,那么您也应该能够正确地呈现这个。
UPDATE: Looked at this Pango engine, and it's the case of banana, the gorilla, and the entire jungle. First it depends on the Glib because it used GObjects, second it cannot render directly into a byte buffer. It has Cario and FreeType backends, so you must use one of them to render the text and export it into bitmaps eventually. That's doesn't look good so far.
更新:看看这个盘古引擎,香蕉、大猩猩和整个丛林都是如此。首先,它依赖于Glib,因为它使用了gobject,其次它不能直接呈现到字节缓存中。它有Cario和FreeType后端,因此您必须使用其中之一来呈现文本并最终将其导出为位图。到目前为止还不太好。
In addition to that, if you want to store the result in a texture, use pango_layout_get_pixel_extents
after setting the text to get the sizes of rectangles to render the text to. Ink rectangle is the rectangle to contain the entire text, it's left-top position is the position relative to the left-top of the logical rectangle. (The bottom line of the logical rectangle is the baseline). Hope this helps.
除此之外,如果您想要将结果存储在一个纹理中,在设置文本后,使用pango_layout_get_pixel_extents来获取矩形的大小以呈现文本。墨水矩形是包含整个文本的矩形,它的左上角位置是相对于逻辑矩形的左上方的位置。(逻辑矩形的底线是基线)。希望这个有帮助。
#7
1
Queso GLC is great for this, I've used it to render Chinese and Cyrillic characters in 3D.
这个问题很好,我用它来渲染中文和西里尔文字。
http://quesoglc.sourceforge.net/
http://quesoglc.sourceforge.net/
The Unicode text sample it comes with should get you started.
它附带的Unicode文本示例应该可以帮助您入门。
#1
0
You could also group the characters by language. Load each language table as needed, and when you need to switch languages, unload the previous language table and load the new one.
您还可以按语言对字符进行分组。根据需要加载每个语言表,当需要切换语言时,卸载前一个语言表并加载新的语言表。
#2
16
You should also check out the FTGL library.
您还应该检查FTGL库。
FTGL is a free cross-platform Open Source C++ library that uses Freetype2 to simplify rendering fonts in OpenGL applications. FTGL supports bitmaps, pixmaps, texture maps, outlines, polygon mesh, and extruded polygon rendering modes.
FTGL是一个免费的跨平台开放源码c++库,它使用Freetype2来简化OpenGL应用程序中的呈现字体。FTGL支持位图、像素图、纹理图、轮廓、多边形网格和挤压多边形渲染模式。
This project was dormant for awhile, but is recently back under development. I haven't updated my project to use the latest version, but you should check it out.
这个项目休眠了一段时间,但最近又重新开始开发。我还没有更新我的项目来使用最新的版本,但是你应该去看看。
It allows for using any True Type Font via the FreeType font library.
它允许通过*字体库使用任何真正的字体类型。
#3
6
I recommend reading this OpenGL font tutorial. It's for the D programming language but it's a nice introduction to various issues involved in implementing a glyph caching system for rendering text with OpenGL. The tutorial covers Unicode compliance, antialiasing, and kerning techniques.
我推荐阅读OpenGL字体教程。它是用于D编程语言的,但是它很好地介绍了实现使用OpenGL呈现文本的字形缓存系统所涉及的各种问题。本教程涵盖了Unicode遵从性、抗锯齿和字距技术。
D is pretty comprehensible to anyone who knows C++ and most of the article is about the general techniques, not the implementation language.
对于任何了解c++的人来说,D都是可以理解的,本文的大部分内容都是关于一般的技术,而不是实现语言。
#4
3
Id recommend FTGL as already recommended above, however I have implemented a freetype/OpenGL renderer myself and thought you might find the code handy if you want reinvent this wheel yourself. I'd really recommend FTGL though, its a lot less hassle to use. :)
我已经按照上面的建议推荐了FTGL,但是我自己已经实现了一个freetype/OpenGL渲染器,如果您想要自己重新创建这个*,您可能会觉得代码很方便。不过我还是推荐FTGL,它使用起来不会那么麻烦。:)
* glTextRender class by Semi Essessi
*
* FreeType2 empowered text renderer
*
*/
#include "glTextRender.h"
#include "jEngine.h"
#include "glSystem.h"
#include "jMath.h"
#include "jProfiler.h"
#include "log.h"
#include <windows.h>
FT_Library glTextRender::ftLib = 0;
//TODO::maybe fix this so it use wchar_t for the filename
glTextRender::glTextRender(jEngine* j, const char* fontName, int size = 12)
{
#ifdef _DEBUG
jProfiler profiler = jProfiler(L"glTextRender::glTextRender");
#endif
char fontName2[1024];
memset(fontName2,0,sizeof(char)*1024);
sprintf(fontName2,"fonts\\%s",fontName);
if(!ftLib)
{
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Font: %s was requested before FreeType was initialised", fn);
#endif
return;
}
// constructor code for glTextRender
e=j;
gl = j->gl;
red=green=blue=alpha=1.0f;
face = 0;
// remember that for some weird reason below font size 7 everything gets scrambled up
height = max(6,(int)floorf((float)size*((float)gl->getHeight())*0.001666667f));
aHeight = ((float)height)/((float)gl->getHeight());
setPosition(0.0f,0.0f);
// look in base fonts dir
if(FT_New_Face(ftLib, fontName2, 0, &face ))
{
// if we dont have it look in windows fonts dir
char buf[1024];
GetWindowsDirectoryA(buf,1024);
strcat(buf, "\\fonts\\");
strcat(buf, fontName);
if(FT_New_Face(ftLib, buf, 0, &face ))
{
//TODO::check in mod fonts directory
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Request for font: %s has failed", fn);
#endif
face = 0;
return;
}
}
// FreeType uses 64x size and 72dpi for default
// doubling size for ms
FT_Set_Char_Size(face, mulPow2(height,7), mulPow2(height,7), 96, 96);
// set up cache table and then generate the first 256 chars and the console prompt character
for(int i=0;i<65536;i++)
{
cached[i]=false;
width[i]=0.0f;
}
for(unsigned short i = 0; i < 256; i++) getChar((wchar_t)i);
getChar(CHAR_PROMPT);
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Font: %s loaded OK", fn);
#endif
}
glTextRender::~glTextRender()
{
// destructor code for glTextRender
for(int i=0;i<65536;i++)
{
if(cached[i])
{
glDeleteLists(listID[i],1);
glDeleteTextures(1,&(texID[i]));
}
}
// TODO:: work out stupid freetype crashz0rs
try
{
static int foo = 0;
if(face && foo < 1)
{
foo++;
FT_Done_Face(face);
face = 0;
}
}
catch(...)
{
face = 0;
}
}
// return true if init works, or if already initialised
bool glTextRender::initFreeType()
{
if(!ftLib)
{
if(!FT_Init_FreeType(&ftLib)) return true;
else return false;
} else return true;
}
void glTextRender::shutdownFreeType()
{
if(ftLib)
{
FT_Done_FreeType(ftLib);
ftLib = 0;
}
}
void glTextRender::print(const wchar_t* str)
{
// store old stuff to set start position
glPushAttrib(GL_TRANSFORM_BIT);
// get viewport size
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
glPopAttrib();
float color[4];
glGetFloatv(GL_CURRENT_COLOR, color);
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
//glDisable(GL_DEPTH_TEST);
// set blending for AA
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTranslatef(xPos,yPos,0.0f);
glColor4f(red,green,blue,alpha);
// call display lists to render text
glListBase(0u);
for(unsigned int i=0;i<wcslen(str);i++) glCallList(getChar(str[i]));
// restore old states
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
glColor4fv(color);
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
void glTextRender::printf(const wchar_t* str, ...)
{
if(!str) return;
wchar_t* buf = 0;
va_list parg;
va_start(parg, str);
// allocate buffer
int len = (_vscwprintf(str, parg)+1);
buf = new wchar_t[len];
if(!buf) return;
vswprintf(buf, str, parg);
va_end(parg);
print(buf);
delete[] buf;
}
GLuint glTextRender::getChar(const wchar_t c)
{
int i = (int)c;
if(cached[i]) return listID[i];
// load glyph and get bitmap
if(FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT )) return 0;
FT_Glyph glyph;
if(FT_Get_Glyph(face->glyph, &glyph)) return 0;
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
int w = roundPow2(bitmap.width);
int h = roundPow2(bitmap.rows);
// convert to texture in memory
GLubyte* texture = new GLubyte[2*w*h];
for(int j=0;j<h;j++)
{
bool cond = j>=bitmap.rows;
for(int k=0;k<w;k++)
{
texture[2*(k+j*w)] = 0xFFu;
texture[2*(k+j*w)+1] = ((k>=bitmap.width)||cond) ? 0x0u : bitmap.buffer[k+bitmap.width*j];
}
}
// store char width and adjust max height
// note .5f
float ih = 1.0f/((float)gl->getHeight());
width[i] = ((float)divPow2(face->glyph->advance.x, 7))*ih;
aHeight = max(aHeight,(.5f*(float)bitmap.rows)*ih);
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
// create gl texture
glGenTextures(1, &(texID[i]));
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texture);
glPopAttrib();
delete[] texture;
// create display list
listID[i] = glGenLists(1);
glNewList(listID[i], GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, texID[i]);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// adjust position to account for texture padding
glTranslatef(.5f*(float)bitmapGlyph->left, 0.0f, 0.0f);
glTranslatef(0.0f, .5f*(float)(bitmapGlyph->top-bitmap.rows), 0.0f);
// work out texcoords
float tx=((float)bitmap.width)/((float)w);
float ty=((float)bitmap.rows)/((float)h);
// render
// note .5f
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, .5f*(float)bitmap.rows);
glTexCoord2f(0.0f, ty);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(tx, ty);
glVertex2f(.5f*(float)bitmap.width, 0.0f);
glTexCoord2f(tx, 0.0f);
glVertex2f(.5f*(float)bitmap.width, .5f*(float)bitmap.rows);
glEnd();
glPopMatrix();
// move position for the next character
// note extra div 2
glTranslatef((float)divPow2(face->glyph->advance.x, 7), 0.0f, 0.0f);
glEndList();
// char is succesfully cached for next time
cached[i] = true;
return listID[i];
}
void glTextRender::setPosition(float x, float y)
{
float fac = ((float)gl->getHeight());
xPos = fac*x+FONT_BORDER_PIXELS; yPos = fac*(1-y)-(float)height-FONT_BORDER_PIXELS;
}
float glTextRender::getAdjustedWidth(const wchar_t* str)
{
float w = 0.0f;
for(unsigned int i=0;i<wcslen(str);i++)
{
if(cached[str[i]]) w+=width[str[i]];
else
{
getChar(str[i]);
w+=width[str[i]];
}
}
return w;
}
#5
2
You may have to generate you own "glyph cache" in texture memory as you go, potentially with some sort of LRU policy to avoid destroying all of the texture memory. Not nearly as easy as your current method, but may be the only way given the number of unicode chars
您可能需要在纹理内存中生成自己的“字形缓存”,可能需要使用某种LRU策略,以避免破坏所有的纹理内存。虽然没有当前方法那么简单,但是考虑到unicode字符的数量,这可能是惟一的方法
#6
2
You should consider using an Unicode rendering library (eg. Pango) to render the stuff into a bitmap and put that bitmap on the screen or into a texture.
您应该考虑使用Unicode呈现库(如。将内容渲染成位图,并将位图放到屏幕上或纹理中。
Rendering unicode text is not simple. So you cannot simply load 64K rectangular glyphs and use it.
呈现unicode文本并不简单。因此,不能简单地加载64K矩形符号并使用它。
Characters may overlap. Eg in this smiley:
字符可能重叠。在这个笑脸如:
( ͡° ͜ʖ ͡°)
(͡°͜ʖ͡°)
Some code points stack accents on the previous character. Consider this excerpt from this notable post:
一些代码点在前一个字符上的堆栈重音。考虑一下这篇著名文章的节选:
...he com̡e̶s, ̕h̵is un̨ho͞ly radiańcé destro҉ying all enli̍̈́̂̈́ghtenment, HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo͟ur eye͢s̸ ̛l̕ik͏e liquid pain, the song of re̸gular expression parsing will extinguish the voices of mortal man from the sphere I can see it can you see ̲͚̖͔̙î̩́t̲͎̩̱͔́̋̀ it is beautiful the final snuffing of the lies of Man ALL IS LOŚ͖̩͇̗̪̏̈́T ALL IS LOST the pon̷y he comes he c̶̮omes he comes the ichor permeates all MY FACE MY FACE ᵒh god no NO NOO̼OO NΘ stop the an*̶͑̾̾̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅s ͎a̧͈͖r̽̾̈́͒͑e not rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ
…他com̡e̶s,̕h̵is联合国̨ho͞ly弧度́cédestro҉应所有enli̍̈́̂̈́ghtenment,HTML标记lea͠ki̧n͘g fr̶ǫm̡͟哟你的眼睛͢s̸̛l̕反向͏e液体uid疼痛,再保险之歌̸喉部的exp ression解析将exti nguish铁道部塔尔人的声音从sp在这里,我可以看到它你能看见̲͚̖͔̙我̩̂́t̲͎̩̱͔́̋̀美丽t他撒谎的最后出现的人都是洛杉矶͖̩͇̗̪́̏̈́t我s失去了彩球̷y他是c̶̮化为他来我或渗透我的脸我的脸ᵒh上帝不不知道了̼O O NΘ停止一个*̶͑̾̾̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅年代̧͎͈͖r̽̾̈́͒͑e n ot再保险̀̑ͧ̌ͨl̘̝̙̃ͤ͂̾̆咱̡͊͠͝LGΌ是ͮ̂҉̯͈͕̹̘̱TO͇̹̺ͅƝ̴ȳ̳TH ë̘͖́̉͠P̯͍̭O̚n̐y̡h̸̡̪̯ͨ͊̽̅̾̎ȩ̶̧̨̬̩̱̹̭̯̾͛ͪ̈́̀́ͧ̾ͬ͘C̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝年代̨̥̫͎̭ͯ̿̔̀ͅ
If you truly want to render Unicode correctly you should be able to render this one correctly too.
如果您确实希望正确地呈现Unicode,那么您也应该能够正确地呈现这个。
UPDATE: Looked at this Pango engine, and it's the case of banana, the gorilla, and the entire jungle. First it depends on the Glib because it used GObjects, second it cannot render directly into a byte buffer. It has Cario and FreeType backends, so you must use one of them to render the text and export it into bitmaps eventually. That's doesn't look good so far.
更新:看看这个盘古引擎,香蕉、大猩猩和整个丛林都是如此。首先,它依赖于Glib,因为它使用了gobject,其次它不能直接呈现到字节缓存中。它有Cario和FreeType后端,因此您必须使用其中之一来呈现文本并最终将其导出为位图。到目前为止还不太好。
In addition to that, if you want to store the result in a texture, use pango_layout_get_pixel_extents
after setting the text to get the sizes of rectangles to render the text to. Ink rectangle is the rectangle to contain the entire text, it's left-top position is the position relative to the left-top of the logical rectangle. (The bottom line of the logical rectangle is the baseline). Hope this helps.
除此之外,如果您想要将结果存储在一个纹理中,在设置文本后,使用pango_layout_get_pixel_extents来获取矩形的大小以呈现文本。墨水矩形是包含整个文本的矩形,它的左上角位置是相对于逻辑矩形的左上方的位置。(逻辑矩形的底线是基线)。希望这个有帮助。
#7
1
Queso GLC is great for this, I've used it to render Chinese and Cyrillic characters in 3D.
这个问题很好,我用它来渲染中文和西里尔文字。
http://quesoglc.sourceforge.net/
http://quesoglc.sourceforge.net/
The Unicode text sample it comes with should get you started.
它附带的Unicode文本示例应该可以帮助您入门。