Как отобразить unicode текст в OpenGL?

Разница между == и equа меня немного смутила, пока я не решил поближе рассмотреть ее. Многие из них говорят, что для сравнения строки вы должны использовать equals, а не ==. Надеюсь, что в этом ответе я смогу сказать разницу.

Лучший способ ответить на этот вопрос будет, задав несколько вопросов самому себе. так что давайте начнем:

. Каков результат для следующей программы:

String mango = "mango";
String mango2 = "mango";
System.out.println(mango != mango2);
System.out.println(mango == mango2);

, если вы говорите,

false
true

Я скажу, что вы right , но почему вы так сказали? и если вы говорите, что выходной сигнал,

true
false

Я скажу, что вы ошибочны , но я все равно спрошу вас, почему вы думаете, что это правильно?

Хорошо, попробуем ответить на этот вопрос:

Каков выход для следующей программы:

String mango = "mango";
String mango3 = new String("mango");
System.out.println(mango != mango3);
System.out.println(mango == mango3);

Now Если вы говорите,

false
true

Я скажу, что вы ошибочны , но почему это неправильно сейчас? правильным выходом для этой программы является

true
false

. Пожалуйста, сравните вышеуказанную программу и попытайтесь об этом подумать.

Хорошо. Теперь это может помочь (пожалуйста, прочтите следующее: напечатать адрес объекта - невозможно, но мы все же можем его использовать.)

String mango = "mango";
String mango2 = "mango";
String mango3 = new String("mango");
System.out.println(mango != mango2);
System.out.println(mango == mango2);
System.out.println(mango3 != mango2);
System.out.println(mango3 == mango2);
// mango2 = "mang";
System.out.println(mango+" "+ mango2);
System.out.println(mango != mango2);
System.out.println(mango == mango2);

System.out.println(System.identityHashCode(mango));
System.out.println(System.identityHashCode(mango2));
System.out.println(System.identityHashCode(mango3));

можете ли вы просто попытаться подумать о вывод последних трех строк в приведенном выше коде: для меня ideone напечатал это ( вы можете проверить здесь код ):

false
true
true
false
mango mango
false
true
17225372
17225372
5433634

О! Теперь вы видите, что идентификаторHashCode (манго) равен идентификаторуHashCode (mango2). Но он не равен identityHashCode (mango3)

. Хотя все строковые переменные - mango, mango2 и mango3 - имеют одинаковое значение, который является «манго», identityHashCode() все еще не является одинаковым для всех.

Теперь попробуйте раскомментировать эту строку // mango2 = "mang"; и запустите его снова, на этот раз вы увидите, что все три identityHashCode() отличаются друг от друга. Хм, это полезный намек

, мы знаем, что если hashcode(x)=N и hashcode(y)=N => x is equal to y

, я не уверен, как java работает внутри, но я предполагаю, что это то, что произошло, когда я сказал:

mango = "mango";

java создал строку "mango", которая была указана (указана) переменной mango примерно так

mango ----> "mango"

Теперь в следующая строка, когда я сказал:

mango2 = "mango";

На самом деле она повторно использовала ту же строку "mango", которая выглядит примерно так

mango ----> "mango" <---- mango2

И манго, и манго2, указывающие на ту же ссылку Теперь когда я сказал

mango3 = new String("mango")

Фактически он создал совершенно новую ссылку (строку) для «манго». который выглядит примерно так:

mango -----> "mango" <------ mango2

mango3 ------> "mango"

, и поэтому, когда я выставляю значения для mango == mango2, он выдает true. и когда я вытащил значение для mango3 == mango2, он выпустил false (даже если значения были одинаковыми).

и когда вы раскоментировали строку // mango2 = "mang";, она фактически создала строку " mang ", который повернул наш график следующим образом:

mango ---->"mango"
mango2 ----> "mang"
mango3 -----> "mango"

Вот почему идентификаторHashCode для всех не одинок.

Надеюсь, это поможет вам, ребята. На самом деле, я хотел создать тестовый пример, где == fail и equals (). Пожалуйста, не стесняйтесь комментировать и дайте мне знать. Если я ошибаюсь.

6
задан Serge 11 August 2008 в 12:50
поделиться

6 ответов

Вы могли также сгруппировать символы языком. Загрузите каждую таблицу языка по мере необходимости, и когда необходимо будет переключить языки, разгрузить предыдущую таблицу языка и загрузить новую.

0
ответ дан 8 December 2019 в 03:29
поделиться

Необходимо также проверить библиотеку FTGL.

FTGL является свободным межплатформенным Открытым исходным кодом библиотека C++, которая использует Freetype2 для упрощения шрифтов рендеринга в приложениях OpenGL. FTGL поддерживает битовые массивы, пиксельные карты, текстурные карты, основы, сетку полигона и вытесненные режимы рендеринга полигона.

Этот проект бездействовал некоторое время, но недавно назад разрабатывается. Я не обновил свой проект использовать последнюю версию, но необходимо проверить его.

Это допускает использование любого Истинного Печатного шрифта через библиотеку шрифтов FreeType.

15
ответ дан 8 December 2019 в 03:29
поделиться

Я рекомендую читать это учебное руководство по шрифту OpenGL. Это для языка программирования D, но это - хорошее введение в различные проблемы, вовлеченные в реализацию системы кэширования глифа для рендеринга текста с OpenGL. Учебное руководство касается соответствия Unicode, сглаживания и использующих кернинг методов.

D довольно понятен любому, кто знает C++, и большая часть статьи об общих методах, не языке реализации.

6
ответ дан 8 December 2019 в 03:29
поделиться

Queso GLC является большим для этого, я использовал его для рендеринга китайских и символов кириллицы в 3D.

http://quesoglc.sourceforge.net/

Текстовый образец Unicode, с которым это идет, должен запустить Вас.

1
ответ дан 8 December 2019 в 03:29
поделиться

Идентификатор рекомендует 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;
}
3
ответ дан 8 December 2019 в 03:29
поделиться

Вам, вероятно, придется генерировать Вас собственный "кэш глифа" в памяти структуры, когда Вы идете, потенциально со своего рода политикой LRU постараться не уничтожать всю память структуры. Совсем не столь же легкий как Ваш существующий метод, но может быть единственный путь, учитывая количество unicode символов

2
ответ дан 8 December 2019 в 03:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: