<p>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</p>

<pre><code>#define FONTLISTRANGE 128
GLuint list;
list = glGenLists(FONTLISTRANGE);
wglUseFontBitmapsW(hDC, 0, FONTLISTRANGE, list);
</code></pre>

<p>just won't do because you can't create enough lists for all unicode characters.</p>

[{'answer_id': 7745, 'author': 'basszero', 'author_id': 287, 'author_profile': 'https://Stackoverflow.com/users/287', 'pm_score': 2, 'selected': False, 'text': '<p>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</p>\n'}, {'answer_id': 7950, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 1, 'selected': True, 'text': '<p>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.</p>\n'}, {'answer_id': 24285, 'author': 'Rob Thomas', 'author_id': 803, 'author_profile': 'https://Stackoverflow.com/users/803', 'pm_score': 4, 'selected': False, 'text': '<p>You should also check out the <a href="http://sourceforge.net/projects/ftgl/" rel="noreferrer">FTGL library</a>.  </p>\n\n<blockquote>\n  <p>FTGL is a free cross-platform Open\n  Source C++ library that uses Freetype2\n  to simplify rendering fonts in OpenGL\n  applications. FTGL supports bitmaps,\n  pixmaps, texture maps, outlines,\n  polygon mesh, and extruded polygon\n  rendering modes.</p>\n</blockquote>\n\n<p>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.</p>\n\n<p>It allows for using any True Type Font via the <a href="http://freetype.sourceforge.net/index2.html" rel="noreferrer">FreeType</a> font library.</p>\n'}, {'answer_id': 71595, 'author': 'Baxissimo', 'author_id': 9631, 'author_profile': 'https://Stackoverflow.com/users/9631', 'pm_score': 3, 'selected': False, 'text': '<p>I recommend reading this <a href="http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1" rel="nofollow noreferrer">OpenGL font tutorial</a>. 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.</p>\n\n<p>D is pretty comprehensible to anyone who knows C++ and most of the article is about the general techniques, not the implementation language.</p>\n'}, {'answer_id': 93732, 'author': 'Andreas Müller', 'author_id': 12203, 'author_profile': 'https://Stackoverflow.com/users/12203', 'pm_score': 1, 'selected': False, 'text': '<p>Queso GLC is great for this, I\'ve used it to render Chinese and Cyrillic characters in 3D.</p>\n\n<p><a href="http://quesoglc.sourceforge.net/" rel="nofollow noreferrer">http://quesoglc.sourceforge.net/</a></p>\n\n<p>The Unicode text sample it comes with should get you started.</p>\n'}, {'answer_id': 480067, 'author': 'jheriko', 'author_id': 17604, 'author_profile': 'https://Stackoverflow.com/users/17604', 'pm_score': 2, 'selected': False, 'text': '<p>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. :)</p>\n\n<pre><code>* glTextRender class by Semi Essessi\n *\n * FreeType2 empowered text renderer\n *\n */\n\n#include "glTextRender.h"\n#include "jEngine.h"\n\n#include "glSystem.h"\n\n#include "jMath.h"\n#include "jProfiler.h"\n#include "log.h"\n\n#include &lt;windows.h&gt;\n\nFT_Library glTextRender::ftLib = 0;\n\n//TODO::maybe fix this so it use wchar_t for the filename\nglTextRender::glTextRender(jEngine* j, const char* fontName, int size = 12)\n{\n#ifdef _DEBUG\n    jProfiler profiler = jProfiler(L"glTextRender::glTextRender");\n#endif\n    char fontName2[1024];\n    memset(fontName2,0,sizeof(char)*1024);\n    sprintf(fontName2,"fonts\\\\%s",fontName);\n\n    if(!ftLib)\n    {\n#ifdef _DEBUG\n        wchar_t fn[128];\n        mbstowcs(fn,fontName,strlen(fontName)+1);\n        LogWriteLine(L"\\x25CB\\x25CB\\x25CF Font: %s was requested before FreeType was initialised", fn);\n#endif\n        return;\n    }\n\n    // constructor code for glTextRender\n    e=j;\n\n    gl = j-&gt;gl;\n\n    red=green=blue=alpha=1.0f;\n\n    face = 0;\n\n    // remember that for some weird reason below font size 7 everything gets scrambled up\n    height = max(6,(int)floorf((float)size*((float)gl-&gt;getHeight())*0.001666667f));\n    aHeight = ((float)height)/((float)gl-&gt;getHeight());\n\n    setPosition(0.0f,0.0f);\n\n    // look in base fonts dir\n    if(FT_New_Face(ftLib, fontName2, 0, &amp;face ))\n    {\n        // if we dont have it look in windows fonts dir\n        char buf[1024];\n        GetWindowsDirectoryA(buf,1024);\n        strcat(buf, "\\\\fonts\\\\");\n        strcat(buf, fontName);\n\n        if(FT_New_Face(ftLib, buf, 0, &amp;face ))\n        {\n            //TODO::check in mod fonts directory\n#ifdef _DEBUG\n            wchar_t fn[128];\n            mbstowcs(fn,fontName,strlen(fontName)+1);\n            LogWriteLine(L"\\x25CB\\x25CB\\x25CF Request for font: %s has failed", fn);\n#endif\n            face = 0;\n            return;\n        }\n    }\n\n    // FreeType uses 64x size and 72dpi for default\n    // doubling size for ms \n    FT_Set_Char_Size(face, mulPow2(height,7), mulPow2(height,7), 96, 96);\n\n    // set up cache table and then generate the first 256 chars and the console prompt character\n    for(int i=0;i&lt;65536;i++) \n    {\n        cached[i]=false;\n        width[i]=0.0f;\n    }\n\n    for(unsigned short i = 0; i &lt; 256; i++) getChar((wchar_t)i);\n    getChar(CHAR_PROMPT);\n\n#ifdef _DEBUG\n    wchar_t fn[128];\n    mbstowcs(fn,fontName,strlen(fontName)+1);\n    LogWriteLine(L"\\x25CB\\x25CB\\x25CF Font: %s loaded OK", fn);\n#endif\n}\n\nglTextRender::~glTextRender()\n{\n    // destructor code for glTextRender\n    for(int i=0;i&lt;65536;i++)\n    {\n        if(cached[i])\n        {\n            glDeleteLists(listID[i],1);\n            glDeleteTextures(1,&amp;(texID[i]));\n        }\n    }\n\n    // TODO:: work out stupid freetype crashz0rs\n    try\n    {\n        static int foo = 0;\n        if(face &amp;&amp; foo &lt; 1)\n        {\n            foo++;\n            FT_Done_Face(face);\n            face = 0;\n        }\n    }\n    catch(...)\n    {\n        face = 0;\n    }\n}\n\n\n// return true if init works, or if already initialised\nbool glTextRender::initFreeType()\n{\n    if(!ftLib)\n    {\n        if(!FT_Init_FreeType(&amp;ftLib)) return true;\n        else return false;\n    } else return true;\n}\n\nvoid glTextRender::shutdownFreeType()\n{\n    if(ftLib)\n    {\n        FT_Done_FreeType(ftLib);\n        ftLib = 0;\n    }\n}\n\nvoid glTextRender::print(const wchar_t* str)\n{\n    // store old stuff to set start position\n    glPushAttrib(GL_TRANSFORM_BIT);\n    // get viewport size\n    GLint viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n\n    gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);\n    glPopAttrib();\n\n    float color[4];\n    glGetFloatv(GL_CURRENT_COLOR, color);\n\n    glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT); \n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n\n    glEnable(GL_TEXTURE_2D);\n    //glDisable(GL_DEPTH_TEST);\n\n    // set blending for AA\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    glTranslatef(xPos,yPos,0.0f);\n\n    glColor4f(red,green,blue,alpha);\n\n    // call display lists to render text\n    glListBase(0u);\n    for(unsigned int i=0;i&lt;wcslen(str);i++) glCallList(getChar(str[i]));\n\n    // restore old states\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n    glPopAttrib();\n\n    glColor4fv(color);\n\n    glPushAttrib(GL_TRANSFORM_BIT);\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n    glPopAttrib();\n}\n\nvoid glTextRender::printf(const wchar_t* str, ...)\n{\n    if(!str) return;\n\n    wchar_t*    buf = 0;\n    va_list  parg;\n    va_start(parg, str);\n\n    // allocate buffer\n    int len = (_vscwprintf(str, parg)+1);\n    buf = new wchar_t[len];\n    if(!buf) return;\n    vswprintf(buf, str, parg);\n    va_end(parg);\n\n    print(buf);\n\n    delete[] buf;\n}\n\nGLuint glTextRender::getChar(const wchar_t c)\n{\n    int i = (int)c;\n\n    if(cached[i]) return listID[i];\n\n    // load glyph and get bitmap\n    if(FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT )) return 0;\n\n    FT_Glyph glyph;\n    if(FT_Get_Glyph(face-&gt;glyph, &amp;glyph)) return 0;\n\n    FT_Glyph_To_Bitmap(&amp;glyph, FT_RENDER_MODE_NORMAL, 0, 1);\n\n    FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;\n    FT_Bitmap&amp; bitmap = bitmapGlyph-&gt;bitmap;\n\n    int w = roundPow2(bitmap.width);\n    int h = roundPow2(bitmap.rows);\n\n    // convert to texture in memory\n    GLubyte* texture = new GLubyte[2*w*h];\n\n    for(int j=0;j&lt;h;j++)\n    {\n        bool cond = j&gt;=bitmap.rows;\n\n        for(int k=0;k&lt;w;k++)\n        {\n                texture[2*(k+j*w)] = 0xFFu;\n                texture[2*(k+j*w)+1] = ((k&gt;=bitmap.width)||cond) ? 0x0u : bitmap.buffer[k+bitmap.width*j];\n        }\n    }\n\n    // store char width and adjust max height\n    // note .5f\n    float ih = 1.0f/((float)gl-&gt;getHeight());\n    width[i] = ((float)divPow2(face-&gt;glyph-&gt;advance.x, 7))*ih;\n    aHeight = max(aHeight,(.5f*(float)bitmap.rows)*ih);\n\n    glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);\n\n    // create gl texture\n    glGenTextures(1, &amp;(texID[i]));\n\n    glEnable(GL_TEXTURE_2D);\n\n    glBindTexture(GL_TEXTURE_2D, texID[i]);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);\n\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texture);\n\n    glPopAttrib();\n\n    delete[] texture;\n\n    // create display list\n    listID[i] = glGenLists(1);\n\n    glNewList(listID[i], GL_COMPILE);\n\n    glBindTexture(GL_TEXTURE_2D, texID[i]);\n\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n\n    // adjust position to account for texture padding\n    glTranslatef(.5f*(float)bitmapGlyph-&gt;left, 0.0f, 0.0f);\n    glTranslatef(0.0f, .5f*(float)(bitmapGlyph-&gt;top-bitmap.rows), 0.0f);\n\n    // work out texcoords\n    float tx=((float)bitmap.width)/((float)w);\n    float ty=((float)bitmap.rows)/((float)h);\n\n    // render\n    // note .5f\n    glBegin(GL_QUADS);\n        glTexCoord2f(0.0f, 0.0f);\n        glVertex2f(0.0f, .5f*(float)bitmap.rows);\n        glTexCoord2f(0.0f, ty);\n        glVertex2f(0.0f, 0.0f);\n        glTexCoord2f(tx, ty);\n        glVertex2f(.5f*(float)bitmap.width, 0.0f);\n        glTexCoord2f(tx, 0.0f);\n        glVertex2f(.5f*(float)bitmap.width, .5f*(float)bitmap.rows);\n    glEnd();\n\n    glPopMatrix();\n\n    // move position for the next character\n    // note extra div 2\n    glTranslatef((float)divPow2(face-&gt;glyph-&gt;advance.x, 7), 0.0f, 0.0f);\n\n    glEndList();\n\n    // char is succesfully cached for next time\n    cached[i] = true;\n\n    return listID[i];\n}\n\nvoid glTextRender::setPosition(float x, float y)\n{\n    float fac = ((float)gl-&gt;getHeight());\n    xPos = fac*x+FONT_BORDER_PIXELS; yPos = fac*(1-y)-(float)height-FONT_BORDER_PIXELS;\n}\n\nfloat glTextRender::getAdjustedWidth(const wchar_t* str)\n{\n    float w = 0.0f;\n\n    for(unsigned int i=0;i&lt;wcslen(str);i++)\n    {\n        if(cached[str[i]]) w+=width[str[i]];\n        else\n        {\n            getChar(str[i]);\n            w+=width[str[i]];\n        }\n    }\n\n    return w;\n}\n</code></pre>\n'}, {'answer_id': 20310693, 'author': 'Calmarius', 'author_id': 58805, 'author_profile': 'https://Stackoverflow.com/users/58805', 'pm_score': 2, 'selected': False, 'text': '<p>You should consider using an Unicode rendering library (eg. <a href="http://en.wikipedia.org/wiki/Pango" rel="nofollow noreferrer">Pango</a>) to render the stuff into a bitmap and put that bitmap on the screen or into a texture. </p>\n\n<p>Rendering unicode text is not simple. So you cannot simply load 64K rectangular glyphs and use it. </p>\n\n<p>Characters may overlap. Eg in this smiley:</p>\n\n<p>( ͡° ͜ʖ ͡°)</p>\n\n<p>Some code points stack accents on the previous character. Consider this excerpt from this <a href="https://stackoverflow.com/a/1732454/58805">notable post</a>:</p>\n\n<blockquote>\n  <p>...he com̡e̶s, ̕h̵i\u200bs un̨ho͞ly radiańcé destro҉ying all\n  enli̍̈́̂̈́ghtenment, HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo\u200b͟ur eye͢s̸ ̛l̕ik͏e\n  liq\u200buid pain, the song of re̸gular exp\u200bression parsing will\n  exti\u200bnguish the voices of mor\u200btal man from the sp\u200bhere I can see it\n  can you see ̲͚̖͔̙î̩́t̲͎̩̱͔́̋̀ it is beautiful t\u200bhe final snuffing of\n  the lie\u200bs of Man ALL IS LOŚ͖̩͇̗̪̏̈́T ALL I\u200bS LOST the pon̷y he comes\n  he c̶̮omes he comes the ich\u200bor permeates all MY FACE MY FACE ᵒh god no\n  NO NOO̼O\u200bO NΘ stop the an\u200b*̶͑̾̾\u200b̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅s\n  ͎a̧͈͖r̽̾̈́͒͑e n\u200bot rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ TO͇̹̺ͅƝ̴ȳ̳\n  TH̘Ë͖́̉ ͠P̯͍̭O̚\u200bN̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘\n  ̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ</p>\n</blockquote>\n\n<p>If you truly want to render Unicode correctly you should be able to render this one correctly too.</p>\n\n<p>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.</p>\n\n<p>In addition to that, if you want to store the result in a texture, use <code>pango_layout_get_pixel_extents</code> 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.</p>\n'}, {'answer_id': 57345074, 'author': 'Richard Kirk', 'author_id': 3387896, 'author_profile': 'https://Stackoverflow.com/users/3387896', 'pm_score': 0, 'selected': False, 'text': "<p>Unicode is supported in the title bar. I have just tried this on a Mac, and it ought to work elsewhere too. If you have (say) some imported data including text labels, and some of the labels just might contain unicode, you could add a tool that echoes the label in the title bar.</p>\n\n<p>It's not a great solution, but it is very easy to do.</p>\n"}]
['https://Stackoverflow.com/questions/7737', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/1007/']