OpenGL Game Tutorial
Visual C++ 6.0



Bitmap fonty


Příklad a zdroják ke stažení (2 932 k)


glDisable(GL_LIGHTING);
glEnable(GL_LIGHTING);
glColor3f();
glGenLists();
glDeleteLists();
glBindTexture();
glNewList();
glBegin();
glEnd();
glTexCoord2f();
glVertex2i();
glTranslated();
glEnable(GL_BLEND);
glDisable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glPopMatrix();
glLoadIdentity();
glOrtho();
glListBase();
glScalef();
glCallLists();




Zdrojový kód bitmap fontů a část popisů funkcí vytvořil kolega Jiří Studnička (Well). Jirko děkuju.

Abychom mohli vytvořit bitmap fonty, budeme k tomu potřebovat obrázek s fontama. Ten vypadá takto:



Z tohoto obrázku pomocí texturových koordinací vyřízneme znak po znaku a pro každý znak vytvoříme čtverec s texturou znaku. Pak čtverce poskládáme za sebou, podle zvoleného textu. To je základní princip. Teď mrknem, jak to udělat.

Nejdříve si v konstruktoru třídy K_CBMPFont vytvoříme 256 Display Listů. Každý Display List bude později obsahovat jeden znak.

// Konstruktor
K_CBMPFont::K_CBMPFont()
{
     iBase = glGenLists(256);     // Vytvoř 256 Display Listů
}

A budeme volat funkci InitBMP()

// Inicializuj font
K_CBMPFont::InitBMP()
{
     if(!LoadFont())             // Jestliže nepude načíst font, tak
          return FALSE;          // Ukonči funkci

     float     f_coord_x;        // X texturová koordinace
     float     f_coord_y;        // Y texturová koordinace

     glBindTexture(GL_TEXTURE_2D, iFontTexture);              // Nastav texturu fontu
     for (int loop = 0; loop < 256; loop++)                   // Cykluj podle počtu 256 Display Listů
     {
          f_coord_x = float(loop % 16) / 16.0f;               // Vypočítej X texturovou koordinaci aktuálního znaku
          f_coord_y = float(loop / 16) / 16.0f;               // Vypočítej Y texturovou koordinaci aktuálního znaku

          glNewList(iBase + loop, GL_COMPILE);                // Vytvoř Display List pro aktuální znak Start Building A List
               glBegin(GL_QUADS);                                             // Začni vykreslovat čtverec s aktuálním znakem
                    glTexCoord2f(f_coord_x,1 - f_coord_y - 0.0625f);                // Nastav texturovou koordinace pro levý dolní vrchol
                    glVertex2i(0,0);                                                // Vykresli levý dolní vrchol
                    glTexCoord2f(f_coord_x + 0.0625f, 1 - f_coord_y - 0.0625f);     // Nastav texturovou koordinace pro pravý dolní vrchol
                    glVertex2i(16,0);                                               // Vykresli pravý dolní vrchol
                    glTexCoord2f(f_coord_x + 0.0625f, 1 - f_coord_y);               // Nastav texturovou koordinace pro pravý horní vrchol
                    glVertex2i(16,16);                                              // Vykresli pravý horní vrchol
                    glTexCoord2f(f_coord_x, 1 - f_coord_y);                         // Nastav texturovou koordinace pro levý horní vrchol
                    glVertex2i(0,16);                                               // Vykresli levý horní vrchol
               glEnd();                                                        // Konec vykreslování čtverce s aktuálním znakem
               glTranslated(10,0,0);                                           // Posuň aktuální znak o 10 vpravo
          glEndList();                                        // Konec definice Display Listu
     }
     return TRUE;     // Pokud dojdeš až sem, tak vrať funkci true
}

Která do všech Display Listů uloží hodnoty pro vykreslování znaků. Než však začne hodnoty ukládat, tak se snaží otevřít obrázek voláním funkce LoadFont()

// Načti bitmap font
K_CBMPFont::LoadFont()
{
     iFontTexture = texture.LoadGLTexture("textures/bmpfont/font.bmp");     // Načti bitmap font
     if(!iFontTexture)                                                      // Pokud se nepodařilo načíst font, tak
          return FALSE;                                                     // Vrať funkci false
     return TRUE;                                                           // Jinak vrať funkci true
}

Funkce InitBMP() se volá jen jednou při inicializaci scény.


K_CBMPFont *pbmpfont;          // Bitmap font

//----------------------------------------------------------------------------------------------------//

// Načti scénu
void K_CScene::InitScene( void )
{

     ...
     ...
     ...

     pbmpfont = new K_CBMPFont();          // Alokuj paměť pro bitmap font
     pbmpfont->InitBMP();                  // Nastav bitmap font

     ...
     ...
     ...
}

Nakonec funkce OutText()

// Vykresli bitmap font
void K_CBMPFont::OutText(int i_x, int i_y, int i_width, int i_height, char *pc_string)
{
     float f_width, f_height;                             // Pomocné proměnné pro výšku a šířku textu
     f_width = (float) (i_width * 0.01);                  // Šířku textu převeď na procenta
     f_height = (float) (i_height * 0.01);                // Výšku textu převeď na procenta
     glEnable(GL_BLEND);                                  // Zapni průhlednost
     glBlendFunc(GL_ONE, GL_ONE);                         // Vše, co je černé je průhledné
     glBindTexture(GL_TEXTURE_2D, iFontTexture);          // Nastav texturu fontu
     glDisable(GL_DEPTH_TEST);                            // Vypni testování Depth Bufferu
     glMatrixMode(GL_PROJECTION);                         // Nastav projekční matici
     glPushMatrix();                                      // Ulož do zásobníku projekční matici
       glLoadIdentity();                                          // Resetuj projekční matici
       glOrtho(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT, -100, 100);     // Nastav pozici textu podle velikosti zobrazovací plochy
       glMatrixMode(GL_MODELVIEW);                                // Nastav modelovou matici
       glPushMatrix();                                            // Ulož do zásobníku modelovou matici
         glLoadIdentity();                                            // Resetuj modelovou matici
         glTranslated(i_x, i_y, 0);                                   // Nastav pozici textu
         glListBase(iBase - 32 + (128));                              // Nastav počáteční znak (0, nebo 1)
         glScalef(f_width, f_height, 0);                              // Zmenši, nebo zvětši text podle hodnot šířky a výšky
         glCallLists(strlen(pc_string), GL_BYTE, pc_string);          // Vykresli výsledný text
         glMatrixMode(GL_PROJECTION);                                 // Nastav projekční matici
       glPopMatrix();                                              // Obnov předešlou modelovou matici
       glMatrixMode(GL_MODELVIEW);                                 // Nastav modelovou matici
     glPopMatrix();                                        // Obnov předešlou projekční matici
     glEnable(GL_DEPTH_TEST);                              // Zapni testování Depth Bufferu
     glDisable(GL_BLEND);                                  // Vypni průhlednost
}


Vykreslí text. Parametry: i_x, i_y je pozice v okně (dle nastavení SCREEN_WIDTH, SCREEN_HEIGHT (640, 480)), i_width, i_height jsem přidal pro možnost výpisu textu v libovolné velikosti. Udává se v procentech. Může překračovat i 100 takže když u obou parametrů i_width i i_height zadáme 200, tak text bude 2x větší než ve skutečnosti je BMP font a to v obou osách (i_x, i_y). No a char *pc_string je asi jasný

Funkce OutText() se volá v nekonečné smyčce při vykreslování scény


K_CBMPFont *pbmpfont;          // Bitmap font
K_CTimer timer;                // Časovač

//----------------------------------------------------------------------------------------------------//

// Vykresli scénu
void K_CScene::DrawScene( void )
{

      ...
      ...
      ...

       // Výpočet hodnot velikosti pro text dle časovače
       static bool b = false;                        // Nastav při startu aplikace proměnnou přepínače na false
       static int i_width = 100, i_height = 100;     // Nastav při startu aplikace proměnné velikosti textu
       if(timer.GetTime() >=5.0)                     // Prováděj výpočty každých 5 milisekund
       {
            if(!b)                    // Jesliže je hodnota přepínače false, tak
            {
               i_width += 1;          // Zvětši šířku textu
               i_height += 1;         // Zvětši výšku textu
            }
            else                      // Pokud je hodnota přepinače true, tak
            {
                 i_width -= 1;        // Zmenši šířku textu
                 i_height -= 1;       // Zmenši výšku textu
            }
            if(i_width == 150)        // Jestliže je šířka rovna 150, tak
                 b = !b;              // Přepni přepínač
            if(i_width == 100)        // Jestliže je šířka rovna 100, tak
                 b = !b;              // Přepni přepínač
            timer.Reset();            // Resetuj časovač
       }
       glDisable(GL_LIGHTING);               // Vypni světlo
       glColor3f(0.0f, 1.0f, 0);             // Nastav barvu textu
       pbmpfont->OutText(20, 20, i_width, i_height, "Developers: Jiri Studnicka & Jan Koci");   // Vykresli text
       glColor3f(1.0f, 1.0f, 1.0f);          // Nastav barvu na bílou
       glEnable(GL_LIGHTING);                // Zapni světlo
}

Jak vidíte, tak před samotným vykreslováním textu tu máme jednoduchý výpočet změny velikosti textu, který se zvětšuje a zmenšuje. Výpočet se volá každých 5 milisekund, nezávisle na aktuálním FPS.

Příště zkusíme načíst QuakeIII scénu, ze souboru BSP.




Home