Najprostszym sposobem na wyświetlenie tekstu w OpenGL jest po prostu wyświetlenie bitmapy zawierającej ten tekst. Jednocześnie możemy wyświetlić ją jako przezroczystą co pozwoli na wyświetlenie samego tekstu bez jego tła. Więc np. tworzymy sobie prymityw typu GL_QUAD i naciągamy na niego poleceniem glTexCoord2f teksturę zawierającą nasz tekst. Przygotowanie bitmapy zawierającej cały alfabet. Tzn. litery ułożone są po kolei poczynając np. od lewego górnego rogu bitmapy. Ważne jest to, że każda litera musi znajdować się w polu o takim samym rozmiarze tzn. szerokości i wysokości. Teraz piszemy procedurę wyświetlającą tekst. Jej podstawowe działanie będzie polegać na wyświetleniu tylko kawałka bitmapy, odpowiadającego żądanej literze. Można to uzyskać dzięki poleceniu glTexCoord2f.
Np. mamy taką bitmapę zawierającą font:
Ma ona rozmiary 256x256 pikseli. Każda litera to pole o rozmiarach 16x16. Pierwsza litera ma kod ASCII równy 0(skrajna lewa, na dole). Należy zauważyć, że obrazek ten zawiera dwa fony, na każdy z fontów przypada po osiem kolumn(my będziemy zajmować się tylko jednym dolnym(jak na tym obrazku) fontem czyli 8 dolnymi wierszami). Naszym zadaniem jest napisanie kodu który wyznaczy współrzędne pola odpowiadającego żądanej literze. Taki kod może wyglądać jak poniżej(C++): #include #include #include void main() { int x1=0,x2=16,y1=0,y2=16,jaki_znak,znak; jaki_znak=65; //65 - znak jakiego współrzędne chcemy uzyskać czyli tu: A znak=0; do { if (x2 != 256)//256 - szerokość obrazka z fontem { x1+=16; x2+=16; znak++; } else { x1=0;x2=16; y1+=16; y2+=16; znak++; }; } while(znak!=jaki_znak); clrscr(); printf("X1 = %d\n",x1); printf("X2 = %d\n",x2); printf("Y1 = %d\n",y1); printf("Y2 = %d\n",y2); } Pole znaku ma postać:
Teraz dysponując współrzędnymi pola żądanego znaku można podstawić je do rozkazu glTexCoord2f dzieląc je przez liczbę 256(czyli szerokość i wysokość bitmapy) - ponieważ parametry tego rozkazu są liczbami z zakresu (0, 1). Należy pamiętać, że współrzędne X1,Y1,X2,Y2 w naszym programie w OpenGL powinny być liczbami typu Glfloat lub Gldouble(wtedy zastosuj glTexCoord2d). Należy też zauważyć, że nasza bitmapa z fontem jest w postaci odwróconej. Jest to związane z tym, że nasza procedura(przedstawiona wcześniej) do wczytywania tekstury z pliku BMP nie uwzględnia faktu, że obraz w tym pliku przechowywany jest w postaci odwróconej. Gotowa procedura wyświetlająca pojedynczą literę może wyglądać tak: void napisz_litere(int jaki_znak) { Glfloat x1=0,x2=16,y1=0,y2=16; int znak=0; do { if (x2 != 256) { x1+=16; x2+=16; znak=znak+1; } else {x1=0;x2=16; y1+=16; y2+=16; znak=znak+1; }; } while(znak!=jaki_znak); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); glTexCoord2f(x1/256, y2/256); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(x2/256, y2/256); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(x2/256, y1/256); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(x1/256, y1/256); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); } Oczywiście można pokusić się jeszcze o napisanie procedury wyświetlającej tekst zawarty w tablicy. W tym celu należy odpowiednio zmodyfikować postać procedury kreślącej literę tak aby można było określić jej rozmiar oraz położenie na ekranie. Może ona wtedy wyglądać tak: void napisz_litere(int jaki_znak,Glfloat gdzie_x,Glfloat gdzie_y,Glfloat rozmiar) { Glfloat x1=0,x2=16,y1=0,y2=16; int znak=0; do { if (x2 != 256) { x1+=16; x2+=16; znak=znak+1; } else {x1=0;x2=16; y1+=16; y2+=16; znak=znak+1; }; } while(znak!=jaki_znak); glBindTexture(GL_TEXTURE_2D, texture[0]);// Tekstura z fontem glBegin(GL_QUADS); glTexCoord2f(x1/256, y2/256); glVertex2f(gdzie_x, gdzie_y-rozmiar); glTexCoord2f(x2/256, y2/256); glVertex2f( gdzie_x+rozmiar, gdzie_y -rozmiar); glTexCoord2f(x2/256, y1/256); glVertex2f( gdzie_x+rozmiar, gdzie_y); glTexCoord2f(x1/256, y1/256); glVertex2f(gdzie_x, gdzie_y); glEnd(); } Teraz można napisać procedurę wyświetlającą tekst zawarty z tablicy której nazwę należy przekazać do niej jako pierwszy parametr: void pisz_tekst(char* tablica_stringu,Glfloat x,Glfloat y,Glfloat rozmiar) { Glfloat XXX = x; Glfloat YYY = y; while(*tablica_stringu != 0) { napisz_litere(*tablica_stringu,XXX,YYY,rozmiar); XXX+=(rozmiar+(rozmiar/12)); tablica_stringu++; } } Teraz możemy ją wykorzystać:
char tablica_ciagu[] = "Tekst OpenGL"; pisz_tekst(tablica_ciagu,-6.0f,0.0f,1.0f); Należy zauważyć, że współrzędne "x" i "y" procedury "pisz_tekst" odnoszą się do skrajnego, górnego, lewego rogu wyświetlanego tekstu. Jednocześnie należy zauważyć, że położenie o współrzędnych (0,0) to środek ekranu, bowiem podawane są one w jednostkach. Dla lepszego zrozumienia działania procedury "pisz_tekst" zamieszczam poniżej jej pierwowzór napisany w Borland C++ dla trybu tekstowego karty graficznej: void pisz_tekst(char* tablica_stringu) { while(*tablica_stringu != 0) { printf("%c",*tablica_stringu); tablica_stringu++; } }
Dodatkowo możemy dodać możliwość wyboru fontu, wtedy procedura rysowania pojedynczego znaku ma postać: void napisz_litere(int jaki_znak,Glfloat gdzie_x,Glfloat gdzie_y,Glfloat rozmiar,int font) { Glfloat x1=0,x2=16,y1=0,y2=16; if (font == 1){y1=129;y2=127+15;} int znak=0; do { if (x2 != 256) { x1+=16; x2+=16; znak=znak+1; } else {x1=0;x2=16; y1+=16; y2+=16; znak=znak+1; }; } while(znak!=jaki_znak); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); glTexCoord2f(x1/256, y2/256); glVertex2f(gdzie_x, gdzie_y-rozmiar); glTexCoord2f(x2/256, y2/256); glVertex2f( gdzie_x+rozmiar, gdzie_y-rozmiar); glTexCoord2f(x2/256, y1/256); glVertex2f( gdzie_x+rozmiar, gdzie_y); glTexCoord2f(x1/256, y1/256); glVertex2f(gdzie_x, gdzie_y); glEnd(); } Natomiast procedura pisania ciągu: void pisz_tekst(char* tablica_stringu,Glfloat x,Glfloat y,Glfloat rozmiar,int jaki_font) { Glfloat XXX = x; Glfloat YYY = y; while(*tablica_stringu != 0) { napisz_litere(*tablica_stringu,XXX,YYY,rozmiar,jaki_font); XXX+=(rozmiar+(rozmiar/12)); tablica_stringu++; } } I przykład wykorzystania tak zmodyfikowanych procedur: pisz_tekst(tablica_ciagu,-6.0f,0.0f, 0.7f,1); Wynika więc, że za wybór fontu odpowiedzialny jest ostatni parametr procedury "pisz_tekst". Jego wartość 0(lub inna, ale różna od 1) oznacza wybór fontu górnego, natomiast jego wartość 1 oznacza wybór fontu dolnego(przy nie odwróconym obrazie pliku fontu). [Patrz też pliki font1.rar i font2.rar w przykładach]