NeHe - Lektion 13 - Bitmap Fonts

Lektion 13



Willkommen zu einem weiteren Tutorial. Diesmal werde ich Ihnen beibringen, wie man Bitmap Fonts verwendet. Sie werden sich wahrscheinlich sagen "was ist so schwer daran, Text auf den Screen zu bekommen". Wenn Sie es jemals ausprobiert haben, wissen Sie, dass es nicht so leicht ist!

Natürlich könnten Sie ein Grafikprogramm öffnen, Text als Bild abspeichern, das Bild in Ihrem OpenGL Programm laden, Blending einschalten und dann den Text auf den Screen mappen. Aber das ist etwas Zeitraubend, das Ergebniss würde verschwommen oder globig aussehen, abhängig von der Art Filter die Sie verwenden und wenn Ihr Bild nicht gerade einen Alpha-Kanal hat, wird Ihr Text transparent (geblended mit den Objekten auf dem Screen), wenn es erst einmal auf dem Screen ist.

Wenn Sie jemals Wordpad, Microsoft Word oder ähliches verwendet haben, werden Sie festgestellt haben, dass verschiedene Fonts (Schriftarten) zur Verfügung stehen. Dieses Tutorial bringt Ihnen bei, wie Sie exakt die selben Fonts in Ihren OpenGL Programmen verwenden. Was Fakt ist... Jeder Font den Sie auf Ihrem Computer installieren, kann in Ihren Demos verwendet werden.

Nicht nur, dass Bitmap Fonts 100 aml besser aussehen, als graphische Fonts (Texturen). Sie können den Text 'on the fly' verändern. Sie müssen keine Textur für jedes Wort oder jeden Buchstaben erstellen, den Sie auf den Screen bringen wollen. Sie müsssen nur den Text positionieren und meinen netten neuen GL-Befehl benutzen, um den Text auf dem Screen anzuzeigen.

Ich habe versucht den Befehl so einfach wie möglich zu halten. Alles was Sie machen müssen ist glPrint("Hello") einzugeben. So einfach ist das. Wie dem auch sei. Sie können sich anhand der langen Einleitung vorstellen, dass ich ziemlich glücklich mit diesem Tutorial bin. Es hat ungefähr 1 1/2 Stunden gedauert, bis ich das Programm geschrieben hatte. Warum so lange? Ganz einfach weil es so gut wie keine Informationen über Bitmap Fonts gibt, es sei denn Sie lieben MFC Code. Um den Code einfach zu halten, habe ich micht entschlossen, dass es nett wäre, wenn ich alles in einfach verstehbaren C Code schreiben würde :)

Eine kleine Anmerkung: dieser Code ist Windows-spezifisch. Er benutzt die wgl Funktionen von Windows um den Font zu erzeugen. Dafür hat Apple aber agl, was das Selbe machen sollte und X hat glx. Unglücklicherweise kann ich Ihnen nicht garantieren, dass der Code portabel ist. Wenn irgendwer einen Plattform unabhängigen Code zum Fonts zeichnen hat, schickt ihn mir und ich werde ein anderes Font-Tutorial schreiben.

Wir fangen mit dem typischen code aus Lektion 1 an. Wir fügen den stdio.h Header für die Standard Ein-/Ausgaben hinzu, den stdarg.h Header um Text zu parsen und Variablen in Text zu verwandeln und letztendlich math.h, damit wir den Text auf dem Bildschirm bewegen können, indem wir SIN und COS verwenden.

#include <windows.h>                        // Header Datei für Windows
#include <math.h>                        // Header Datei für Windows Math Library    ( HINZUGEFÜGT )
#include <stdio.h>                        // Header Datei für Standard Input/Output    ( HINZUGEFÜGT )
#include <stdarg.h>                        // Header Datei für Variable Argumente Routinen    ( HINZUGEFÜGT )
#include <gl\gl.h>                        // Header Datei für die OpenGL32 Library
#include <gl\glu.h>                        // Header Datei für die GLu32 Library
#include <gl\glaux.h>                        // Header Datei für die GLaux Library

HDC        hDC=NULL;                    // Privater GDI Device Context
HGLRC        hRC=NULL;                    // Permanenter Rendering Context
HWND        hWnd=NULL;                    // Enthält unser Fenster-Handle
HINSTANCE    hInstance;                    // Enthält die Instanz der Applikation

Außerdem fügen wir 3 neue Variablen hinzu. base wird die Nummer der ersten Display Liste enthalten, die wir erzeugen. Jeder Buchstabe benötigt eine eigene Display Liste. Der Buchstabe 'A' ist 65 in der Display Liste, 'B' ist 66, 'C' ist 67, usw. Deshalb wir 'A' in der Display Liste base+65 gespeichert.

Als nächstes fügen wir zwei Zähler (cnt1 & cnt2) hinzu. Diese Zähler, zählen in unterschiedlichen Intervallen und werden verwendet um den Text auf dem Screen mittels SIN und COS zu bewegen. Das erzeugt eine halb-zufällige Bewegung auf dem Screen. Wir werden die Zähler auch zum kontrollieren der Buchstabenfarbe verwenden (mehr dazu später).

GLuint    base;                            // Basis Display Liste für den Font Satz
GLfloat    cnt1;                            // erster Zähler wird benutzt um den Text zu bewegen & zur Färbung
GLfloat    cnt2;                            // zweiter Zähler wird benutzt um den Text zu bewegen & zur Färbung

bool    keys[256];                        // Array das für die Tastatur Routine verwendet wird
bool    active=TRUE;                        // Fenster Aktiv Flag standardmäßig auf TRUE gesetzt
bool    fullscreen=TRUE;                    // Fullscreen Flag ist standardmäßig auf TRUE gesetzt

LRESULT    CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);        // Deklaration für WndProc

Der folgende Codeabschnitt erzeugt den eigentlichen Font. Das war der schwierigste Codeteil. 'HFONT font' teilt Windows in einfachem deutsch mit, dass wir einen Windows Font manipulieren werden. oldfont wird benutzt, um nach alles wieder herstellen zu können.

Als nächstes definieren wir base. Das machen wir, indem wir eine Gruppe von 96 Display Listen mittels glGenLists(96) erzeugen. Nachdem die Display Listen erzeugt wurden, enthält base die Nummer der ersten Liste.

GLvoid BuildFont(GLvoid)                    // erzeuge unseren Bitmap Font
{
    HFONT    font;                        // Windows Font ID
    HFONT    oldfont;                    // für später

    base = glGenLists(96);                    // Speicherplatz für 96 Buchstaben ( NEU )

Nun zum spaßigen Teil. Wir erzeugen unseren eigenen Font. Wir fangen damit an, die Größe des Fonts zu spezifizieren. Sie werden bemerken, dass es eine negative Zahl ist. Indem wir ein Minus voranstellen, teilen wir Windows mit, dass uns ein Font basierend auf der BUCHSTABEN Höhe gesucht werden soll. Wenn wir eine positive Zahl verwenden, suchen wir nach einem Font basierend auf der ZELL Höhe.

    font = CreateFont(    -24,                // Höhe unseres Font ( NEU )

Dann geben wir die Zell-Breite an. Sie werden bemerken, dass ich diese auf 0 gesetzt habe. Dadurch, dass Werte auf 0 gesetzt werden, wird Windows die Standardwerte verwenden. Sie können mit diesem Wert etwas rumspielen, wenn Sie wollen. Machen Sie den Font breiter, etc.

                0,                // Breite unseres Font

Der Fluchtwinkel (Angle of Escapement) rotiert den Font. Unglücklicherweise ist das nicht gerade ein nützliches Feature. Es sei denn, Sie sind bei 0, 90, 180 und 270 Grad, ansonsten wird der Font abgeschnitten um in die unsichtbare Grenze zu passen. Orientierungwinkel 'Orientation Angle' ist laut MSDN Hilfe der Winkel in Zehntel Grad zwischen den Buchstabens Basislinie und der X-Achse des Devices. Leider habe ich keine Idee, was das bedeuet :(

                0,                // Angle Of Escapement
                0,                // Orientation Angle

Font Weight ist ein großartiger Parameter, mit dem man die Dicke des Fonts einstellen kann. Sie können ein Zahl zwischen 0 und 1000 verwenden oder Sie benutzen eine der vordefinierten Werte. FW_DONTCARE ist gleich 0, FW_NORMAL ist 400, FW_BOLD ist 700 und FW_BLACK entspricht 900. Es gibt noch viel mehr vordefinierte Werte, aber diese 4 geben eine gute Übersicht. Je höher der Wert, um so dicker der Font.

                FW_BOLD,            // Font Dicke

Italic (kursiv), Underline (unterstrichen) und Strikeout (durchgestrichen) können entweder TRUE oder FALSE sein. Wenn Underline also auf TRUE gesetzt wird, wird der FONT unterstrichen. Wenn es gleich FALSE ist, dann nicht. Ziemlich einfach :)

                FALSE,                // Italic
                FALSE,                // Underline
                FALSE,                // Strikeout

'Character set Identifier' beschreibt die Art der Buchstaben, die Sie verwenden wollen. Es gibt zu viele Arten, um diese hier zu erklären. CHINESEBIG5_CHARSET (chinesisch), GREEK_CHARSET (griechisch), RUSSIAN_CHARSET (russisch), DEFAULT_CHARSET (standard), etc. ANSI ist das was ich benutze, obwohl DEFAULT wohl genau so gut arbeiten würde.

Wenn Sie Fonts wie Webdings oder Wingdings verwenden wollen, müssen Sie SYMBOL_CHARSET anstatt von ANSI_CHARSET verwenden.

                ANSI_CHARSET,            // Character Set Identifier

Die Ausgabe Genauigkeit (Output Precision) ist sehr wichtig. Sie teilt Windows die Art des Zeichensatz mit, der verwendet werden soll, wenn mehr als eine Art verfügbar ist. OUT_TT_PRECIS teilt Windows mit, dass, für den Fall das es mehr als eine Font-Art mit dem entsprechenden Namen zu wählen ist, die TRUETYPE Version des Fonts gewählt werden soll. Truetype Fonts sehen immer besser aus, insbesondere wenn Sie sie groß machen. Sie können auch OUT_TT_ONLY_PRECIS verwenden, was IMMER versucht TRUETYPE Fonts zu verwenden.

                OUT_TT_PRECIS,            // Output Precision

Clipping Precision (Abschneide-Genauigkeit) ist die Art des Abschneidens, die vorgenommen werden soll, wenn der Font sich außerhalb der Clipping Region befindet. Es gibt nicht viel dazu zu sagen, lassen Sie es einfach beim Standard-Wert.

                CLIP_DEFAULT_PRECIS,        // Clipping Precision

Die Ausgabe Qualität ist sehr wichtig. Sie können folgende benutzen: PROOF, DRAFT, NONANTIALIASED, DEFAULT oder ANTIALIASED. Wir alle wissen, dass antialiased Fonts gut aussehen:) Eine Font zu Antialiasen ist der selbe Effekt als wenn Sie Smoothing in Windows einschalten. Es lässt alles weniger kantig aussehen.

                ANTIALIASED_QUALITY,        // Ausgabe Qualität

Als nächstes haben wir Familie und Pitch Eigenschaften. Für Pitch können Sie die Werte DEFAULT_PITCH, FIXED_PITCH und VARIABLE_PITCH haben und für Familie FF_DECORATIVE, FF_MODERN, FF_ROMAN, FF_SCRIPT, FF_SWISS, FF_DONTCARE. Spielen Sie etwas mit diesen Werten herum, um herauszufinden, was diese bewirken. Ich setze beide auf die Standardwerte.

                FF_DONTCARE|DEFAULT_PITCH,    // Familie und Pitch

Schließlich... haben wir den Namen des Fonts. Starten Sie Microsoft Word oder einen anderen Texteditor. Schauen Sie sich die Schriftarten an und suchen Sie sich einen aus, der Ihnen gefällt. Um den entsprechenden Font zu nutzen, ersetzen Sie 'Courier New' mit dem Namen des Fonts, den Sie ausgewählt haben.

                "Courier New");            // Font Name

oldFont speichert den zuvor genutzten Font ab. SelectObject gibt den Font (oder pen, oder filler, oder welches GDI Objekt auch immer) zurück, das zuvir gesetzt war, als wir zum neuen Font gewechselt haben. Auf Art wie das GDI funktioniert, ist der Rückgabewert von SelectObject nicht gerade offensichtlich. Zu erst sieht es so aus, als ob der Code den neuen Font auswählt und einen Zeiger zurückgibt, der in oldFont gespeichert wird.

    oldfont = (HFONT)SelectObject(hDC, font);        // wähle den Font aus, den wir wollen
    wglUseFontBitmaps(hDC, 32, 96, base);            // erzeuge 96 Buchstaben beginnend mit Buchstabe 32
    SelectObject(hDC, oldfont);                // wähle den Font aus, den wir wollen
    DeleteObject(font);                    // Lösche den Font
}

Der folgende Code ist ziemlich einfach. Er löscht die 96 Display Listen aus dem Speicher, beginnend mit der ersten Liste, die durch 'base' spezifiziert ist. Ich bin mir nicht sicher, ob Windows das für Sie machen würde, aber es besser auf der sicheren Seite zu stehen, als das Nachsehen zu haben :)

GLvoid KillFont(GLvoid)                        // Lösche die Font Liste
{
     glDeleteLists(base, 96);                // Lösche alle 96 Zeichen ( NEU )
}

Nun zur meiner kleinen handlichen GL Text Routine. Sie rufen diesen Codeabschnit mit dem Befehl glPrint("hier ihr Text") auf. Der Text ist in dem char String *fmt gespeichert.

GLvoid glPrint(const char *fmt, ...)                // eigene GL "Print" Routine
{

Die erste folgende Zeile erzeugt Speicherplatz für eine 256 lange Zeichenkette. text ist der String, den wir auf den Bildschirm bringen werden. Die zweite Zeile erzeugt einen Zeiger, der in die Liste der Argumente zeigt, die wir mit dem String übergeben. Wenn wir irgendwelche Variablen mit dem Text übergeben, wird dieser auf diese zeigen.

    char        text[256];                // enthält unseren String
    va_list        ap;                    // Zeiger in die Liste der Argumente

Die nächsten beiden Zeilen überprüfen, ob es etwas zum anzeigen gibt. Wenn es keinen Text gibt, ist fmt gleich nichts (NULL) und nichts wird auf dem Screen gezeichnet.

    if (fmt == NULL)                    // wenn kein Text vorhanden ist
        return;                        // mache nichts

Die folgenden drei Zeilen Code konvertieren jegliche Symbole aus dem Text in die eigentlichen Zahlen, die das Symbol repräsentiert. Der endgültige Text und alle konvertierten Symbole werden in dem String namens 'text' abgespeichert. Ich erkläre Symbole weiter unter noch detaillierter.

    va_start(ap, fmt);                    // Parse den String für Variablen
        vsprintf(text, fmt, ap);                // und konvertiere Symbole in Zahlen
    va_end(ap);                        // Ergebnisse werden in text gespeichert

Wir pushen dann GL_LIST_BIT, das verhindert, dass glListBase andere Display Listen, die wir vielleicht in unserem Programm verwenden, beeinflusst werden.

Der Befehl glListBase(base-32) ist etwas schwierig zu erklären. Sagen wir, wir zeichnen den Buchstaben 'A', der durch die Zahl 65 repräsentiert wird. Ohne glListBase(base-32) würde OpenGL diesen Buchstaben nicht finden. OpenGL würde in der 65ten Display Liste danach suchen, wenn aber base gleich 1000 wäre, wäre 'A' in der Display Liste 1065 gespeichert. Indem wir einen Basis Startpunkt setzen, weiß OpenGL wo die richtige Display Liste liegt. Der Grund warum wir 32 subtrahieren ist der, dass wir niemals Gebrauch von den ersten 32 Display Listen machen. Wir überspringen sie. Das müssen wir OpenGL wissen lassen und deshalb subtrahieren wir 32 vom Basis-Wert. Ich hoffe das macht Sinn.

    glPushAttrib(GL_LIST_BIT);                // Pusht die Display Listen Bits    ( NEU )
    glListBase(base - 32);                    // Setze den Anfangsbuchstaben auf 32    ( NEU )

Nun, da OpenGL weiß, wo sich die Buchstaben befinden, können wir OpenGL mitteilen, Text auf den Screen zu schreiben. glCallLists ist ein sehr interessanter Befehl. Er ermöglicht es, mehr als eine Display Liste auf einmal auf den Screen zu bringen.

Die Zeile macht folgendes: als erstes teilen wir OpenGL mit, dass wir Display Listen auf den Screen brignen. strlen(text) findet heraus, wieviele Buchstaben wir auf den Bildschirm bringen. Als nächstes müssen wir wissen, welches die größte Listennummer ist, die wir senden werden. Wir werden nicht mehr als 255 Buchstaben senden. Die Listen Parameter werden als ein Array von unsigned Bytes behandelt, jedes in einer Spanne von 0 bis 255. Letzendlich sagen wir noch, was wir angezeigt haben wollen, indem wir den Text übergeben (Zeiger auf unseren String).

Für den Fall das Sie sich wundern, warum die Buchstaben nicht zusammenstossen. Jede Display Liste für jeden Buchstaben weiß, wo die rechte Seite des Buchstaben ist. Nachdem der Buchstabe gezeichnet wurde, translatiert OpenGL zur rechten Seite des gezeichneten Buchstabens. Der nächste Buchstabe oder das nächste Objekte, dass gezeichnet wird, wird an dem Ort gezeichnet, zu dem OpenGL zu letzt translatiert hat, in diesem Falle also recht von dem zuletzt gezeichneten.

Letztendlich poppen wir GL_LIST_BIT setzen GL so zurück, wie es vorher war, bevor wir unsere Basis Einstellung mittels glListBase(base-32) setzen.

    glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);    // zeichnet den Display Listen Text    ( NEU )
    glPopAttrib();                        // Poppt die Display Listen Bits    ( NEU )
}

Die einzige Änderung im Init Code ist die Zeile BuildFont(). Diese ruft den obigen Code auf, um den Font zu erzeugen, so dass OpenGL ihn später verwenden kann.

int InitGL(GLvoid)                        // Der ganze Setup Kram für OpenGL kommt hier rein
{
    glShadeModel(GL_SMOOTH);                // aktiviert Smooth Shading
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);            // Schwarzer Hintergrund
    glClearDepth(1.0f);                    // Depth Buffer Setup
    glEnable(GL_DEPTH_TEST);                // aktiviert Depth Testing
    glDepthFunc(GL_LEQUAL);                    // Die Art des auszuführenden Depth Test
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);    // wirklich nette Perspektiven Berechnungen

    BuildFont();                        // erzeuge den Font

    return TRUE;                        // Initialisierung war OK
}

Nun zum Zeichnen-Code. Wir fangen mit dem löschen des Screens und des Depth Buffers an. Wir rufen glLoadIdentity() auf, um alles zu resetten. Dann gehen wir eine Einheit in den Screen hinein. Wenn wir uns nicht bewegen, wir der Text nicht angezeigt werden. Bitmap Fonts arbeiten besser, wenn Sie die Ortho Projektion anstatt der Perspektiven Projektion benutzen, aber Ortho sieht so schlecht aus, dass wir uns bewegen, um es in der Perspektiven Projektion zum laufen zu kriegen.

Sie werden bemerken, dass, wenn Sie sich tiefer in den Screen hineinbewegen, der Font nicht kleiner wird, so wie Sie es erwartet haben. Was tatsächlich passiert wenn Sie sich tiefer in den Screen bewegen, Sie haben mehr Kontrolle darüber, wo der Text auf dem Screen ist. Wenn Sie eine Einheit in den Screen hineingehen, können Sie den Text irgendwo zwischen -0.5 und +0.5 auf der X-Achse plazieren. Wenn Sie 10 Einheiten in den Screen hinein gehen, können Sie den Text irgendwo zwischen -5 und +5 plazieren. Es gibt Ihnen einfach mehr Kontrolle, anstatt Dezimalzahlen zur exakten positionierung des Textes zu verwenden. Nichts wird die Größe Ihres Textes ändern. Nicht einmal glScalef(x,y,z). Wenn Sie den Font größer oder kleiner haben wollen, machen Sie Ihn einfach größer oder kleiner, wenn Sie ihn erzeugen!

int DrawGLScene(GLvoid)                        // Hier kommt der ganze Zeichnen-Kram hin
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // Lösche den Bildschirm und den Depth-Buffer
    glLoadIdentity();                    // Resette die View
    glTranslatef(0.0f,0.0f,-1.0f);                // bewege eine Einheit in den Screen hinein

Nun benutzen wir etwas abgefahrene Mathematik, um die Farben pulsieren zu lassen. Machen Sie sich nichts draus, wenn Sie nicht verstehen, was ich hier mache. Ich möchte den Vorteil der vielen Variablen nutzen und mit einigen dummen Tricks ein paar Ergebnisse erreichen :)

In diesem Fall benutze ich die zwei Zähler, mit denen wir den Text über den Bildschirm bewegen, um die Rot, Grün und Blau Farben zu ändern. Rot wird von -1.0 bis 1.0 gehen und COS und Zähler 1 verwerden. Grün wird ebenfalls sich zwischen -1.0 und 1.0 bewegen und SIN und Zähler 2 verwenden. Blau wird von 0.5 bis 1.5 gehen und COS, Counter 1 und 2 verwenden. Auf diese Weise wird blau niemals gleich 0 sein und der Text sollte niemals ganz unsichtbar sein. Verrückt, aber es funktioniert :)

    // Pulsing Colors Based On Text Position
    glColor3f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)));

Nun zu einem neuen Befehl. glRasterPos2f(x,y) positioniert die Bitmap Fonts auf dem Screen. Das Mittelpunkt des Screens ist immer noch 0,0. Beachten Sie, dass es keine Z-Position gibt. Bitmap Fonts benutzen lediglich die X-Achse (links/rechts) und Y-Achse (hoch/runter). Da wir uns eine Einheit in den Bildschirm hineinbewegt haben, das weiteste links ist -0.5 und das weiteste rechts ist +0.5. Sie werden bemerken, dass ich mich 0.45 Pixel nach links auf der X-Achse bewege. Das bewegt den Text ins Zentrum des Screens. Ansonsten wäre er mehr rechts auf dem Screen, da der Text vom Mittelpunkt nach rechts gezeichnet werden würde.

Die verrückte(?) Mathematik macht so ziemlich das Selbe, wie bei der Setzung der Farben. Sie bewegt den Text auf der X-Achse von -0.50 bis -0.40 (erinnern Sie sich, wir subtrahieren 0.45 direkt am Anfangs). Dadurch bleibt der Text die ganze Zeit auf dem Screen. Er schwingt nach links und rechts, indem COS und Zähler 1 verwendet werden. Hier wird sich zwischen -0.35 und +0.35 auf der Y-Achse mittels SIN und Zähler 2 bewegt.

    // Positioniere den Text auf dem Bildschirm
    glRasterPos2f(-0.45f+0.05f*float(cos(cnt1)), 0.35f*float(sin(cnt2)));

Nun zu meinem Lieblinspart... Den eigentlich Text auf den Screen bringen. Ich habe versucht das super einfach und benutzerfreundlich zu halten. Sie werden bemerken, dass es wie ein OpenGL Befehl aussieht, kombiniert mit dem guten alten Print Statement :) Alles was Sie machen müssen, um Text auf den Screen zu bekommen ist glPrint ("{den Text den Sie wollen}"). So einfach ist das. Der Text wird genau an die Stelle gezeichnet, wo Sie ihn positioniert haben.

Shawn T. hat mir den modifizierten Code eingeschickt, der glPrint erlaubt, Variablen zu übergeben. Das bedeutet, dass Sie einen Zähler inkrementieren können und das Ergebnis auf dem Bildschirm anzeigen lassen können. Das funktioniert wir folgt... In der folgende Zeile sehen Sie unseren normalen Text. Dann kommt ein Leerzeichen, ein Spiegelstrich (-), ein Leerzeichen, dann ein "Symbol" (%7.2f). Nun schauen Sie vielleicht auf %7.2f und fragen sich, was zur Hölle soll das. Das ist sehr einfach. % ist wie eine Makierung, die sag, gebe 7.2f nicht auf dem Screen aus, da es eine Variable repräsentiert. Die 7 bedeutet die maximale Anzahl an Ziffern (also 7), die links vom Dezimalzeichen ausgegeben werden. Dann das Dezimalzeichen und rechts, neben dem Dezimalzeichen ist eine 2. Die 2 bedeutet, dass nur 2 Ziffern rechts nach dem Dezimalzeichen ausgegeben werden. Letztendlich das f. Das f bedeutet, dass die auszugebende Zahl ein Fließkommawert ist. Wir wollen den Wert von cnt1 auf dem Bildschirm ausgeben. Als ein Beispiel; wenn cnt1 gleich 300,12345f ist, würde auf dem Bildschirm 300,12 ausgegeben werden. Die 3, 4 und 5 nach dem Dezimalzeichen würden abgeschnitten werden, da wir nur 2 Ziffern nach dem Dezimalzeichen ausgegeben haben wollen.

Ich weiß, wenn Sie ein erfahrener C Programmierer sind, ist das absoult grundlegenden Stoff, aber es gibt so viele Leute da draußen, die noch nie printf verwendet haben. Wenn Sie mehr über Symbole lernen wollen, kaufen Sie sich ein Buch oder lesen Sie sich durch die MSDN.

     glPrint("Active OpenGL Text With NeHe - %7.2f", cnt1);    // gebe GL Text auf dem Screen aus

Nun müssen wir noch die beiden Counter um verschiedene Werte erhöhen, damit die Farbe pulsiert und der Text bewegt wird.

    cnt1+=0.051f;                        // erhöhe den ersten Counter
    cnt2+=0.005f;                        // erhöhe den zweiten Counter
    return TRUE;                        // alles war OK
}

Als letztes muss noch KillFont() am Ende unserer KillGLWindow() eingefügt werden, ungefähr so, wie ich es unten stehen habe. Es ist wichtig, diese Zeile einzufügen. Sie räumt noch etwas auf, bevor wir das Programm beenden.

    if (!UnregisterClass("OpenGL",hInstance))        // Können wir die Klasse de-registrieren?
    {
        MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hInstance=NULL;                    // Setze hInstance auf NULL
    }

    KillFont();                        // zerstöre Font
}

Das ist alles... Alles was Sie wissen müssen um Bitmap Fonts in Ihren eigenen OpenGL Projekten zu verwenden. Ich habe das Internet nach einem ähnlichen Tutorial durchsucht, aber nichts gefunden. Vielleicht ist meine Seite die erste, die dieses Thema in einfachen verstehbaren C-Code abdeckt? Wie dem auch sei. Geniesen Sie das Tutorial und happy coding!

Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code für diese Lektion.

* DOWNLOAD Borland C++ Builder 6 Code für diese Lektion. ( Conversion by Christian Kindahl )
* DOWNLOAD Code Warrior 5.3 Code für diese Lektion. ( Conversion by Scott Lupton )
* DOWNLOAD Delphi Code für diese Lektion. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code für diese Lektion. ( Conversion by Dan )
* DOWNLOAD Euphoria Code für diese Lektion. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code für diese Lektion. ( Conversion by Milikas Anastasios )
* DOWNLOAD Irix / GLUT Code für diese Lektion. ( Conversion by Rob Fletcher )
* DOWNLOAD Java Code für diese Lektion. ( Conversion by Jeff Kirby )
* DOWNLOAD JoGL Code für diese Lektion. ( Conversion by Nicholas Campbell )
* DOWNLOAD LCC Win32 Code für diese Lektion. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code für diese Lektion. ( Conversion by Richard Campbell )
* DOWNLOAD Linux/GLX Code für diese Lektion. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code für diese Lektion. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code für diese Lektion. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code für diese Lektion. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code für diese Lektion. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code für diese Lektion. ( Conversion by Andras Kobor )
* DOWNLOAD Pelles C Code für diese Lektion. ( Conversion by Pelle Orinius )
* DOWNLOAD Python Code für diese Lektion. ( Conversion by Brian Leair )
* DOWNLOAD Visual Basic Code für diese Lektion. ( Conversion by Ross Dawson )
* DOWNLOAD Visual Basic Code für diese Lektion. ( Conversion by Edo )
* DOWNLOAD Visual Studio .NET Code für diese Lektion. ( Conversion by Grant James )



Deutsche Übersetzung: Joachim Rohde
Der original Text ist hier zu finden.
Die original OpenGL Tutorials stammen von NeHe's Seite.