2008-08-11 8 views
6

Windowsでは、OpenGLでユニコードテキストを表示する良い方法はありますか?たとえば、異なる言語を扱う必要がある場合などです。あなたはすべてのUnicode文字のための十分なリストを作成することはできませんのでOpenGLでユニコードテキストを表示する方法は?

#define FONTLISTRANGE 128 
GLuint list; 
list = glGenLists(FONTLISTRANGE); 
wglUseFontBitmapsW(hDC, 0, FONTLISTRANGE, list); 

のような最も一般的なアプローチだけで行うことはありません。

答えて

0

また、言語によって文字をグループ化することもできます。必要に応じて各言語表をロードし、言語を切り替える必要がある場合は、前の言語表をアンロードして新しい表をロードします。

+5

これは、未処理の文字数がまだかなり大きい(数千グリフ)アジアン言語には最適な解決策ではありません。また、任意のGLアプリケーションでは、それらの一部を使用する可能性が高いです。ダイナミックなグリフキャッシュのアプローチが優れています。 – Baxissimo

2

テクスチャメモリにすべての「グリフキャッシュ」を生成しなければならない場合があります。テクスチャメモリをすべて破壊しないようにLRUポリシーを使用することもできます。あなたの現在の方法ほど簡単ではありませんが、ユニコード文字の数が与えられている唯一の方法かもしれません。

17

FTGL libraryもチェックしてください。

FTGLは、OpenGL アプリケーションでのフォントのレンダリングを簡素化するためにfreetype2の を使用して無料のクロスプラットフォームのオープンソース C++ライブラリです。 FTGLは、ビットマップ、 ピックスマップ、テクスチャマップ、アウトライン、 ポリゴンメッシュ、押出ポリゴン レンダリングモードをサポートしています。

このプロジェクトはしばらくの間休止していましたが、最近は開発中です。最新のバージョンを使用するように私のプロジェクトを更新していませんが、それをチェックアウトする必要があります。

フォントライブラリFreeTypeで任意のTrueTypeフォントを使用できます。

+0

こんにちは、フリータイプライブラリを使用しています。本当に満足しています。今私は曲線としてテキストをレンダリングするとき、パフォーマンスが非常に遅くなるので、私はより速く表示するテクスチャ技術にフォントを行います。しかし、私はグリフの限られた量だけをレンダリングするので、このように私は全体のユニコードフォントを使用することはできません。この場合、あなたが提案する方法はありますか?私は主に英語とギリシャ語をサポートすることに興味があります。 –

6

私はこれを読むことをお勧めしますOpenGL font tutorial。これはDプログラミング言語用ですが、OpenGLでテキストを描画するためのグリフキャッシングシステムの実装に関連するさまざまな問題の素敵な紹介です。このチュートリアルでは、Unicode準拠、アンチエイリアス、およびカーニングのテクニックについて説明します。

DはC++を知っている人にとっては分かりやすく、記事のほとんどは実装言語ではなく一般的なテクニックに関するものです。

+0

あなたのリンクは死んでいます。 –

1

Queso GLCはこれには最適です。中国語とキリル文字を3Dでレンダリングするために使用しました。

http://quesoglc.sourceforge.net/

それはあなたが始める必要がありますが付属してUnicodeテキストサンプル。

3

Idは既に上記のように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; 
} 
2

あなたは(例えば。Pango)Unicodeのレンダリングライブラリを使用することを検討すべきであるビットマップにものをレンダリングし、画面上やテクスチャにそのビットマップを配置します。

レンダリングするユニコードテキストは単純ではありません。したがって、単純に64K長方形グリフを読み込んで使用することはできません。

文字が重複する可能性があります。このスマイリーでの例:

(͡°͜ʖ͡°)

いくつかのコード・ポイントが前の文字にアクセントを積み重ねます。こんにちは、すべて 啓発、HTMLタグが漏れるfr̶ǫmYO URの目のような LIQ uidの痛み、通常のEXPの歌をdestro҉yingとんでもない輝きをよ...彼が来る、

:このnotable postからこの抜粋を考えてみましょう私はそれを見ることができる あなたが見ることができる それは美しいですか?彼は最後の嗅ぐことはできません 男の嘘ALL ISLOŚ͖̩͇̗̪̏̈TALL I彼は来るpon̷y彼は来る 彼は彼がichに来るか、またはすべての私の顔私の顔を浸透するᵒh神no NOいーえONθ停止AN *̶͑̾̾GLES されたn個のot本当ZA̡͊͠͝LGΌISͮ҉̯͈͕̹̘TO͇̹̺Ɲ̴ȳ̳ THE PO NYH̸̡̪̯ͨ͊̽̅̾Ȩ̬̩̾͛ͪ̈͘ ̶̧̨̹̭̯ͧ̾ͬC̷̙̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔

あなたが本当にUnicodeをレンダリングしたい場合は、正しく次のことができるようにすべきですこれも正しくレンダリングします。

更新:このパンゴエンジンを見て、それはバナナ、ゴリラ、そしてジャングル全体のケースです。最初はGObjectを使用していたのでGlibに依存していました.2番目はGバイトを直接バイトバッファにレンダリングできません。それはCarioとFreeTypeのバックエンドを持っているので、それらを使ってテキストをレンダリングし、最終的にビットマップにエクスポートする必要があります。それは今のところよく見えません。

さらに、結果をテクスチャに格納する場合は、テキストを設定した後にpango_layout_get_pixel_extentsを使用して、テキストをレンダリングする矩形のサイズを取得します。 Ink rectangleはテキスト全体を含む矩形で、左上の位置は論理矩形の左上からの相対的な位置です。 (論理長方形の下の行がベースラインです)。お役に立てれば。

関連する問題