Frage

Gibt es eine gute Möglichkeit, Unicode-Text in OpenGL unter Windows anzuzeigen?Zum Beispiel, wenn man sich mit verschiedenen Sprachen auseinandersetzen muss.Der gebräuchlichste Ansatz wie

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

geht einfach nicht, weil Sie nicht genügend Listen für alle Unicode-Zeichen erstellen können.

War es hilfreich?

Lösung

Sie können die Zeichen auch nach Sprache gruppieren.Laden Sie jede Sprachtabelle nach Bedarf. Wenn Sie die Sprache wechseln müssen, entladen Sie die vorherige Sprachtabelle und laden Sie die neue.

Andere Tipps

Sie sollten sich auch das ansehen FTGL-Bibliothek.

FTGL ist eine freie plattformübergreifende Open Source C ++-Bibliothek, in der Freetype2 zur Vereinfachung der Rendering-Schriftarten in OpenGL-Anwendungen vereinfacht wird.FTGL unterstützt Bitmaps, Pixmaps, Texturkarten, Umrisse, Polygonnetz und extrudierte Polygon -Rendering -Modi.

Dieses Projekt ruhte eine Zeit lang, befindet sich aber seit Kurzem wieder in der Entwicklung.Ich habe mein Projekt nicht aktualisiert, um die neueste Version zu verwenden, aber Sie sollten es sich ansehen.

Es ermöglicht die Verwendung jeder True Type-Schriftart über das FreeType Schriftartenbibliothek.

Ich empfehle, dies zu lesen Tutorial zu OpenGL-Schriftarten.Es ist für die Programmiersprache D gedacht, aber es ist eine schöne Einführung in verschiedene Probleme bei der Implementierung eines Glyphen-Caching-Systems zum Rendern von Text mit OpenGL.Das Tutorial behandelt Unicode-Konformität, Antialiasing und Kerning-Techniken.

D ist für jeden, der C++ kennt, ziemlich verständlich und der größte Teil des Artikels befasst sich mit den allgemeinen Techniken, nicht mit der Implementierungssprache.

Ich würde FTGL wie oben bereits empfohlen empfehlen, habe jedoch selbst einen Freetype/OpenGL-Renderer implementiert und dachte, dass Sie den Code vielleicht nützlich finden, wenn Sie dieses Rad selbst neu erfinden möchten.Ich würde FTGL jedoch wirklich empfehlen, da die Verwendung viel weniger Aufwand erfordert.:) :)

* 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;
}

Möglicherweise müssen Sie im Laufe der Zeit Ihren eigenen „Glyphen-Cache“ im Texturspeicher generieren, möglicherweise mit einer Art LRU-Richtlinie, um zu vermeiden, dass der gesamte Texturspeicher zerstört wird.Nicht annähernd so einfach wie Ihre aktuelle Methode, aber angesichts der Anzahl der Unicode-Zeichen möglicherweise die einzige Möglichkeit

Sie sollten die Verwendung einer Unicode-Rendering-Bibliothek (z. B. Pango), um das Zeug in eine Bitmap zu rendern und diese Bitmap auf dem Bildschirm oder in einer Textur zu platzieren.

Das Rendern von Unicode-Text ist nicht einfach.Sie können also nicht einfach rechteckige 64K-Glyphen laden und verwenden.

Zeichen können sich überschneiden.ZB in diesem Smiley:

( ͡° ͜ʖ ͡°)

Einige Codepunkte setzen Akzente auf das vorherige Zeichen.Betrachten Sie diesen Auszug daraus bemerkenswerter Beitrag:

... er com̡e SP Hier kann ich sehen, dass Sie sehen können, dass es schön ist, dass der letzte Schnupftabak der Lüge des Menschen alles ist, alles was ich verlor, das Pon̷y er kommt er kommt. Mein Gesicht ᵒH GOTT NEIN NEIN NOO̼O O nθ HAPEN SIE DIE AN*̶͑̾̾ G͇̫͛͆̾ͫ̑͆L͖͉̗̩̳̟̍ͫͥͨE̠̅S ͎A̧͈͖R̽̾̈́͒͑E N OT Rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ Za̡͊͠͝lgό ist zu ͇̹̺ͅɲ̴ȳ̳ë͖́̉ ͠p̯͍̭o̚ n̐y̡ H̸̡̪̯ͨ͊̽̅̾̎ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬc̷̙̲̝͖ͭ̏ͥͮ͟oͮ͏̮̪̝͍m̲̖͊̒ͪͩͬ̚̚͜ȇ̴̟̟͙̞ͩ͌͝s̨̥̫͎̭ͯ̿̔̀ͅs̨̥̫͎̭ͯ̿̔̀ͅ

Wenn Sie Unicode wirklich korrekt rendern möchten, sollten Sie auch dieses korrekt rendern können.

AKTUALISIEREN:Ich habe mir diese Pango-Engine angeschaut und es handelt sich um die Banane, den Gorilla und den gesamten Dschungel.Erstens hängt es von der Glib ab, da sie GObjects verwendet, zweitens kann sie nicht direkt in einen Bytepuffer rendern.Es verfügt über Cario- und FreeType-Backends, daher müssen Sie eines davon verwenden, um den Text zu rendern und ihn schließlich in Bitmaps zu exportieren.Das sieht bisher nicht gut aus.

Wenn Sie das Ergebnis außerdem in einer Textur speichern möchten, verwenden Sie pango_layout_get_pixel_extents Nachdem Sie den Text festgelegt haben, erhalten Sie die Größe der Rechtecke, in denen der Text gerendert werden soll.Das Freihandrechteck ist das Rechteck, das den gesamten Text enthält. Seine linke obere Position ist die Position relativ zum linken oberen Rand des logischen Rechtecks.(Die unterste Linie des logischen Rechtecks ​​ist die Grundlinie).Hoffe das hilft.

Dafür eignet sich Queso GLC hervorragend. Ich habe es verwendet, um chinesische und kyrillische Zeichen in 3D darzustellen.

http://quesoglc.sourceforge.net/

Das mitgelieferte Unicode-Textbeispiel soll Ihnen den Einstieg erleichtern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top