Lektion 15: 3D-Fonts mit Texturen
Hallo. In diesem fünfzehnten Tutorial wird es darum gehen, mit Hilfe des
im letzten Teil besprochenen codes und einer interssanten Funktion, die uns
die passenden Texturkoordinaten generiert, einen 3D-Font mit einer geladenen
Textur zu "überziehen".
Bei den includes bleibt fast alles beim alten, nur wird diesmal stdarg.h nicht
benötigt.
#include <windows.h> // Header File For Windows
#include <math.h> // Header File For Windows Math Library
#include <stdio.h> // Header File For Standard Input/Output
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library
HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
Wir brauchen einen Integer um die Texturspäter ansprechen zu können
GLuint texture[1]; // One Texture Map ( NEW )
GLuint base; // Base Display List For The Font Set
GLfloat rot; // Used To Rotate The Text
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// Declaration For WndProc
Im folgenden gibt es einige kleinere Änderungen. Es soll ein Totenkopf
mit gekreutzten Knochen (Wingdings, Buchstabe "N") ausgegeben werden.
Wingdings ist kein Standardfont, es muss also SYMBOL_CHARSET genutzt werden
(Alles andere würde nicht richtig funktionieren.).
GLvoid BuildFont(GLvoid) // Build Our Bitmap Font
{
GLYPHMETRICSFLOAT gmf[256]; // Address Buffer For Font Storage
HFONT font; // Windows Font ID
base = glGenLists(256); // Storage For 256 Characters
font = CreateFont( -12, // Height Of Font
0, // Width Of Font
0, // Angle Of Escapement
0, // Orientation Angle
FW_BOLD, // Font Weight
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout
SYMBOL_CHARSET, // Character Set Identifier ( Modified )
OUT_TT_PRECIS, // Output Precision
CLIP_DEFAULT_PRECIS, // Clipping Precision
ANTIALIASED_QUALITY, // Output Quality
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
Da wir die Schriftart als SYMBOL klassifiziert haben, läßt ich jetzt
guten Gewissens Wingdings auswählen.
"Wingdings"); // Font Name ( Modified )
SelectObject(hDC, font); // Selects The Font We Created
wglUseFontOutlines( hDC, // Select The Current DC
0, // Starting Character
255, // Number Of Display Lists To Build
base, // Starting Display Lists
Um Fehler zu vermeiden muss OpenGL eine leichte Abweichung von den Originaldaten
des Fonts erlaubt werden. 0.1f sieht aber immernoch sehr gut aus. Der Rest ändert
sich nicht.
0.1f, // Deviation From The True Outlines
0.2f, // Font Thickness In The Z Direction
WGL_FONT_POLYGONS, // Use Polygons, Not Lines
gmf); // Address Of Buffer To Recieve Data
}
Vor ReSizeGLScene() müssen noch die schon aus den vorhergehenden Tuts
bekannten Funktionen zum Laden der Textur übernommen werden.
Die textur heißt "lights.bmp" und wird in texture[0] geladen.
AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL
}
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
if (TextureImage[0]=LoadBMP("Data/Lights.bmp")) // Load The Bitmap
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(1, &texture[0]); // Create The Texture
// Build Linear Mipmapped Texture
glBindTexture(GL_TEXTURE_2D, texture[0]);
gluBuild2DMipmaps(GL_TEXTURE_2D,
3,
TextureImage[0]->sizeX,
TextureImage[0]->sizeY,
GL_RGB,
GL_UNSIGNED_BYTE,
TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
Die nächsten Zeilen generieren automatisch Texturkoordinaten für
Objekte die ausgegeben werden sollen. Das glTexGen-Kommando ist so komplex das
es den Rahmen dieses Tuts sprengen würde. Wichtig sind GL_S und GL_T, beide
Texturkoordinaten. Normalerweise enthalten sie die aus den aktuellen X- und
Y-Positionen generierten Texturkoordinaten.
GL_TEXTURE_GEN_MODE - Legt den Modus des Texturmappings fest, dabei gibt es
drei Möglichkeiten:
GL_EYE_LINEAR - Die Textur ist an den Hintergrund gebunden, bewegt sich also
nicht mit wenn sich das Objekt bewegt.
GL_OBJECT_LINEAR - Dieser Modus wird diesmal genutzt, die Textur ist auf dem
sich bewegenden Objekt fixiert.
GL_SPHERE_MAP - Ein interessanter Effekt, am besten selbst ausprobieren ;)
Mehr dazu gibt es in der MSDN.
// Texturing Contour Anchored To The Object
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
// Texturing Contour Anchored To The Object
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glEnable(GL_TEXTURE_GEN_S); // Auto Texture Generation
glEnable(GL_TEXTURE_GEN_T); // Auto Texture Generation
}
if (TextureImage[0]) // If Texture Exists
{
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status; // Return The Status
}
InitGL() ist um ein paar Zeichen reicher geworden. BuildFont() ist hinter
die Funktion zum Texturladen gerückt. glEnable(GL_COLOR_MATERIAL) fehlt
jetzt, sollte man später glColor3f(r,g,b) nutzen wollen, muss die Zeile
natürlich wieder eingefügt werden.
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
if (!LoadGLTextures()) // Jump To Texture Loading Routine
{
return FALSE; // If Texture Didn't Load Return FALSE
}
BuildFont(); // Build The Font
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glEnable(GL_LIGHT0); // Quick And Dirty Lighting (Assumes Light0 Is Set Up)
glEnable(GL_LIGHTING); // Enable Lighting
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// Really Nice Perspective Calculations
2D Texturmapping wird aktiviert und die Textur ausgwählt. Die Textur
wird von dort an auf jedes ausgegebene Objekt gemappt.
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select The Texture
return TRUE; // Initialization Went OK
}
DrawGLScene hat sich natülich auch noch ein wenig verändert.
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
Wieder wird das Objekt mithilfe des Cosinus und des Sinus bewegt.
// Position The Text
glTranslatef(1.1f*float(cos(rot/16.0f)),0.8f*float(sin(rot/20.0f)),-3.0f);
Jetzt die Rotation um die drei Achsen.
glRotatef(rot,1.0f,0.0f,0.0f); // Rotate On The X Axis
glRotatef(rot*1.2f,0.0f,1.0f,0.0f); // Rotate On The Y Axis
glRotatef(rot*1.4f,0.0f,0.0f,1.0f); // Rotate On The Z Axis
Das ganze muss in die Mitte gerückt werden:
glTranslatef(-0.35f,-0.35f,0.1f); // Center On X, Y, Z Axis
Und hier jetzt endlich die Ausgabe des N's (Dem Totenschädel in Wingdings.).
rot wird erhöht um das Objekt zu bewegen.
glPrint("N"); // Draw A Skull And Crossbones Symbol
rot+=0.1f; // Increase The Rotation Variable
return TRUE; // Keep Going
}
Und jetzt noch die Aufräumarbeiten am Ende von KillGLWindow():
if (!UnregisterClass("OpenGL",hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL; // Set hInstance To NULL
}
KillFont(); // Destroy The Font
}
Es sollte jetzt keine größeren Probleme mehr mit dem generieren von
Texturen geben und der Ausgabe von Fonts generell geben. Viel Spaß beim
coden:
nehe.
Die Source Codes und Ausführbaren Dateien zu den Kursen liegen auf der Neon
Helium Website
Übersetzt und leicht modifiziert von Hans-Jakob Schwer 10.09.2k2, www.codeworx.org