NeHe - Lektion 38 - Texturen aus Ressource-Dateien

Lektion 38



Willkommen zum 38. NeHe Productions Tutorial. Es ist schon eine Weile her, seit meinem letzten Tutorial, deswegen mag mein Schreibstil vielleicht etwas eingerostet wirken. Das, und die Tatsache, dass ich nun seit fast 24 Stunden wach bin und an dem Code gearbeitet habe :)

Nun wissen Sie wie man ein Quadrat texturiert und wie man Bitmap-Images lädt, tga's, etc. Aber wie zur Hölle texturiert man ein Dreieck. Und was macht man, wenn man die Texturen in der .EXE Datei verstecken will?

Zwei Fragen die ich täglich gefragt werde, werden jetzt bald beantwortet sein und wenn Sie einmal gesehen haben, wie einfach das ist, werden Sie sich selbst fragen, warum Sie nicht selbst drauf gekommen sind :)

Anstatt alles großartig im Detail zu erklären, habe ich ein paar Screenshots eingefügt, damit Sie genau wissen, worüber ich rede. Ich werde den aktuellsten Basecode verwenden. Sie können sich ihn von der Hauptseite unter "NeHeGL I Basecode" herunterladen oder den entsprechenden Code am Ende des Tutorials.

Als erstes müssen wir die Bilder zu unserer Ressource-Datei hinzufügen. Viele von Ihnen haben das schon herausgefunden, wie man das macht, haben dabei allerdings ein paar wichtige Schritte vergessen und herausgekommen ist eine nutzlose Ressource Datei gefüllt mit Bitmaps, die Sie nicht verwenden können.

Bedenken Sie, dass dieses Tutorial in Visual C++ 6.0 geschrieben wurde. Wenn Sie was anderes als Visual C++ verwenden, wird der Abschnitt über die Ressourcen (insbesonder die Screenshots) nicht sonderlich viel Sinn machen.

* Zur Zeit können Sie nur 24 Bit BMP Images verwenden. Es benötigt viel Extra-Code, um eine 8 Bit BMP Datei zu laden. Ich würde gerne von jemanden hören, der einen kleinen / optimierten BMP Loader hat. Den Code den ich zur Zeit habe, um 8 und 24 Bit BMP's zu laden, ist der letzte Dreck. Etwas, dass LoadImage benutzen würde, wäre nett.



Öffnen Sie das Projekt und klicken Sie EINFÜGEN (insert) im Haupt-Menp. Wenn das EINFÜGEN Menü geöffnet wurde, wählen Sie RESSOURCE.



Sie werden nun gefragt, welche Art von Ressource Sie importieren möchten. Wählen Sie BITMAP und klicken Sie auf den IMPORTIEREN (import) Button.



Ein Datei-Auswahl-Dialog öffnet sich. Öffnen Sie das DATA-Verzeichnis und markieren Sie alle drei Bilder (halten Sie die STRG Taste gedrückt, wenn Sie die Bilder auswählen). Wenn Sie erst einmal alle drei ausgewählt haben, klicken Sie auf den IMPORTIEREN Button. Wenn Sie keine Bitmap-Dateien sehen, stellen Sie sicher, dass DATEIART am unteren Rand auf ALLE DATEIEN (*.*) gestellt ist.



Eine Warnung wird dreimal angezeigt (für jedes zu importierende Bild einmal). Alles was diese Ihnen mitteilt ist, dass das Bild importiert werden konnte, das Bild aber nicht angezeigt oder bearbeitet werden kann, weil es mehr als 256 Farben hat. Nichts, worüber man sich einen Kopf machen muss!



Wenn alle drei Bilder importiert wurden, wird eine Liste angezeigt. Jedem Bitmap wurde eine ID zugewiesen. Jede ID beginnt mit IDB_BITMAP gefolgt von einer Zahl von 1 - 3. Wenn Sie faul sind, können Sie die ID's so lassen und zum Code springen. Glücklicherweise sind wir nicht faul!



Rechtsklick auf jede ID und Eigenschaften (properties) auswählen. Bennen Sie jede ID so um, dass Sie mit dem Namen der originalen Bitmap-Datei übereinstimmt. Schauen Sie sich das Bild an, wenn Sie sich nicht sicher sind, was ich meine.



Wenn Sie damit fertig sind, wählen Sie Datei (file) aus dem Hauptmenü und wählen Alles speichern (save all) aus, da Sie gerade eine neue Ressource-Datei erstellt haben. Windows wird Sie fragen, wie Sie die Datei nennen wollen. Sie können die Datei unter dem Standard-Dateinamen speichern oder in lesson38.rc umbennen. Wenn Sie sich für einen Namen entschieden haben, klicken Sie auf Speichern (save).

Bis hier hin sind die meisten Leute gekommen. Sie haben eine Ressource-Datei. Sie ist voll von Bitmap-Images und wurde auf der Festplatte gespeichert. Um die Bilder zu verwenden, benötigen Sie noch ein paar mehr Schritte.



Als nächstes müssen Sie die Ressource-Datei zu Ihrem aktuellen Projekt hinzufügen. Wählen Sie Projekt (project) aus dem Hauptmenü aus, 'Dem Projekt hinzufügen' (add to project) und dann 'Dateien' (files).



Wähle Sie die resource.h Datei und die Ressource Datei (Lesson38.rc). Halten Sie die STRG-Taste um mehr als eine Datei gleichzeitig zu markieren oder fügen Sie jede Datei einzeln hinzu.



Als letztes müssen Sie sicherstellen, dass die Ressource Datei (Lesson38.rc) in den Ressourcedateien (Resource files) Ordner gelandet ist. Wie Sie in dem obigen Bild sehen können, wurde Sie im Quellcodedateien (source files) Ordner abgelegt. Klicken Sie mit der Maus auf die Datei und ziehen Sie in den Ressourcedateien Ordner.

Wenn die Ressource-Datei dann verschoben wurde, wählen Sie im Menü DATEI den Punkt ALLE SPEICHERN aus. Der harte Teil ist geschafft! ... Einfach zu viele Bilder :)

So, nun können wir mit dem Code beginnen! Die wichtigste Zeile im folgenden Codeabschnitt ist #include "resource.h". Ohne diese Zeile werden Sie einen Haufen undeklarierter Identifizierer Fehler erhalten, wenn Sie versuchen, den Code zu kompilieren. Die resource.h Datei deklariert die Objekte in der Ressource-Datei. Wenn Sie also IDB_BUTTERFLY1 verwenden wollen, sollten Sie besser daran denken, die Header Datei zu inkludieren.

#include <windows.h>                                        // Header Datei für Windows
#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
#include "NeHeGL.h"                                        // Header Datei für NeHeGL
#include "resource.h"                                        // Header Datei für Ressource (*WICHTIG*)

#pragma comment( lib, "opengl32.lib" )                                // suche während des Linkens nach OpenGL32.lib
#pragma comment( lib, "glu32.lib" )                                // Suche nach GLu32.lib während des Linkes
#pragma comment( lib, "glaux.lib" )                                // Suche nach GLaux.lib während des Linkens

#ifndef CDS_FULLSCREEN                                        // CDS_FULLSCREEN ist bei einigen Compiler nicht
#define CDS_FULLSCREEN 4                                    // definiert. Indem wir hier es definieren, können
#endif                                                // wir Fehler vermeiden

GL_Window*    g_window;
Keys*        g_keys;

Die erste folgende Zeile macht Platz für drei Texturen, die wir erzeugen werden.

Die Struktur wird verwendet, um Informationen über 50 verschiedene Objekte zu speichern, die wir über den Bildschirm bewegen werden.

tex verfolgt, welche Textur für das Objekt verwendet wird. x ist die X Position des Objekts, y die Y Position des Objekts, z ist die Objekt-Position auf der Z-Achse, yi wird eine zufällige Zahl sein, die kontrolliert, wie schnell das Objekt rotiert. flap wird verwendet, um die Objekt-Flügel zu kontrollieren (dazu später mehr) und fi ist ein zufälliger Wert, der kontrolliert, wie schnell die Flügel schlagen.

Wir erzeugen 50 Instanzen von obj[] basierend auf der Objekt-Struktur.

// User Defined Variables
GLuint texture[3];                                        // Speicherplatz für 3 Texturen

struct object                                            // erzeuge eine Struktur namens Object
{
    int   tex;                                        // Integer um unsere Textur auszuwählen
    float x;                                        // X Position
    float y;                                        // Y Position
    float z;                                        // Z Position
    float yi;                                        // Y steigende Geschwindigkeit (Fallgeschwindigkeit)
    float spinz;                                        // Z Achsen Rotierung
    float spinzi;                                        // Z Achsen Rotationsgeschwindigkeit
    float flap;                                        // Flügelschlangende Dreiecke :)
    float fi;                                        // Flügelschlag Richtun (steigender Wert)
};

object obj[50];                                            // erzeuge 50 Objekte basierend auf der Object Struktur

Der folgende Codeteil weist dem Objekt (obj[]) loop zufällige Startwerte zu. loop kann jeder Wert zwischen 0 - 49 sein (eins von den 50 Objekten).

Wir fangen mit einer zufälligen Textur zwischen 0 und 2 an. Dadurch erhalten wir zufällig colorierte Schmetterlinge.

Wir weisen eine zufällige X-Position zwischen -17.0f und 17.0f zu. Die Startposition für Y wird 18.0f sein, was über unserem Screen sein wird, so dass wir sie nicht von anfang an sehen.

Die Z-Position ist ebenfalls ein zufälliger Wert zwischen -10.0f und -40.0f. Der spinzi Wert ist ein zufälliger Wert zwischen -1.0f und 1.0f. flap wird auf 0.0f gesetzt (was die Zentrumsposition für die Flügel ist).

Letztendlich werden der Flügelschlaggeschwindigketi (fi) und der Fallgeschwindigkeit (yi) ebenfalls zufällige Werte zugewiesen.

void SetObject(int loop)                                    // Setzt die Initialisierungswerte für jedes Objekt (zufällig)
{
    obj[loop].tex=rand()%3;                                    // Textur kann eine aus 3 Texturen sein
    obj[loop].x=rand()%34-17.0f;                                // zufälliger X-Wert zwischen -17.0f und 17.0f
    obj[loop].y=18.0f;                                    // Setze y Position auf 18 (oberhalb des Screen)
    obj[loop].z=-((rand()%30000/1000.0f)+10.0f);                        // z ist ein zufälliger Wert zwischen -10.0f und -40.0f
    obj[loop].spinzi=(rand()%10000)/5000.0f-1.0f;                        // spinzi ist ein zufälliger Wert zwischen -1.0f und 1.0f
    obj[loop].flap=0.0f;                                    // flap beginnt bei 0.0f;
    obj[loop].fi=0.05f+(rand()%100)/1000.0f;                        // fi ist ein zufälliger Wert zwischen 0.05f und 0.15f
    obj[loop].yi=0.001f+(rand()%1000)/10000.0f;                        // yi ist ein zufälliger Wert zwischen 0.001f und 0.101f
}

Nun zum spaßigen Teil! Ein Bitmap aus einer Ressource-Datei zu laden und in eine Textur zu konvertieren.

hBMP ist ein Zeiger auf unsere Bitmap-Datei. Er wird unserem Programm mitteilen, wo die Daten her kommen. BMP ist eine Bitmap-Struktur, die wir mit den Daten aus unserer Ressource-Datei füllen können.

Wir teilen unserem Programm mit, welche ID's in der dritten Codezeile verwendet werden soll. Wir wollen IDB_BUTTEFLY1, IDB_BUTTEFLY2 und IDB_BUTTERFLY3 laden. Wenn Sie mehr Bilder hinzufügen wollen, fügen Sie das Bild in die Ressource-Datei ein und fügen Sie die ID zu Texture[ ] hinzu.

void LoadGLTextures()                                        // erzeugt Texturen aus Bitmaps in der Ressource Datei
{
    HBITMAP hBMP;                                        // Handle des Bitmaps
    BITMAP    BMP;                                        // Bitmap Struktur

    // Die ID der 3 Bitmap Images die wir aus der Ressource-Datei laden wollen
    byte    Texture[]={ IDB_BUTTERFLY1, IDB_BUTTERFLY2, IDB_BUTTERFLY3 };

Die folgende Zeile benutzt sizeof(Texture) um herauszufinden, wie viele Texturen wir erstellen wollen. Wir haben 3 ID's in Texture[], weshalb der Wert 3 sein wird. sizeof(Texture) wird ebenfalls in der Hauptschleife verwendet.

    glGenTextures(sizeof(Texture), &texture[0]);                        // erzeuge 3 Texturen (sizeof(Texture)=3 ID's)
    for (int loop=0; loop<sizeof(Texture); loop++)                        // durchlaufe alle ID's (Bitmap Images)
    {

LoadImage werden folgende Parameter übergeben: GetModuleHandle(NULL) - Ein Handle der Instanz. MAKEINTRESOURCE(Texture[loop]) - konvertiert ein Integer Wert (Texture[loop]) in einen Ressource-Wert (das zu ladende Image). IMAGE_BITMAP - teilt unserem Programm mit, dass die zu ladende Ressource ein Bitmap Image ist.

Die nächsten beiden Parameter (0,0) ist die gewünschte Höhe und Breite des Bilds in Pixeln. Wir wollen die Standard-Größe benutzen, weshalb wir beide auf 0 setzen.

Der letzte Parameter (LR_CREATEDIBSECTION) gibt ein DIB Section Bitmap zurück, was ein Bitmap ohne Abspeicherung der Farbinformationen in den Daten ist. Genau das was wir brauchen.

hBMP zeigt auf die Bitmap-Daten, die mit LoadImage() geladen wurden.

        hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(Texture[loop]), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);

Als nächstes überprüfen wir, ob der Zeiger (hBMP) wirklich auf Daten zeigt. Wenn Sie wollen, können Sie eine Fehlerüberprüfung einbauen, hBMP überprüfen und eine Messagebox anzeigen, wenn keine Daten existieren.

Wenn Daten existieren, benutzen wir GetObject() um alle Daten (sizeof(BMP)) von hBMP zu erholen und sie in unserem BMP (Bitmap Struktur) zu speichern.

glPixelStorei teilt OpenGL mit, dass die Daten bei der Speicherung als Word ausgerichtet sind (4 Bytes pro Pixel).

Dann binden wir unsere Textur, setzen die Filterung auf GL_LINEAR_MIPMAP_LINEAR (nett und weich) und erzeugen die Textur.

Beachten Sie, dass wir BMP.bmWidth und BMP.bmHeight benutzen, um die Höhe und Breite des Bitmaps zu ermitteln. Wir müssen ebenfalls die Rot und Blau-Werte austauschen, da wir GL_BGR_EXT benutzen. Die eigentlichen Ressource-Daten kommen aus BMP.bmBits.

Der letzte Schritt ist das Löschen des Bitmap Objekts, um alle damit verbundenen System-Ressourcen freizugeben.

        if (hBMP)                                    // Existiert das Bitmap?
        {                                        // Falls ja...
            GetObject(hBMP,sizeof(BMP), &BMP);                    // hole das Objekt
                                                // hBMP: Handle des Graphics Objekt
                                                // sizeof(BMP): Größe des Buffers für die Objekt Informationen
                                                // Buffer für Objekt Informationen
            glPixelStorei(GL_UNPACK_ALIGNMENT,4);                    // Pixel Speicherungs Modus (Word Ausrichtung / 4 Bytes)
            glBindTexture(GL_TEXTURE_2D, texture[loop]);                // Binde unsere Textur
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);        // Lineares Filtering
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // Mipmap Linear Filtering

            // erzeuge Mipmapped Textur (3 Bytes, Breite, Höhe und Daten aus BMP)
            gluBuild2DMipmaps(GL_TEXTURE_2D, 3, BMP.bmWidth, BMP.bmHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
            DeleteObject(hBMP);                            // lösche das Bitmap Objekt
        }
    }
}

Nichts wirklich aufregendes im Init Code. Wir fügen LoadGLTexture() hinzu, um den obigen Code aufzurufen. Der Screen wird auf schwarz gelöscht. Depth Test wird deaktiviert (einfacher Weg zum blenden). Wir aktivieren Textur-Mapping und aktivieren dann Blending.

BOOL Initialize (GL_Window* window, Keys* keys)                            // Jeder GL Initialisierungs Code & Benutzer Initialisierung kommt hier hin
{
    g_window    = window;
    g_keys        = keys;

    // Start der Benutzer Initialsierung
    LoadGLTextures();                                    // Lade die Texturen  aus unserer Ressource-Datei

    glClearColor (0.0f, 0.0f, 0.0f, 0.5f);                            // schwarzer Hintergrund
    glClearDepth (1.0f);                                    // Depth Buffer Setup
    glDepthFunc (GL_LEQUAL);                                // Die Art des Depth Testing (kleiner oder gleich)
    glDisable(GL_DEPTH_TEST);                                // deaktiviere Depth Testing
    glShadeModel (GL_SMOOTH);                                // wähleSmooth Shading aus
    glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);                    // Setze Perspective Calculations To Most Accurate
    glEnable(GL_TEXTURE_2D);                                // Enable Texture Mapping
    glBlendFunc(GL_ONE,GL_SRC_ALPHA);                            // Setze Blending Mode (einfach / schnell)
    glEnable(GL_BLEND);                                    // aktiviere Blending

Wir müssen direkt am Anfang alle 50 Objekte initialisieren, so dass sie nicht alle in der Mitte des Screens oder alle am selben Ort erscheinen. Die folgende Schleife macht genau das.

    for (int loop=0; loop// durchlaufe alle 50 Objekte, um sie zu initialisieren
    {
        SetObject(loop);                                // RufeSetObject auf, um neue Zufallswerte zuzuweisen
    }

    return TRUE;                                        // gebeTRUE zurück (Initialisierung war erfolgreich)
}

void Deinitialize (void)                                    // Jede Benutzer DeInitialisation kommt hier hin
{
}

void Update (DWORD milliseconds)                                // führe hier die Bewegungsaktualisierung aus
{
    if (g_keys->keyDown [VK_ESCAPE] == TRUE)                        // wurde ESC gedrückt?
    {
        TerminateApplication (g_window);                        // beende das Programm
    }

    if (g_keys->keyDown [VK_F1] == TRUE)                            // Wurde F1 gedrückt?
    {
        ToggleFullscreen (g_window);                            // wechsel Fullscreen Modus
    }
}

Nun zum Zeichnen-Code. In diesem Abschnitt werde ich den einfachsten Weg erklären, um ein einzelnen Bild über zwei Dreiecke zu texturieren. Aus irgendwelchen Gründen scheint jeder zu denken, dass es fast unmöglich ist, ein Dreieck zu texturieren.

Die Wahrheit ist, dass Sie ein Bild auf jede Form texturieren können, die sie haben wollen. Mit nur sehr wenig Aufwand. Das Bild kann mit der Form übereinstimmen oder komplett anders aussehen. Es ist wirklich egal.

Das wichtige zuerst... wir löschen den Screen und rendern unsere 50 Schmetterlinge (Objekte) in einer Schleife.

void Draw (void)                                        // Zeichne die Szene
{
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                    // LöscheScreen und Depth Buffer

    for (int loop=0; loop// durchlaufe alle 50 (zeichne 50 Objekte)
    {

Wir rufen glLoadIdentity() auf, um unsere Modelview Matrix zu resetten. Dann wählen wir die Textur aus, die mit dem Objekt (obj[loop].tex) verbunden werden soll.

Wir positionieren den Schmetterling mittels glTranslatef() und rotieren den Schmetterling um 45 Grad auf seiner X-Achse. Das dreht den Schmetterling etwas mehr zum Betrachter hin, so dass es nicht wie ein flaches 2D Objekt aussieht.

Die letzte Rotation lässt den Schmetterling auf seiner Z-Achse rotieren, was ihn so rotieren lässt, als ob er den Screen hinunter fallen würde.

        glLoadIdentity ();                                // Resette die Modelview Matrix
        glBindTexture(GL_TEXTURE_2D, texture[obj[loop].tex]);                // Binde unsere Textur
        glTranslatef(obj[loop].x,obj[loop].y,obj[loop].z);                // Positioniere das Objekt
        glRotatef(45.0f,1.0f,0.0f,0.0f);                        // Rotiere auf der X-Achse
        glRotatef((obj[loop].spinz),0.0f,0.0f,1.0f);                    // Rotiere auf der Z-Achse

Ein Dreieck zu texturieren untescheidet sich nicht wesentlich von einem Dreieck. Bloß weil Sie nur 3 Vertices haben, bedeutet das nicht, dass Sie kein Quad auf Ihr Dreieck texturieren können. Der einzige Unterschied ist, dass Sie bei den Texturkoordinaten mehr aufpassen müssen

Im folgenden Code zeichnen wir aks erstes das Dreieck. Wir fangen in der oberen rechten Ecke eines unsichtbaren Quadrats an. Wir bewegen uns dann nach links, bis wir zur oberen linken Ecke komme. Von da aus, gehen wir zur unteren linken Ecke.

Der folgende Code wird folgendes Bild rendern:



Beachten Sie, dass die Hälfte des Schmetterlings auf das erste Dreieck gerendert wird. Die andere Hälfte wird auf's zweite Dreieck gerendert. Die Texturkoordinaten stimmen mit den Vertexkoordinaten überein und obwohl es nur 3 Texturkoordinaten gibt, gibt es genügend Informationen, um OpenGL mitzuteilen, welche Bilder auf die Dreiecke gemapped werden sollen.

        glBegin(GL_TRIANGLES);                                // Fange an Dreiecke zu zeichnen
            // Erstes Dreieck
            glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);            // Punkt1 (oben rechts)
            glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f, obj[loop].flap);    // Punkt2 (oben links)
            glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);            // Punkt3 (unten links)

Der folgende Code renderte die zweite Hälfte des Dreiecks. Selbe Technik wie eben, aber diesmal rendern wir von oben rechts nach unten links und dann rüber nach unten rechts.



Der zweite Punkt des ersten Dreiecks und der dritte Punkt des zweiten Dreiecks bewegen sich auf der Z-Achse vor und zurück, um die Illusion eines Flügelschlags zu erzeugen. Was wirklich passiert, ist, dass der Punkt von -1.0f bis 1.0f sich bewegt und zurück, was die beiden Dreiecke im Zentrum zusammenkommen lässt, da wo der Schmetterlingskörper ist.

Wenn Sie sich die zwei Bilder anschauen, werden Sie bemerken, dass die Punkt 2 und 3 die Spitzen der Flügel sind. Das erzeugt einen netten Flügelschlag Effekt mit minimalen Aufwand.

            // zweites Dreieck
            glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);            // Punkt1 (oben rechts)
            glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);            // Punkt2 (unten links)
            glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f,-1.0f, obj[loop].flap);    // Punkt3 (unten rechts)

        glEnd();                                    // Fertig mit Dreiecken zeichnen

Der folgende Codeteil bewegt den Schmetterling den Screen hinunter, indem obj[loop].yi von obj[loop].y subtrahiert wird. Der Schmetterling spinz Wert wird um spinzi (was ein negativer oder positiver Wert sein kann) erhöht und die flap wird um fi erhöht. fi kann ebenfalls eine negative oder positive Richtung haben, abhängig von der Richtung in die die Flügel schlagen sollen.

        obj[loop].y-=obj[loop].yi;                            // bewege Objekt den Screen hinunter
        obj[loop].spinz+=obj[loop].spinzi;                        // inkrementiere Z Rotation um spinzi
        obj[loop].flap+=obj[loop].fi;                            // Inkrementiere flap Wert um fi

Nachdem der Schmetterling den Bildschirm hinunter bewegt wurde, müssen wir schauen, ob er das untere Ende des Bildschirms schon passiert hat (nicht mehr sichtbar ist). Falls ja, rufen wir SetObject(loop) auf, um den Schmetterling mit einer neuen Textur, neuer Fallgeschwindigkeit, etc. zu verbinden.

        if (obj[loop].y// Ist Object nicht mehr auf dem Screen?
        {
            SetObject(loop);                            // Wenn ja, da weiße neue Werte zu
        }

Um die Flügel schlagen zu lassen überprüfen wir, ob der flap Wert größer oder kleiner als 1.0f und -1.0f ist. Wenn der Wert größer oder kleiner als diese Werte sind, ändern wir die Flügelschlagrichtung, indem wir fi=-fi setzen.

Wenn die Flügel also hochgehen und 1.0f erreichen, wird fi zu einem negativen Wert, was die Flügel wieder nach unten gehen lässt.

Sleep(15) wurde hinzugefügt, um das Programm um 15 Millisekunden zu verlangsamen. Das Programm lief unglaublich schnell auf dem Rechner eines Freundes und ich war zu faul den Code zu modifizieren und vom Timer gebrauch zu machen :)

        if ((obj[loop].flap>1.0f) || (obj[loop].flap// Ist es Zeit die Flügelschlag-Richtung zu ändern?
        {
            obj[loop].fi=-obj[loop].fi;                        // Ändere die Richtung, indem fi auf -fi gesetzt wird
        }
    }

    Sleep(15);                                        // erzeuge eine kurze Verzögerung (15 Millisekunden) 

    glFlush ();                                        // Flushe die GL Rendering Pipeline
}

Ich hoffe Sie haben das Tutorial genossen. Hoffentlich macht es das Laden von Texturen aus Ressourcen um ein vielfaches einfacher zu verstehen und Dreiecke zu texturieren zu einem Klacks. Ich habe dieses Tutorial nun 5 Mal durchgelesen und es sieht so aus, als ob es einfach genug ist, aber wenn Sie immer noch Probleme haben, lassen Sie es mich wissen! Wie immer will ich die Tutorials so gut wie möglich machen und Feedback ist ausdrücklich gewünscht.

Vielen Dank an Jeden für die großartige Unterstützung! Diese Seite wäre nichts ohne seine Besucher!!!

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 Warren Moore )
* DOWNLOAD Game GLUT Code For This Lesson. ( Conversion by Alexandre Ribeiro de Sá )
* DOWNLOAD LCC Win32 Code für diese Lektion. ( Conversion by Robert Wishlaw )
* DOWNLOAD Mac OS X/Cocoa Code für diese Lektion. ( Conversion by Bryan Blackburn )
* DOWNLOAD Visual Studio .NET Code für diese Lektion. ( Conversion by Grant James )


* DOWNLOAD Lesson 38 - Erweitert (Masking, Sorting, Keyboard - NeHe).
* DOWNLOAD Lesson 38 - Screensaver by Brian Hunsucker.




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