Buchempfehlung
MySQL kurz & gut
MySQL kurz & gut
Das preiswerte Taschen- buch stellt MySQL-rele- vante Inhalte systematisch und knapp dar, sodass es sich optimal zum Nach- schlagen beim Pro- grammieren eignet. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Tutorial

OpenGL und FreeBASIC - eine kleine Einführung - Teil 5 - Texturen

von MitgliedEastler_dartSeite 3 von 6

TEXTUREN IN EINEM UNTERPROGRAMM LADEN - VERWENDBAR

Na, hat Ihnen das Schnupperbeispiel gefallen?

Aber es hat ja den Haken, daß es nur mit der Datei "Mauer_128.bmp"
funktioniert, ansonsten nicht.
Das Beispiel war ja auch nur dazu gedacht, Ihnen die notwendigen
FreeBasic- und OpenGL-Funktionen mal näherzubringen, mit denen
man Texturen auf ein Objekt bringt.

Nun wollen wir das Erarbeitete in ein Unterprogramm packen, welchem
wir einfach den Dateinamen einer Bitmapdatei übergeben und den
Namen/Nummer der OpenGL-Textur zurückerhalten, mit dem wir diese
dann aktivieren können.

Aber ergänzenderweise muß ich sagen, daß ich solangsam Bedenken
habe, weil wir bisher immer ohne Fehlerauswertung gearbeitet haben.
Ohne diese wird zwar alles etwas übersichtlicher, aber nun arbeiten
wir mit Dateien, und da geht ganz schnell mal was schief.

Also wird diese SUB die Bitmap-Datei analysieren und prüfen,
ob sie überhaupt verwendbar ist. Falls nicht, müssen entsprechende
Fehlermeldungen raus und das Programm beendet werden.

eine Fehlerausgabe

Deshalb erstellen wir erst mal eine Sub für diese Fehlermeldungen,
in welcher die Meldungen auf dem Console-Fenster und auch in einer
Datei ausgegeben werden.

Das Ausgeben von Texten in dem Consolefenster kennen Sie ja bereits,
das zusätzliche Schreiben in eine Datei sollte Ihnen auch nicht
fremd sein. Also hier diese SUB:

SUB Schreibe(Text AS STRING)
   DIM AS INTEGER DateiNummer
   'AUF DEN MONITOR IN DIE TEXTCONSOLE
   DateiNummer=FREEFILE
   OPEN "CONS" FOR OUTPUT AS #DateiNummer
   PRINT #DateiNummer, Text
   CLOSE #DateiNummer
   'NOCHMAL IN EINE DATEI
   DateiNummer=FREEFILE
   OPEN "Protokoll.txt" FOR APPEND AS #DateiNummer
   PRINT #DateiNummer, DATE & " " & TIME & " " & Text
   CLOSE #DateiNummer
END SUB

Die Datei benennen wir "Protokoll.txt". Damit diese nicht bei
jedem Aufruf von Schreibe() gelöscht werden würde, öffnen wir
die Datei für "Append" = anhängen.
Damit wird diese Datei aber nie gelöscht, sodaß bei einem
Zweiten/Dritten/... Start unseres Programmes die Protokoll-
einträge immer noch unten dran geschrieben werden.
Um jetzt die Einträge zuordnen zu können, schreiben wir bei
jeder Ausgabe das Datum und die Uhrzeit vornedran.

Im DeclareBereich natürlich diese SUB auch declarieren

DECLARE SUB Schreibe(Text AS STRING)

So, nun können wir uns an das Unterprogramm für das Bildeinlesen
heranwagen. Nochmal, zur Veranschaulichung. Bei dieser Routine
soll es darum gehen, ein Bild auf der Festplatte an OpenGL zu
übergeben, sodaß man später mit diesem Bild Texturieren kann.
Dieser Vorgang sollte gleich nach dem Initialisieren von OpenGL
aufgerufen werden, sodaß das Bild im Speicher der Grafikkarte
steht.
Erst viel später werden dann Objekte erstellt, und ggf. diese
mit dem Bild texturiert, somit kommt das Texturieren selber
hier nicht rein.

Hier also "nur" das Kopieren des Bildes auf die Grafikkarte.
Im Grunde nehmen wir die selben Befehle wie zuvor, nur daß
wir nun die Datei prüfen, aus der Datei die Bildgröße holen,
sodaß wir nur den Namen der Datei an die Sub übergeben müssen.

von der Festplatte in den Arbeitsspeicher

Tja, hierbei kommt der größe neue Brocken auf uns zu.
Das Prüfen der übergebenen Datei, ob diese für Texturen
verwendbar ist.
1.Check: "ist die Datei überhaupt da?"
2.Check: "ist das überhaupt eine Bitmap-Datei?"
3.Check: "ist das Bild da drin auch wirklich UNKomprimiert?"
4.Check: "Ist die Größe des Bildes für Texturen verwendbar?"
-------- Da wir immer noch für sämtliche OpenGL-Versionen
-------- ab Version 1.0 schreiben, hab ich die Größen auf
-------- den für alle passenden Werte festgelegt:
-------- A) Bild muß quadratisch sein
-------- B) Die Kantenlängen dürfen
-------- 64Pixel, 128Pixel oder 256Pixel lang sein

Nur wenn alle Bedingungen erfüllt sind, kann jedes OpenGL
das Bild als Textur verwenden.

Oh Gott, was hat er denn nun vor? werden Sie denken, aber
es ist leichter, als es klingt.
In jeder Bitmapdatei stehen vor den eigentlichen Bilddaten
einige Infos drin, anhand derer wir das Ganze überprüfen
werden. Diese Infos sehen wie folgt aus:

Bitmapdatei Header-Aufschlüsselung

Position Inhalt VarTyp zum Einlesen:
01 bis 02Dateiformat immer "BM" für Bitmap 2 x UByte Als Chr()Wert
03 bis 06DateigroesseBytes (unzuverlässig) Integer
07 bis 10Null Integer
11 bis 14Position der Bilddaten (Pointerwert) Integer
15 bis 18Länge des Headers ab hier Integer
19 bis 22Bildbreite (Pixel) Integer
23 bis 26Bildhöhe (Pixel) Integer
27 bis 28Ebenenanzahl (sollte 1 sein) Short
29 bis 30Farbtiefe (Bits pro Pixel) Short
31 bis 34Kompressionsmethode (0=keine) Integer
35 bis 38Datenmenge ohne Header Integer
39 bis 42horizontale Auflösung (Pixel/Meter) Integer
43 bis 46vertikale Auflösung (Pixel/Meter) Integer
47 bis 50Anzahl benutzter Farben (bei 1/2/4 oder 8-bit) Integer
51 bis 54Anzahl wichtiger Farben (bei 1/2/4 oder 8-bit) Integer

Die Positionen gelten für das Einlesen per GET#, das Erste Byte ist dort Nr 1 (nicht 0)
ANMERKUNG ZUR Bildhoehe: Wenn der Wert Negativ ist, ist das Bild in der Datei vertikal gespiegelt!


hier finden wir also alles, was wir brauchen.

Also basteln wir das erste Stück, das Überprüfen der Datei:

Nun hoffe ich, daß Sie mit dem Umgang von FreeBasic vertraut
sind, daß Sie IF-THEN und deren Verschachtelung verstehen.

Denn wir packen die oben genannte 4 Checks in vierfach
verschachtelte IF-THEN-Prüfungen, wobei wir immer auf Falsch
prüfen, ggf. das Programm mit Fehlermeldung beenden, Falls nicht
falsch(ELSE), machen wir da drin weiter.
Bedeutet schlichtweg, wenn der Programmablauf durch alle
vier IF-THENs durchläuft, und das Programm sich nicht
beendet, weil eine Bedingung nicht paßt, dann hat die
übergebenen Datei volle Gültigkeit, deshalb wird in der
vierten IF-Bedingung bei ELSE gleich der RAM per ImageCreate
reserviert und die Datei per BLOAD dort rein kopiert.

Die Routine also als Function dimmen, damit wir Werte an
den aufrufenden Befehl zurückgeben können.
Die Funktion nennen wir mal BmpToOgl.
Als Erstes brauchen wir dann ein paar Variablen:

FUNCTION BmpToOgl(BmpName AS STRING) AS INTEGER
   DIM AS BYTE PTR DateiImRamPtr, SpBmpPixelZeiger
   DIM AS INTEGER DateiNummer, Ganzzahl, Breite, Hoehe
   DIM AS UINTEGER TexturNummer, RotWert, BlauWert, ZeilenZaehler, PunktZaehler
   DIM AS UBYTE Buchstabe
   DIM AS STRING Dummy

Danach können wir gleich mit dem Datei-Check beginnen:

   DateiNummer = FREEFILE
   OPEN BmpName FOR INPUT AS #DateiNummer
   IF LOF(DateiNummer) = 0 THEN
      'BildDatei Existiert nicht, die Datei hat eine Länge von NULL
      Schreibe("Die Bilddatei " & BmpName & " ist nicht vorhanden oder hat Laenge 0! breche ab")
      CLOSE #DateiNummer
      END
   ELSE
      'BildDatei ist vorhanden, String aus den ersten zwei Bytes in der Datei basteln
      GET #DateiNummer, 1, Buchstabe
      Dummy=CHR(Buchstabe)
      GET #DateiNummer, 2, Buchstabe
      Dummy = Dummy + CHR(Buchstabe)
      IF Dummy <> "BM" THEN
         'keine Bitmap-Datei
         Schreibe("Die Bilddatei " & BmpName & " ist keine Bitmapdatei! Kennung=" & Dummy & " breche ab")
         CLOSE #DateiNummer
         END
      ELSE
         'Datei ist Bitmap, prüfen ob komprimiert
         GET #DateiNummer, 31, Ganzzahl
         IF Ganzzahl <> 0 THEN
            'Bitampdatei ist komprimiert
            Schreibe("Die Bilddatei " & BmpName & " ist komprimiert gespeichert, kann damit nicht umgehen, breche ab!")
            CLOSE #DateiNummer
            END
         ELSE
            'unkomprimierte Bitmap-Datei, prüfen ob quadratisch und 64/128/256 bytes kantenlänge
            GET #DateiNummer, 19, Breite
            GET #DateiNummer, 23, Hoehe
            IF (Breite <> Hoehe) OR (Breite <> 64 AND Breite <> 128 AND Breite <> 256) THEN
               'Bild ist entweder nicht quadratisch oder nicht 64/128/256er Kantenlängen
               Schreibe("Die Bilddatei " & BmpName & " ist entweder nicht Quadratisch oder hat keine Kantenlänge von 64, 128 oder 256 Pixel")
               Schreibe("       Breite:" & Breite & " Hoehe:" & Hoehe & "   breche ab!")
               CLOSE #DateiNummer
               END
            ELSE
               '***************************************
               'Bilddatei ist OK, kann verwendet werden
               '***************************************
               CLOSE #DateiNummer
               DateiImRamPtr = IMAGECREATE(Breite, Hoehe, 0, 32)
               BLOAD(BmpName, DateiImRamPtr)
            END IF
         END IF
      END IF
   END IF

So, wenn das alles durch ist, das Programm nicht abgebrochen hat,
dann haben wir nun in DateiImRamPtr den Zeiger auf das Bild
im Arbeitsspeicher, das Bild ist bereits dahin kopiert.

Farben Rot und Blau tauschen

Genauso, wie im ersten Beispiel, setzen wir nun gleich die
vertauschten Rot- und Blau-Werte richtig:

   SpBmpPixelZeiger = DateiImRamPtr + Len(FB.IMAGE)
   FOR ZeilenZaehler = 0 TO Hoehe-1
      FOR PunktZaehler = 0 TO Breite-1
         BlauWert = SpBmpPixelZeiger[0]        :'aus Ram das Byte mit dem Blauwert des grad zu bearbeitenden Pixels holen
         RotWert  = SpBmpPixelZeiger[2]        :'aus Ram das Byte mit dem Rotwert des grad zu bearbeitenden Pixels holen
         SpBmpPixelZeiger[0] = RotWert         :'den Rotwert an die Stelle des Blauwertes im RAM schreiben
         SpBmpPixelZeiger[2] = BlauWert        :'den Blauwert an die Stelle des Rotwertes im RAM schreiben
         SpBmpPixelZeiger = SpBmpPixelZeiger+4 :'Ram-Adresse um 4 bytes erhöhen = Start Pixeldaten des nächsten Pixels
      NEXT PunktZaehler
   NEXT ZeilenZaehler

Auch hier wieder, wir nehmen (noch) keine Rücksicht darauf,
das unser Bild nun senkrecht gespiegelt ist, damit uns ein
einziges ImageCreate ausreicht


Nun kommt nochmal etwas Neues dazu. Am Anfang hatten wir doch
festgestellt, daß "neuere" Grafikkarten viel schneller arbeiten,
wenn die Bilddaten mit 32-bit im Speicher stehen.
Aber feststellen, ob die Karte nun schnell oder alt ist, läßt
sich nicht zuverlässig.
Nun hab ich dazu eine andere Überlegung. Wenn ich ein OpenGL
- Programm erstelle, liste ich dem Anwender gerne die Möglich-
keiten seiner Grafikkarte auf und er soll auswählen, mit
welcher Auflösung er das Programm laufen lassen will.
Und genau da häng ich mich dann: Wenn er eine ältere Karte
hat, wird er wohl kaum auf 32-bit Farbtiefe schalten, hat er
eine neuere, klickt er freudig auf "bitte 32-bit einstellen".
Also prüfen wir hier einfach, mit welcher Farbtiefe das
OpenGL-Fenster grad läuft.
Bei 32-bittigem OpenGL-Fenster legen wir das Texturbild
ebenfalls mit 32-bit Farbtiefe auf der Grafikkarte ab (GL_RGBA)
ansonsten halt mit 24- oder 16-bit (GL_RGB, ob 16 oder 24
zu nehmen ist, regelt OpenGL automatisch).
Jedenfalls müssen wir eine Variable anlegen, in der wir
die Farbtiefe des OpenGL-Fensters speichern und mit dem
FreeBasic-Befehl SCREENCONTROL die Farbtiefe in der Variablen
ablegen:

Auf Grafikkarte kopieren lassen

   DIM AS INTEGER FensterFarbTiefe
   SCREENCONTROL 5, FensterFarbTiefe :' 5 = GET_SCREEN_DEPTH : Farbtiefe in Bits des OpenGL-Fensters ermitteln

Nun wieder wie gehabt, für ein neues Texturbild einen Eintrag
erstellen lassen, sich den Namen(Nummer) der Textur geben
lassen:

   glGenTextures 1, @TexturNummer
   glBindTexture GL_TEXTURE_2D, TexturNummer

und je nachdem, was in FensterFarbTiefe drin steht, das
Bild im Ram auf die Grafikkarte abholen lassen:

   IF FensterFarbTiefe = 32 THEN
      glTexImage2D GL_TEXTURE_2D, 0, GL_RGBA, Breite, Hoehe, 0, GL_RGBA, GL_UNSIGNED_BYTE, DateiImRamPtr+Len(FB.IMAGE)
   ELSE
      glTexImage2D GL_TEXTURE_2D, 0, GL_RGB, Breite, Hoehe, 0, GL_RGBA, GL_UNSIGNED_BYTE, DateiImRamPtr+Len(FB.IMAGE)
   END IF

Die Parameter für das Texturieren bei nah dran und weit weg
einstellen:

   glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
   glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR

Nachdem nun das Bild auf der Grafikkarte steht, können
wir das Bild im Arbeitsspeicher wieder löschen und den
Speicher wieder freigeben:

   ImageDestroy(DateiImRamPtr)

Da wir unsere Einleseroutine als Function angelegt haben,
sorgen wir nun noch dafür, daß der Name(Nummer) der
Textur an den aufrufenden Befehl zurückgegeben wird:

   BmpToOgl=TexturNummer
END FUNCTION

Eine Zweite Textur

Ja, Sie lesen richtig, da wir die Funktionen für das Bild
von Festplatte bis zur Grafikkarte kopieren in eine
Function ausgelagert haben, können wir diese ja auch
mehrfach aufrufen. So wie die Function angelegt ist,
stört sie sich nicht daran, mehrmals laufen zu müssen.
Das Einzigste, was wir brauchen, ist eine zweite INTEGER
Variable, damit wir den Namen(Nummer) der zweiten
Textur auch speichern können:

DIM AS UINTEGER TexturNummer, TexturZwei :'Texturnummer war ja schon, TexturZwei ist für die zweite Textur

Jetzt sollten wir aber auch ein anderes Bild haben,
zweimal das Gleiche wär ja langweilig.
Ist zwar irgendwie verrückt, aber ich hab eins mit
Kirschen, das gefällt mir irgendwie und ist lustig:
Kirschen_256.bmp
Die Datei hat den Namen Kirschen_256. Sie merken bestimmt,
dieses Bild ist größer, hat eine Seitenlänge von 256 Pixel.

Klicken Sie das Bild mit der rechten Maustaste an und
wählen Sie "Speichern unter".
Speichern Sie die Datei dorthin, wo bereits Mauer_128.bmp steht,
also in das Verzeichnis, wo auch das kompilierte, ausführbare
Programm stehen wird.

Nachdem das Bild nun an der richtigen Stelle auf der Festplatte
gespeichert ist, können wir es als Textur an OpenGL übergeben.
Mit unserer Function ist das ein Leichtes, einfach Aufrufen,
als Parameter nun "Kirschen_256.bmp" übergeben, und die Rückgabe
der Function (Texturname/nummer) in der Variablen TexturZwei
speichern:

TexturZwei   =  BmpToOgl("Kirschen_256.bmp")   ' eine zweite Bitmapdatei als Textur an OpenGL schicken

Schwupps, das wars schon. Nun können wir bereits die Kirschen
als Textur einsetzen - aber wo?

Klar doch, jetzt gehts an die Pyramiden ;-)
Dabei müssen wir nur beachten, daß wir die beiden Pyramiden
mit einer einzigen Routine erstellen, bei der wir direkt
davor per glTranslatef die Position, an der zu erstellen ist,
ändern.
Das bedeutet, wenn wir direkt in der Pyramidensub das verwenden
der Textur reinschreiben, haben beide Pyramiden die gleiche
Textur.
Soll heißen: In der SUB schreiben wir nur die TexturKoordinaten
vor die 3D-Punkte, das aktivieren eines Bildes als Textur machen
wir schon im Hauptprogramm, somit können wir erst die Mauertextur
aktivieren, eine Pyramide erstellen, dann die Kirschentextur
aktivieren und die zweite Pyramide erstellen.

den Pyramiden Texturkoordinaten geben

Also gehen wir in die PyramidenSUB. Dort stehen im Kern dann
die Beschreibungslisten des Quadrates als Boden und der
vier Dreiecke als Seitenflächen.
Fangen wir mit dem Boden an, ein Texturbild auf ein Quadrat,
das hatten wir ja schon.
Einfach direkt vor jede Punktdeffinition(glVertex3f) die
Punktangabe auf dem TexturBild setzen. Damit der Zusammenhang
deutlich zu sehen ist, schreiben wir die Texturpunktdeffinition
und den 3D-Punkt(Vertex) in eine Zeile, wie wir wissen, müssen
wir mehrere FreeBasic-Befehle in einer Zeile mit Doppelpunkt
voneinander trennen.
Für das Bestimmen, ob die Ecke des Quads nun links/oben oder
rechts/oben usw ist, müssen Sie sich grundsätzlich daran
halten, von "außen" auf das Objekt schauen.
Das ist bei unserem Pyramidenboden in der 3D-Welt von unten
nach oben schauen. Und in der Sichtweise arbeiten wir dann
GEGEN den Uhrzeigersinn.
Hier der Auszug der Deffinition Pyramidenboden=QUAD:

         glBegin GL_QUADS
            glColor3f  Farbe5Rot, Farbe5Gruen, Farbe5Blau :'falls Texturieren Disabled ist, wird diese Farbe genommen
            glTexCoord2d 0.0, 1.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'Ecke links oben
            glTexCoord2d 0.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'Ecke links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'Ecke rechts unten
            glTexCoord2d 1.0, 1.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'Ecke rechts oben
         glEnd

Und nun die Dreiecke der Seitenflächen, man beachte hier,
daß wir nun vier weitere Objekte haben, und auf diese
genauso wie auf dem Quad des Bodens das selbe Texturbild
kleben. Also ein Bild für viele Objekte, kein Problem.

Jedoch der Übersichtlichkeit hier nochmal eine Skizze,
wie wir auf dem Texturbild die TexturKoordinaten bei
Dreiecken setzen:
Ogl_tut_5_Texturkoordinaten_fuer_Dreieck
Sie sehen, wir schneiden aus dem Bild per Texturkoordinaten
einfach eine passende Fläche aus. Genau wegen solchen
Fällen gibt es diese Texturkoordinaten, egal ob Sterne,
Dreiecke, oder sonstige unförmige Objekte, jeden Punkt
des Objekt als Punkt auf dem Texturbild so passend
deffinieren, daß eine passende Form ausgeschnitten wird,
schon paßts.

Also gehen wirs an, die vier Dreiecke sind in unserer
Sub jedes für sich deffiniert, also bei allen vier
die Texturkoordinaten davor setzen. Auch hier wieder
von außen auf das Objekt schauend, gegen den Uhrzeigersinn
die Punktreihenfolgen wählen.
Auszug der Dreiecke:

         glBegin GL_TRIANGLES
            '   Dreieckseite 1 = linke Seite
            glColor3f  Farbe1Rot, Farbe1Gruen, Farbe1Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0       , 0-(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0       , 0+(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.1, 1.0 : glVertex3f 0                , YLaenge , 0             :'Spitze oben
            '   Dreieckseite 2 = hintere Seite /Rückseite
            glColor3f  Farbe2Rot, Farbe2Gruen, Farbe2Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.5, 1.0 : glVertex3f 0                , YLaenge , 0        :'Spitze oben mitte
            '   Dreieckseite 3 = rechte Seite
            glColor3f  Farbe3Rot, Farbe3Gruen, Farbe3Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.5, 1.0 : glVertex3f 0                , YLaenge , 0        :'Spitze oben mitte
            '   Dreieckseite 4 = Vorderseite
            glColor3f  Farbe4Rot, Farbe4Gruen, Farbe4Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.5, 1.0 : glVertex3f 0                , YLaenge , 0        :'Spitze oben mitte
         glEnd

Das wars schon, jedem 3D-Punkt der Pyramidenteile
ist nun ein Punkt auf der Textur zugeordnet - fertig.

Jetzt müssen wir nur noch ins Hauptprogramm,
genauer gesagt, in die Schleife, wo die Pyramiden
aufgerufen werden, und dort jeweils das Texturieren
erlauben und ein Bild auf der Grafikkarte als Textur
festlegen.
Da wir beide Pyramiden direkt hintereinander aufrufen,
Schalten wir vor der ersten das Texturieren ein, und
nach der Zweiten dann erst wieder aus.
Da wir verschiedene Bilder für die beiden Pyramiden
zum Texturieren verwenden, müssen wir natürlich
direkt vor dem Aufruf der Pyramidensub jeweils
ein Bild aktivieren (klar, einmal Mauer, einmal Kirsche).

    Koordinatensystem("Anzeigen", "", 0, 0, 0) :' den Stringwert "Anzeigen" übergeben
    Schachbrettboden("BeschreibungsListeBoden", "", 0, 0, 0):' SchachbrettBoden in der 3D-Welt erstellen
    glPushMatrix                                                             :'akt.Position und Drehgrade sichern
    glEnable GL_TEXTURE_2D                    :'***********Texturieren erlauben*************
    glBindTexture GL_TEXTURE_2D, TexturNummer :'***********das erste Bild(mauer) als Textur aktivieren*************
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'die erste Pyramide
    glPopMatrix                                                              :'auf gesichterte Position und Drehgrade zurücksetzen
    glPushMatrix                                                             :'akt.Position und Drehgrade sichern
    glTranslatef -2, 0, 0                                                    :'hier der Verschiebebefehl, damit die 2.Pyramide woanderst steht
    glBindTexture GL_TEXTURE_2D, TexturZwei   :'***********das zweite Bild(Kirschen) als Textur aktivieren*************
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'und eine zweite Pyramide
    glPopMatrix                                                              :'auf gesichterte Position und Drehgrade zurücksetzen
    glDisable GL_TEXTURE_2D                    :'***********Texturieren wieder ausschalten*************

So, das hätten wir nun soweit, alle Codeschnippsel haben
wir besprochen. Wenn wir die nun alle in das Beispiel-
listing aus Tutorial 4 an den richtigen Stellen
einbauen, entsteht ein Programm, welches nach einigem
rumirren in unserer kleinen 3D-Welt folgendes Bild
anzeigt:
Ogl_tut_5_zwei_pyra_zwei_texturen
und wie gewohnt, hier zum Ende der Seite das komplette,
funktionsfähige Listing, mit allem was hier besprochen wurde:

'REM Tutorial 4 - OpenGL-Tutorial von Eastler
'-------------------------
'DIMs
'-------------------------
DIM SHARED AS STRING Tastendruck
DIM SHARED AS STRING Tlinks, Trechts, Tvor, Tzurueck, TCtrlVor, TCtrlZurueck, TCtrlLinks, TCtrlRechts
Tlinks       = CHR(255) & CHR( 75)  :' beim Drücken der Taste CursorLinks gibt die Tastatur CHR(255) & CHR( 75) zurück
Trechts      = CHR(255) & CHR( 77)  :' CursorRechts
Tvor         = CHR(255) & CHR( 72)  :' CursorHoch
Tzurueck     = CHR(255) & CHR( 80)  :' CursorRunter
TCtrlVor     = CHR(255) & CHR(141)  :'Ctrl oder STRG zusammen mit CursorHoch
TCtrlZurueck = CHR(255) & CHR(145)  :'Ctrl oder STRG zusammen mit CursorRunter
TCtrlLinks   = CHR(255) & CHR(115)  :'<--------CURSOR NACH LINKS-Variable mit Wert belegen
TCtrlRechts  = CHR(255) & CHR(116)  :'<--------CURSOR NACH RECHTS-Variable mit Wert belegenDIM AS SINGLE XRichtg, YRichtg, ZRichtg
DIM AS SINGLE XRichtg, YRichtg, ZRichtg
DIM AS SINGLE PyraXDrehw, PyraYDrehw, PyraZDrehw :'<------------------------ für Pyramide per Tasten drehen
DIM AS SINGLE WeltDrehX, WeltDrehY, WeltDrehZ
DIM AS INTEGER ConNr                :' Dateinummerspeicher beim Consolefenster öffnen
DIM AS UINTEGER TexturNummer, TexturZwei
DIM SHARED AS DOUBLE Pi
Pi = 3.14159265358979323846
'-------------------------
'Includes
'-------------------------
#include "fbgfx.bi"
#include once "GL/gl.bi"
#include once "GL/glu.bi"
#include once "vbcompat.bi" '<--------------um Zahlen per "format()" formatieren zu können

'-------------------------
'Declarationen
'-------------------------
DECLARE SUB Koordinatensystem(was AS STRING, TxtPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
DECLARE SUB Schachbrettboden(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
DECLARE SUB Pyramide (was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
DECLARE FUNCTION BmpToOgl(BmpName AS STRING) AS INTEGER
DECLARE SUB Schreibe(Text AS STRING)
'-------------------------
' das Fenster öffnen
'-------------------------
screen 19, 32, , 2

'-------------------------
' Open-GL Init
'-------------------------
glViewport 0, 0, 800, 600                      ' den Current Viewport auf eine Ausgangsposition setzen
glMatrixMode GL_PROJECTION                     ' Den Matrix-Modus Projection wählen
glLoadIdentity                                 ' Diesen Modus auf Anfangswerte setzen
gluPerspective 45.0, 800.0/600.0, 0.1, 100.0   ' Grundeinstellungen des Anezeigefensters festlegen
glMatrixMode GL_MODELVIEW                      ' Auf den Matrix-Modus Modelview schalten
glLoadIdentity                                 ' und auch diesen auf Anfangswerte setzen
'TexturNummer = BmpToOgl("Mauer_128.bmp")                      ' Bitmapdatei als Textur an OpenGL schicken
TexturNummer = BmpToOgl("Mauer_128.bmp")       ' Bitmapdatei als Textur an OpenGL schicken
TexturZwei   =  BmpToOgl("Kirschen_256.bmp")   ' eine zweite Bitmapdatei als Textur an OpenGL schicken
glClearColor 0.5, 0.5, 0.50, 0.0               ' Setze Farbe für löschen auf Mittelgrau
glClearDepth 1.0                               ' Depth-Buffer Löschen erlauben
glEnable GL_DEPTH_TEST                         ' den Tiefentest GL_DEPTH_TEST einschalten
glClear GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT  'Tiefen- und Farbpufferbits löschen
'---------------------------
'HAUPTTEIL
'---------------------------
Schachbrettboden("SetzKantenLaenge", "", 0.5,  0,    0)
Schachbrettboden("SetzQuadsZahl",    "", 24,   24,   0)     :'6 Einheiten +und- = 12Einheiten Koordiantensystem, bei 0.5 Quadgröße 24 Stück
Schachbrettboden("SetzFarbe1",       "", 0,    0,    0.5)   :'erste Farbe dunkleres blau
Schachbrettboden("SetzFarbe2",       "", 0.25, 0.25, 0.25)  :'erste Farbe dunkles grau
Schachbrettboden("SetzStartPos",     "", -6,   -6,   -1)     :'ganz vorne ganz links beginnen, Boden auf Hoehe(3.Para)-1 verlegen(Y)

Pyramide("SetzLaengen" , "", 1, 1,  1)
Pyramide("SetzFarbe1"  , "", 1, 0, 0)
Pyramide("SetzFarbe2"  , "", 0, 1, 0)
Pyramide("SetzFarbe3"  , "", 0, 0, 1)
Pyramide("SetzFarbe4"  , "", 1, 1, 0)
Pyramide("SetzFarbe5"  , "", 1, 0, 1)

DO UNTIL Tastendruck = CHR(27)                         :'die Schleife solange immer wiederholen, bis in der Variablen Tastendruck die Esc-Taste (chr(27) steht
   Tastendruck = INKEY                                 :'Jeder Tastendruck wird sofort in die Variable Tastendruck gespeichert
   '---------------------------
   'ProgrammSchleife
   '---------------------------

   'JE NACH TASTENDRUCK DEN ENTSPRECHENDEN POSITIONSWERT VERÄNDERN
   SELECT CASE Tastendruck
      CASE "K", "K"
         Koordinatensystem("AnAus", "", 0, 0, 0) :' Schalter umstellen, falls An ist, auf Aus, sonst auf An
      CASE TCtrlrechts                :'Falls die Tasten "Cursor nach rechts" zuammen mit Strg- bzw. Ctrl gedrückt wurde
         XRichtg = XRichtg - COS((WeltDrehY * Pi) / 180) * 0.04 :' Den X-Pos-Wert anpassen
         ZRichtg = ZRichtg - SIN((WeltDrehY * Pi) / 180) * 0.04 :' Den Y-Pos-Wert anpassen
      CASE TCtrllinks                 :'Falls die Tasten "Cursor nach rechts" zuammen mit Strg- bzw. Ctrl gedrückt wurde
         XRichtg = XRichtg + COS((WeltDrehY * Pi) / 180) * 0.04 :' Den X-Pos-Wert anpassen
         ZRichtg = ZRichtg + SIN((WeltDrehY * Pi) / 180) * 0.04 :' Den Y-Pos-Wert anpassen
      CASE TCtrlzurueck               :'Falls die Tasten "Cursor unten" zuammen mit Strg- bzw. Ctrl gedrückt wurde
         YRichtg = YRichtg + 0.04 :'HOCH und Runter bleibt unberührt von der Y-Drehung
      CASE TCtrlvor                   :'Falls die Tasten "Cursor hoch" zuammen mit Strg- bzw. Ctrl gedrückt wurde
         YRichtg = YRichtg - 0.04 :'HOCH und Runter bleibt unberührt von der Y-Drehung
      CASE TZurueck                   :'Falls die Taste "Cursor runter" gedrückt wurde
         XRichtg = XRichtg + COS((WeltDrehY-90) * Pi / 180) * 0.04 :' Den X-Pos-Wert anpassen
         ZRichtg = ZRichtg + SIN((WeltDrehY-90) * Pi / 180) * 0.04 :' Den Y-Pos-Wert anpassen
      CASE TVor                       :'Falls die Taste "Cursor hoch" gedrückt wurde
         XRichtg = XRichtg + COS((WeltDrehY+90) * Pi / 180) * 0.04 :' Den X-Pos-Wert anpassen
         ZRichtg = ZRichtg + SIN((WeltDrehY+90) * Pi / 180) * 0.04 :' Den Y-Pos-Wert anpassen
      CASE TLinks                      :'Falls die Taste "Cursor links" gedrückt wurde
         WeltDrehY = WeltDrehY - 1
      CASE TRechts                     :'Falls die Taste "Cursor rechts" gedrückt wurde
         WeltDrehY = WeltDrehY + 1
      CASE "x"
         PyraXDrehw=PyraXDrehw+12
      CASE "x"
         PyraXDrehw=PyraXDrehw-12
      CASE "y"
         PyraYDrehw=PyraYDrehw+12
      CASE "y"
         PyraYDrehw=PyraYDrehw-12
      CASE "z"
         PyraZDrehw=PyraZDrehw+12
      CASE "z"
         PyraZDrehw=PyraZDrehw-12
      CASE "i", "i"                       :'<------------------------
         ConNr = FREEFILE                 :'nächste freie Dateinummer für öffnen von FreeBasic holen und in ConNr merken
         open "con" FOR OUTPUT AS #ConNr  :'und nun die Konsole als Datei unter Nr ConNr öffnen
            PRINT #ConNr, "PyraXDrehw:" & format(PyraXDrehw,"0.00") & "  PyraYDrehw:" & format(PyraYDrehw,"0.00") & "  PyraZDrehw:" & format(PyraZDrehw,"0.00")
            PRINT #ConNr, "XRichtg:" & format(XRichtg,"0.00") & "  YRichtg:" & format(YRichtg,"0.00") & "  ZRichtg:" & format(ZRichtg,"0.00")
         CLOSE #ConNr
   END SELECT   'PRÜFEN, DASS DIE POSITIONSWERTE IN ALLEN DREI RICHTUNGEN ZWISCHEN -3 und +3 BLEIBEN
   IF XRichtg >  6 THEN XRichtg =  6           :'falls zu weit rechts, bei  6 festnageln
   IF XRichtg < -6 THEN XRichtg = -6           :'falls zu weit links,  bei -6 festnageln
   IF YRichtg >  6 THEN YRichtg =  6           :'falls zu weit hoch,   bei  6festnageln
   IF YRichtg < -6 THEN YRichtg = -6           :'falls zu weit runter, bei -6 festnageln
   IF ZRichtg >  5 THEN ZRichtg =  5           :'falls zu weit zurück, bei 10 festnageln
   IF ZRichtg < -10 THEN ZRichtg = -10           :'falls zu weit vor,    bei -6 festnageln
   glClear GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT  :'bisherig erstellte Objekte löschen, unsere 3D-Welt wieder von Neuem an erstellen
   glPushMatrix                                        :'aktuelle Position + Drehgrade sichern (2.Zettel mit gleicher Pos auf PositionsSTACK)
    glRotatef WeltDrehY, 0, 1, 0                       :'Rotationsbefehl der Kamera, um Y ist zu drehen
    glTranslatef XRichtg, YRichtg, ZRichtg             :'Verschiebung der Kamera, auf neue Werte einstellen

    '-------------------------
    'AB HIER OBJEKTE ERSTELLEN
    '-------------------------
    glPointSize(5)                             :' Punktgröße auf 5 = deutlich groß
    glColor3f 1.0,0.0,0.0                      :' Anzeigefarbe auf ROT setzen
    Koordinatensystem("Anzeigen", "", 0, 0, 0) :' den Stringwert "Anzeigen" übergeben
    Schachbrettboden("BeschreibungsListeBoden", "", 0, 0, 0):' SchachbrettBoden in der 3D-Welt erstellen
    glPushMatrix                                                             :'akt.Position und Drehgrade sichern
    glEnable GL_TEXTURE_2D                    :'***********Texturieren erlauben*************
    glBindTexture GL_TEXTURE_2D, TexturNummer :'***********das erste Bild(mauer) als Textur aktivieren*************
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'die erste Pyramide
    glPopMatrix                                                              :'auf gesichterte Position und Drehgrade zurücksetzen
    glPushMatrix                                                             :'akt.Position und Drehgrade sichern
    glTranslatef -2, 0, 0                                                    :'hier der Verschiebebefehl, damit die 2.Pyramide woanderst steht
    glBindTexture GL_TEXTURE_2D, TexturZwei   :'***********das zweite Bild(Kirschen) als Textur aktivieren*************
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'und eine zweite Pyramide
    glPopMatrix                                                              :'auf gesichterte Position und Drehgrade zurücksetzen
    glDisable GL_TEXTURE_2D                    :'***********Texturieren wieder ausschalten*************

    '-----------------
    'OBJEKTE ERSTELLEN
    '-----------------

'-------------------------------------------------------------------
'XXXXXXXXXXXXXXXXXXXXX RECHTECK MIT TEXTUR ERZEUGEN XXXXXXXXXXXXXXXX
'-------------------------------------------------------------------
   glEnable GL_TEXTURE_2D          :'Texturieren mit dem grad aktiven Bild einschalten/erlauben
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) :'texturieren "voll drauf" kein durchsichtig etc
   glBindTexture GL_TEXTURE_2D, TexturNummer      :'Unser Bild auf der Grafikkarte als aktives setzen
   glColor3f 1.0,0.0,0.0                          :'Anzeigefarbe (für das Rechteck) auf ROT setzen
   glBegin GL_QUADS                               :'Beginn Beschreibungsliste Objekt Viereck
      glTexCoord2d 0.0, 1.0 : glVertex3f -1.0,  1.0, -4.0  :'die linke obere Ecke des Rechtecks
      glTexCoord2d 0.0, 0.0 : glVertex3f -1.0, -1.0, -4.0  :'die linke untere Ecke des Rechtecks
      glTexCoord2d 1.0, 0.0 : glVertex3f +1.0, -1.0, -4.0  :'die rechte untere Ecke des Rechtecks
      glTexCoord2d 1.0, 1.0 : glVertex3f +1.0,  1.0, -4.0  :'die rechte obere Ecke des Rechtecks
   glEnd                                          :'Fertig mit dem Objekt
   glDisable GL_TEXTURE_2D         :'Texturieren ausschalten (es soll ja nur das Viereck texturiert werden, nicht die Pyramiden)
'-------------------------------------------------------------------
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
'-------------------------------------------------------------------
   glEnable GL_TEXTURE_2D          :'Texturieren mit dem grad aktiven Bild einschalten/erlauben
   glBindTexture GL_TEXTURE_2D, TexturNummer      :'Unser Bild auf der Grafikkarte als aktives setzen
   glColor3f 1.0,0.0,0.0                          :'Anzeigefarbe (für das Rechteck) auf ROT setzen
   glBegin GL_QUADS                               :'Beginn Beschreibungsliste Objekt Viereck
      glTexCoord2d 0.0, 1.0 : glVertex3f -4.0,  1.0, -4.0  :'die linke obere Ecke des Rechtecks
      glTexCoord2d 0.0, 0.0 : glVertex3f -4.0, -1.0, -4.0  :'die linke untere Ecke des Rechtecks
      glTexCoord2d 1.0, 0.0 : glVertex3f -2.0, -1.0, -4.0  :'die rechte untere Ecke des Rechtecks
      glTexCoord2d 1.0, 1.0 : glVertex3f -2.0,  1.0, -4.0  :'die rechte obere Ecke des Rechtecks
   glEnd                                          :'Fertig mit dem Objekt
   glDisable GL_TEXTURE_2D         :'Texturieren ausschalten (es soll ja nur das Viereck texturiert werden, nicht die Pyramiden)
'-------------------------------------------------------------------
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
'-------------------------------------------------------------------


    flip                                               :'liebes OpenGL, zeig alles, was in der Schleife für dich vornedran steht, auf Monitor an
   '---------------------------
   'Ende der Schleife
   '---------------------------
   glPopMatrix                                         :' Aufgabe erledigt, den zweiten Zettel mit der geänderten Pos wegschmeißen, dann ist Alte Pos wieder aktuelle Pos
LOOP

END

'--------------------------------
SUB Koordinatensystem(was AS STRING, TxtPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
   DIM AS INTEGER Zaehler
   STATIC AS INTEGER AnzeigeSchalter
   SELECT CASE UCASE(was)
      CASE "AnAus"
         IF AnzeigeSchalter = 0 THEN AnzeigeSchalter = 1 ELSE AnzeigeSchalter = 0
      CASE "Anzeigen"
        IF AnzeigeSchalter = 1 THEN
         glBegin GL_LINES:' Ja, wir beginnen mit der Beschreibungsliste fuer Linien
         'und zwar zuerst die positiven Bereiche jeder Achse
         glColor3f 1.0, 1.0, 1.0        :' Positives Maß = weiße Teilstriche (Rot 1.0, blau 1.0, grün 1.0 = weiß)
         FOR Zaehler = 1 TO 6 :'fuer die Maßeinheitspositionen 1, 2 und 3 Striche Ziehen
            'X-ACHSE
               'senkrechter Strich (wie Y-Achse)
            glVertex3f  Zaehler+Para1,  0.2+Para2,  0.0+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1, -0.2+Para2,  0.0+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
               'waagerechter Strich (wie Z-Achse)
            glVertex3f  Zaehler+Para1,  0.0+Para2,  0.2+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1,  0.0+Para2, -0.2+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
            'Y-ACHSE
               'Strich wie X-Achse
            glVertex3f  0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach +X, Tiefe = 0
            glVertex3f -0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach -X, Tiefe = 0
               'Strich wie Z-Achse
            glVertex3f  0.0+Para1, Zaehler+Para2,  0.2+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach vorne/+Z, Seite (X) = 0
            glVertex3f  0.0+Para1, Zaehler+Para2, -0.2+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach hinten/-Z, Seite (X) = 0
            'Z-ACHSE
               'Strich waagerecht (X)
            glVertex3f  0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach rechts +X, Hoehe = 0
            glVertex3f -0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach links -X, Hoehe = 0
               'Strich senkreicht (Y)
            glVertex3f  0.0+Para1,  0.2+Para2,  Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach oben +Y, Seite = 0
            glVertex3f  0.0+Para1, -0.2+Para2,  Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach unten -Y, Seite = 0
         NEXT Zaehler
         glColor3f 0.0, 0.0, 0.0        :' Negatives Maß = schwrze Teilstriche (alles auf 0)
         FOR Zaehler = -6 TO -1 :'fuer die Maßeinheitspositionen -3, -2 und -1 Striche Ziehen
         'X-ACHSE
            'senkrechter Strich (wie Y-Achse)
            glVertex3f  Zaehler+Para1,  0.2+Para2,  0.0+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1, -0.2+Para2,  0.0+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
            'waagerechter Strich (wie Z-Achse)
            glVertex3f  Zaehler+Para1,  0.0+Para2,  0.2+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1,  0.0+Para2, -0.2+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
            'Y-ACHSE
               'Strich wie X-Achse
            glVertex3f  0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach +X, Tiefe = 0
            glVertex3f -0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach -X, Tiefe = 0
               'Strich wie Z-Achse
            glVertex3f  0.0+Para1, Zaehler+Para2,  0.2+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach vorne/+Z, Seite (X) = 0
            glVertex3f  0.0+Para1, Zaehler+Para2, -0.2+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach hinten/-Z, Seite (X) = 0
            'Z-ACHSE
               'Strich waagerecht (X)
            glVertex3f  0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach rechts +X, Hoehe = 0
            glVertex3f -0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach links -X, Hoehe = 0
               'Strich senkreicht (Y)
            glVertex3f  0.0+Para1,  0.2+Para2,  Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach oben +Y, Seite = 0
            glVertex3f  0.0+Para1, -0.2+Para2,  Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach unten -Y, Seite = 0
         NEXT Zaehler
         'UND NUN DIE DREI ACHSEN SELBST:
         'X-ACHSE
         glColor3f 1.0, 0.0, 0.0        :' Xachse = rot
         glVertex3f  -6.0+Para1, 0+Para2, 0+Para3
         glVertex3f  +6.0+Para1, 0+Para2, 0+Para3
         'Y-ACHSE
         glColor3f 0.0, 1.0, 0.0        :' Yachse = grün
         glVertex3f  0+Para1, -6.0+Para2, 0+Para3
         glVertex3f  0+Para1, +6.0+Para2, 0+Para3
         'Z-ACHSE
         glColor3f 0.0, 0.0, 1.0        :' Zachse = blau
         glVertex3f  0+Para1, 0+Para2, -6.0+Para3
         glVertex3f  0+Para1, 0+Para2, +6.0+Para3
         glEnd
       END IF
   END SELECT
END SUB
'-------------------------
SUB Schachbrettboden(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
   STATIC AS SINGLE QuadKantenLaenge, QuadsQuer, QuadsTief
   STATIC AS SINGLE Farbe1Rot, Farbe1Gruen, Farbe1Blau
   STATIC AS SINGLE Farbe2Rot, Farbe2Gruen, Farbe2Blau
   STATIC AS SINGLE StartPosX, StartPosZ, BodenHoehe
   STATIC AS INTEGER ZaehlerX, ZaehlerZ                   :'ForNext-Zählvars, ggf. rekursiver aufruf dieser Sub, drum STATIC
   SELECT CASE UCASE(was)
      CASE "SetzKantenLaenge"
         'Aufruf hierfür in Para1 die Länge der Kanten der Quadrate
         QuadKantenLaenge = Para1
      CASE "SetzQuadsZahl"
         'Aufruf hierfür in Para1 die Anzahl von Quads quer,
         'in Para2 die Anzahl in der Tiefenrichtung
         QuadsQuer = Para1
         QuadsTief = Para2
      CASE "SetzFarbe1"
         'in Para1 Para2 Para2 die Rot Grün und Blauwerte der ersten Quadratfarbe
         Farbe1Rot   = Para1
         Farbe1Gruen = Para2
         Farbe1Blau  = Para3
      CASE "SetzFarbe2"
         'in Para1 Para2 Para2 die Rot Grün und Blauwerte der ersten Quadratfarbe
         Farbe2Rot   = Para1
         Farbe2Gruen = Para2
         Farbe2Blau  = Para3
      CASE "SetzStartPos"
         'in Para1 Para2 Para2 die X und Z Position, von wo begonnen wird,
         'die vielen Quadrate zu erstellen
         StartPosX   = Para1
         StartPosZ   = Para2
         BodenHoehe  = Para3
      CASE "BeschreibungsListeBoden"
         'Hier erstellen wir die FOR-NEXT-SCHLEIFEN,
         'welche die OpenGL-Beschreibungsliste
         'zum Anzeigen des Bodens erstellen
         glBegin GL_QUADS
            FOR ZaehlerX = 1 TO QuadsQuer     :'Laufnr des grad zu zeichnenden Quads auf der X-Achse
               FOR ZaehlerZ = 1 TO QuadsTief  :'Laufnr des grad zu zeichnenden Quads auf der Z-Achse
                  'Die Farbe festlegen
                  IF ((ZaehlerX+ZaehlerZ)\2)*2=(ZaehlerX+ZaehlerZ) THEN
                     'Wenn die Summe von ZahlerX+ZaehlerY gerade ist Farbe1 nehmen
                     glColor3f Farbe1Rot, Farbe1Gruen, Farbe1Blau
                  ELSE
                     'Wenn die Summe von ZahlerX+ZaehlerY UNgerade ist Farbe2 nehmen
                     glColor3f Farbe2Rot, Farbe2Gruen, Farbe2Blau
                  END IF
                  'Die Eckpunkte der Quadrate benennen wir in der Reihenfolge GEGEN DEN UHRZEIGERSINN, von oben draufschauend
                  glVertex3f StartPosX+(ZaehlerX-1)*QuadKantenLaenge,  BodenHoehe,  StartPosZ+(ZaehlerZ-1)*QuadKantenLaenge
                  glVertex3f StartPosX+ ZaehlerX   *QuadKantenLaenge,  BodenHoehe,  StartPosZ+(ZaehlerZ-1)*QuadKantenLaenge
                  glVertex3f StartPosX+ ZaehlerX   *QuadKantenLaenge,  BodenHoehe,  StartPosZ+ ZaehlerZ   *QuadKantenLaenge
                  glVertex3f StartPosX+(ZaehlerX-1)*QuadKantenLaenge,  BodenHoehe,  StartPosZ+ ZaehlerZ   *QuadKantenLaenge
               NEXT ZaehlerZ
            NEXT ZaehlerX
         glEnd
      CASE ELSE
         'Hier kommen alle SUB-Aufrufe an, welche als
         'was-Parameter einen Eintrag haben, der hier
         'nicht ausgewertet wurde.
         'Tippfehler vom Programmierer????
   END SELECT
END SUB
'-------------------------
SUB Pyramide(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
   'Pyramide erstellen, Grundfläche/Quadrat = auf Höhe 0, seitlich mittig auf X- und Z-Achse Positioniert
   'Grundflächengroesse = XLaenge x ZLaenge, Höhe Pyramide = ZLaenge
   STATIC AS SINGLE XLaenge, YLaenge, ZLaenge
   STATIC AS SINGLE Farbe1Rot, Farbe1Gruen, Farbe1Blau
   STATIC AS SINGLE Farbe2Rot, Farbe2Gruen, Farbe2Blau
   STATIC AS SINGLE Farbe3Rot, Farbe3Gruen, Farbe3Blau
   STATIC AS SINGLE Farbe4Rot, Farbe4Gruen, Farbe4Blau
   STATIC AS SINGLE Farbe5Rot, Farbe5Gruen, Farbe5Blau
   STATIC AS INTEGER ZaehlerX, ZaehlerZ                   :'ForNext-Zählvars, ggf. rekursiver aufruf dieser Sub, drum STATIC
   SELECT CASE UCASE(was)
      CASE "SetzLaengen"  : XLaenge   = Para1 : YLaenge     = Para2 : ZLaenge     = Para3
      CASE "SetzFarbe1"   : Farbe1Rot = Para1 : Farbe1Gruen = Para2 : Farbe1Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe2"   : Farbe2Rot = Para1 : Farbe2Gruen = Para2 : Farbe2Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe3"   : Farbe3Rot = Para1 : Farbe3Gruen = Para2 : Farbe3Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe4"   : Farbe4Rot = Para1 : Farbe4Gruen = Para2 : Farbe4Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe5"   : Farbe5Rot = Para1 : Farbe5Gruen = Para2 : Farbe5Blau  = Para3 :'der Boden/Quadrat
      CASE "BeschreibungsListe"
         glrotatef Para1, 1, 0, 0    :'<----------- um X-Achse drehen
         glrotatef Para2, 0, 1, 0    :'<----------- um Y-Achse drehen
         glrotatef Para3, 0, 0, 1    :'<----------- um Z-Achse drehen
         'die OpenGL-Beschreibungsliste zum Anzeigen der Pyramide erstellen
         glBegin GL_QUADS
            'der Boden der Pyramide als Quadrat, auf Höhe 0(Y-Achse),
            'seitliche Ausrichtungen = Quadratmitte = X-Achsenmitte und Z-Achsenmitte
            'damit Zentriert sitzt, für 1.Punkt einfach halbe Kantenlänge von 0 Abziehen, für 2. dazuaddieren
            'Reihenfolge Eckpunktangabe gegen Uhrzeigersinn VON UNTEN her gesehen (unten=Außenseite später)
            glColor3f  Farbe5Rot, Farbe5Gruen, Farbe5Blau :'falls Texturieren Disabled ist, wird diese Farbe genommen
            glTexCoord2d 0.0, 1.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'Ecke links oben
            glTexCoord2d 0.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'Ecke links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'Ecke rechts unten
            glTexCoord2d 1.0, 1.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'Ecke rechts oben
         glEnd
         glBegin GL_TRIANGLES
            '   Dreieckseite 1 = linke Seite
            glColor3f  Farbe1Rot, Farbe1Gruen, Farbe1Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0       , 0-(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0       , 0+(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.1, 1.0 : glVertex3f 0                , YLaenge , 0             :'Spitze oben
            '   Dreieckseite 2 = hintere Seite /Rückseite
            glColor3f  Farbe2Rot, Farbe2Gruen, Farbe2Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.5, 1.0 : glVertex3f 0                , YLaenge , 0        :'Spitze oben mitte
            '   Dreieckseite 3 = rechte Seite
            glColor3f  Farbe3Rot, Farbe3Gruen, Farbe3Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.5, 1.0 : glVertex3f 0                , YLaenge , 0        :'Spitze oben mitte
            '   Dreieckseite 4 = Vorderseite
            glColor3f  Farbe4Rot, Farbe4Gruen, Farbe4Blau
            glTexCoord2d 0.0, 0.0 : glVertex3f 0-(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'links unten
            glTexCoord2d 1.0, 0.0 : glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2) :'rechts unten
            glTexCoord2d 0.5, 1.0 : glVertex3f 0                , YLaenge , 0        :'Spitze oben mitte
         glEnd
      CASE ELSE
         'Hier kommen alle SUB-Aufrufe an, welche als
         'was-Parameter einen Eintrag haben, der hier
         'nicht ausgewertet wurde.
         'Tippfehler vom Programmierer????
   END SELECT
END SUB
'--------------------------------
FUNCTION BmpToOgl(BmpName AS STRING) AS INTEGER
   DIM AS BYTE PTR DateiImRamPtr, SpBmpPixelZeiger
   DIM AS INTEGER DateiNummer, Ganzzahl, Breite, Hoehe
   DIM AS UINTEGER TexturNummer, RotWert, BlauWert, ZeilenZaehler, PunktZaehler
   DIM AS UBYTE Buchstabe
   DIM AS STRING Dummy
   'Von Festplatte in den RAM
   DateiNummer = FREEFILE
   OPEN BmpName FOR INPUT AS #DateiNummer
   IF LOF(DateiNummer) = 0 THEN
      'BildDatei Existiert nicht
      Schreibe("Die Bilddatei " & BmpName & " ist nicht vorhanden oder hat Laenge 0! breche ab")
      CLOSE #DateiNummer
      END
   ELSE
      'BildDatei ist vorhanden, String aus den ersten zwei Bytes in der Datei basteln
      GET #DateiNummer, 1, Buchstabe
      Dummy=CHR(Buchstabe)
      GET #DateiNummer, 2, Buchstabe
      Dummy = Dummy + CHR(Buchstabe)
      IF Dummy <> "BM" THEN
         'keine Bitmap-Datei
         Schreibe("Die Bilddatei " & BmpName & " ist keine Bitmapdatei! Kennung=" & Dummy & " breche ab")
         CLOSE #DateiNummer
         END
      ELSE
         'Datei ist Bitmap, prüfen ob komprimiert
         GET #DateiNummer, 31, Ganzzahl
         IF Ganzzahl <> 0 THEN
            'Bitampdatei ist komprimiert
            Schreibe("Die Bilddatei " & BmpName & " ist komprimiert gespeichert, kann damit nicht umgehen, breche ab!")
            CLOSE #DateiNummer
            END
         ELSE
            'unkomprimierte Bitmap-Datei, prüfen ob quadratisch und 64/128/256 bytes kantenlänge
            GET #DateiNummer, 19, Breite
            GET #DateiNummer, 23, Hoehe
            IF (Breite <> Hoehe) OR (Breite <> 64 AND Breite <> 128 AND Breite <> 256) THEN
               'Bild ist entweder nicht quadratisch oder nicht 64/128/256er Kantenlängen
               Schreibe("Die Bilddatei " & BmpName & " ist entweder nicht Quadratisch oder hat keine Kantenlänge von 64, 128 oder 256 Pixel")
               Schreibe("       Breite:" & Breite & " Hoehe:" & Hoehe & "   breche ab!")
               CLOSE #DateiNummer
               END
            ELSE
               '***************************************
               'Bilddatei ist OK, kann verwendet werden
               '***************************************
               CLOSE #DateiNummer
               DateiImRamPtr = IMAGECREATE(Breite, Hoehe, 0, 32)
               BLOAD(BmpName, DateiImRamPtr)
            END IF
         END IF
      END IF
   END IF
   'Entweder das Programm hat abgebrochen, oder die Datei ist OK und das Bild steht jetzt im Ram an Adresse DateiImRamPtr
   SpBmpPixelZeiger = DateiImRamPtr + Len(FB.IMAGE)
   FOR ZeilenZaehler = 0 TO Hoehe-1
      FOR PunktZaehler = 0 TO Breite-1
         BlauWert = SpBmpPixelZeiger[0]        :'aus Ram das Byte mit dem Blauwert des grad zu bearbeitenden Pixels holen
         RotWert  = SpBmpPixelZeiger[2]        :'aus Ram das Byte mit dem Rotwert des grad zu bearbeitenden Pixels holen
         SpBmpPixelZeiger[0] = RotWert         :'den Rotwert an die Stelle des Blauwertes im RAM schreiben
         SpBmpPixelZeiger[2] = BlauWert        :'den Blauwert an die Stelle des Rotwertes im RAM schreiben
         SpBmpPixelZeiger = SpBmpPixelZeiger+4 :'Ram-Adresse um 4 bytes erhöhen = Start Pixeldaten des nächsten Pixels
      NEXT PunktZaehler
   NEXT ZeilenZaehler
   'Farbtiefe des OpenGL-Fensters holen
   DIM AS INTEGER FensterFarbTiefe
   SCREENCONTROL 5, FensterFarbTiefe :' 5 = GET_SCREEN_DEPTH : Farbtiefe in Bits des OpenGL-Fensters ermitteln
   'XXXXXXXXXXXXXXXXXXXXX UND RAM-BILD AN OPENGL ÜBERGEBRN XXXXXXXXXXXXXXXX
   glGenTextures 1, @TexturNummer
   glBindTexture GL_TEXTURE_2D, TexturNummer
   IF FensterFarbTiefe = 32 OR FensterFarbTiefe = 24 THEN
      glTexImage2D GL_TEXTURE_2D, 0, GL_RGBA, Breite, Hoehe, 0, GL_RGBA, GL_UNSIGNED_BYTE, DateiImRamPtr+Len(FB.IMAGE)
   ELSE
      glTexImage2D GL_TEXTURE_2D, 0, GL_RGB, Breite, Hoehe, 0, GL_RGBA, GL_UNSIGNED_BYTE, DateiImRamPtr+Len(FB.IMAGE)
   END IF
   glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
   glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
   ImageDestroy(DateiImRamPtr)
   BmpToOgl=TexturNummer
END FUNCTION
'-------------------
SUB Schreibe(Text AS STRING)
   DIM AS INTEGER DateiNummer
   'AUF DEN MONITOR IN DIE TEXTCONSOLE
   DateiNummer=FREEFILE
   OPEN "CONS" FOR OUTPUT AS #DateiNummer
   PRINT #DateiNummer, Text
   CLOSE #DateiNummer
   'NOCHMAL IN EINE DATEI
   DateiNummer=FREEFILE
   OPEN "Protokoll.txt" FOR APPEND AS #DateiNummer
   PRINT #DateiNummer, DATE & " " & TIME & " " & Text
   CLOSE #DateiNummer
END SUB

 

Gehe zu Seite Gehe zu Seite  1  2  3  4  5  6  
Zusätzliche Informationen und Funktionen
  • Das Tutorial wurde am 28.09.2008 von MitgliedEastler_dart angelegt.
  • Die aktuellste Version wurde am 30.09.2008 von MitgliedEastler_dart gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen