<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Sascha+Willems</id>
		<title>DGL Wiki - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Sascha+Willems"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php/Spezial:Beitr%C3%A4ge/Sascha_Willems"/>
		<updated>2026-04-14T22:00:11Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glNormal&amp;diff=23705</id>
		<title>glNormal</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glNormal&amp;diff=23705"/>
				<updated>2009-06-12T20:17:07Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= glNormal =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glNormal''' - setzt die aktuell gültige Normale.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glNormal3b'''(''nx'': TGLbyte; ''ny'': TGLbyte; ''nz'': TGLbyte);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3d'''(''nx'': TGLdouble; ''ny'': TGLdouble; ''nz'': TGLdouble);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3f'''(''nx'': TGLfloat; ''ny'': TGLfloat; ''nz'': TGLfloat);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3i'''(''nx'': TGLint; ''ny'': TGLint; ''nz'': TGLint);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3s'''(''nx'': TGLshort; ''ny'': TGLshort; ''nz'': TGLshort);&amp;lt;br&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 procedure '''glNormal3bv'''(const ''v'': PGLbyte);&amp;lt;br&amp;gt; &lt;br /&gt;
 procedure '''glNormal3dv'''(const ''v'': PGLdouble);&amp;lt;br&amp;gt;     &lt;br /&gt;
 procedure '''glNormal3fv'''(const ''v'': PGLfloat);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3iv'''(const ''v'': PGLint);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3sv'''(const ''v'': PGLshort);&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
Version mit 3 Einzelparametern (glNormal3*) :&lt;br /&gt;
&amp;lt;table border=1 rules=all&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''nx'', ''ny'', ''nz''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;Geben die x, y und z Koordinaten der neuen Normale an.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version mit Parameterfeld (glNormal3*v) :&lt;br /&gt;
&amp;lt;table border=1 rules=all&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''v''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''v'' ist ein Zeiger auf ein Feld welches 3 Werte enthält. Diese 3 Werte stellen die x, y und z-Koordinaten der neuen Normale dar.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Initialisiert ist die Normale mit den Werten (0,0,1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die aktuelle Normale wird immer dann auf die Übergebenen Koordinaten ausgerichtet, wenn '''glNormal''' aufgerufen wird. &amp;lt;br&amp;gt;&lt;br /&gt;
Parameter in Byte-, Short- oder Integer-Typen werden so in Fließkommazahlen umgerechnet, dass die kleinstmögliche Zahl des Paramtertyps zu -1.0 und die größtmögliche Zahl zu 1.0 wird. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Dglwiki_glnormal.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dieses Bild zeigt auf der linken Seite (harte) Normalen die per Fläche gesetzt wurden, während auf der rechten Seite (weiche) Normalen zu sehen sind die für jeden Eckpunkt gesetzt wurden und vorher im 3D Modeller über den Mesh hinweg gemittelt wurden (&amp;quot;weiche&amp;quot; Normalen). Visualisiert wurde dies mit Hilfe eines [[Shader|Shaders]]. Wie zu erkennen werden hier die XYZ-Koordinaten der passenden Normalen auf die RGB-Werte projeziert, so wird also aus einer Normalen die nach oben zeigt (0, 1, 0) ein grüner Pixel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
* Normalisierte Normalen&lt;br /&gt;
** Normale, die mit '''glNormal''' gesetzt werden, müssen keine Einheitslänge haben. (||n|| &amp;lt;&amp;gt; 1)&lt;br /&gt;
** Wenn Normalisierung aktiviert wurde, wird die Normale nach der Transformation normalisiert.&lt;br /&gt;
** Normalisierung kann mittels [[glEnable | glEnable/glDisable]] und dem Argument '''GL_NORMALIZE''' kontrolliert werden.&lt;br /&gt;
** Standardmäßig ist Normalisierung deaktiviert.&lt;br /&gt;
* Die Normale kann zu jeder Zeit neu gesetzt werden. So kann '''glNormal''' auch innerhalb von [[glBegin]]-[[glEnd]] Blöcken aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
keine&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGet]] mit Token GL_CURRENT_NORMAL &amp;lt;br&amp;gt;&lt;br /&gt;
[[glIsEnabled]] mit GL_NORMALIZE&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glBegin]], [[glColor]], [[glIndex]], [[glTexCoord]], [[glVertex]]&lt;br /&gt;
&lt;br /&gt;
Hintergrundwissen: [[Normalen]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|Normal]]&lt;br /&gt;
 [[Kategorie:GL1.0]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=glNormal&amp;diff=23704</id>
		<title>glNormal</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=glNormal&amp;diff=23704"/>
				<updated>2009-06-12T20:15:54Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* glNormal */  Bild mit Darstellung von Normalen per Fläche und weichen Normalen per Eckpunkt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Bildwunsch|Ein kleiner Beispielcode mit Bild. Z.B. eine aus 4x4 Quads zusammengesetzte &amp;quot;Landschaft&amp;quot; mit eingezeichneten Normalen. Einmal mit &amp;quot;harten&amp;quot; Kanten und einmal weich.}}&lt;br /&gt;
= glNormal =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''glNormal''' - setzt die aktuell gültige Normale.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 procedure '''glNormal3b'''(''nx'': TGLbyte; ''ny'': TGLbyte; ''nz'': TGLbyte);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3d'''(''nx'': TGLdouble; ''ny'': TGLdouble; ''nz'': TGLdouble);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3f'''(''nx'': TGLfloat; ''ny'': TGLfloat; ''nz'': TGLfloat);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3i'''(''nx'': TGLint; ''ny'': TGLint; ''nz'': TGLint);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3s'''(''nx'': TGLshort; ''ny'': TGLshort; ''nz'': TGLshort);&amp;lt;br&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 procedure '''glNormal3bv'''(const ''v'': PGLbyte);&amp;lt;br&amp;gt; &lt;br /&gt;
 procedure '''glNormal3dv'''(const ''v'': PGLdouble);&amp;lt;br&amp;gt;     &lt;br /&gt;
 procedure '''glNormal3fv'''(const ''v'': PGLfloat);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3iv'''(const ''v'': PGLint);&amp;lt;br&amp;gt;&lt;br /&gt;
 procedure '''glNormal3sv'''(const ''v'': PGLshort);&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
Version mit 3 Einzelparametern (glNormal3*) :&lt;br /&gt;
&amp;lt;table border=1 rules=all&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''nx'', ''ny'', ''nz''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;Geben die x, y und z Koordinaten der neuen Normale an.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version mit Parameterfeld (glNormal3*v) :&lt;br /&gt;
&amp;lt;table border=1 rules=all&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''v''&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;td&amp;gt;''v'' ist ein Zeiger auf ein Feld welches 3 Werte enthält. Diese 3 Werte stellen die x, y und z-Koordinaten der neuen Normale dar.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Initialisiert ist die Normale mit den Werten (0,0,1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die aktuelle Normale wird immer dann auf die Übergebenen Koordinaten ausgerichtet, wenn '''glNormal''' aufgerufen wird. &amp;lt;br&amp;gt;&lt;br /&gt;
Parameter in Byte-, Short- oder Integer-Typen werden so in Fließkommazahlen umgerechnet, dass die kleinstmögliche Zahl des Paramtertyps zu -1.0 und die größtmögliche Zahl zu 1.0 wird. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Datei:Dglwiki_glnormal.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dieses Bild zeigt auf der linken Seite (harte) Normalen die per Fläche gesetzt wurden, während auf der rechten Seite (weiche) Normalen zu sehen sind die für jeden Eckpunkt gesetzt wurden und vorher im 3D Modeller über den Mesh hinweg gemittelt wurden (&amp;quot;weiche&amp;quot; Normalen). Visualisiert wurde dies mit Hilfe eines [[Shader|Shaders]]. Wie zu erkennen werden hier die XYZ-Koordinaten der passenden Normalen auf die RGB-Werte projeziert, so wird also aus einer Normalen die nach oben zeigt (0, 1, 0) ein grüner Pixel.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise ==&lt;br /&gt;
* Normalisierte Normalen&lt;br /&gt;
** Normale, die mit '''glNormal''' gesetzt werden, müssen keine Einheitslänge haben. (||n|| &amp;lt;&amp;gt; 1)&lt;br /&gt;
** Wenn Normalisierung aktiviert wurde, wird die Normale nach der Transformation normalisiert.&lt;br /&gt;
** Normalisierung kann mittels [[glEnable | glEnable/glDisable]] und dem Argument '''GL_NORMALIZE''' kontrolliert werden.&lt;br /&gt;
** Standardmäßig ist Normalisierung deaktiviert.&lt;br /&gt;
* Die Normale kann zu jeder Zeit neu gesetzt werden. So kann '''glNormal''' auch innerhalb von [[glBegin]]-[[glEnd]] Blöcken aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
== Fehlermeldungen ==&lt;br /&gt;
keine&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Zugehörige Wertrückgaben ==&lt;br /&gt;
[[glGet]] mit Token GL_CURRENT_NORMAL &amp;lt;br&amp;gt;&lt;br /&gt;
[[glIsEnabled]] mit GL_NORMALIZE&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[glBegin]], [[glColor]], [[glIndex]], [[glTexCoord]], [[glVertex]]&lt;br /&gt;
&lt;br /&gt;
Hintergrundwissen: [[Normalen]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:GL|Normal]]&lt;br /&gt;
 [[Kategorie:GL1.0]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:Dglwiki_glnormal.jpg&amp;diff=23703</id>
		<title>Datei:Dglwiki glnormal.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:Dglwiki_glnormal.jpg&amp;diff=23703"/>
				<updated>2009-06-12T20:08:19Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Szene aus Projekt &amp;quot;W&amp;quot; mit visualisierten Normalen. Links Normalen per Fläche und rechts per Eckpunkt und über den ganzen Mesh hinweg geglättet.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Szene aus Projekt &amp;quot;W&amp;quot; mit visualisierten Normalen. Links Normalen per Fläche und rechts per Eckpunkt und über den ganzen Mesh hinweg geglättet.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Wiki:Anmelden&amp;diff=23213</id>
		<title>DGL Wiki:Anmelden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Wiki:Anmelden&amp;diff=23213"/>
				<updated>2009-04-01T12:58:13Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In diesem Artikel wird beschrieben wie man sich im '''Wiki''' erfolgreich '''anmeldet''' um Beiträge zu verfassen oder zu editieren. &lt;br /&gt;
&lt;br /&gt;
* Registieren Sie sich im Forum, falls Sie es noch nicht getan haben [http://www.delphigl.com/forum/profile.php?mode=register]&lt;br /&gt;
* Schreiben Sie an [http://www.delphigl.com/forum/privmsg.php?mode=post&amp;amp;u=59  Sascha] oder [http://www.delphigl.com/forum/privmsg.php?mode=post&amp;amp;u=3 Phobeus] eine PM, dass Sie sich mit Forenbenutzernamen und -Kennwort im Wiki einloggen möchten.&lt;br /&gt;
* Nachdem Sie von einem der beiden in die Benutzergruppe Wiki aufgenommen worden sind, können Sie sich mit den Forendaten im Wiki [[Spezial:Userlogin|anmelden]] und ab sofort Einträge verfassen oder editieren.&lt;br /&gt;
&lt;br /&gt;
Warum diese umständliche Methode nötig wurde erfahrt ihr im Artikel [[FAQ Wiki]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hinweise für alle die Mithelfen wollen==&lt;br /&gt;
&lt;br /&gt;
Jeder der Lust hat kann mithelfen die Artikel im Wiki zu verbessern. Als erstes muss man sich dazu wie hier beschrieben einen Account erstellen. Sobald ihr angemeldet seid, könnt ihr einfach auf bearbeiten (ganz oben) bei einem Artikel klicken. Möchte man einen neuen Artikel erstellen (Klick auf einen roten Link), so sollte man sich vorher die [[DGL_Wiki:Hinweise_zum_Artikel_erstellen|Hinweise zum Artikel erstellen]] durchlesen.&lt;br /&gt;
&lt;br /&gt;
Diskussionen zum Wiki selbst (nicht zu einzelnen Artikeln) sollten zentral in unserem [http://delphigl.com/forum Forum] und nicht im Wiki ausgetragen werden.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:SwapBuffers&amp;diff=23212</id>
		<title>Diskussion:SwapBuffers</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:SwapBuffers&amp;diff=23212"/>
				<updated>2009-03-31T19:55:39Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Die Seite wurde neu angelegt: Ich habe den Hinweis mit ShowModal und Fehlschlagen von SwapBuffers entfernt, da dies i.d.R. NICHT passiert. Ich selbst nutze sowas u.a. in einem Editor, und dort funkt...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ich habe den Hinweis mit ShowModal und Fehlschlagen von SwapBuffers entfernt, da dies i.d.R. NICHT passiert. Ich selbst nutze sowas u.a. in einem Editor, und dort funktioniert SwapBuffers sehr wohl wenn ein modales Fenster angezeigt wird, oder war der Vermerk anders gemeint? Ansonsten sollte hier diskutiert werden und ein solcher Vermerk nur in den Artikel eingebracht werden wenn dieser auch auf die meisten GL-Implementationen zutrifft. Sowohl bei aktuellen NVidia als auch ATI-karten gibt es mit ShowModal und SwapBuffers keine Probleme&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 19:55, 31. Mär. 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=SwapBuffers&amp;diff=23211</id>
		<title>SwapBuffers</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=SwapBuffers&amp;diff=23211"/>
				<updated>2009-03-31T19:53:00Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Änderungen von Yogu (Beiträge) rückgängig gemacht und letzte Version von Flo wiederhergestellt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SwapBuffers =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''SwapBuffers''' - tauscht Back- und Frontbuffer aus.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 '''function''' SwapBuffers(''DC'' : HDC) : Boolean;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
{| border=1 rules=all&lt;br /&gt;
! '''DC'''&lt;br /&gt;
|Steht für den Device Kontext und bezeichnet die aktuelle Zeichenfläche&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Die Funktion SwapBuffers tauscht Back- und Frontbuffer aus.&amp;lt;br&amp;gt;&lt;br /&gt;
Diese Methode ist essentiell für das [[Doppelpufferung|Doublebuffering]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Zugehörige Wertrückgaben ==&lt;br /&gt;
Diese Funktion liefert TRUE zurück, wenn der Buffertausch vollzogen werden konnte. Andernfalls wird FALSE zurückgeliefert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Siehe auch ==&lt;br /&gt;
[[Doppelpufferung|Doublebuffering]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23159</id>
		<title>dglOpenGL.pas/en</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23159"/>
				<updated>2009-03-20T12:57:49Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Sourcetags&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, especially as it lacks most of OpenGL's current functionality.'''''}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;[[Bild:Flag_german.gif]][[dglOpenGL.pas| Deutsche Version dieser Seite ]][[Bild:Flag_german.gif]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=The DelphiGL header=&lt;br /&gt;
So to compensate for the flaws of the outdated and buggy default header that is shipped with Delphi, the [http://www.delphigl.com (german) Delphi OpenGL Community] is providing it's own header that's permanently updated to provide steady support for new OpenGL features and functionality. This makes updating to a new header version easily (usually backwards compatibility is preserved), and it's even possible to use the header with other pascal compilers like Freepascal.&lt;br /&gt;
&lt;br /&gt;
It includes all OpenGL functions (currently up-to and including OpenGL 3.0) as well as all GLU ('''OpenGL Utility Libary''') functions and supports all ARB, EXT, NV and ATI extensions. It also includes additional, though lesser common extensions from other vendors like Apple, HP and SGI.&lt;br /&gt;
&lt;br /&gt;
A special feature of this header are boolean variables for each included extensions that are flagged upon initialisation (those boolean vars carry the same as their corresponding extensions), so you can quickly check wether an extension is support or not (instead of checking the strings returned by [[glGetString/en]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Licence/Terms of use==&lt;br /&gt;
The '''dglOpenGL.pas''' is distributed unter the terms and conditions of the '''Mozilla Public License Version 1.1'''. You can grab a copy of that licence [http://www.mozilla.org/MPL/MPL-1.1.html here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;The contents of the dglOpenGL.pas are used with permission, subject to&amp;lt;br&amp;gt;&lt;br /&gt;
the Mozilla Public License Version 1.1 (the &amp;quot;License&amp;quot;); you may&amp;lt;br&amp;gt;&lt;br /&gt;
not use this file except in compliance with the License. You may&amp;lt;br&amp;gt;&lt;br /&gt;
obtain a copy of the License at&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mozilla.org/MPL/MPL-1.1.html&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Software distributed under the License is distributed on an&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;AS IS&amp;quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or&amp;lt;br&amp;gt;&lt;br /&gt;
implied. See the License for the specific language governing&amp;lt;br&amp;gt;&lt;br /&gt;
rights and limitations under the License.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==.NET support==&lt;br /&gt;
Due to lack of interest, .NET support has been removed as of header version 2.1!&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|The .Net header won't be developed any further, but reported errors may be fixed. So new OpenGL functionality can only be found in the normal header.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Initializing function pointers (crucial)==&lt;br /&gt;
Along with the removal of .NET support, support for loading methods dynamically has also been removed and is no longer possible with the standard header. So it's crucial to call either '''AtivateRenderingContext''' or '''ReadExtensions''' alongside with '''ReadImplementationProperties''' in your application before accessing any of the OpenGL functions. Otherwise you'll likely be prompted with an access violation at address 0x00000000. &lt;br /&gt;
&lt;br /&gt;
''So if you get such an access violation please check if you called the above functions!''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example for '''initializing''' the OpenGL function pointers (''needs to be called before you access any OpenGL functions'') :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure OpenGLInit;&lt;br /&gt;
 begin&lt;br /&gt;
 InitOpenGL; // Don't forget, or first gl-Call will result in an access violation!&lt;br /&gt;
 MyDC := GetDC(...);&lt;br /&gt;
 MyRC := CreateRenderingContext(...);&lt;br /&gt;
 ActivateRenderingContext(MyDC, MyRC); // Necessary, will also load function pointers for all extension&lt;br /&gt;
 ...&lt;br /&gt;
 end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example for '''finishing''' the OpenGL render context (''should be called before quitting your application'') :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure OpenGLFinish;&lt;br /&gt;
 begin&lt;br /&gt;
 DeactivateRenderingContext; // Deactivates the current context&lt;br /&gt;
 wglDeleteContext(myRC);&lt;br /&gt;
 ReleaseDC(Handle, myDC);&lt;br /&gt;
 end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL.zip Current dglOpenGL.pas] (Supports ''OpenGL 3.0'', works with Delphi 4 and up and Freepascal))'''&lt;br /&gt;
&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL_net.zip Last dglOpenGL.pas wit .NET support] (Supports ''OpenGL 2.1'')'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''For Delphi 3 users :'''&lt;br /&gt;
''[[Benutzer:Mars|Mars]] has posted a version of the dglOpenGL.pas that will work with Delphi 3, you can get it here :&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.delphigl.com/forum/viewtopic.php?p=26697#25642 dglOpenGL.pas for Delphi 3] &amp;lt;br&amp;gt;&lt;br /&gt;
''(You need to be registered on the forums to download it)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''There is also an inofficial version of this [http://www.delphigl.com/forum/viewtopic.php?t=4216 headers for C++].''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
{{dglOpenGL_History}}&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23158</id>
		<title>dglOpenGL.pas/en</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23158"/>
				<updated>2009-03-20T12:53:24Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, especially as it lacks most of OpenGL's current functionality.'''''}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;[[Bild:Flag_german.gif]][[dglOpenGL.pas| Deutsche Version dieser Seite ]][[Bild:Flag_german.gif]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=The DelphiGL header=&lt;br /&gt;
So to compensate for the flaws of the outdated and buggy default header that is shipped with Delphi, the [http://www.delphigl.com (german) Delphi OpenGL Community] is providing it's own header that's permanently updated to provide steady support for new OpenGL features and functionality. This makes updating to a new header version easily (usually backwards compatibility is preserved), and it's even possible to use the header with other pascal compilers like Freepascal.&lt;br /&gt;
&lt;br /&gt;
It includes all OpenGL functions (currently up-to and including OpenGL 3.0) as well as all GLU ('''OpenGL Utility Libary''') functions and supports all ARB, EXT, NV and ATI extensions. It also includes additional, though lesser common extensions from other vendors like Apple, HP and SGI.&lt;br /&gt;
&lt;br /&gt;
A special feature of this header are boolean variables for each included extensions that are flagged upon initialisation (those boolean vars carry the same as their corresponding extensions), so you can quickly check wether an extension is support or not (instead of checking the strings returned by [[glGetString/en]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Licence/Terms of use==&lt;br /&gt;
The '''dglOpenGL.pas''' is distributed unter the terms and conditions of the '''Mozilla Public License Version 1.1'''. You can grab a copy of that licence [http://www.mozilla.org/MPL/MPL-1.1.html here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;The contents of the dglOpenGL.pas are used with permission, subject to&amp;lt;br&amp;gt;&lt;br /&gt;
the Mozilla Public License Version 1.1 (the &amp;quot;License&amp;quot;); you may&amp;lt;br&amp;gt;&lt;br /&gt;
not use this file except in compliance with the License. You may&amp;lt;br&amp;gt;&lt;br /&gt;
obtain a copy of the License at&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mozilla.org/MPL/MPL-1.1.html&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Software distributed under the License is distributed on an&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;AS IS&amp;quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or&amp;lt;br&amp;gt;&lt;br /&gt;
implied. See the License for the specific language governing&amp;lt;br&amp;gt;&lt;br /&gt;
rights and limitations under the License.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==.NET support==&lt;br /&gt;
Due to lack of interest, .NET support has been removed as of header version 2.1!&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|The .Net header won't be developed any further, but reported errors may be fixed. So new OpenGL functionality can only be found in the normal header.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Initializing function pointers (crucial)==&lt;br /&gt;
Along with the removal of .NET support, support for loading methods dynamically has also been removed and is no longer possible with the standard header. So it's crucial to call either '''AtivateRenderingContext''' or '''ReadExtensions''' alongside with '''ReadImplementationProperties''' in your application before accessing any of the OpenGL functions. Otherwise you'll likely be prompted with an access violation at address 0x00000000. &lt;br /&gt;
&lt;br /&gt;
''So if you get such an access violation please check if you called the above functions!''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example for '''initializing''' the OpenGL function pointers (''needs to be called before you access any OpenGL functions'') :&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure OpenGLInit;&lt;br /&gt;
 begin&lt;br /&gt;
 InitOpenGL; // Don't forget, or first gl-Call will result in an access violation!&lt;br /&gt;
 MyDC := GetDC(...);&lt;br /&gt;
 MyRC := CreateRenderingContext(...);&lt;br /&gt;
 ActivateRenderingContext(MyDC, MyRC); // Necessary, will also load function pointers for all extension&lt;br /&gt;
 ...&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example for '''finishing''' the OpenGL render context (''should be called before quitting your application'') :&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure OpenGLFinish;&lt;br /&gt;
 begin&lt;br /&gt;
 DeactivateRenderingContext; // Deactivates the current context&lt;br /&gt;
 wglDeleteContext(myRC);&lt;br /&gt;
 ReleaseDC(Handle, myDC);&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL.zip Current dglOpenGL.pas] (Supports ''OpenGL 3.0'', works with Delphi 4 and up and Freepascal))'''&lt;br /&gt;
&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL_net.zip Last dglOpenGL.pas wit .NET support] (Supports ''OpenGL 2.1'')'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''For Delphi 3 users :'''&lt;br /&gt;
''[[Benutzer:Mars|Mars]] has posted a version of the dglOpenGL.pas that will work with Delphi 3, you can get it here :&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.delphigl.com/forum/viewtopic.php?p=26697#25642 dglOpenGL.pas for Delphi 3] &amp;lt;br&amp;gt;&lt;br /&gt;
''(You need to be registered on the forums to download it)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''There is also an inofficial version of this [http://www.delphigl.com/forum/viewtopic.php?t=4216 headers for C++].''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
{{dglOpenGL_History}}&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23157</id>
		<title>dglOpenGL.pas/en</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23157"/>
				<updated>2009-03-20T12:53:06Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Initializing function pointers (crucial, see readme) */ Added example for init and deinit&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, especially as it lacks most of OpenGL's current functionality.'''''}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;[[Bild:Flag_german.gif]][[dglOpenGL.pas| Deutsche Version dieser Seite ]][[Bild:Flag_german.gif]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=The DelphiGL header=&lt;br /&gt;
So to compensate for the flaws of the outdated and buggy default header that is shipped with Delphi, the [http://www.delphigl.com (german) Delphi OpenGL Community] is providing it's own header that's permanently updated to provide steady support for new OpenGL features and functionality. This makes updating to a new header version easily (usually backwards compatibility is preserved), and it's even possible to use the header with other pascal compilers like Freepascal.&lt;br /&gt;
&lt;br /&gt;
It includes all OpenGL functions (currently up-to and including OpenGL 3.0) as well as all GLU ('''OpenGL Utility Libary''') functions and supports all ARB, EXT, NV and ATI extensions. It also includes additional, though lesser common extensions from other vendors like Apple, HP and SGI.&lt;br /&gt;
&lt;br /&gt;
A special feature of this header are boolean variables for each included extensions that are flagged upon initialisation (those boolean vars carry the same as their corresponding extensions), so you can quickly check wether an extension is support or not (instead of checking the strings returned by [[glGetString/en]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Licence/Terms of use==&lt;br /&gt;
The '''dglOpenGL.pas''' is distributed unter the terms and conditions of the '''Mozilla Public License Version 1.1'''. You can grab a copy of that licence [http://www.mozilla.org/MPL/MPL-1.1.html here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;The contents of the dglOpenGL.pas are used with permission, subject to&amp;lt;br&amp;gt;&lt;br /&gt;
the Mozilla Public License Version 1.1 (the &amp;quot;License&amp;quot;); you may&amp;lt;br&amp;gt;&lt;br /&gt;
not use this file except in compliance with the License. You may&amp;lt;br&amp;gt;&lt;br /&gt;
obtain a copy of the License at&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mozilla.org/MPL/MPL-1.1.html&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Software distributed under the License is distributed on an&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;AS IS&amp;quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or&amp;lt;br&amp;gt;&lt;br /&gt;
implied. See the License for the specific language governing&amp;lt;br&amp;gt;&lt;br /&gt;
rights and limitations under the License.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==.NET support==&lt;br /&gt;
Due to lack of interest, .NET support has been removed as of header version 2.1!&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|The .Net header won't be developed any further, but reported errors may be fixed. So new OpenGL functionality can only be found in the normal header.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Initializing function pointers (crucial)==&lt;br /&gt;
Along with the removal of .NET support, support for loading methods dynamically has also been removed and is no longer possible with the standard header. So it's crucial to call either '''AtivateRenderingContext''' or '''ReadExtensions''' alongside with '''ReadImplementationProperties''' in your application before accessing any of the OpenGL functions. Otherwise you'll likely be prompted with an access violation at address 0x00000000. &lt;br /&gt;
&lt;br /&gt;
''So if you get such an access violation please check if you called the above functions!''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example for '''initializing''' the OpenGL function pointers (''needs to be called before you access any OpenGL functions'') :&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure OpenGLInit;&lt;br /&gt;
 begin&lt;br /&gt;
 InitOpenGL; // Don't forget, or first gl-Call will result in an access violation!&lt;br /&gt;
 MyDC := GetDC(...);&lt;br /&gt;
 MyRC := CreateRenderingContext(...);&lt;br /&gt;
 ActivateRenderingContext(MyDC, MyRC); // Necessary, will also load function pointers for all extension&lt;br /&gt;
 ...&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example for '''finishing''' the OpenGL render context (''should be called before quitting your application'') :&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure OpenGLFinish;&lt;br /&gt;
 begin&lt;br /&gt;
 DeactivateRenderingContext; // Deactivates the current context&lt;br /&gt;
 wglDeleteContext(myRC);&lt;br /&gt;
 ReleaseDC(Handle, myDC);&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL.zip Current dglOpenGL.pas] (Supports ''OpenGL 3.0'', works with Delphi 4 and up and Freepascal))'''&lt;br /&gt;
&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL_net.zip Last dglOpenGL.pas wit .NET support] (Supports ''OpenGL 2.1'')'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''For Delphi 3 users :'''&lt;br /&gt;
''[[Benutzer:Mars|Mars]] has posted a version of the dglOpenGL.pas that will work with Delphi 3, you can get it here :&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.delphigl.com/forum/viewtopic.php?p=26697#25642 dglOpenGL.pas for Delphi 3] &amp;lt;br&amp;gt;&lt;br /&gt;
''(You need to be registered on the forums to download it)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''There is also an inofficial version of this [http://www.delphigl.com/forum/viewtopic.php?t=4216 headers for C++].''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
{{dglOpenGL_History}}&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23135</id>
		<title>dglOpenGL.pas/en</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23135"/>
				<updated>2009-03-19T17:12:52Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, especially as it lacks most of OpenGL's current functionality.'''''}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=The DelphiGL header=&lt;br /&gt;
So to compensate for the flaws of the outdated and buggy default header that is shipped with Delphi, the [http://www.delphigl.com (german) Delphi OpenGL Community] is providing it's own header that's permanently updated to provide steady support for new OpenGL features and functionality. This makes updating to a new header version easily (usually backwards compatibility is preserved), and it's even possible to use the header with other pascal compilers like Freepascal.&lt;br /&gt;
&lt;br /&gt;
It includes all OpenGL functions (currently up-to and including OpenGL 3.0) as well as all GLU ('''OpenGL Utility Libary''') functions and supports all ARB, EXT, NV and ATI extensions. It also includes additional, though lesser common extensions from other vendors like Apple, HP and SGI.&lt;br /&gt;
&lt;br /&gt;
A special feature of this header are boolean variables for each included extensions that are flagged upon initialisation (those boolean vars carry the same as their corresponding extensions), so you can quickly check wether an extension is support or not (instead of checking the strings returned by [[glGetString/en]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Licence/Terms of use==&lt;br /&gt;
The '''dglOpenGL.pas''' is distributed unter the terms and conditions of the '''Mozilla Public License Version 1.1'''. You can grab a copy of that licence [http://www.mozilla.org/MPL/MPL-1.1.html here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;The contents of the dglOpenGL.pas are used with permission, subject to&amp;lt;br&amp;gt;&lt;br /&gt;
the Mozilla Public License Version 1.1 (the &amp;quot;License&amp;quot;); you may&amp;lt;br&amp;gt;&lt;br /&gt;
not use this file except in compliance with the License. You may&amp;lt;br&amp;gt;&lt;br /&gt;
obtain a copy of the License at&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mozilla.org/MPL/MPL-1.1.html&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Software distributed under the License is distributed on an&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;AS IS&amp;quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or&amp;lt;br&amp;gt;&lt;br /&gt;
implied. See the License for the specific language governing&amp;lt;br&amp;gt;&lt;br /&gt;
rights and limitations under the License.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==.NET support==&lt;br /&gt;
Due to lack of interest, .NET support has been removed as of header version 2.1!&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|The .Net header won't be developed any further, but reported errors may be fixed. So new OpenGL functionality can only be found in the normal header.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Initializing function pointers (crucial, see readme)==&lt;br /&gt;
Along with the removal of .NET support, support for loading methods dynamically has also been removed and is no longer possible with the standard header. So it's crucial to call either ''AtivateRenderingContext'' or ''ReadExtensions'' alongside with ''ReadImplementationProperties'' in your application before accessing any of the OpenGL functions. Otherwise you'll likely be prompted with an access violation at address 0x00000000. &lt;br /&gt;
&lt;br /&gt;
''So if you get such an access violation please check if you called the above functions!''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
&amp;lt;pascal&amp;gt;Version 1.0   - Initial Release&lt;br /&gt;
&lt;br /&gt;
Version 1.1   - Added PPointer in Tpyessection for compatiblity with Delphi&lt;br /&gt;
                versions lower than 7                                    (SW)&lt;br /&gt;
              - Added a function named RaiseLastOSError including a comment&lt;br /&gt;
                on how to make it run under Delphi versions lower than 7 (SW)&lt;br /&gt;
              - Added some data types according to the GL-Syntax         (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.2   - Fixed some problems with getting the addresses of some&lt;br /&gt;
                Extensions (e.g. glTexImage3D) where the EXT/ARB did work&lt;br /&gt;
                but not the core-functions                               (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.3   - A second call to ReadimplementationProperties won't&lt;br /&gt;
                revert to the default libs anymore                       (MW)&lt;br /&gt;
              - Libraries now will be released if necessary              (MW)&lt;br /&gt;
&lt;br /&gt;
Version 1.3a  - Small fixes for glSlang-functions                        (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.3b  - Fixed a small bug with GL_ARB_shader_objects, that lead&lt;br /&gt;
                lead to that extension not loaded correctly              (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.3c  - More GL 1.5 compliance by FOG_COORD_xx and&lt;br /&gt;
                ARB-less VBO and occlusion query routines                (MW)&lt;br /&gt;
&lt;br /&gt;
Version 1.3d  - Fixed linebreaks (should now be corrected under D5)      (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.4   - Changed header to correspond to the OpenGL-Shading&lt;br /&gt;
              - Language specification 1.10 :&lt;br /&gt;
                 - Added new GL_SAMPLER_*-Constants&lt;br /&gt;
                 - Added Constant GL_SHADING_LANGUAGE_VERSION_ARB&lt;br /&gt;
                 - Added Constant GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB&lt;br /&gt;
              - Added Constant GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB    (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.4a  - Fixed a missing stdcall for glBindAttribLocationARB      (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.4b  - Fixed declaration for glUniform*(f/i)vARB (added count)  (MW)&lt;br /&gt;
              - glCompileShaderARB changed from function to procedure    (MW)&lt;br /&gt;
&lt;br /&gt;
Version 1.5   - Added support for FreePascal                             (BR)&lt;br /&gt;
              - Added type TGLVectorf3/TGLVector3f                       (SW)&lt;br /&gt;
&lt;br /&gt;
Version 1.6   - Added Extension GL_EXT_framebuffer_object                (SX)&lt;br /&gt;
&lt;br /&gt;
Version 1.7   - Added Extension GL_ARB_fragment_program_shadow           (SX)&lt;br /&gt;
              - Added Extension GL_ARB_draw_buffers                      (SX)&lt;br /&gt;
              - Added Extension GL_ARB_texture_rectangle                 (SX)&lt;br /&gt;
              - Added Extension GL_ARB_color_buffer_float                (SX)&lt;br /&gt;
              - Added Extension GL_ARB_half_float_pixel                  (SX)&lt;br /&gt;
              - Added Extension GL_ARB_texture_float                     (SX)&lt;br /&gt;
              - Added Extension GL_ARB_pixel_buffer_object               (SX)&lt;br /&gt;
              - Added Extension GL_EXT_depth_bounds_test                 (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_mirror_clamp              (SX)&lt;br /&gt;
              - Added Extension GL_EXT_blend_equation_separate           (SX)&lt;br /&gt;
              - Added Extension GL_EXT_pixel_buffer_object               (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_compression_dxt1          (SX)&lt;br /&gt;
              - Added Extension GL_NV_fragment_program_option            (SX)&lt;br /&gt;
              - Added Extension GL_NV_fragment_program2                  (SX)&lt;br /&gt;
              - Added Extension GL_NV_vertex_program2_option             (SX)&lt;br /&gt;
              - Added Extension GL_NV_vertex_program3                    (SX)&lt;br /&gt;
&lt;br /&gt;
Version 1.8   - Added explicit delegate type definitions                 (LM)&lt;br /&gt;
              - Added .Net 1.1 Support                                   (LM)&lt;br /&gt;
              - Added .Net overloaded functions                          (LM)&lt;br /&gt;
              - Added delayed extension loading and stubs                (LM)&lt;br /&gt;
              - Added automatic InitOpenGL call in CreateRenderingContext(LM)&lt;br /&gt;
              - Added extra Read_* function                              (LM)&lt;br /&gt;
&lt;br /&gt;
Version 2.0   - fixed some Problem with version string and damn drivers.&lt;br /&gt;
                String 1.15 identified as OpenGL 1.5 not as OpenGL 1.1   (SX)&lt;br /&gt;
              - Removed unexisting extension GL_ARB_texture_mirror_repeat(SX)&lt;br /&gt;
              - Added Extension WGL_ARB_pixel_format_float               (SX)&lt;br /&gt;
              - Added Extension GL_EXT_stencil_clear_tag                 (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_rectangle                 (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_edge_clamp                (SX)&lt;br /&gt;
              - Some 1.5 Core Consts added (now completed)               (SX)&lt;br /&gt;
              - gluProject need pointer for not .net                     (SX)&lt;br /&gt;
              - gluUnProject need pointer for not .net                   (SX)&lt;br /&gt;
              - wglUseFontOutlines* need pointer for not .net            (SX)&lt;br /&gt;
              - wglSwapMultipleBuffers need pointer for not .net         (SX)&lt;br /&gt;
              - Bug with wglGetExtensionsStringEXT removed&lt;br /&gt;
                different type for .net                                  (SX)&lt;br /&gt;
              - Added OpenGL 2.0 Core                                    (SX)&lt;br /&gt;
&lt;br /&gt;
Version 2.0.1 - fixed some problems with glGetActiveAttrib in 2.0 Core   (SX)&lt;br /&gt;
              - fixes some problems with gluProject                      (SX)&lt;br /&gt;
              - fixes some problems with gluUnProject                    (SX)&lt;br /&gt;
              - fixes some problems with gluTessVertex                   (SX)&lt;br /&gt;
              - fixes some problems with gluLoadSamplingMatrices         (SX)&lt;br /&gt;
&lt;br /&gt;
Version 2.1   - Removed .NET Support                                     (SX)&lt;br /&gt;
              - Better support for Linux                                 (SX)&lt;br /&gt;
              - Better Codeformation                                     (SX)&lt;br /&gt;
              - Added some more Vector/Matrix types                      (SX)&lt;br /&gt;
              - Added OpenGL 2.1 Core                                    (SX)&lt;br /&gt;
              - Added Extension GL_EXT_packed_depth_stencil              (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_sRGB                      (SX)&lt;br /&gt;
              - Added Extension GL_EXT_framebuffer_blit                  (SX)&lt;br /&gt;
              - Added Extension GL_EXT_framebuffer_multisample           (SX)&lt;br /&gt;
              - Added Extension GL_EXT_timer_query                       (SX)&lt;br /&gt;
              - Added Extension GL_EXT_gpu_program_parameters            (SX)&lt;br /&gt;
              - Added Extension GL_EXT_bindable_uniform                  (SX)&lt;br /&gt;
              - Added Extension GL_EXT_draw_buffers2                     (SX)&lt;br /&gt;
              - Added Extension GL_EXT_draw_instanced                    (SX)&lt;br /&gt;
              - Added Extension GL_EXT_framebuffer_sRGB                  (SX)&lt;br /&gt;
              - Added Extension GL_EXT_geometry_shader4                  (SX)&lt;br /&gt;
              - Added Extension GL_EXT_gpu_shader4                       (SX)&lt;br /&gt;
              - Added Extension GL_EXT_packed_float                      (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_array                     (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_buffer_object             (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_compression_latc          (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_compression_rgtc          (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_integer                   (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_shared_exponent           (SX)&lt;br /&gt;
              - Added Extension GL_NV_depth_buffer_float                 (SX)&lt;br /&gt;
              - Added Extension GL_NV_fragment_program4                  (SX)&lt;br /&gt;
              - Added Extension GL_NV_framebuffer_multisample_coverage   (SX)&lt;br /&gt;
              - Added Extension GL_NV_geometry_program4                  (SX)&lt;br /&gt;
              - Added Extension GL_NV_gpu_program4                       (SX)&lt;br /&gt;
              - Added Extension GL_NV_parameter_buffer_object            (SX)&lt;br /&gt;
              - Added Extension GL_NV_transform_feedback                 (SX)&lt;br /&gt;
              - Added Extension GL_NV_vertex_program4                    (SX)&lt;br /&gt;
&lt;br /&gt;
Version 3.0   - fixed some const of GL_EXT_texture_shared_exponent       (SX)&lt;br /&gt;
              - possible better support for mac                          (SX)&lt;br /&gt;
              - Added OpenGL 3.0 Core                                    (SX)&lt;br /&gt;
              - Added Extension GL_ARB_depth_buffer_float                (SX)&lt;br /&gt;
              - Added Extension GL_ARB_draw_instanced                    (SX)&lt;br /&gt;
              - Added Extension GL_ARB_framebuffer_object                (SX)&lt;br /&gt;
              - Added Extension GL_ARB_framebuffer_sRGB                  (SX)&lt;br /&gt;
              - Added Extension GL_ARB_geometry_shader4                  (SX)&lt;br /&gt;
              - Added Extension GL_ARB_half_float_vertex                 (SX)&lt;br /&gt;
              - Added Extension GL_ARB_instanced_arrays                  (SX)&lt;br /&gt;
              - Added Extension GL_ARB_map_buffer_range                  (SX)&lt;br /&gt;
              - Added Extension GL_ARB_texture_buffer_object             (SX)&lt;br /&gt;
              - Added Extension GL_ARB_texture_compression_rgtc          (SX)&lt;br /&gt;
              - Added Extension GL_ARB_texture_rg                        (SX)&lt;br /&gt;
              - Added Extension GL_ARB_vertex_array_object               (SX)&lt;br /&gt;
              - Added Extension GL_NV_conditional_render                 (SX)&lt;br /&gt;
              - Added Extension GL_NV_present_video                      (SX)&lt;br /&gt;
              - Added Extension GL_EXT_transform_feedback                (SX)&lt;br /&gt;
              - Added Extension GL_EXT_direct_state_access               (SX)&lt;br /&gt;
              - Added Extension GL_EXT_vertex_array_bgra                 (SX)&lt;br /&gt;
              - Added Extension GL_EXT_texture_swizzle                   (SX)&lt;br /&gt;
              - Added Extension GL_NV_explicit_multisample               (SX)&lt;br /&gt;
              - Added Extension GL_NV_transform_feedback2                (SX)&lt;br /&gt;
              - Added Extension WGL_ARB_create_context                   (SX)&lt;br /&gt;
              - Added Extension WGL_NV_present_video                     (SX)&lt;br /&gt;
              - Added Extension WGL_NV_video_out                         (SX)&lt;br /&gt;
              - Added Extension WGL_NV_swap_group                        (SX)&lt;br /&gt;
              - Added define DGL_TINY_HEADER to suppress automatic&lt;br /&gt;
                function loading                                         (SX)&lt;br /&gt;
              - glProcedure renamed to dglGetProcAddress and now it's&lt;br /&gt;
                visible from outside the unit to custom load functions   (SX)&lt;br /&gt;
              - dglCheckExtension added to check if an extension exists  (SX)&lt;br /&gt;
              - Read_GL_ARB_buffer_object renamed to&lt;br /&gt;
                Read_GL_ARB_vertex_buffer_object                         (SX)&lt;br /&gt;
                &lt;br /&gt;
Version 3.0.1 - fixed an problem with fpc                                (SX)&lt;br /&gt;
&lt;br /&gt;
Version 3.0.2 - fixed an problem with WGL_ARB_create_context             (SX)&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL.zip Current dglOpenGL.pas] (Supports ''OpenGL 3.0'', works with Delphi 4 and up and Freepascal))'''&lt;br /&gt;
&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL_net.zip Last dglOpenGL.pas wit .NET support] (Supports ''OpenGL 2.1'')'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''For Delphi 3 users :'''&lt;br /&gt;
''[[Benutzer:Mars|Mars]] has posted a version of the dglOpenGL.pas that will work with Delphi 3, you can get it here :&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.delphigl.com/forum/viewtopic.php?p=26697#25642 dglOpenGL.pas for Delphi 3] &amp;lt;br&amp;gt;&lt;br /&gt;
''(You need to be registered on the forums to download it)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''There is also an inofficial version of this [http://www.delphigl.com/forum/viewtopic.php?t=4216 headers for C++].''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23134</id>
		<title>dglOpenGL.pas/en</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23134"/>
				<updated>2009-03-19T15:44:59Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, especially as it lacks most of OpenGL's current functionality.'''''}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=The DelphiGL header=&lt;br /&gt;
So to compensate for the flaws of the outdated and buggy default header that is shipped with Delphi, the [http://www.delphigl.com (german) Delphi OpenGL Community] is providing it's own header that's permanently updated to provide steady support for new OpenGL features and functionality. This makes updating to a new header version easily (usually backwards compatibility is preserved), and it's even possible to use the header with other pascal compilers like Freepascal.&lt;br /&gt;
&lt;br /&gt;
It includes all OpenGL functions (currently up-to and including OpenGL 3.0) as well as all GLU ('''OpenGL Utility Libary''') functions and supports all ARB, EXT, NV and ATI extensions. It also includes additional, though lesser common extensions from other vendors like Apple, HP and SGI.&lt;br /&gt;
&lt;br /&gt;
A special feature of this header are boolean variables for each included extensions that are flagged upon initialisation (those boolean vars carry the same as their corresponding extensions), so you can quickly check wether an extension is support or not (instead of checking the strings returned by [[glGetString/en]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Licence/Terms of use==&lt;br /&gt;
The '''dglOpenGL.pas''' is distributed unter the terms and conditions of the '''Mozilla Public License Version 1.1'''. You can grab a copy of that licence [http://www.mozilla.org/MPL/MPL-1.1.html here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;The contents of the dglOpenGL.pas are used with permission, subject to&amp;lt;br&amp;gt;&lt;br /&gt;
the Mozilla Public License Version 1.1 (the &amp;quot;License&amp;quot;); you may&amp;lt;br&amp;gt;&lt;br /&gt;
not use this file except in compliance with the License. You may&amp;lt;br&amp;gt;&lt;br /&gt;
obtain a copy of the License at&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mozilla.org/MPL/MPL-1.1.html&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Software distributed under the License is distributed on an&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;AS IS&amp;quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or&amp;lt;br&amp;gt;&lt;br /&gt;
implied. See the License for the specific language governing&amp;lt;br&amp;gt;&lt;br /&gt;
rights and limitations under the License.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==.NET support==&lt;br /&gt;
Due to lack of interest, .NET support has been removed as of header version 2.1!&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|The .Net header won't be developed any further, but reported errors may be fixed. So new OpenGL functionality can only be found in the normal header.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Initializing function pointers (crucial, see readme)==&lt;br /&gt;
Along with the removal of .NET support, support for loading methods dynamically has also been removed and is no longer possible with the standard header. So it's crucial to call either ''AtivateRenderingContext'' or ''ReadExtensions'' alongside with ''ReadImplementationProperties'' in your application before accessing any of the OpenGL functions. Otherwise you'll likely be prompted with an access violation at address 0x00000000. &lt;br /&gt;
&lt;br /&gt;
''So if you get such an access violation please check if you called the above functions!''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL.zip Current dglOpenGL.pas] (Supports ''OpenGL 3.0''))'''&lt;br /&gt;
&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL_net.zip Last dglOpenGL.pas wit .NET support] (Supports ''OpenGL 2.1'')'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''For Delphi 3 users :'''&lt;br /&gt;
''[[Benutzer:Mars|Mars]] has posted a version of the dglOpenGL.pas that will work with Delphi 3, you can get it here :&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.delphigl.com/forum/viewtopic.php?p=26697#25642 dglOpenGL.pas for Delphi 3] &amp;lt;br&amp;gt;&lt;br /&gt;
''(You need to be registered on the forums to download it)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''There is also an inofficial version of this [http://www.delphigl.com/forum/viewtopic.php?t=4216 headers for C++].''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23133</id>
		<title>dglOpenGL.pas/en</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=dglOpenGL.pas/en&amp;diff=23133"/>
				<updated>2009-03-19T15:43:39Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Die Seite wurde neu angelegt: {{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, esp...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis| '''Delphi is already shipping with an OpenGL header, but that header is ''outdated and also buggy''. Therefore we ''urge everyone to NOT use that header, especially as it lacks most of OpenGL's current functionality.'''''}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=The DelphiGL header=&lt;br /&gt;
So to compensate for the flaws of the outdated and buggy default header that is shipped with Delphi, the [http://www.delphigl.com (german) Delphi OpenGL Community] is providing it's own header that's permanently updated to provide steady support for new OpenGL features and functionality. This makes updating to a new header version easily (usually backwards compatibility is preserved), and it's even possible to use the header with other pascal compilers like Freepascal.&lt;br /&gt;
&lt;br /&gt;
It includes all OpenGL functions (currently up-to and including OpenGL 3.0) as well as all GLU ('''OpenGL Utility Libary''')functions and supports all ARB, EXT, NV and ATI extensions. It also includes additional, though lesser common extensions from other vendors like Apple, HP and SGI.&lt;br /&gt;
&lt;br /&gt;
A special feature of this header are boolean variables for each included extensions that are flagged upon initialisation (those boolean vars carre the same as their corresponding extensions), so you can quickly check wether an extension is support or not (instead of checking the strings returned by [[glGetString/en]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Licence/Terms of use==&lt;br /&gt;
The '''dglOpenGL.pas''' is distributed unter the terms and conditions of the '''Mozilla Public License Version 1.1'''. You can grab a copy of that licence [http://www.mozilla.org/MPL/MPL-1.1.html here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;The contents of the dglOpenGL.pas are used with permission, subject to&amp;lt;br&amp;gt;&lt;br /&gt;
the Mozilla Public License Version 1.1 (the &amp;quot;License&amp;quot;); you may&amp;lt;br&amp;gt;&lt;br /&gt;
not use this file except in compliance with the License. You may&amp;lt;br&amp;gt;&lt;br /&gt;
obtain a copy of the License at&amp;lt;br&amp;gt;&lt;br /&gt;
http://www.mozilla.org/MPL/MPL-1.1.html&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Software distributed under the License is distributed on an&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;quot;AS IS&amp;quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or&amp;lt;br&amp;gt;&lt;br /&gt;
implied. See the License for the specific language governing&amp;lt;br&amp;gt;&lt;br /&gt;
rights and limitations under the License.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==.NET support==&lt;br /&gt;
Due to lack of interest, .NET support has been removed as of header version 2.1!&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|The .Net header won't be developed any further, but reported errors may be fixed. So new OpenGL functionality can only be found in the normal header.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Initializing function pointers (crucial, see readme)==&lt;br /&gt;
Along with the removal of .NET support, support for loading methods dynamically has also been removed and is no longer possible with the standard header. So it's crucial to call either ''AtivateRenderingContext'' or ''ReadExtensions'' alongside with ''ReadImplementationProperties'' in your application before accessing any of the OpenGL functions. Otherwise you'll likely be prompted with an access violation at address 0x00000000. &lt;br /&gt;
&lt;br /&gt;
''So if you get such an access violation please check if you called the above functions!''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL.zip Current dglOpenGL.pas] (Supports ''OpenGL 3.0''))'''&lt;br /&gt;
&lt;br /&gt;
'''[http://files.delphigl.com/download/dglOpenGL_net.zip Last dglOpenGL.pas wit .NET support] (Supports ''OpenGL 2.1'')'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''For Delphi 3 users :'''&lt;br /&gt;
''[[Benutzer:Mars|Mars]] has posted a version of the dglOpenGL.pas that will work with Delphi 3, you can get it here :&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.delphigl.com/forum/viewtopic.php?p=26697#25642 dglOpenGL.pas for Delphi 3] &amp;lt;br&amp;gt;&lt;br /&gt;
''(You need to be registered on the forums to download it)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''There is also an inofficial version of this [http://www.delphigl.com/forum/viewtopic.php?t=4216 headers for C++].''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=22834</id>
		<title>Techniken und Algorithmen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=22834"/>
				<updated>2009-03-09T19:55:19Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Sonstiges */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Artikel dieses Wiki-Abschnittes sind im Gegensatz zu den [[Tutorial]]s meist kürzer. Dafür enthalten sie mitunter sehr viel Code der direkt verwendet werden, oder als Grundlage für die eigene Arbeit dienen kann.&lt;br /&gt;
&lt;br /&gt;
== Was hier hinein gehört ==&lt;br /&gt;
Hier kommen, wie der Name vermuten lässt '''Erklärungen''' zu, in der 3D-Echtzeitprogrammierung verwendeten, '''Techniken''' hin. Z.B. verschiedene Schattentechniken, Bump-Mapping, etc.&lt;br /&gt;
&lt;br /&gt;
[[Hintergrundwissen]] gehört hier nicht rein. Sachen wie ''&amp;quot;was ist ein Tiefenpuffer und wofür ist er gut&amp;quot;'' haben hier nichts zu suchen.&amp;lt;br&amp;gt;&lt;br /&gt;
Sollte es für eine Technik/Thematik (siehe unten für Beispiel) mehrere &amp;quot;Lösungswege&amp;quot; geben, sollte eine kleine Überschrift eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr einen Technik oder Algorithmus Artikel erstellt, so solltet ihr unter den Artikel ein&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[Kategorie:Technik_oder_Algorithmus]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
stellen. Damit wird der Artikel der  [[:Kategorie:Technik_oder_Algorithmus]] zugeordnet.&lt;br /&gt;
Falls dieser Artikel nicht nur erklärt was der Begriff bedeutet, sondern auch noch eine Anleitung ist, wie man die entsprechende Technik realisiert, so könnt ihr den Artikel auch noch der Kategorie [[:Kategorie:Anleitung|Anleitung]] zuweisen.&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
=== Sammlungen ===&lt;br /&gt;
* [[Materialsammlung]] (Enthält Materialien für [[glMaterial]].)&lt;br /&gt;
* [[Shadersammlung]] (Enthält Shader.)&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Helfer ===&lt;br /&gt;
In dieser Rubrik findet sich all das, was ein OpenGL/Graphikprogrammierer immer brauch oder schnell mal zur Hand haben muss:&lt;br /&gt;
* [[Framecounter]] (Wie schnell läuft mein Programm?)&lt;br /&gt;
* [[Frameratenbegrenzung]] (Beschränken der Bildwiederholrate und sparen von CPU-Leistung und Strom)&lt;br /&gt;
* [[Texture Loader]] (Laden und verwalten von Texturen)&lt;br /&gt;
* [[Model Loader]] (Laden von Modellen die mit Programmen wie 3D Studio Max, Lightwave, Milkshape usw. erstellt wurden.)&lt;br /&gt;
* Eine Möglichkeit zum [[Text ausgeben]]&lt;br /&gt;
* [[Kamera]]&lt;br /&gt;
** [[Kamera (1)]] (Szene in drei Ebenen verschieben und drehen, jetzt mit Beispielprogramm)&lt;br /&gt;
** [[Kamera (2)]] (Kamera Source, letztes Update 1.10.2006)&lt;br /&gt;
** [[Kamera (3)]] (Für die Kamera benötigte Utilities)&lt;br /&gt;
* [[Extensionausgabe]] (Ausgabe der unterstützten Extensions und sonstiger Eigenschaften)&lt;br /&gt;
* [[Techniken_zur_Matrixinversion|Techniken zur Matrixinversion]]&lt;br /&gt;
&lt;br /&gt;
=== Mathematisches ===&lt;br /&gt;
==== Geometrie Objekte ====&lt;br /&gt;
In dieser Rubrik findet ihr Code zum erzeugen von komplexen geometrischen Objekten, denn nicht immer ist die Kapselung die z.B. eine [[Quadrik]] bietet das was man sucht. &lt;br /&gt;
&lt;br /&gt;
* [[Zweifach_Parametrisierte_Geometrie|Geometrie durch zwei Parameter]]&lt;br /&gt;
* [[Geometrie_durch_Kurven|Geometrie durch Kurven]]&lt;br /&gt;
* [[Rotationskörper]]&lt;br /&gt;
* [[Kreis]]&lt;br /&gt;
* [[Kuchenstück]]&lt;br /&gt;
* [[Kugel]]&lt;br /&gt;
* [[Scheibe]]&lt;br /&gt;
* [[Würfel]]&lt;br /&gt;
* [[Zylinder]]&lt;br /&gt;
&lt;br /&gt;
==== Rechenhilfen ====&lt;br /&gt;
* [[Matrixmultiplikation]]&lt;br /&gt;
&lt;br /&gt;
=== Licht und Schatten ===&lt;br /&gt;
Das Beleuchtungsmodell von OpenGL besitzt von Haus aus keine Möglichkeit zur Darstellung von Schatten (nicht zuletzt weil es dafür immernoch keine einheitliche Methode gibt), allerdings haben sich über die Jahre hinweg einige Techniken mehr oder weniger durchgesetzt :&amp;lt;br&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Lightmaps]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Projezierte Shadowmaps]] / [[Projezierte Textur]]en&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Volumetrische Stencilschatten]]{{excIcon}}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Silhouette]] {{icpIcon}}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Bloom(pseudo-HDR)]] {{icpIcon}}&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Statische Umgebungen ===&lt;br /&gt;
Besonders in Aussenszenen ist es oft nötig dem Betrachter den Eindruck zu vermitteln, er befinde sich in einer unendlich großen Umgebung. Da man dies jedoch schlecht über speziell dafür erstellte Geometrie lösen kann (weil das schlichtweg zu viel Aufwand und zu leistungsintensiv wäre), haben sich einige Techniken eingebürgert, mit denen man dem Betrachter eine solche unendliche Landschaft mit  wenig Geometrie und einigen Tricks vorgaugeln kann :&amp;lt;br&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Skyboxen]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Skydome]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Skysphere]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Dynamische Effekte ===&lt;br /&gt;
Das Auge ißt bekanntlich mit. Auch bei 3D Anwendungen, vor allem in der Unterhaltungsindustrie, spielen gigantische Effekte, die dem User ein &amp;quot;Ohhh&amp;quot; und &amp;quot;Ahhh&amp;quot; und vor allem &amp;quot;Wow!&amp;quot; entlocken eine immer größere Rolle. Wie man solche Effekte am besten implementiert finden Sie in den Artikeln dieses Abschnitts.&amp;lt;br&amp;gt;&lt;br /&gt;
(Befassen Sie sich zuerst mit den Grundlagen von [[Partikelsysteme|Partikelsystemen]].)&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Explosionen]] (Allseits gern gesehen. Außer in direkter Nachbarschaft)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Lichtsäulen]] (Bekannt für die magischen Momente in diversen Rollenspielen.) &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Partikelsysteme]] {{excIcon}} (Grundlage für viele Effekte) &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Natürliche Phänomene ===&lt;br /&gt;
Ziel vieler Echtzeit 3D-Anwendung (auch wenn genau der gegenteilige Trend manchmal interessant sein dürfte) ist eine zumindest optische Annäherung an die Realität, also Szenen möglichst &amp;quot;naturgetreu&amp;quot; (auch urbane Szenen können &amp;quot;naturgetreu&amp;quot; sein, auch wenn diese wenig natürlich sind) darzustellen. Dazu gehören auch natürliche Phänomene, wie z.B. realistisch spiegelndes Wasser, Wetterbedingungen (Regen, Schnee, Nebel), Feuer, etc. Oft gibt es für ein natürliches Phänomen recht fortgeschrittene Umsetzungsmöglichkeiten, manchmal liegt die Lösung aber auch recht nahe :&amp;lt;br&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Prozeduale Bäume|Bäume]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Blitz]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Feuer]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Himmel]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Nebel]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Staub]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Wasser]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Wettereffekt]]e (Regen, Schnee)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Wolken]] (als Ergänzung zu den statischen Umgebungen)&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Raumunterteilungstechniken ===&lt;br /&gt;
Moderne 3D-Anwendungen müssen immer größere und komplexere 3D-Umgebungen darstellen, wobei oft jedoch große Teile eben dieser nicht sichtbar sind, aber ohne entsprechende Optimierungen trotzdem über den Datenbus geschoben (und von der Grafikkarte geclippt) werden müssen. Deshalb finden diverse Raumunterteilungstechniken (die u.a. aus anderen Bereichen stammen) in modernen 3D-Programmen Anwendung :&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[BSP-Bäume]] (Binary Space Partitioning = Binäre Raumunterteilung)&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt;[[Octree]]s (Dreidimensionale Erweiterung eines Quadtrees)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Portal]]e (Logische Sichtbegrenzung an Durchgängen)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[PVS]] (Potentially Visible Sets = Mögliche sichtbare Sets)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Terrain Darstellung ===&lt;br /&gt;
In vielen 3D Anwendungen, vom Flugsimulator über Egoshooter bis zum Strategiespiel, muss die Umgebung visualisiert werden. Welche Techniken bei der Speicherung (siehe auch '''Raumunterteilungstechniken'''), Bildaufbau und Texturierung zum Einsatz kommen, findet ihr hier:&amp;lt;br&amp;gt;&lt;br /&gt;
:'''[[LOD|Level of Detail]] Algorithmen für Landschaften'''&lt;br /&gt;
&lt;br /&gt;
*[[VDPM]] ('''V'''iew-'''D'''ependent '''P'''rogressive '''M'''eshes)&lt;br /&gt;
*[[ROAM]] ('''R'''eal-time '''O'''ptimally '''A'''dapting '''M'''eshes)&lt;br /&gt;
*[[Tutorial_Terrain3|Röttger Algorithmus]]&lt;br /&gt;
*[[Geometrical Mipmapping]]&lt;br /&gt;
*[[VIPMs]] ('''V'''iew '''I'''ndependent '''P'''rogressive '''M'''eshe'''s''')&lt;br /&gt;
&lt;br /&gt;
:'''Texturierung'''&lt;br /&gt;
&lt;br /&gt;
*[[Texture Splatting]] (Kombination von Texturen mittels [[Blenden|Blending]] und [[Multitexturing]])&lt;br /&gt;
*[[Texture Backing]] (Dynamisches erstellen von Texturen)&lt;br /&gt;
&lt;br /&gt;
=== Prozeduale Grafiken ===&lt;br /&gt;
Prozeduale Grafiken werden häufig verwendet um&lt;br /&gt;
*eine vielfältige Umgebung zu gewährleisten&lt;br /&gt;
*Speicherplatz auf der Festplatte zu sparen&lt;br /&gt;
*den Grafikern die Arbeit zu erleichtern (und teilweise sogar erst zu ermöglichen)&lt;br /&gt;
Die Algorithmen und Möglichkeiten die sich dabei bieten sind hier aufgelistet:&amp;lt;br&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Perlin Noise]] {{excIcon}} (Algorithmus für Texturen, Landschaft und vieles mehr)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[L-Systems]] (aus wenig mach viel, Landschaftsgenerierung, Baumgenerierung, ...)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Fault Formation]] (primär zur Landschaftsgenerierung)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Prozeduale Landschaft]] (Spezielle Hinweise und Techniken zur Landschaftsgenerierung&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Midpoint Displacement]] (primär zur Landschaftsgenerierung)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Hügel_Algorithmen]] (primär zur Landschaftsgenerierung)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Prozeduale Bäume]] (Techniken und Algorithmen speziell zur Baumgenerierung)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Prozeduale Texturen]] (Spezielle Hinweise zu Wasser, Lava und ähnliches)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pathfinding ===&lt;br /&gt;
Pathfinding ist einer der grundlegenden Bereiche der Künstlichen Intelligenz, und aus diesem Grund für Spiele mit Computergegnern meistens unumgänglich.&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Tiefensuche]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Breitensuche]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[A-Stern]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Dijkstra]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Floyd Warshall]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Navigation Meshes]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;[[Pathfinding-Level of Detail]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sonstiges ===&lt;br /&gt;
&lt;br /&gt;
* [[Bilder als Ressourcen]] speichern und laden&lt;br /&gt;
* [[Blenderscript|Exportscript für Blender]]&lt;br /&gt;
* [[Blenderexporter|Blenderexport ausführliche Anleitung]]&lt;br /&gt;
* [[GUI_Leitfaden|Leitfaden Graphisches Nutzerinterface]]&lt;br /&gt;
* [[Interpolation]]&lt;br /&gt;
* [[Lokalisierung]]&lt;br /&gt;
* [[Pixelweise Bildbearbeitung]]&lt;br /&gt;
* [[Physik und 3D|Wie verbinde ich Physikberechnung und 3D Rendering?]]&lt;br /&gt;
* [[Screenshot]]s von OpenGL Ausgaben&lt;br /&gt;
* [[Tesselierung|Polygone tesselieren]]&lt;br /&gt;
* [[TGA Bilder laden]]&lt;br /&gt;
* [[Zielen auf bewegte Gegner]]&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
Weitere Links zum Thema &amp;quot;Effekte unter OpenGL&amp;quot; findet ihr in der [[Link]]-Sammlung unter [[Link#Effekte_und_Techniken_mit_OpenGL|Effekte und Techniken mit OpenGL]].&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22833</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22833"/>
				<updated>2009-03-09T19:51:18Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Keine Unterscheidung zwischen Fenster und GUI===&lt;br /&gt;
In einer frühen Version der GUI für Projekt &amp;quot;W&amp;quot; wurde noch zwischen einer Vollbild-GUI (z.B. Hauptmenü, Spielendeschirm) und den normalen Fenstern unterschieden. So etwas soltle man nicht machen, und in der aktuellen Version der GUI für PjW nutzen auch Vollbild-GUI Schirme ein Fenster als Grundlage. Allerdings ist dieses Fenster nicht bewegbar, nicht sichtbar und immer so groß wie der Viewport des Spiels. Dadurch spart man sich viel Arbeit, da man ansonsten vieles doppelt implementieren muss. Also von Anfang an gleich alles auf Fensterbasis entwickeln.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Unterstützung für mehrere Sprachen===&lt;br /&gt;
Hier sind natürlich nicht Programmiersprachen gemeint, sondern gesprochene Sprachen. Auch wenn man sein Projekt erstmal nur in einer Sprache veröffentlichen will sollte man trotzdem Unterstützung für mehrere Sprachen von Anfang ein einplanen. So etwas direkt einzubinden ist kaum Aufwand, dies später nachzurüsten kann aber durchaus in Arbeit ausarten. Einfachste Methode (die ich auch in Projekt &amp;quot;W&amp;quot; verwende) ist es für alle benötigten Elemente (z.B. die Beschriftung eines Labels oder Buttons) statt eines Strings ein ''String array'' zu verwenden (eine ''TStringList'' wäre hier zu aufwendig). Wenn man dann auch noch ein erweiterbares Dateiformat wie XML verwendet, ist es mit dieser einfachen Methode kein Problem später weitere Sprachen hinzuzufügen. Zur Ausgabe von Text o.ä. greift man dann nicht mehr direkt auf die Variable zu, sondern nutzt eine Funktion (z.B. ''TGLLabel.GetCaption'') die dann je nach eingestellter Sprache (in Projekt &amp;quot;W&amp;quot; wird die eingestellte Sprache in einer Eigenschaft von ''TLocalizationDB'' gespeichert, einer Klasse die sich um das Laden und wechseln der Sprachen kümmert) die passende Beschriftung zurückgibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nachrichtenbehandlung (aka ''Messagehandling'')===&lt;br /&gt;
In diesem Punkt darf man sich ruhig ein wenig an Windows orientieren, allerdings nicht zu sehr, eine Nachrichtenbehandlung für die eigene GUI muss selten so komplex sein wie eines Betriebssystems. Denn die eigene GUI muss nur auf die Ereignisse einer einzelnen Anwendung reagieren, und nicht auf dutzende geöffnete Anwendungen verteilen. Daher ist diese recht einfach zu implementieren. Im Normalfall sollte es reichen wenn eine Nachricht an alle offenen Fenster weitergereicht wird (in Projekt &amp;quot;W&amp;quot; geschieht dies über einen Callback, siehe weiter unten). Wenn also ein Button gedrückt wird, erzeugt dieser eine Nachricht die dann an einen globalen Verteiler (''TGUI.GlobalWindowMessage'') übergeben wird der diese dann an die Fenster weiterleitet. Innerhalb des entsprechenden Callbacks (''TGLWindow.MessageCallBack'') wird dann überpfüft ob die Nachricht für dieses Fenster vorgesehen ist und wenn ja, wird diese auch hier verarbeitet. Klingt sehr einfach und ist es auch. Mehr wird man aber selten benötigen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Callbacks verwenden===&lt;br /&gt;
Besonders Anfänger haben gerne mal Probleme mit sog. ''Callbacks'', aber wer etwas fortgeschritten ist lernt diese zu schätzen, tragen sie doch stark zur Flexibilität einer Programmiersprache bei und erlauben es z.B. Zirkelbezüge (zwei Units die gegenseitig auf sich zugreifen wollen) zu umschiffen. Für größere Projekte also fast unumgänglich, und in einer GUI für ein Spiel quasi ein Muss. Warum? Weil man nur so die benötigte (optische) Flexibiliät bekommt die man benötigt, denn nicht immer reicht es wenn man z.B. eine Iconbox (in meinem Falle ein Objekt ähnlich einer Listbox, nur mit Texturen statt Einträgen) einfach alle Texturen rendern lässt. In bestimmten Fällen will man evtl. noch zusätzliche Informationen anzeigen. Ein gutes Beispiel ist die Liste der Spione auf dem Screenshot am Anfang des Artikels. Dahinter steckt eine ''TGLIconBox'' die normalerweise nur die Personalbilder darstellen würde. Dank eines Callbacks der (wenn zugewiesen) bei jedem Rendern eines solchen Bildes aufgerufen wird kann man aber bequem mehr Informationen rendern (Erfahrung, Zusatzsymbole, Name). Ohne Callbacks wäre das kaum, bzw. nur über Umwege machbar. Aber nicht nur für optische Anpassungen sollten Callback verwendet werden, sondern auch um auf Ereignisse zu reagieren. In Projekt &amp;quot;W&amp;quot; hat jedes Fenster einen festen Satz von Callbacks :&lt;br /&gt;
&amp;lt;pascal&amp;gt; TGLWindow = class&lt;br /&gt;
 ...&lt;br /&gt;
 BeforeItemDrawCallBack : TGLWindowContentCallBack;      // Wird aufgerufen bevor GUI Elemente gezeichnet werden&lt;br /&gt;
 AfterItemDrawCallBack  : TGLWindowContentCallBack;      // Wird aufgerufen nachdem alle GUI Elemente gezeichnet wurden&lt;br /&gt;
 MessageCallBack        : TGLWindowGUIMessageCallBack;   // Verarbeitet Nachrichten (also z.B. die Nachricht die von einem gedrückten Button gesendet wird)&lt;br /&gt;
 UpdateCallBack         : TGLWindowUpdateCallBack;       // Wird aufgerufen wenn der Inhalt des Fensters aktualisiert werden soll, i.d.R. durch einen globalen Aufruf (''TGLGUI.GlobalWindowUpdate'')&lt;br /&gt;
 ...&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Gruppensichtbarkeit===&lt;br /&gt;
In einer komplexen GUI wird man irgendwann bestimmte Objekte ein- bzw. ausblenden müssen. Ein Beispiel aus Projekt &amp;quot;W&amp;quot; : Im Spionageschirm können Spion unterschiedlichen Typs angezeigt werden, und je nach gewähltem Spiontyp müssen z.B. diverse Panels und Labels gezeigt oder auch verstekct werden. In der GUI von Projekt &amp;quot;W&amp;quot; hat daher jedes GUI-Element eine Eigenschaft namens ''GroupID'' über dass die Elemente bestimmten Sichtbarkeitsgruppen zugeordnet werden. Die GUI bietet dann eine Funktion namens ''ToggleVisibility'' mit der man ganze Gruppen ein- und ausblenden kann. Leicht zu implementieren und äusserst praktisch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Echtzeitvorschau===&lt;br /&gt;
Die vermutlich wichtigste Komponente des Editors. Sie stellt das aktuelle geladene Fenster bzw. die GUI so dar wie man es im Spiel sieht. Bei Bedarf werden natürlich noch ein paar Dinge eingeblendet, wie z.B. Debuglinien oder Auswahlrahmen. Für den Editor muss man hier noch auf Klicks reagieren um Objekte auszuwählen, diese Funktionalität sollte man aber direkt in der GUI verankern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Eigenschaftseditor===&lt;br /&gt;
Natürlich muss man die Eigenschaften der gewählten GUI-Elemente irgendwie verändern können. Ähnlich wie in Delphi bietet sich hier ein ''TValueListEditor'' an, der sehr flexibel ist. Neben einfachen Werteingaben kann man hier auch Dropdownlisten für vorgegebene Werte, oder sogar Buttons einfügen die dann einen externen Editor (z.B. für die Punkte einer Region oder den Text eines Memos) aufrufen lässt.&lt;br /&gt;
Neben dem Eigenschaftseditor für GUI-Elemente benötigt man natürlich auch einen für das aktuelle Fenster. Hier kann man dann Fenstertitel, Größe und ein paar andere Kleinigkeiten anpassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Möglichkeit direkt neue GUI-Elemente zu erstellen===&lt;br /&gt;
Hier gibts nicht viel zu erzählen. Ein GUI-Editor wäre natürlich kaum nützlich wenn man keine neuen GUI-Elemente hinzufügen könnte. Wie man das präsentiert ist dem persönlichen Geschmack überlassen. Mir reicht eine einfache Liste mit allen verfügbaren GUI-Elemente, schöner wären natürlich Icons wie in Delphi. Die Implementation ist hier auch recht einfach, denn die GUI an sich sollte bereits eine Möglichkeit bieten einem Fenster neue Elemente hinzuzufügen (z.B. ''TGLWindow.AddButton(...)''). Dann wird im Editor letztendlich nur (je nach ausgewählten Element) die entsprechende Funktion aus der GUI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Umschalten zwischen Editor- und Ingame-GUI===&lt;br /&gt;
Eher von praktischem Nutzen ist die Möglichkeit zwischen Editor und der Ingame-GUI umzuschalten. So kann man im Editor schnell sehen wie die GUI im Spiel letztendlich aussieht und reagiert. Denn während im Editormodus i.d.R. alle Elemente angezeigt werden gibt es im Ingame-Modus z.B. graphische Buttons die nur beim Mouseover angezeigt werden sollen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Debugmodus===&lt;br /&gt;
Wo würde der Debugmodus besser reinpassen als direkt in den Editor? Im Spiel würde er kaum Sinn machen, denn besonders bei Spielen die lange Laden und komplex sind würde es immer ewig dauern bis man den Debugmodus zu Gesicht bekäme. Daher sollte der Editor eine Möglichkeit bieten eben diesen Modus aktivieren zu können. So kann man schnell sehen ob bzw. was nicht stimmt. In der GUI für Projekt &amp;quot;W&amp;quot; ist dieser Modus besonders für das ''TGLSkinnedControl'' sehr nützlich, so kann man direkt sehen wenn z.B. der polygonale Selektionsbereich an der falschen Stelle liegt.&lt;br /&gt;
[[Bild:wiki_gui_editor_debug.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Gruppensichtbarkeit===&lt;br /&gt;
Die entsprechende Funktionalität ist ja bereits in der GUI selbst vorhanden, und da man im Editor durchaus mehrere Objekte direkt an der selben Stelle liegen hat (siehe Beispiel mit den verschiedenen Spiontypen) ist eine Möglichkeit die Gruppensichtbarkeit einzustellen sehr praktisch. Hierzu iteriert man am besten durch alle GUI-Elemente des Fensters und packt alle Gruppen in eine ''TCheckListBox''. Dort kann man dann per Haken wählen welche Gruppen gerade sichtbar sein sollen. Am besten sollte man direkt in der GUI einen Zeiger auf diese ''TGLCheckListBox'' unterbringen, und beim Rendern in einem Fenster prüft man auf den Editiermodus (Flag in der GUI-Unit) und checkt dann gegen diese Liste welche GUI-Elemente gerendert werden sollen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Mehrfachauswahl===&lt;br /&gt;
Der Editor sollte die Möglichkeit bieten mehrere GUI-Elemente gleichzetig auswählen zu können. So kann man mehrere Objekte gleichzeitig bearbeiten. Hier muss man dann natürlich Funktionalität implementieren die die geimeinsamen Eigenschaften der gewählten GUI-Elemente ermittelt und diese dann in den Objekteditor schreibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Kleinigkeiten===&lt;br /&gt;
Damit sind weniger wichtige Funktionen gemeint die das Arbeiten mit dem GUI-Editor erleichtern oder erweitern. Im Falle des Editors für Projekt &amp;quot;W&amp;quot; gibt es da einige kleine Helfer :&lt;br /&gt;
*Hintergrundbild laden (sehr pratkisch um zu sehen wie die GUI auf Spielhintergrund aussieht)&lt;br /&gt;
*GUI-Elemente sortieren (sortiert die Elemente der GUI nach Z-Wert neu, u.a. nützlich wenn man Alphatestprobleme hat)&lt;br /&gt;
*GUI-Elemente nach Gruppe auswählen (wenn man z.B. ne ganze Objektgruppe auf einmal verschieben oder anpassen will)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22832</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22832"/>
				<updated>2009-03-09T19:23:03Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Der GUI-Editor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Keine Unterscheidung zwischen Fenster und GUI===&lt;br /&gt;
In einer frühen Version der GUI für Projekt &amp;quot;W&amp;quot; wurde noch zwischen einer Vollbild-GUI (z.B. Hauptmenü, Spielendeschirm) und den normalen Fenstern unterschieden. So etwas soltle man nicht machen, und in der aktuellen Version der GUI für PjW nutzen auch Vollbild-GUI Schirme ein Fenster als Grundlage. Allerdings ist dieses Fenster nicht bewegbar, nicht sichtbar und immer so groß wie der Viewport des Spiels. Dadurch spart man sich viel Arbeit, da man ansonsten vieles doppelt implementieren muss. Also von Anfang an gleich alles auf Fensterbasis entwickeln.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Unterstützung für mehrere Sprachen===&lt;br /&gt;
Hier sind natürlich nicht Programmiersprachen gemeint, sondern gesprochene Sprachen. Auch wenn man sein Projekt erstmal nur in einer Sprache veröffentlichen will sollte man trotzdem Unterstützung für mehrere Sprachen von Anfang ein einplanen. So etwas direkt einzubinden ist kaum Aufwand, dies später nachzurüsten kann aber durchaus in Arbeit ausarten. Einfachste Methode (die ich auch in Projekt &amp;quot;W&amp;quot; verwende) ist es für alle benötigten Elemente (z.B. die Beschriftung eines Labels oder Buttons) statt eines Strings ein ''String array'' zu verwenden (eine ''TStringList'' wäre hier zu aufwendig). Wenn man dann auch noch ein erweiterbares Dateiformat wie XML verwendet, ist es mit dieser einfachen Methode kein Problem später weitere Sprachen hinzuzufügen. Zur Ausgabe von Text o.ä. greift man dann nicht mehr direkt auf die Variable zu, sondern nutzt eine Funktion (z.B. ''TGLLabel.GetCaption'') die dann je nach eingestellter Sprache (in Projekt &amp;quot;W&amp;quot; wird die eingestellte Sprache in einer Eigenschaft von ''TLocalizationDB'' gespeichert, einer Klasse die sich um das Laden und wechseln der Sprachen kümmert) die passende Beschriftung zurückgibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nachrichtenbehandlung (aka ''Messagehandling'')===&lt;br /&gt;
In diesem Punkt darf man sich ruhig ein wenig an Windows orientieren, allerdings nicht zu sehr, eine Nachrichtenbehandlung für die eigene GUI muss selten so komplex sein wie eines Betriebssystems. Denn die eigene GUI muss nur auf die Ereignisse einer einzelnen Anwendung reagieren, und nicht auf dutzende geöffnete Anwendungen verteilen. Daher ist diese recht einfach zu implementieren. Im Normalfall sollte es reichen wenn eine Nachricht an alle offenen Fenster weitergereicht wird (in Projekt &amp;quot;W&amp;quot; geschieht dies über einen Callback, siehe weiter unten). Wenn also ein Button gedrückt wird, erzeugt dieser eine Nachricht die dann an einen globalen Verteiler (''TGUI.GlobalWindowMessage'') übergeben wird der diese dann an die Fenster weiterleitet. Innerhalb des entsprechenden Callbacks (''TGLWindow.MessageCallBack'') wird dann überpfüft ob die Nachricht für dieses Fenster vorgesehen ist und wenn ja, wird diese auch hier verarbeitet. Klingt sehr einfach und ist es auch. Mehr wird man aber selten benötigen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Callbacks verwenden===&lt;br /&gt;
Besonders Anfänger haben gerne mal Probleme mit sog. ''Callbacks'', aber wer etwas fortgeschritten ist lernt diese zu schätzen, tragen sie doch stark zur Flexibilität einer Programmiersprache bei und erlauben es z.B. Zirkelbezüge (zwei Units die gegenseitig auf sich zugreifen wollen) zu umschiffen. Für größere Projekte also fast unumgänglich, und in einer GUI für ein Spiel quasi ein Muss. Warum? Weil man nur so die benötigte (optische) Flexibiliät bekommt die man benötigt, denn nicht immer reicht es wenn man z.B. eine Iconbox (in meinem Falle ein Objekt ähnlich einer Listbox, nur mit Texturen statt Einträgen) einfach alle Texturen rendern lässt. In bestimmten Fällen will man evtl. noch zusätzliche Informationen anzeigen. Ein gutes Beispiel ist die Liste der Spione auf dem Screenshot am Anfang des Artikels. Dahinter steckt eine ''TGLIconBox'' die normalerweise nur die Personalbilder darstellen würde. Dank eines Callbacks der (wenn zugewiesen) bei jedem Rendern eines solchen Bildes aufgerufen wird kann man aber bequem mehr Informationen rendern (Erfahrung, Zusatzsymbole, Name). Ohne Callbacks wäre das kaum, bzw. nur über Umwege machbar. Aber nicht nur für optische Anpassungen sollten Callback verwendet werden, sondern auch um auf Ereignisse zu reagieren. In Projekt &amp;quot;W&amp;quot; hat jedes Fenster einen festen Satz von Callbacks :&lt;br /&gt;
&amp;lt;pascal&amp;gt; TGLWindow = class&lt;br /&gt;
 ...&lt;br /&gt;
 BeforeItemDrawCallBack : TGLWindowContentCallBack;      // Wird aufgerufen bevor GUI Elemente gezeichnet werden&lt;br /&gt;
 AfterItemDrawCallBack  : TGLWindowContentCallBack;      // Wird aufgerufen nachdem alle GUI Elemente gezeichnet wurden&lt;br /&gt;
 MessageCallBack        : TGLWindowGUIMessageCallBack;   // Verarbeitet Nachrichten (also z.B. die Nachricht die von einem gedrückten Button gesendet wird)&lt;br /&gt;
 UpdateCallBack         : TGLWindowUpdateCallBack;       // Wird aufgerufen wenn der Inhalt des Fensters aktualisiert werden soll, i.d.R. durch einen globalen Aufruf (''TGLGUI.GlobalWindowUpdate'')&lt;br /&gt;
 ...&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Gruppensichtbarkeit===&lt;br /&gt;
In einer komplexen GUI wird man irgendwann bestimmte Objekte ein- bzw. ausblenden müssen. Ein Beispiel aus Projekt &amp;quot;W&amp;quot; : Im Spionageschirm können Spion unterschiedlichen Typs angezeigt werden, und je nach gewähltem Spiontyp müssen z.B. diverse Panels und Labels gezeigt oder auch verstekct werden. In der GUI von Projekt &amp;quot;W&amp;quot; hat daher jedes GUI-Element eine Eigenschaft namens ''GroupID'' über dass die Elemente bestimmten Sichtbarkeitsgruppen zugeordnet werden. Die GUI bietet dann eine Funktion namens ''ToggleVisibility'' mit der man ganze Gruppen ein- und ausblenden kann. Leicht zu implementieren und äusserst praktisch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Echtzeitvorschau===&lt;br /&gt;
Die vermutlich wichtigste Komponente des Editors. Sie stellt das aktuelle geladene Fenster bzw. die GUI so dar wie man es im Spiel sieht. Bei Bedarf werden natürlich noch ein paar Dinge eingeblendet, wie z.B. Debuglinien oder Auswahlrahmen. Für den Editor muss man hier noch auf Klicks reagieren um Objekte auszuwählen, diese Funktionalität sollte man aber direkt in der GUI verankern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Eigenschaftseditor===&lt;br /&gt;
Natürlich muss man die Eigenschaften der gewählten GUI-Elemente irgendwie verändern können. Ähnlich wie in Delphi bietet sich hier ein ''TValueListEditor'' an, der sehr flexibel ist. Neben einfachen Werteingaben kann man hier auch Dropdownlisten für vorgegebene Werte, oder sogar Buttons einfügen die dann einen externen Editor (z.B. für die Punkte einer Region oder den Text eines Memos) aufrufen lässt.&lt;br /&gt;
Neben dem Eigenschaftseditor für GUI-Elemente benötigt man natürlich auch einen für das aktuelle Fenster. Hier kann man dann Fenstertitel, Größe und ein paar andere Kleinigkeiten anpassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Möglichkeit direkt neue GUI-Elemente zu erstellen===&lt;br /&gt;
Hier gibts nicht viel zu erzählen. Ein GUI-Editor wäre natürlich kaum nützlich wenn man keine neuen GUI-Elemente hinzufügen könnte. Wie man das präsentiert ist dem persönlichen Geschmack überlassen. Mir reicht eine einfache Liste mit allen verfügbaren GUI-Elemente, schöner wären natürlich Icons wie in Delphi. Die Implementation ist hier auch recht einfach, denn die GUI an sich sollte bereits eine Möglichkeit bieten einem Fenster neue Elemente hinzuzufügen (z.B. ''TGLWindow.AddButton(...)''). Dann wird im Editor letztendlich nur (je nach ausgewählten Element) die entsprechende Funktion aus der GUI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Umschalten zwischen Editor- und Ingame-GUI===&lt;br /&gt;
Eher von praktischem Nutzen ist die Möglichkeit zwischen Editor und der Ingame-GUI umzuschalten. So kann man im Editor schnell sehen wie die GUI im Spiel letztendlich aussieht und reagiert. Denn während im Editormodus i.d.R. alle Elemente angezeigt werden gibt es im Ingame-Modus z.B. graphische Buttons die nur beim Mouseover angezeigt werden sollen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Debugmodus===&lt;br /&gt;
Wo würde der Debugmodus besser reinpassen als direkt in den Editor? Im Spiel würde er kaum Sinn machen, denn besonders bei Spielen die lange Laden und komplex sind würde es immer ewig dauern bis man den Debugmodus zu Gesicht bekäme. Daher sollte der Editor eine Möglichkeit bieten eben diesen Modus aktivieren zu können. So kann man schnell sehen ob bzw. was nicht stimmt. In der GUI für Projekt &amp;quot;W&amp;quot; ist dieser Modus besonders für das ''TGLSkinnedControl'' sehr nützlich, so kann man direkt sehen wenn z.B. der polygonale Selektionsbereich an der falschen Stelle liegt.&lt;br /&gt;
[[Bild:wiki_gui_editor_debug.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Gruppensichtbarkeit===&lt;br /&gt;
Die entsprechende Funktionalität ist ja bereits in der GUI selbst vorhanden, und da man im Editor durchaus mehrere Objekte direkt an der selben Stelle liegen hat (siehe Beispiel mit den verschiedenen Spiontypen) ist eine Möglichkeit die Gruppensichtbarkeit einzustellen sehr praktisch. Hierzu iteriert man am besten durch alle GUI-Elemente des Fensters und packt alle Gruppen in eine ''TCheckListBox''. Dort kann man dann per Haken wählen welche Gruppen gerade sichtbar sein sollen. Am besten sollte man direkt in der GUI einen Zeiger auf diese ''TGLCheckListBox'' unterbringen, und beim Rendern in einem Fenster prüft man auf den Editiermodus (Flag in der GUI-Unit) und checkt dann gegen diese Liste welche GUI-Elemente gerendert werden sollen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Mehrfachauswahl===&lt;br /&gt;
Der Editor sollte die Möglichkeit bieten mehrere GUI-Elemente gleichzetig auswählen zu können. So kann man mehrere Objekte gleichzeitig bearbeiten. Hier muss man dann natürlich Funktionalität implementieren die die geimeinsamen Eigenschaften der gewählten GUI-Elemente ermittelt und diese dann in den Objekteditor schreibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Kleinigkeiten===&lt;br /&gt;
Damit sind weniger wichtige Funktionen gemeint die das Arbeiten mit dem GUI-Editor erleichtern oder erweitern. Im Falle des Editors für Projekt &amp;quot;W&amp;quot; gibt es da einige kleine Helfer :&lt;br /&gt;
*Hintergrundbild laden (sehr pratkisch um zu sehen wie die GUI auf Spielhintergrund aussieht)&lt;br /&gt;
*GUI-Elemente sortieren (sortiert die Elemente der GUI nach Z-Wert neu, u.a. nützlich wenn man Alphatestprobleme hat)&lt;br /&gt;
*GUI-Elemente nach Gruppe auswählen (wenn man z.B. ne ganze Objektgruppe auf einmal verschieben oder anpassen will)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_editor_debug.jpg&amp;diff=22831</id>
		<title>Datei:wiki gui editor debug.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_editor_debug.jpg&amp;diff=22831"/>
				<updated>2009-03-09T19:08:30Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Editor Debug ©2009 - Sascha Willems&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Editor Debug ©2009 - Sascha Willems&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22830</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22830"/>
				<updated>2009-03-09T18:55:46Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Keine Unterscheidung zwischen Fenster und GUI===&lt;br /&gt;
In einer frühen Version der GUI für Projekt &amp;quot;W&amp;quot; wurde noch zwischen einer Vollbild-GUI (z.B. Hauptmenü, Spielendeschirm) und den normalen Fenstern unterschieden. So etwas soltle man nicht machen, und in der aktuellen Version der GUI für PjW nutzen auch Vollbild-GUI Schirme ein Fenster als Grundlage. Allerdings ist dieses Fenster nicht bewegbar, nicht sichtbar und immer so groß wie der Viewport des Spiels. Dadurch spart man sich viel Arbeit, da man ansonsten vieles doppelt implementieren muss. Also von Anfang an gleich alles auf Fensterbasis entwickeln.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Unterstützung für mehrere Sprachen===&lt;br /&gt;
Hier sind natürlich nicht Programmiersprachen gemeint, sondern gesprochene Sprachen. Auch wenn man sein Projekt erstmal nur in einer Sprache veröffentlichen will sollte man trotzdem Unterstützung für mehrere Sprachen von Anfang ein einplanen. So etwas direkt einzubinden ist kaum Aufwand, dies später nachzurüsten kann aber durchaus in Arbeit ausarten. Einfachste Methode (die ich auch in Projekt &amp;quot;W&amp;quot; verwende) ist es für alle benötigten Elemente (z.B. die Beschriftung eines Labels oder Buttons) statt eines Strings ein ''String array'' zu verwenden (eine ''TStringList'' wäre hier zu aufwendig). Wenn man dann auch noch ein erweiterbares Dateiformat wie XML verwendet, ist es mit dieser einfachen Methode kein Problem später weitere Sprachen hinzuzufügen. Zur Ausgabe von Text o.ä. greift man dann nicht mehr direkt auf die Variable zu, sondern nutzt eine Funktion (z.B. ''TGLLabel.GetCaption'') die dann je nach eingestellter Sprache (in Projekt &amp;quot;W&amp;quot; wird die eingestellte Sprache in einer Eigenschaft von ''TLocalizationDB'' gespeichert, einer Klasse die sich um das Laden und wechseln der Sprachen kümmert) die passende Beschriftung zurückgibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nachrichtenbehandlung (aka ''Messagehandling'')===&lt;br /&gt;
In diesem Punkt darf man sich ruhig ein wenig an Windows orientieren, allerdings nicht zu sehr, eine Nachrichtenbehandlung für die eigene GUI muss selten so komplex sein wie eines Betriebssystems. Denn die eigene GUI muss nur auf die Ereignisse einer einzelnen Anwendung reagieren, und nicht auf dutzende geöffnete Anwendungen verteilen. Daher ist diese recht einfach zu implementieren. Im Normalfall sollte es reichen wenn eine Nachricht an alle offenen Fenster weitergereicht wird (in Projekt &amp;quot;W&amp;quot; geschieht dies über einen Callback, siehe weiter unten). Wenn also ein Button gedrückt wird, erzeugt dieser eine Nachricht die dann an einen globalen Verteiler (''TGUI.GlobalWindowMessage'') übergeben wird der diese dann an die Fenster weiterleitet. Innerhalb des entsprechenden Callbacks (''TGLWindow.MessageCallBack'') wird dann überpfüft ob die Nachricht für dieses Fenster vorgesehen ist und wenn ja, wird diese auch hier verarbeitet. Klingt sehr einfach und ist es auch. Mehr wird man aber selten benötigen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Callbacks verwenden===&lt;br /&gt;
Besonders Anfänger haben gerne mal Probleme mit sog. ''Callbacks'', aber wer etwas fortgeschritten ist lernt diese zu schätzen, tragen sie doch stark zur Flexibilität einer Programmiersprache bei und erlauben es z.B. Zirkelbezüge (zwei Units die gegenseitig auf sich zugreifen wollen) zu umschiffen. Für größere Projekte also fast unumgänglich, und in einer GUI für ein Spiel quasi ein Muss. Warum? Weil man nur so die benötigte (optische) Flexibiliät bekommt die man benötigt, denn nicht immer reicht es wenn man z.B. eine Iconbox (in meinem Falle ein Objekt ähnlich einer Listbox, nur mit Texturen statt Einträgen) einfach alle Texturen rendern lässt. In bestimmten Fällen will man evtl. noch zusätzliche Informationen anzeigen. Ein gutes Beispiel ist die Liste der Spione auf dem Screenshot am Anfang des Artikels. Dahinter steckt eine ''TGLIconBox'' die normalerweise nur die Personalbilder darstellen würde. Dank eines Callbacks der (wenn zugewiesen) bei jedem Rendern eines solchen Bildes aufgerufen wird kann man aber bequem mehr Informationen rendern (Erfahrung, Zusatzsymbole, Name). Ohne Callbacks wäre das kaum, bzw. nur über Umwege machbar. Aber nicht nur für optische Anpassungen sollten Callback verwendet werden, sondern auch um auf Ereignisse zu reagieren. In Projekt &amp;quot;W&amp;quot; hat jedes Fenster einen festen Satz von Callbacks :&lt;br /&gt;
&amp;lt;pascal&amp;gt; TGLWindow = class&lt;br /&gt;
 ...&lt;br /&gt;
 BeforeItemDrawCallBack : TGLWindowContentCallBack;      // Wird aufgerufen bevor GUI Elemente gezeichnet werden&lt;br /&gt;
 AfterItemDrawCallBack  : TGLWindowContentCallBack;      // Wird aufgerufen nachdem alle GUI Elemente gezeichnet wurden&lt;br /&gt;
 MessageCallBack        : TGLWindowGUIMessageCallBack;   // Verarbeitet Nachrichten (also z.B. die Nachricht die von einem gedrückten Button gesendet wird)&lt;br /&gt;
 UpdateCallBack         : TGLWindowUpdateCallBack;       // Wird aufgerufen wenn der Inhalt des Fensters aktualisiert werden soll, i.d.R. durch einen globalen Aufruf (''TGLGUI.GlobalWindowUpdate'')&lt;br /&gt;
 ...&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Gruppensichtbarkeit===&lt;br /&gt;
In einer komplexen GUI wird man irgendwann bestimmte Objekte ein- bzw. ausblenden müssen. Ein Beispiel aus Projekt &amp;quot;W&amp;quot; : Im Spionageschirm können Spion unterschiedlichen Typs angezeigt werden, und je nach gewähltem Spiontyp müssen z.B. diverse Panels und Labels gezeigt oder auch verstekct werden. In der GUI von Projekt &amp;quot;W&amp;quot; hat daher jedes GUI-Element eine Eigenschaft namens ''GroupID'' über dass die Elemente bestimmten Sichtbarkeitsgruppen zugeordnet werden. Die GUI bietet dann eine Funktion namens ''ToggleVisibility'' mit der man ganze Gruppen ein- und ausblenden kann. Leicht zu implementieren und äusserst praktisch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Echtzeitvorschau===&lt;br /&gt;
Die vermutlich wichtigste Komponente des Editors. Sie stellt das aktuelle geladene Fenster bzw. die GUI so dar wie man es im Spiel sieht. Bei Bedarf werden natürlich noch ein paar Dinge eingeblendet, wie z.B. Debuglinien oder Auswahlrahmen. Für den Editor muss man hier noch auf Klicks reagieren um Objekte auszuwählen, diese Funktionalität sollte man aber direkt in der GUI verankern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Eigenschaftseditor===&lt;br /&gt;
Natürlich muss man die Eigenschaften der gewählten GUI-Elemente irgendwie verändern können. Ähnlich wie in Delphi bietet sich hier ein ''TValueListEditor'' an, der sehr flexibel ist. Neben einfachen Werteingaben kann man hier auch Dropdownlisten für vorgegebene Werte, oder sogar Buttons einfügen die dann einen externen Editor (z.B. für die Punkte einer Region oder den Text eines Memos) aufrufen lässt.&lt;br /&gt;
Neben dem Eigenschaftseditor für GUI-Elemente benötigt man natürlich auch einen für das aktuelle Fenster. Hier kann man dann Fenstertitel, Größe und ein paar andere Kleinigkeiten anpassen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Möglichkeit direkt neue GUI-Elemente zu erstellen===&lt;br /&gt;
Hier gibts nicht viel zu erzählen. Ein GUI-Editor wäre natürlich kaum nützlich wenn man keine neuen GUI-Elemente hinzufügen könnte. Wie man das präsentiert ist dem persönlichen Geschmack überlassen. Mir reicht eine einfache Liste mit allen verfügbaren GUI-Elemente, schöner wären natürlich Icons wie in Delphi. Die Implementation ist hier auch recht einfach, denn die GUI an sich sollte bereits eine Möglichkeit bieten einem Fenster neue Elemente hinzuzufügen (z.B. ''TGLWindow.AddButton(...)''). Dann wird im Editor letztendlich nur (je nach ausgewählten Element) die entsprechende Funktion aus der GUI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Umschalten zwischen Editor- und Ingame-GUI===&lt;br /&gt;
Eher von praktischem Nutzen ist die Möglichkeit zwischen Editor und der Ingame-GUI umzuschalten. So kann man im Editor schnell sehen wie die GUI im Spiel letztendlich aussieht und reagiert. Denn während im Editormodus i.d.R. alle Elemente angezeigt werden gibt es im Ingame-Modus z.B. graphische Buttons die nur beim Mouseover angezeigt werden sollen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Gruppensichtbarkeit===&lt;br /&gt;
Die entsprechende Funktionalität ist ja bereits in der GUI selbst vorhanden, und da man im Editor durchaus mehrere Objekte direkt an der selben Stelle liegen hat (siehe Beispiel mit den verschiedenen Spiontypen) ist eine Möglichkeit die Gruppensichtbarkeit einzustellen sehr praktisch. Hierzu iteriert man am besten durch alle GUI-Elemente des Fensters und packt alle Gruppen in eine ''TCheckListBox''. Dort kann man dann per Haken wählen welche Gruppen gerade sichtbar sein sollen. Am besten sollte man direkt in der GUI einen Zeiger auf diese ''TGLCheckListBox'' unterbringen, und beim Rendern in einem Fenster prüft man auf den Editiermodus (Flag in der GUI-Unit) und checkt dann gegen diese Liste welche GUI-Elemente gerendert werden sollen.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22829</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22829"/>
				<updated>2009-03-09T12:42:47Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Gedanken zur GUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Keine Unterscheidung zwischen Fenster und GUI===&lt;br /&gt;
In einer frühen Version der GUI für Projekt &amp;quot;W&amp;quot; wurde noch zwischen einer Vollbild-GUI (z.B. Hauptmenü, Spielendeschirm) und den normalen Fenstern unterschieden. So etwas soltle man nicht machen, und in der aktuellen Version der GUI für PjW nutzen auch Vollbild-GUI Schirme ein Fenster als Grundlage. Allerdings ist dieses Fenster nicht bewegbar, nicht sichtbar und immer so groß wie der Viewport des Spiels. Dadurch spart man sich viel Arbeit, da man ansonsten vieles doppelt implementieren muss. Also von Anfang an gleich alles auf Fensterbasis entwickeln.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Unterstützung für mehrere Sprachen===&lt;br /&gt;
Hier sind natürlich nicht Programmiersprachen gemeint, sondern gesprochene Sprachen. Auch wenn man sein Projekt erstmal nur in einer Sprache veröffentlichen will sollte man trotzdem Unterstützung für mehrere Sprachen von Anfang ein einplanen. So etwas direkt einzubinden ist kaum Aufwand, dies später nachzurüsten kann aber durchaus in Arbeit ausarten. Einfachste Methode (die ich auch in Projekt &amp;quot;W&amp;quot; verwende) ist es für alle benötigten Elemente (z.B. die Beschriftung eines Labels oder Buttons) statt eines Strings ein ''String array'' zu verwenden (eine ''TStringList'' wäre hier zu aufwendig). Wenn man dann auch noch ein erweiterbares Dateiformat wie XML verwendet, ist es mit dieser einfachen Methode kein Problem später weitere Sprachen hinzuzufügen. Zur Ausgabe von Text o.ä. greift man dann nicht mehr direkt auf die Variable zu, sondern nutzt eine Funktion (z.B. ''TGLLabel.GetCaption'') die dann je nach eingestellter Sprache (in Projekt &amp;quot;W&amp;quot; wird die eingestellte Sprache in einer Eigenschaft von ''TLocalizationDB'' gespeichert, einer Klasse die sich um das Laden und wechseln der Sprachen kümmert) die passende Beschriftung zurückgibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nachrichtenbehandlung (aka ''Messagehandling'')===&lt;br /&gt;
In diesem Punkt darf man sich ruhig ein wenig an Windows orientieren, allerdings nicht zu sehr, eine Nachrichtenbehandlung für die eigene GUI muss selten so komplex sein wie eines Betriebssystems. Denn die eigene GUI muss nur auf die Ereignisse einer einzelnen Anwendung reagieren, und nicht auf dutzende geöffnete Anwendungen verteilen. Daher ist diese recht einfach zu implementieren. Im Normalfall sollte es reichen wenn eine Nachricht an alle offenen Fenster weitergereicht wird (in Projekt &amp;quot;W&amp;quot; geschieht dies über einen Callback, siehe weiter unten). Wenn also ein Button gedrückt wird, erzeugt dieser eine Nachricht die dann an einen globalen Verteiler (''TGUI.GlobalWindowMessage'') übergeben wird der diese dann an die Fenster weiterleitet. Innerhalb des entsprechenden Callbacks (''TGLWindow.MessageCallBack'') wird dann überpfüft ob die Nachricht für dieses Fenster vorgesehen ist und wenn ja, wird diese auch hier verarbeitet. Klingt sehr einfach und ist es auch. Mehr wird man aber selten benötigen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Callbacks verwenden===&lt;br /&gt;
Besonders Anfänger haben gerne mal Probleme mit sog. ''Callbacks'', aber wer etwas fortgeschritten ist lernt diese zu schätzen, tragen sie doch stark zur Flexibilität einer Programmiersprache bei und erlauben es z.B. Zirkelbezüge (zwei Units die gegenseitig auf sich zugreifen wollen) zu umschiffen. Für größere Projekte also fast unumgänglich, und in einer GUI für ein Spiel quasi ein Muss. Warum? Weil man nur so die benötigte (optische) Flexibiliät bekommt die man benötigt, denn nicht immer reicht es wenn man z.B. eine Iconbox (in meinem Falle ein Objekt ähnlich einer Listbox, nur mit Texturen statt Einträgen) einfach alle Texturen rendern lässt. In bestimmten Fällen will man evtl. noch zusätzliche Informationen anzeigen. Ein gutes Beispiel ist die Liste der Spione auf dem Screenshot am Anfang des Artikels. Dahinter steckt eine ''TGLIconBox'' die normalerweise nur die Personalbilder darstellen würde. Dank eines Callbacks der (wenn zugewiesen) bei jedem Rendern eines solchen Bildes aufgerufen wird kann man aber bequem mehr Informationen rendern (Erfahrung, Zusatzsymbole, Name). Ohne Callbacks wäre das kaum, bzw. nur über Umwege machbar. Aber nicht nur für optische Anpassungen sollten Callback verwendet werden, sondern auch um auf Ereignisse zu reagieren. In Projekt &amp;quot;W&amp;quot; hat jedes Fenster einen festen Satz von Callbacks :&lt;br /&gt;
&amp;lt;pascal&amp;gt; TGLWindow = class&lt;br /&gt;
 ...&lt;br /&gt;
 BeforeItemDrawCallBack : TGLWindowContentCallBack;      // Wird aufgerufen bevor GUI Elemente gezeichnet werden&lt;br /&gt;
 AfterItemDrawCallBack  : TGLWindowContentCallBack;      // Wird aufgerufen nachdem alle GUI Elemente gezeichnet wurden&lt;br /&gt;
 MessageCallBack        : TGLWindowGUIMessageCallBack;   // Verarbeitet Nachrichten (also z.B. die Nachricht die von einem gedrückten Button gesendet wird)&lt;br /&gt;
 UpdateCallBack         : TGLWindowUpdateCallBack;       // Wird aufgerufen wenn der Inhalt des Fensters aktualisiert werden soll, i.d.R. durch einen globalen Aufruf (''TGLGUI.GlobalWindowUpdate'')&lt;br /&gt;
 ...&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Echtzeitvorschau===&lt;br /&gt;
Die vermutlich wichtigste Komponente des Editors. Sie stellt das aktuelle geladene Fenster bzw. die GUI so dar wie man es im Spiel sieht. Bei Bedarf werden natürlich noch ein paar Dinge eingeblendet, wie z.B. Debuglinien oder Auswahlrahmen.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22827</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22827"/>
				<updated>2009-03-08T16:01:59Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Keine Unterscheidung zwischen Fenster und GUI===&lt;br /&gt;
In einer frühen Version der GUI für Projekt &amp;quot;W&amp;quot; wurde noch zwischen einer Vollbild-GUI (z.B. Hauptmenü, Spielendeschirm) und den normalen Fenstern unterschieden. So etwas soltle man nicht machen, und in der aktuellen Version der GUI für PjW nutzen auch Vollbild-GUI Schirme ein Fenster als Grundlage. Allerdings ist dieses Fenster nicht bewegbar, nicht sichtbar und immer so groß wie der Viewport des Spiels. Dadurch spart man sich viel Arbeit, da man ansonsten vieles doppelt implementieren muss. Also von Anfang an gleich alles auf Fensterbasis entwickeln.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Echtzeitvorschau===&lt;br /&gt;
Die vermutlich wichtigste Komponente des Editors. Sie stellt das aktuelle geladene Fenster bzw. die GUI so dar wie man es im Spiel sieht. Bei Bedarf werden natürlich noch ein paar Dinge eingeblendet, wie z.B. Debuglinien oder Auswahlrahmen.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22825</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22825"/>
				<updated>2009-03-08T15:48:32Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Gedanken zur GUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22824</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22824"/>
				<updated>2009-03-08T15:48:09Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Von Anfang an einen GUI-Editor mitentwickeln */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
Hilfreich wäre es zudem wenn direkt in der GUI einige Flags für den Editormodus implementiert werden. Rein optisch wird es zwischen der Darstellung der GUI im Editor und Spiel bis auf Sichtbarkeit einiger Elemente keine Unterschiede geben, aber z.B. bei der Auswahl von Elementen sieht es im Editormodus anders aus als im Spielmodus, und während man im Spiel oft Elemente komplett ausblendet sollten diese im Editor zumindest via Knopfdruck sichtbar zu machen sein.&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22823</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22823"/>
				<updated>2009-03-08T15:41:41Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Thema GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Optische Anpassbarkeit und Flexibilität===&lt;br /&gt;
In diesem Punkt wird sich die eigene GUI i.d.R. sehr stark von der des Betriebssystems abheben. Zwar bietet z.B. Windows inzwischen Unterstützung für Themes, diese gelten aber global und sind nicht wirklich flexibel. Da die eigene GUI aber oft selbst innerhalb eines einzigen Spiels optisch anpassbar sein sollte (wird sie in mehreren Spielen verwendet ist dies natürlich mandatorisch), muss entsprechende Funktionalität direkt in ihr verankert werden. Grundlegend sind hier sog. ''&amp;quot;Skins&amp;quot;''. Ein ''&amp;quot;Skin&amp;quot;'' (einen passenden deutschen Begriff gibt es hierfür leider nicht) ist im Prinzip eine Textur die alle graphischen Teile der GUI beinhaltet (Fensterrahmen, Buttonteile, Pfeile, etc.) die dann später mittels Texturemapping aus dieser Datei gesampelt werden. Da die eigenen GUI-Elemente in Einzelteilen gerendert werden müssen die entsprechenden Teile nicht 1:1 in der Textur abgelegt werden, sondern werden dann entsprechend beim Rendern des Elements mehrfach oder gestreckt aus dieser Textur gerendert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_skin.jpg]][[Bild:wiki_gui_skinnedcontrol.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ausserdem sollte die GUI nicht komplett statisch sein, sprich ein Button sollte beginnen sich optisch abzuheben wenn man den Cursor darauf positioniert. Dank OpenGL sollte dies kein Problem sein und hier sind vielfältige Effekte denkbar. In Projekt &amp;quot;W&amp;quot; z.B. ändern sich Buttons beim Mouseover (im &amp;quot;Skin&amp;quot; gibt es für Buttons je einen normalen Teil und einen hervorgehobene), Teile einer TGLSkinnedControl hingegen werden weich eingeblendet und vergrößert und vice versa. Hier sind also kaum Grenzen gesetzt, man könnte dies sogar mit einem [[Partikelsystem]] verbinden dass z.B. Funken sprühen lässt wenn man einen Button selektiert, oder gar Flammen um diesen herum erscheinen lässt. Animationen sind natürlich auch denkbar. Auch hier sollte man sich keinesfalls an Windows orientieren, sondern die Möglichkeiten nutzen die OpenGl bietet. Die GUI für ein Spiel muss nicht immer rein praktischer Natur sein (je nach Spiel darf sie das auch garnicht sein, man denke an Spiele die die GUI direkt ins Gameplay integrieren), hier kann man ruhig mal etwas verspieltes machen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der GUI-Editor==&lt;br /&gt;
Eine komplexe GUI benötigt wie bereits angesprochen einen entsprechenden Editor mit dem man seine Fenster erstellen kann, und da ich im Forum bereits mehrfach darauf angesprochen wurde werde ich anhand des Editors von Projekt &amp;quot;W&amp;quot; aufzeigen wie ich einen GUI-Editor aufgebaut habe. Natürlich ist dieser auch auf meine GUI angepasst (deshalb auch keine Veröffentlichung), aber sicherlich findet hier jeder den ein oder anderen Punkt den er auch gerne in seinem eigenen Editor sehen würde.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_editor.jpg]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_skinnedcontrol.jpg&amp;diff=22822</id>
		<title>Datei:wiki gui skinnedcontrol.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_skinnedcontrol.jpg&amp;diff=22822"/>
				<updated>2009-03-08T15:33:14Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Skinned Control ©2009 - Sascha Willems&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Skinned Control ©2009 - Sascha Willems&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_skin.jpg&amp;diff=22821</id>
		<title>Datei:wiki gui skin.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_skin.jpg&amp;diff=22821"/>
				<updated>2009-03-08T15:25:54Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Skin ©2009 - Sascha Willems&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Skin ©2009 - Sascha Willems&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_editor.jpg&amp;diff=22820</id>
		<title>Datei:wiki gui editor.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_editor.jpg&amp;diff=22820"/>
				<updated>2009-03-08T15:00:38Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Editor ©2009 - Sascha Willems&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - GUI Editor ©2009 - Sascha Willems&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22819</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22819"/>
				<updated>2009-03-08T14:59:50Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Warum eine eigene GUI? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
[[Bild:wiki_gui_ingame.jpg]]&lt;br /&gt;
&lt;br /&gt;
(Finale GUI aus Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22818</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22818"/>
				<updated>2009-03-08T14:58:51Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Gedanken zur GUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
Zudem wird man je nach Spiel auch GUI-Elemente benötigen die es so nicht in Windows gibt. In Projekt &amp;quot;W&amp;quot; gibt es z.B. ein Element namens ''TGLSkinnedControl'' welches neben einer Hintergrundtextur Unterelemente besitzt die auf einer polygonalen Auswahlkontur basieren. So hat man ein GUI-Element das quasi jede Form annehmen kann und für grafisch aufwendige GUI-Elemente genutzt werden kann die keiner Standardform entsprechend. Man könnte ein solches Element von der Funktionalität her natürlich auch mit normalen GUI-Elementen (z.B. Buttons) nachbilden, rein optisch wäre dass dann aber weniger schön und würde den &amp;quot;Look-and-Feel&amp;quot; des Spiels stark stören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI parallel zum Spiel entwickeln===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_ingame.jpg&amp;diff=22817</id>
		<title>Datei:wiki gui ingame.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:wiki_gui_ingame.jpg&amp;diff=22817"/>
				<updated>2009-03-08T14:57:20Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - Ingame GUI
©2009 - Sascha Willems&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Projekt &amp;quot;W&amp;quot; - &amp;quot;Phase 2&amp;quot; - Ingame GUI&lt;br /&gt;
©2009 - Sascha Willems&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22814</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22814"/>
				<updated>2009-03-08T14:22:37Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Gedanken zur GUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI mit dem Spiel wachsen lassen===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ein erweiterbares Format verwenden===&lt;br /&gt;
Wie im vorgen Punkt erwähnt wächst die GUI mit dem Spiel, und selbst wenn man abstrakt entwickelt und von Anfang an alles implementiert wird man irgendwann an einen Punkt kommen an dem man die GUI erweitern muss, sei es um neue Elemente, oder einfach nur eine neue Eigenschaft für ein bestehendes Element. Spätestens dann wird es sich auszahlen wenn man ein erweiterbares Format gewählt hat, denn während eigene binäre Format nur schwer zu erweitern sind lassen sich mit einem Format wie XML (für das es in Delphi direkten Support gibt) leicht Veränderungen an der GUI realisieren. Statt sein eigenes Format erweitern zu müssen kann man in XML einfach einen neuen Attribut an einen bestehenden Knoten anhängen oder einfach neue Knoten hinzufügen. Zusätzlich ist XML (wenn man ordentlich Attribut- und Knotennamen vergibt) auch noch vom Menschen lesbar, man kann dort also schnell Fehler finden bzw. es sogar selbst von Hand erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Von Anfang an einen GUI-Editor mitentwickeln===&lt;br /&gt;
Auch wenn man anfänglich noch das ein oder andere Fenster seiner GUI von Hand erstellen kann (dank XML kein Problem), so sollte man doch direkt mit der Entwicklung eines GUI-Editors beginnen. Spätestens wenn man komplexere Fenster erstellen will übersteigt der Zeitaufwand fürs manuelle Erstellen direkt in XML den Zeitaufwand für die Entwicklung eines GUI-Editors. Also am besten gleichzeitig mit der GUI auch den passenden Editor entwickeln.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22812</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22812"/>
				<updated>2009-03-08T13:47:46Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Gedanken zur GUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Objektorientiert entwickeln===&lt;br /&gt;
&lt;br /&gt;
Eigentlich ein &amp;quot;überflüssiger&amp;quot; Punkt, da selbstverständlich. Bei kaum einem anderen Projekt lässt sich OOP so schön und effektiv anwenden wie bei einer GUI. Es sollte ein Basisobjekt geben ('''TGLGUIItem''') welches alle grundlegenden Eigenschaften (''Größe, Position, evtl. auch weiterführende Dinge wie Schriftart'') und Funktionen (''Speichern und Laden, Zeichnen, dort wo nötig mit '''virtual''' arbeiten'') besitzt die siche alle GUI-Element teilen. Hier sollte man aber nicht immer den kleinsten gemeinsamen Nenner suchen, also auch ruhig die ein oder andere Eigenschaft bzw. Funktion ins Grundelement verlegen die nur von zwei oder drei abgeleiteten Elementen genutzt wird. Das kostet zwar ein wenig mehr Speicher, spart aber viel Arbeit. &lt;br /&gt;
Zusätzlich zu den Elementen der GUI gibt es dann als Grundelement noch das Fenster '''TGLWindow''') welches letzendlich ein Kontainer für eben diese Objekt ist und ein paar zusätzliche Funktionen zur Nutzerinteraktion bereitstellt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Nicht zu sehr an der Windows-UI orientieren===&lt;br /&gt;
Auch wenn es naheliegend wäre die eigene GUI an der UI von Windows (oder Linux) zu orientieren sollte man davon Abstand halten. Während die Benutzeroberfläche von Windows für Anwendungen (dazu noch mehrere gleichzeitig) ausgelegt ist, soll die eigene GUI ja auch zum &amp;quot;Look-and-Feel&amp;quot; des Spiels beitragen und auch einfach zu nutzen sein. Die Windows UI ist sehr abstrakt gehalten, da es für sie keinen direkt definierten Einsatzbereich gibt, ist also entsprechend komplex. Bei der GUI für das eigene Spiel (die dann wenn überhaupt nur in weiteren eigenen Spielen genutzt wird) muss man nichtg krampfhaft versuchen diese Funktionalität nachzubauen. Das kostet viel Zeit und Arbeit die man besser in andere Bereiche investiert (Gameplay, Grafik). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Die GUI mit dem Spiel wachsen lassen===&lt;br /&gt;
Dieser Punkt ergänzt quasi den oberen Punkt. Wer von Anfang an eine GUI plant die alle möglichen Elemente beinhaltet und alles möglich kann macht sich unnötig viel Arbeit. GUI-Elemente sollte man dann implementieren wenn man diese benötigt, die GUI also nur erweitern wenn dies für das Spiel benötigt wird. Man implementiert zuerst also nur einen Grundstock von Elementen die definitiv benötigt werden, z.B. Fenster, Buttons, Panels, Memos, Listboxen und erweitert dann nach und nach. Da man ja ein Grundelement hat ('''TGLGUIItem''') ist es relativ einfach die GUI um neue Elemente zu erweitern. Das ist letztendlich weitaus effizienter als von Anfang an alle möglichen GUI-Elemente zu implementieren die man dann letztendlich nicht benötigt.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22806</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22806"/>
				<updated>2009-03-08T13:06:37Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Wer ein etwas komplexeres Spiel mit einer 3D-API entwickelt wird früher oder später an dem Punkt angelangt sein, an dem er eine graphische Benutzeroberfläche (engl. &amp;quot;GUI&amp;quot; - Graphical user interface) benötigt um dem Spieler wichtige Daten zu präsentieren, und um diesen mit dem Spiel interagieren zu lassen. Mit steigender Spielkomplexität wird eine gute GUI immer wichtiger, denn während z.B. ein Jump'n'Run (Beispiele wären hier Sonic, Mario) nur wenige GUI-Elemente benötigt (Punkte, Leben, Lebensenergie) die zudem meist nur als Anzeigen dienen (also keine Nutzerinteraktion erwarten), benötigen komplexe Spiele wie z.B. Strategiespiele komplexe Nutzeroberflächen um alle wichtigen Daten in ansprechender Form präsentieren zu können, und v.a. um den Spieler auch mit dem Spiel interagieren lassen zu können. &lt;br /&gt;
&lt;br /&gt;
In diesem Artikel (es handelt sich hier nicht um ein Tutorial per se) werde ich mein Erfahrungen, die ich während der Entwicklung einer GUI für [http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;] gesammelt habe (und immernoch tue, das Projekt wird ja weiterentwickelt), zusammenfassen und so versuchen eine Leitfaden für die Erstellung einer komplexen Spiele-GUI zu geben. Der Artikel soll nicht als Anleitung gesehen werden, sondern wie gesagt als Leitfaden an dem man sich bei der Erstellung der eigenen GUI orientieren kann, nicht soll. Er soll v.a. zeigen welche Dinge es bei der Erstellung einer solchen GUI zu beachten gibt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Warum eine eigene GUI?==&lt;br /&gt;
Zum einen weil OpenGL keine eigene GUI-Bibliothek bietet, und zum anderen weil man für ein Spiel das eine 3D-API nutzt letztendlich nicht die Standard UI-Elemente des Betriebssystems nutzen kann. Diese sehen nicht nur langweilig aus, sondern deren Aussehen kann auch nur sehr rudimentär angepasst werden. Ausserdem ist nicht garantiert dass diese auch über dem Renderkontext gezeichnet werden. Fertige OpenGL GUI-Bibliotheken gibts es zudem auch kaum, und für Delphi/Pascal (momentan, siehe [[DGLGUI_Pflichtenheft|DGLGUI]]) erst recht nicht.&lt;br /&gt;
&lt;br /&gt;
Zudem trägt die Benutzeroberfläche viel zum ''&amp;quot;Look and Feel&amp;quot;'' eines Spiels bei, weshalb man hier je nach Komplexität letztendlich sowieso eine eigene Lösung entwickeln muss.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Gedanken zur GUI==&lt;br /&gt;
''Hinweis : ''Dieser Abschnitt ist stark von meinem persönlichen Programmierstil gekennzeichnet. Riesige UML-Diagramme oder umfangreiche Planung ist nicht mein Stil, ich programmiere gerne &amp;quot;on-the-fly&amp;quot;.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22805</id>
		<title>GUI Leitfaden</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=GUI_Leitfaden&amp;diff=22805"/>
				<updated>2009-03-08T12:33:58Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Die Seite wurde neu angelegt: {{Offline}}  ''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine dir...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Offline}}&lt;br /&gt;
&lt;br /&gt;
''Nach Anregung im Forum entsteht hier ein Artikel zum Them GUI plus Editor für Spiele. KEIN Tutorial, es wird also weder Code geben noch wird es eine direkte Anleitung. Mehr eine Gedankensammlung und ein Leitfaden aus Erfahrungen mit meiner eigenen GUI.''&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 12:33, 8. Mär. 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Vertexbufferobject&amp;diff=22453</id>
		<title>Tutorial Vertexbufferobject</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Vertexbufferobject&amp;diff=22453"/>
				<updated>2009-01-12T13:00:50Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Ave! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=GL_ARB_Vertex_Buffer_Object=&lt;br /&gt;
==Ave!==&lt;br /&gt;
&lt;br /&gt;
Und willkommen zu meinem zweiten GL_ARB-Extension Tutorial. Diesmal beschäftigen wir uns mit der recht neuen '''GL_ARB_Vertex_Buffer_Object'''-Extension, die vom ARB am 12.Februar 2003 fertiggestellt und vor kurzem auch als Corefeature in OpenGL 1.5 promoted wurde.&lt;br /&gt;
&lt;br /&gt;
VBOs (Vertex Buffer Objects) sind quasi eine Erweiterung der recht weit verbreiteten Vertexarrays, die jedoch den großen Vorteil besitzen, dass ihre Vertexdaten serverseitig, also im schnellen VRAM der Grafikkarte, statt wie bei den VAs im Hauptspeicher, abgelegt werden. Das ist bei einer Displayliste zwar (fast) genauso der Fall, allerdings können die Daten nicht so einfach dynamisch geändert werden, was bei einem VBO aber bei Bedarf sehr einfach ist.&lt;br /&gt;
&lt;br /&gt;
Kurz gesagt vereint das VBO also die Flexibilität eines Vertexarrays mit der Geschwindigkeit einer Displayliste und eignet sich daher besonders für das Rendern aufwändiger Geometrie, egal ob statisch oder dynamisch.&lt;br /&gt;
&lt;br /&gt;
Eine weitere tolle Neuerung der VBO-API ist die Tatsache, dass man sich von OpenGL einen Pointer übergeben lassen kann, mit dessen Hilfe man Vertexdaten direkt in den VRAM schreiben kann. Dadurch spart man sich natürlich den Umweg über den Hauptspeicher und somit auch den erhöhten Speicherbedarf des Programmes beim Laden von Modellen o.&amp;amp;nbsp;Ä.&lt;br /&gt;
&lt;br /&gt;
VBOs bieten übrigens auch die Möglichkeit, sie je nach Anwendungsfall vom Grafikkartentreiber &amp;quot;optimieren&amp;quot; zu lassen. So legt man Vertexdaten, die im Nachhinein nicht mehr verändert werden sollenm am besten mit dem Schlüsselwort ''STATIC_DRAW'' ab, während dynamische Vertexdaten über ''DYNAMIC_DRAW'' abgelegt werden sollten. Doch dazu gibts später nähere Informationen.&lt;br /&gt;
&lt;br /&gt;
==Hardwareunterstützung==&lt;br /&gt;
&lt;br /&gt;
Inzwischen sollten alle gängigen Grafikkarten diese Extension problemlos unterstützen, ältere Modelle tun dies aber evtl. nur emuliert über den Treiber. Will man sein Programm auch für sehr alte Hardware (Karten älter als ATIs Radeon 9x00 bzw. NVidias GeForce 4-Serie) lauffähig machen, sollte man noch einen alternativen Renderpfad auf Basis von Displaylisten einbauen.&lt;br /&gt;
&lt;br /&gt;
==Erstellen des Vertexbufferobjects==&lt;br /&gt;
&lt;br /&gt;
Wie der Name vermuten lässt, handelt es sich beim VBO um ein Objekt, welches in Sachen Syntax an die anderen in OpenGL verfügbaren Objekte wie z.&amp;amp;nbsp;B. Texturenobjekte angelehnt ist. Das Erstellen eines VBOs geht daher genauso einfach von der Hand:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glGenBuffers(1, @VBO);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun sollten wir in VBO eine gültige ID zurückgeliefert bekommen haben, welche ein Vertex buffer object referenziert.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun ein VBO erstellt haben, sollten wir dieses natürlich auch &amp;quot;aktivieren&amp;quot; (also binden), damit wir mit ihm arbeiten können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBindBufferARB(GL_ARRAY_BUFFER, VBO);&lt;br /&gt;
glEnableClientState(GL_VERTEX_ARRAY);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie erwähnt binden wir in der ersten Zeile unser frisch erstelltes VBO, während wir in der zweiten Zeile Vertexarrays auf der Clientseite aktivieren. Dies ist deshalb nötig, da wir das VBO später genauso zeichnen werden wie dies bei einem normalen VA der Fall wäre.&lt;br /&gt;
&lt;br /&gt;
==Übergabe der Vertexdaten (Variante 1: Ohne Umweg über den Hauptspeicher)==&lt;br /&gt;
&lt;br /&gt;
Wie in der Einleitung bereits erwähnt, bietet uns die VBO-API die Möglichkeit, unsere Vertexdaten ohne Umweg über den Hauptspeicher direkt in den Grafikkartenspeicher zu schreiben. Da dies eines der besten Features dieser neuen Extension ist, wollen wir uns auch zuerst mit dieser Übergabemethode beschäftigen.&lt;br /&gt;
&lt;br /&gt;
''Allerdings erstmal eine kleine Warnung vorweg: Pointer sind ein recht komplexes Thema, und ihre Nutzung erfordert einige Kenntnisse. Wer weder weiß, wie man damit umgeht, noch wie man sie einsetzt, sollte sich da zuerstmal schlau machen. Denn mit Pointer kann man ganz böse Sachen machen, wenn man sie nicht richtig nutzen kann!''&lt;br /&gt;
&lt;br /&gt;
Um unsere Vertexdaten als Pointer zu nutzen,müssen wir erstmal eine Vertexstruktur erstellen und auch einen passenden Pointertyp. Der Pointertyp ist zwar nicht zwingend (ein ^ täte es auch), aber macht die Sache übersichtlicher:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
PVertex = ^TVertex;&lt;br /&gt;
TVertex = packed record&lt;br /&gt;
 S,T,X,Y,Z : TGLFloat;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sicher fragen sich einige von euch jetzt, warum unser TVertex gerade so aussieht (also zuerst S,T und dann der Rest). Das liegt daran, dass wir unser VBO später über die Funktion [[glInterleavedArrays]] rendern werden, welche wissen will, wie unsere Vertexdaten im Speicher abgelegt sind. Unsere Vertexstruktur entspricht dabei dem Format ''GL_T2F_V3F''. ''T2F'' entspricht 2 Floats für die Texturenkoordinaten (S&amp;amp;T), gefolgt von ''V3F'' für die drei Floatwerte die unsere Vertexkoordinaten repräsentieren. Wenn ihr ein anderes Vertexformat verwendet, müsst ihr euch auch ein passendes Vertexformat aus der Spezifikation heraussuchen.&lt;br /&gt;
Ich verwende oben übrigens einen '''packed Record''' (auch wenn dies bei unserem Vertexformat nicht unbedingt ein Muss ist). Dies tue ich deshalb, da Delphi Werte bei einem normalen Record für einen beschleunigten Zugriff an einem (Double)Word-Raster ausrichtet und dies deshalb bei bestimmten Vertexformaten Probleme bereiten könnte.&lt;br /&gt;
&lt;br /&gt;
Hoffe mal das euch obiges klar ist,denn jetzt gehts ans Eingemachte. Wir kommen zum &amp;quot;schwersten&amp;quot; (ist ja ein relativer Begriff) Teil des Tutorials, nämlich der Übergabe der Vertexdaten an das VBO. Dazu müssen wir OpenGL zuerstmal mitteilen, wie groß unser VBO eigentlich sein soll,damit wir auch genug Platz im VRAM bekommen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBufferDataARB(GL_ARRAY_BUFFER, VertexAnzahl*SizeOf(TVertex), nil, GL_STATIC_DRAW);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schauen wir uns also mal die Parameter von [[glBufferData]] an. Zuerst müssen wir OpenGL mitteilen, was für einen Puffer wir erstellen wollen (in zukünftigen Versionen werden wohl noch andere folgen, z.&amp;amp;nbsp;B. Überbuffer). In unserem Falle also einen Arraypuffer. Parameter zwei übergibt dann den Speicherplatz, den wir reservieren wollen und ist recht selbsterklärend. Der dritte Parameter würde normalerweise einen Pointer auf unsere Vertexdaten enthalten. Da wir diese aber nicht im Hauptspeicher abgelegt haben, sondern über einen Pointer dort noch ablegen wollen, übergeben wir hier '''nil'''. OpenGL nimmt dies zur Kenntnis und spuckt dementsprechend auch keinen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Den letzten Parameter hab ich auch schon kurz in der Einführung angesprochen. Er teilt OpenGL mit, auf welchen Anwendungsfall unser VBO optimiert werden soll. Dabei gibt es folgende Anwendungsfälle,die ihr euch dann entsprechend eurer VBO-Verwendung aussuchen könnt:&lt;br /&gt;
&lt;br /&gt;
{|rules=&amp;quot;all&amp;quot; border = &amp;quot;1&amp;quot;&lt;br /&gt;
! STREAM_DRAW&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann eher selten als Quelle für OpenGL-Befehle genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! STREAM_READ&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann selten von der Anwendung angefordert.&lt;br /&gt;
|-&lt;br /&gt;
! STREAM_COPY&lt;br /&gt;
| Die Vertexdaten werden einmal durch Kopieren von der GL übergeben und dann eher selten als Quelle für OpenGL-Befehle genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! STATIC_DRAW&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann recht oft von der Anwendung zum Rendern genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! STATIC_READ&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann recht oft von der Anwendung angefordert.&lt;br /&gt;
|-&lt;br /&gt;
! STATIC_COPY&lt;br /&gt;
| Die Vertexdaten werden einmal durch Kopieren von der GL übergeben und dann recht oft von der Anwendung zum Rendern genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! DYNAMIC_DRAW&lt;br /&gt;
| Die Vertexdaten werden wiederholt angegeben (verändert) und recht oft von der Anwendung zum Rendern genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! DYNAMIC_READ&lt;br /&gt;
| Die Vertexdaten werden wiederholt durch das Auslesen von Daten durch OpenGL angegeben (verändert) und oft von der Anwendung angefordert.&lt;br /&gt;
|-&lt;br /&gt;
! DYNAMIC_COPY&lt;br /&gt;
| Die Vertexdaten werden wiederholt durch das Auslesen von Daten durch OpenGL angegeben (verändert) und recht oft zum Rendern genutzt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beachtet werden sollte, dass es sich bei obigen Anwendungsmuster nur um Hinweise (Hints) handelt, die es auch in anderen Bereichen von OpenGL gibt. Diese Hinweise sind allerdings nicht verbindlich und werden von Treiber zu Treiber unterschiedlich behandelt.&lt;br /&gt;
&lt;br /&gt;
Nachdem OpenGL nun weiss was für ein VBO wir genau haben wollen, brauchen wir letztendlich nur noch einen Pointer, der &amp;quot;auf&amp;quot; das VBO zeigt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
VBOPointer := glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glMapBuffer]] liefert uns einen Pointer zurück, der den Speicherplatz des VBOs in den Adressraum des Clients &amp;quot;ummappt&amp;quot;, also in den Hauptspeicher. Dadurch wird es dann möglich, über eine Adresse im Hauptspeicher des Rechners direkt in den Grafikkartenspeicher zu schreiben. Der zweite Parameter gibt übrigens an, das wir in das VBO schreiben wollen. Der einzige weitere zulässige Parameter ist hier '''GL_READ_ONLY''', welcher zum Auslesen des VBOs dient.&lt;br /&gt;
&lt;br /&gt;
Endlich haben wir einen Pointer auf unser inzwischen auch im VRAM der Grafikkarte richtig dimensioniertes Vertexbufferobject, und sind nun in der Lage dort unsere Vertexdaten abzulegen. Was jetzt folgt ist ein wenig Pseudo-Code der diesen Vorgang darstellt. Pseudo-Code deshalb, weil die Vertexdaten die ins VBO kommen ja in jeder Anwendung unterschiedlich sind, und man so auch selbst ein wenig denken muss:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
VertexDatenLaenge := 0;&lt;br /&gt;
for i := 0 to High(MeineVertexDaten) do&lt;br /&gt;
 begin&lt;br /&gt;
 VertexPointer    := VBOPointer;&lt;br /&gt;
&lt;br /&gt;
 VertexPointer^.X := GeneriertesVertex.X;&lt;br /&gt;
 VertexPointer^.Y := GeneriertesVertex.Y;&lt;br /&gt;
 VertexPointer^.Z := GeneriertesVertex.Z;&lt;br /&gt;
 VertexPointer^.S := GeneriertesVertex.S;&lt;br /&gt;
 VertexPointer^.T := GeneriertesVertex.T;&lt;br /&gt;
&lt;br /&gt;
 inc(Integer(VBOPointer), SizeOf(TVertex));&lt;br /&gt;
&lt;br /&gt;
 inc(VertexDatenLaenge);&lt;br /&gt;
 end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da sich dieses Tutorial (und v.&amp;amp;nbsp;a. diese Methode der Vertexdatenübergabe) an die fortgeschritteneren wendet, rede ich nicht lange um den heissen Brei herum. Wir durchlaufen also eine Schleife, in der wir unsere Vertexdaten dynamisch erstellen. Entweder in jedem Durchlauf, oder wir laden die Daten vor der Schleife z.&amp;amp;nbsp;B. aus einem 3D-Modell und entfernen sie danach aus dem Hauptspeicher. Erste Methode spart sowohl beim Programmstart, also auch während des Programmlaufes Arbeitsspeicher, während letztere dies nur während des Programmablaufs macht.&lt;br /&gt;
&lt;br /&gt;
Wir setzen die Adresse des Pointers der auf das momentan zu verändernde Vertex zeigt also auf die aktuelle Zeigerposition im VBO und schreiben dann unser Vertex direkt in den Grafikkartenspeicher. Ist dies getan, müssen wir die Adresse unseres VBOPointers natürlich um die Größe des gerade geschriebenen Vertexes erhöhen. Der Typecast auf ein Integer geschieht deshalb, weil man Pointer in Delphi nicht so einfach erhöhen oder verringern kann, Integers hingegen schon.&lt;br /&gt;
&lt;br /&gt;
Ich gehe mal davon aus,das meine Leserschaft mit obigem Codeschnippsel keinerlei Probleme hatte und bringe diese Methode der Übergabe von Vertexdaten an das VBO dann auch mit folgender Quellcodezeile zu Ende:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glUnMapBuffer(GL_ARRAY_BUFFER);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie unschwer zu erraten geben wir hier unser VBO für den weiteren Zugriff wieder frei. Dies ist nötig um dies später rendern zu können.&lt;br /&gt;
&lt;br /&gt;
==Übergabe der Vertexdaten (Variante 2: Über den Hauptspeicher)==&lt;br /&gt;
&lt;br /&gt;
Wem obige Variante nicht zugesagt hat, weil sie ihm zu komplex war, oder weil er seine Vertexdaten aus diversen Gründen im Hauptspeicher braucht, dem wird in diesem Abschnitt geholfen.&lt;br /&gt;
&lt;br /&gt;
Das Übergeben der Vertexdaten an das VBO über den Hauptspeicher gestaltet sich nämlich sehr einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBufferData(GL_ARRAY_BUFFER, SizeOf(VertexDaten), @VertexDaten, GL_STATIC_DRAW);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht einfach aus,hört sich einfach an und ist auch einfach! Statt wie im letzten Kapitel für die Vertexdaten einen Zeiger auf '''nil''' zu übergeben, übergeben wir OpenGL jetzt einen direkten Zeiger auf die Vertexdaten die im Hauptspeicher abgelegt sind. Die Daten werden dann zum VBO hochgeladen, und können anschliessen auch wieder aus dem Hauptspeicher entfernt werden.&lt;br /&gt;
&lt;br /&gt;
==Rendern des VBOs==&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun also schon zum Ende unseres VBO-Tutorials. Dank der Einfachheit dieser Extension gabs halt einfach nicht mehr zu erklären. Das Zeichnen gestaltet sich nämlich OpenGL-typisch mehr als einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glInterleavedArrays(GL_T2F_V3F, SizeOf(TVertex), nil);&lt;br /&gt;
glDrawArrays(GL_QUADS, 0, VertexDatenLaenge);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schnell gezeichnet und schnell erklärt. Der erste Parameter gibt an, in welchem Format die Vertexdaten unseres VBOs abgelegt wurden (wir erinnern uns: '''GL_T2F_V3F'''), während der zweite Parameter den Speicherplatz, der zwischen zwei Vertices liegt, angibt. Würden wir ein einfaches Vertexarray zeichnen, so wäre der letzte Parameter ein Pointer auf die Vertexdaten im Hauptspeicher. Da wir allerdings vorher unser VBO gebunden haben, teilt hier ein '''nil''' mit, dass die vorher ins VBO geschriebenen Vertexdaten gerendert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Mittels [[glDrawArrays]] sagen wir OpenGL dann noch, das es unsere VBO-Daten als Quads rendern soll.&lt;br /&gt;
&lt;br /&gt;
==Freigabe==&lt;br /&gt;
&lt;br /&gt;
Wie mit allen Objekten in der OpenGL ists auch keine schlechte Idee, unser VBO freizugeben,wenn es nicht mehr benötigt wird. Und obwohl beim Löschen des Renderkontextes solche Objekte vom Grafikkartentreiber freigegeben werden sollten, wäre es keine schlechte Idee des selbst zu erledigen,für den Fall das der Treiber da schlampig arbeitet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glDeleteBuffers(1, @VBO);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Weitere Vertexformate==&lt;br /&gt;
Wem allein Texturkoordinaten und Vertices nicht reichen, sondern auch Farbangaben oder Vertexnormalen braucht, muss sich eines der folgenden Formate aussuchen. Die Konstantennamen sind logisch aufgebaut: ''GL_AngabeAnzahlTyp_AngabeAnzahlTyp...''&lt;br /&gt;
Als Angabe gibt es '''V'''ertex, '''T'''exturkoordinaten, '''N'''ormalen und '''C'''olor-Werte, also Farben.&lt;br /&gt;
Anzahl ist die Anzahl der Komponenten pro Angabe (V3 wären zum Bespiel die X, Y und Z-Koordinaten eines dreidimensionalen Vertex).&lt;br /&gt;
Typ ist entweder '''F'''loat oder '''U'''nsigned '''B'''yte. Die Vertexdaten müssen in der richtigen Reihenfolge mit den richtigen Typen an das VBO übergeben werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  GL_V2F&lt;br /&gt;
  GL_V3F&lt;br /&gt;
  GL_C4UB_V2F&lt;br /&gt;
  GL_C4UB_V3F&lt;br /&gt;
  GL_C3F_V3F           &lt;br /&gt;
  GL_N3F_V3F           &lt;br /&gt;
  GL_C4F_N3F_V3F       &lt;br /&gt;
  GL_T2F_V3F&lt;br /&gt;
  GL_T4F_V4F&lt;br /&gt;
  GL_T2F_C4UB_V3F&lt;br /&gt;
  GL_T2F_C3F_V3F&lt;br /&gt;
  GL_T2F_N3F_V3F      // Wohl eines der sinnvollsten Vertexformate. 2 Floats für Texturkoordinaten, 3 Floats für den Normalenvektor und 3 Floats für den eigentlichen Vertex.&lt;br /&gt;
  GL_T2F_C4F_N3F_V3F&lt;br /&gt;
  GL_T4F_C4F_N3F_V4F&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist sinnvoll, sich für jedes der Vertexformate, die man verwendet, einen Typen anzulegen, um später einfacher mit den VBOs arbeiten zu können.&lt;br /&gt;
&lt;br /&gt;
Falls man mit Shadern arbeitet kann man sich die Wahl des Vertexformates eigentlich sparen, denn hier kann man z.B. für jeden Attributtyp den man braucht (Vertex, Normale, Farbe, Normale, etc.) ein eigenes VBO anlegen und dieses dann entsprechend seinen Bedürfnissen im Shader interpretieren, oder einfach nur ein riesiges VBO nutzen und dort alle Daten nach Belieben ablegen und im Shader selbst interpretieren.&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Das wars auch schon. Wie zu erkennen ist das Vertexbufferobjekt mal wieder eine gut durchdachte, recht nützliche und zudem auch weit nutzbare Erweiterung, die OpenGL technisch wieder einen Schritt weitergebracht hat.&lt;br /&gt;
&lt;br /&gt;
Wer mehr wissen will, der sollte sich unbedingt mal die passende [http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt Spezifikation] ansehen.&lt;br /&gt;
&lt;br /&gt;
Hoffe das Tutorial hat euch soviel Spaß gemacht wie mir das Verfassen des selbigen und ich hoffe auf reges Feedback!&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
&lt;br /&gt;
Sascha Willems (webmaster_at_delphigl.de)&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
[http://developer.nvidia.com/attach/6427 Nvidia: Using Vertex Buffer Objects]&lt;br /&gt;
&lt;br /&gt;
[http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt Spezifikation]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Cubemap]]|[[Tutorial_Vertexprogramme]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Vertexbuffer]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Vertexbufferobject&amp;diff=22452</id>
		<title>Tutorial Vertexbufferobject</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Vertexbufferobject&amp;diff=22452"/>
				<updated>2009-01-12T12:59:34Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Aktualisiert, kleine Änderungen, neue Extensions statt alter ARB-Varianten&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=GL_ARB_Vertex_Buffer_Object=&lt;br /&gt;
==Ave!==&lt;br /&gt;
&lt;br /&gt;
Und willkommen zu meinem zweiten GL_ARB-Extension Tutorial. Diesmal beschäftigen wir uns mit der recht neuen '''GL_ARB_Vertex_Buffer_Object'''-Extension, die vom ARB am 12.Februar 2003 fertiggestellt und vor kurzem auch als Corefeature in OpenGL 1.5 promoted wurde.&lt;br /&gt;
&lt;br /&gt;
VBOs (Vertex Buffer Objects) sind quasi eine Erweiterung der recht weit verbreiteten Vertexarrays, die jedoch den großen Vorteil besitzen, dass ihre Vertexdaten serverseitig, also im schnellen VRAM der Grafikkarte, statt wie bei den VAs im Hauptspeicher, abgelegt werden. Das ist bei einer Displayliste zwar (fast) genauso der Fall, allerdings können die Daten nicht so einfach dynamisch geändert werden, was bei einem VBO aber bei Bedarf sehr einfach ist.&lt;br /&gt;
&lt;br /&gt;
Kurz gesagt vereint das VBO also die Flexibilität eines Vertexarrays mit der Geschwindigkeit einer Displayliste und eignet sich daher besonders für das Rendern aufwändiger Geometrie, egal ob statisch oder dynamisch.&lt;br /&gt;
&lt;br /&gt;
Eine weitere tolle Neuerung der VBO-API ist die Tatsache, dass man sich von OpenGL einen Pointer übergeben lassen kann, mit dessen Hilfe man Vertexdaten direkt in den VRAM schreiben kann. Dadurch spart man sich natürlich den Umweg über den Hauptspeicher und somit auch den erhöhten Speicherbedarf des Programmes beim Laden von Modellen o.&amp;amp;nbsp;Ä.&lt;br /&gt;
&lt;br /&gt;
VBOs bieten übrigens auch die Möglichkeit, sie je nach Anwendungsfall vom Grafikkartentreiber &amp;quot;optimieren&amp;quot; zu lassen. So legt man Vertexdaten, die im Nachhinein nicht mehr verändert werden sollenm am besten mit dem Schlüsselwort ''STATIC_DRAW_ARB'' ab, während dynamische Vertexdaten über ''DYNAMIC_DRAW_ARB'' abgelegt werden sollten. Doch dazu gibts später nähere Informationen.&lt;br /&gt;
&lt;br /&gt;
==Hardwareunterstützung==&lt;br /&gt;
&lt;br /&gt;
Inzwischen sollten alle gängigen Grafikkarten diese Extension problemlos unterstützen, ältere Modelle tun dies aber evtl. nur emuliert über den Treiber. Will man sein Programm auch für sehr alte Hardware (Karten älter als ATIs Radeon 9x00 bzw. NVidias GeForce 4-Serie) lauffähig machen, sollte man noch einen alternativen Renderpfad auf Basis von Displaylisten einbauen.&lt;br /&gt;
&lt;br /&gt;
==Erstellen des Vertexbufferobjects==&lt;br /&gt;
&lt;br /&gt;
Wie der Name vermuten lässt, handelt es sich beim VBO um ein Objekt, welches in Sachen Syntax an die anderen in OpenGL verfügbaren Objekte wie z.&amp;amp;nbsp;B. Texturenobjekte angelehnt ist. Das Erstellen eines VBOs geht daher genauso einfach von der Hand:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glGenBuffers(1, @VBO);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun sollten wir in VBO eine gültige ID zurückgeliefert bekommen haben, welche ein Vertex buffer object referenziert.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun ein VBO erstellt haben, sollten wir dieses natürlich auch &amp;quot;aktivieren&amp;quot; (also binden), damit wir mit ihm arbeiten können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBindBufferARB(GL_ARRAY_BUFFER, VBO);&lt;br /&gt;
glEnableClientState(GL_VERTEX_ARRAY);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie erwähnt binden wir in der ersten Zeile unser frisch erstelltes VBO, während wir in der zweiten Zeile Vertexarrays auf der Clientseite aktivieren. Dies ist deshalb nötig, da wir das VBO später genauso zeichnen werden wie dies bei einem normalen VA der Fall wäre.&lt;br /&gt;
&lt;br /&gt;
==Übergabe der Vertexdaten (Variante 1: Ohne Umweg über den Hauptspeicher)==&lt;br /&gt;
&lt;br /&gt;
Wie in der Einleitung bereits erwähnt, bietet uns die VBO-API die Möglichkeit, unsere Vertexdaten ohne Umweg über den Hauptspeicher direkt in den Grafikkartenspeicher zu schreiben. Da dies eines der besten Features dieser neuen Extension ist, wollen wir uns auch zuerst mit dieser Übergabemethode beschäftigen.&lt;br /&gt;
&lt;br /&gt;
''Allerdings erstmal eine kleine Warnung vorweg: Pointer sind ein recht komplexes Thema, und ihre Nutzung erfordert einige Kenntnisse. Wer weder weiß, wie man damit umgeht, noch wie man sie einsetzt, sollte sich da zuerstmal schlau machen. Denn mit Pointer kann man ganz böse Sachen machen, wenn man sie nicht richtig nutzen kann!''&lt;br /&gt;
&lt;br /&gt;
Um unsere Vertexdaten als Pointer zu nutzen,müssen wir erstmal eine Vertexstruktur erstellen und auch einen passenden Pointertyp. Der Pointertyp ist zwar nicht zwingend (ein ^ täte es auch), aber macht die Sache übersichtlicher:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
PVertex = ^TVertex;&lt;br /&gt;
TVertex = packed record&lt;br /&gt;
 S,T,X,Y,Z : TGLFloat;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sicher fragen sich einige von euch jetzt, warum unser TVertex gerade so aussieht (also zuerst S,T und dann der Rest). Das liegt daran, dass wir unser VBO später über die Funktion [[glInterleavedArrays]] rendern werden, welche wissen will, wie unsere Vertexdaten im Speicher abgelegt sind. Unsere Vertexstruktur entspricht dabei dem Format ''GL_T2F_V3F''. ''T2F'' entspricht 2 Floats für die Texturenkoordinaten (S&amp;amp;T), gefolgt von ''V3F'' für die drei Floatwerte die unsere Vertexkoordinaten repräsentieren. Wenn ihr ein anderes Vertexformat verwendet, müsst ihr euch auch ein passendes Vertexformat aus der Spezifikation heraussuchen.&lt;br /&gt;
Ich verwende oben übrigens einen '''packed Record''' (auch wenn dies bei unserem Vertexformat nicht unbedingt ein Muss ist). Dies tue ich deshalb, da Delphi Werte bei einem normalen Record für einen beschleunigten Zugriff an einem (Double)Word-Raster ausrichtet und dies deshalb bei bestimmten Vertexformaten Probleme bereiten könnte.&lt;br /&gt;
&lt;br /&gt;
Hoffe mal das euch obiges klar ist,denn jetzt gehts ans Eingemachte. Wir kommen zum &amp;quot;schwersten&amp;quot; (ist ja ein relativer Begriff) Teil des Tutorials, nämlich der Übergabe der Vertexdaten an das VBO. Dazu müssen wir OpenGL zuerstmal mitteilen, wie groß unser VBO eigentlich sein soll,damit wir auch genug Platz im VRAM bekommen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBufferDataARB(GL_ARRAY_BUFFER, VertexAnzahl*SizeOf(TVertex), nil, GL_STATIC_DRAW);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schauen wir uns also mal die Parameter von [[glBufferData]] an. Zuerst müssen wir OpenGL mitteilen, was für einen Puffer wir erstellen wollen (in zukünftigen Versionen werden wohl noch andere folgen, z.&amp;amp;nbsp;B. Überbuffer). In unserem Falle also einen Arraypuffer. Parameter zwei übergibt dann den Speicherplatz, den wir reservieren wollen und ist recht selbsterklärend. Der dritte Parameter würde normalerweise einen Pointer auf unsere Vertexdaten enthalten. Da wir diese aber nicht im Hauptspeicher abgelegt haben, sondern über einen Pointer dort noch ablegen wollen, übergeben wir hier '''nil'''. OpenGL nimmt dies zur Kenntnis und spuckt dementsprechend auch keinen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Den letzten Parameter hab ich auch schon kurz in der Einführung angesprochen. Er teilt OpenGL mit, auf welchen Anwendungsfall unser VBO optimiert werden soll. Dabei gibt es folgende Anwendungsfälle,die ihr euch dann entsprechend eurer VBO-Verwendung aussuchen könnt:&lt;br /&gt;
&lt;br /&gt;
{|rules=&amp;quot;all&amp;quot; border = &amp;quot;1&amp;quot;&lt;br /&gt;
! STREAM_DRAW&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann eher selten als Quelle für OpenGL-Befehle genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! STREAM_READ&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann selten von der Anwendung angefordert.&lt;br /&gt;
|-&lt;br /&gt;
! STREAM_COPY&lt;br /&gt;
| Die Vertexdaten werden einmal durch Kopieren von der GL übergeben und dann eher selten als Quelle für OpenGL-Befehle genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! STATIC_DRAW&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann recht oft von der Anwendung zum Rendern genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! STATIC_READ&lt;br /&gt;
| Die Vertexdaten werden einmal übergeben und dann recht oft von der Anwendung angefordert.&lt;br /&gt;
|-&lt;br /&gt;
! STATIC_COPY&lt;br /&gt;
| Die Vertexdaten werden einmal durch Kopieren von der GL übergeben und dann recht oft von der Anwendung zum Rendern genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! DYNAMIC_DRAW&lt;br /&gt;
| Die Vertexdaten werden wiederholt angegeben (verändert) und recht oft von der Anwendung zum Rendern genutzt.&lt;br /&gt;
|-&lt;br /&gt;
! DYNAMIC_READ&lt;br /&gt;
| Die Vertexdaten werden wiederholt durch das Auslesen von Daten durch OpenGL angegeben (verändert) und oft von der Anwendung angefordert.&lt;br /&gt;
|-&lt;br /&gt;
! DYNAMIC_COPY&lt;br /&gt;
| Die Vertexdaten werden wiederholt durch das Auslesen von Daten durch OpenGL angegeben (verändert) und recht oft zum Rendern genutzt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Beachtet werden sollte, dass es sich bei obigen Anwendungsmuster nur um Hinweise (Hints) handelt, die es auch in anderen Bereichen von OpenGL gibt. Diese Hinweise sind allerdings nicht verbindlich und werden von Treiber zu Treiber unterschiedlich behandelt.&lt;br /&gt;
&lt;br /&gt;
Nachdem OpenGL nun weiss was für ein VBO wir genau haben wollen, brauchen wir letztendlich nur noch einen Pointer, der &amp;quot;auf&amp;quot; das VBO zeigt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
VBOPointer := glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glMapBuffer]] liefert uns einen Pointer zurück, der den Speicherplatz des VBOs in den Adressraum des Clients &amp;quot;ummappt&amp;quot;, also in den Hauptspeicher. Dadurch wird es dann möglich, über eine Adresse im Hauptspeicher des Rechners direkt in den Grafikkartenspeicher zu schreiben. Der zweite Parameter gibt übrigens an, das wir in das VBO schreiben wollen. Der einzige weitere zulässige Parameter ist hier '''GL_READ_ONLY''', welcher zum Auslesen des VBOs dient.&lt;br /&gt;
&lt;br /&gt;
Endlich haben wir einen Pointer auf unser inzwischen auch im VRAM der Grafikkarte richtig dimensioniertes Vertexbufferobject, und sind nun in der Lage dort unsere Vertexdaten abzulegen. Was jetzt folgt ist ein wenig Pseudo-Code der diesen Vorgang darstellt. Pseudo-Code deshalb, weil die Vertexdaten die ins VBO kommen ja in jeder Anwendung unterschiedlich sind, und man so auch selbst ein wenig denken muss:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
VertexDatenLaenge := 0;&lt;br /&gt;
for i := 0 to High(MeineVertexDaten) do&lt;br /&gt;
 begin&lt;br /&gt;
 VertexPointer    := VBOPointer;&lt;br /&gt;
&lt;br /&gt;
 VertexPointer^.X := GeneriertesVertex.X;&lt;br /&gt;
 VertexPointer^.Y := GeneriertesVertex.Y;&lt;br /&gt;
 VertexPointer^.Z := GeneriertesVertex.Z;&lt;br /&gt;
 VertexPointer^.S := GeneriertesVertex.S;&lt;br /&gt;
 VertexPointer^.T := GeneriertesVertex.T;&lt;br /&gt;
&lt;br /&gt;
 inc(Integer(VBOPointer), SizeOf(TVertex));&lt;br /&gt;
&lt;br /&gt;
 inc(VertexDatenLaenge);&lt;br /&gt;
 end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da sich dieses Tutorial (und v.&amp;amp;nbsp;a. diese Methode der Vertexdatenübergabe) an die fortgeschritteneren wendet, rede ich nicht lange um den heissen Brei herum. Wir durchlaufen also eine Schleife, in der wir unsere Vertexdaten dynamisch erstellen. Entweder in jedem Durchlauf, oder wir laden die Daten vor der Schleife z.&amp;amp;nbsp;B. aus einem 3D-Modell und entfernen sie danach aus dem Hauptspeicher. Erste Methode spart sowohl beim Programmstart, also auch während des Programmlaufes Arbeitsspeicher, während letztere dies nur während des Programmablaufs macht.&lt;br /&gt;
&lt;br /&gt;
Wir setzen die Adresse des Pointers der auf das momentan zu verändernde Vertex zeigt also auf die aktuelle Zeigerposition im VBO und schreiben dann unser Vertex direkt in den Grafikkartenspeicher. Ist dies getan, müssen wir die Adresse unseres VBOPointers natürlich um die Größe des gerade geschriebenen Vertexes erhöhen. Der Typecast auf ein Integer geschieht deshalb, weil man Pointer in Delphi nicht so einfach erhöhen oder verringern kann, Integers hingegen schon.&lt;br /&gt;
&lt;br /&gt;
Ich gehe mal davon aus,das meine Leserschaft mit obigem Codeschnippsel keinerlei Probleme hatte und bringe diese Methode der Übergabe von Vertexdaten an das VBO dann auch mit folgender Quellcodezeile zu Ende:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glUnMapBuffer(GL_ARRAY_BUFFER);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie unschwer zu erraten geben wir hier unser VBO für den weiteren Zugriff wieder frei. Dies ist nötig um dies später rendern zu können.&lt;br /&gt;
&lt;br /&gt;
==Übergabe der Vertexdaten (Variante 2: Über den Hauptspeicher)==&lt;br /&gt;
&lt;br /&gt;
Wem obige Variante nicht zugesagt hat, weil sie ihm zu komplex war, oder weil er seine Vertexdaten aus diversen Gründen im Hauptspeicher braucht, dem wird in diesem Abschnitt geholfen.&lt;br /&gt;
&lt;br /&gt;
Das Übergeben der Vertexdaten an das VBO über den Hauptspeicher gestaltet sich nämlich sehr einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glBufferData(GL_ARRAY_BUFFER, SizeOf(VertexDaten), @VertexDaten, GL_STATIC_DRAW);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht einfach aus,hört sich einfach an und ist auch einfach! Statt wie im letzten Kapitel für die Vertexdaten einen Zeiger auf '''nil''' zu übergeben, übergeben wir OpenGL jetzt einen direkten Zeiger auf die Vertexdaten die im Hauptspeicher abgelegt sind. Die Daten werden dann zum VBO hochgeladen, und können anschliessen auch wieder aus dem Hauptspeicher entfernt werden.&lt;br /&gt;
&lt;br /&gt;
==Rendern des VBOs==&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun also schon zum Ende unseres VBO-Tutorials. Dank der Einfachheit dieser Extension gabs halt einfach nicht mehr zu erklären. Das Zeichnen gestaltet sich nämlich OpenGL-typisch mehr als einfach:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glInterleavedArrays(GL_T2F_V3F, SizeOf(TVertex), nil);&lt;br /&gt;
glDrawArrays(GL_QUADS, 0, VertexDatenLaenge);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schnell gezeichnet und schnell erklärt. Der erste Parameter gibt an, in welchem Format die Vertexdaten unseres VBOs abgelegt wurden (wir erinnern uns: '''GL_T2F_V3F'''), während der zweite Parameter den Speicherplatz, der zwischen zwei Vertices liegt, angibt. Würden wir ein einfaches Vertexarray zeichnen, so wäre der letzte Parameter ein Pointer auf die Vertexdaten im Hauptspeicher. Da wir allerdings vorher unser VBO gebunden haben, teilt hier ein '''nil''' mit, dass die vorher ins VBO geschriebenen Vertexdaten gerendert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Mittels [[glDrawArrays]] sagen wir OpenGL dann noch, das es unsere VBO-Daten als Quads rendern soll.&lt;br /&gt;
&lt;br /&gt;
==Freigabe==&lt;br /&gt;
&lt;br /&gt;
Wie mit allen Objekten in der OpenGL ists auch keine schlechte Idee, unser VBO freizugeben,wenn es nicht mehr benötigt wird. Und obwohl beim Löschen des Renderkontextes solche Objekte vom Grafikkartentreiber freigegeben werden sollten, wäre es keine schlechte Idee des selbst zu erledigen,für den Fall das der Treiber da schlampig arbeitet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glDeleteBuffers(1, @VBO);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Weitere Vertexformate==&lt;br /&gt;
Wem allein Texturkoordinaten und Vertices nicht reichen, sondern auch Farbangaben oder Vertexnormalen braucht, muss sich eines der folgenden Formate aussuchen. Die Konstantennamen sind logisch aufgebaut: ''GL_AngabeAnzahlTyp_AngabeAnzahlTyp...''&lt;br /&gt;
Als Angabe gibt es '''V'''ertex, '''T'''exturkoordinaten, '''N'''ormalen und '''C'''olor-Werte, also Farben.&lt;br /&gt;
Anzahl ist die Anzahl der Komponenten pro Angabe (V3 wären zum Bespiel die X, Y und Z-Koordinaten eines dreidimensionalen Vertex).&lt;br /&gt;
Typ ist entweder '''F'''loat oder '''U'''nsigned '''B'''yte. Die Vertexdaten müssen in der richtigen Reihenfolge mit den richtigen Typen an das VBO übergeben werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  GL_V2F&lt;br /&gt;
  GL_V3F&lt;br /&gt;
  GL_C4UB_V2F&lt;br /&gt;
  GL_C4UB_V3F&lt;br /&gt;
  GL_C3F_V3F           &lt;br /&gt;
  GL_N3F_V3F           &lt;br /&gt;
  GL_C4F_N3F_V3F       &lt;br /&gt;
  GL_T2F_V3F&lt;br /&gt;
  GL_T4F_V4F&lt;br /&gt;
  GL_T2F_C4UB_V3F&lt;br /&gt;
  GL_T2F_C3F_V3F&lt;br /&gt;
  GL_T2F_N3F_V3F      // Wohl eines der sinnvollsten Vertexformate. 2 Floats für Texturkoordinaten, 3 Floats für den Normalenvektor und 3 Floats für den eigentlichen Vertex.&lt;br /&gt;
  GL_T2F_C4F_N3F_V3F&lt;br /&gt;
  GL_T4F_C4F_N3F_V4F&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist sinnvoll, sich für jedes der Vertexformate, die man verwendet, einen Typen anzulegen, um später einfacher mit den VBOs arbeiten zu können.&lt;br /&gt;
&lt;br /&gt;
Falls man mit Shadern arbeitet kann man sich die Wahl des Vertexformates eigentlich sparen, denn hier kann man z.B. für jeden Attributtyp den man braucht (Vertex, Normale, Farbe, Normale, etc.) ein eigenes VBO anlegen und dieses dann entsprechend seinen Bedürfnissen im Shader interpretieren, oder einfach nur ein riesiges VBO nutzen und dort alle Daten nach Belieben ablegen und im Shader selbst interpretieren.&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Das wars auch schon. Wie zu erkennen ist das Vertexbufferobjekt mal wieder eine gut durchdachte, recht nützliche und zudem auch weit nutzbare Erweiterung, die OpenGL technisch wieder einen Schritt weitergebracht hat.&lt;br /&gt;
&lt;br /&gt;
Wer mehr wissen will, der sollte sich unbedingt mal die passende [http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt Spezifikation] ansehen.&lt;br /&gt;
&lt;br /&gt;
Hoffe das Tutorial hat euch soviel Spaß gemacht wie mir das Verfassen des selbigen und ich hoffe auf reges Feedback!&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
&lt;br /&gt;
Sascha Willems (webmaster_at_delphigl.de)&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
[http://developer.nvidia.com/attach/6427 Nvidia: Using Vertex Buffer Objects]&lt;br /&gt;
&lt;br /&gt;
[http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt Spezifikation]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Cubemap]]|[[Tutorial_Vertexprogramme]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Vertexbuffer]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Benutzer:Sascha_Willems&amp;diff=21729</id>
		<title>Benutzer:Sascha Willems</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Benutzer:Sascha_Willems&amp;diff=21729"/>
				<updated>2008-05-16T13:37:06Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[http://www.saschawillems.de Meine Homepage]&amp;lt;br&amp;gt;&lt;br /&gt;
OpenGL Demos und Tutorials, meine Projekte, und mehr.&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
''Ich bin der Geist, der stets verneint! Und das mit Recht; denn alles, was entsteht, ist wert, daß es zugrunde geht. Drum besser wär's, wenn nichts entstünde. So ist denn alles, was ihr Sünde, Zerstörung, kurz, das Böse nennt, mein eigentliches Element'' - [http://de.wikipedia.org/wiki/Mephistopheles Mephisto]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Modelformat&amp;diff=21728</id>
		<title>Modelformat</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Modelformat&amp;diff=21728"/>
				<updated>2008-05-15T13:56:14Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Bruteforce durch Immediate (korrektere Bezeichnung ersetzt), Statement zu Displaliste vs. VBO angepasst, siehe u.a. Dokumente von NVidia und ATI&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es gibt einige Arten von Modelformaten: Textbasierende, binäre, sogar grafische (siehe parametrisierte Geometry Maps).&lt;br /&gt;
Die Formate sind auf bestimmte Ziele ausgerichtet und dementsprechend auch im Aufbau unterschiedlich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In diesem Artikel möchte ich ein für OpenGL optimiertes Format vorstellen, welches als weiteres Kriterium eine sehr geringe CPU und Ladezeit in Anspruch nimmt. Also sollten wir uns erstmal die für OpenGL benötigten Daten angucken.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;typedef Vertex   float        x,y,z;&lt;br /&gt;
typedef Color    float        r,g,b;&lt;br /&gt;
typedef Normal   float        x,y,z;&lt;br /&gt;
typedef Texcoord float        u,v;&lt;br /&gt;
typedef Index    unsigned int i;&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
OpenGL bietet mehrere Möglichkeiten diese Daten darzustellen.&lt;br /&gt;
*[[VBO]] (vertex buffer object)&lt;br /&gt;
*Immediate (direkter Modus)([[glBegin]]/glEnd)&lt;br /&gt;
*[[Vertexarray]]&lt;br /&gt;
*[[Displayliste]]&lt;br /&gt;
Die effektivsten Varianten sind Displaylisten mit Vertexarray und VBO. In Sachen Geschwindigkeit sind Displaylisten immer noch die beste Möglichkeit (siehe z.B. [http://ati.amd.com/developer/gdc/2006/GDC06-OpenGL_Tutorial_Day-Hart-OpenGL_03_Performance.pdf folgendes Dokument] von ATI für die GDC2006, Seite 14), haben aber in Sachen Flexibilität Nachteile (entweder müssen sie neu erstellt werden, oder im Shader angepasst werden). VBO bietet uns zwei Möglichkeiten, die Daten in den VRam zu speichern. Entweder in Form mehrer Streams oder als ein einziger Stream. Hier sollte man alle Daten als einzelne Streams behandeln, also Vertexliste, Normalliste, Colorliste,... . So können wir später einzelne Streams abschalten und anschalten, wenn wir sie beim Zeichnen benötigen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wozu der Index? Der Index zeigt auf einen Wert in der Vertex-, Color-, Normal-, ...-Stream. Man kann also bei großen Models viel Platz sparen, wenn man Indices verwendet, da man jedes Datenelement nur einmal ablegt und durch den Index mehrfach verwenden kann.&lt;br /&gt;
&amp;lt;cpp&amp;gt;struct Model&lt;br /&gt;
{&lt;br /&gt;
 Vertex   *Verticelist;&lt;br /&gt;
 Normal   *Normallist;&lt;br /&gt;
 Color    *Colorlist;&lt;br /&gt;
 Texcoord *Texcoordlist;&lt;br /&gt;
 Index    *Indices;&lt;br /&gt;
};&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun brauchen wir auch Texturen und Shader für unsere Models. Um diese zu verwenden brauchen wir Faces, also müssen wir Flächen bilden. Jede Fläche bekommt den Startindex, die Vertexanzahl und ein Material zugewiesen. Das Material ist ein Name, über den wir auf eine Ressource zugreifen können, die die Texturen und Shader verwalten.&lt;br /&gt;
&amp;lt;cpp&amp;gt;struct Face&lt;br /&gt;
{&lt;br /&gt;
  unsigned int Start;&lt;br /&gt;
  unsigned int Count;&lt;br /&gt;
  string       MaterialName;&lt;br /&gt;
};&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Der Name ist allerdings ziemlich groß und würde in jeden Face wieder auftreten. Also speichern wir im Format eine Liste von Materialnamen und speichern im Face den Index in der Liste.&lt;br /&gt;
&amp;lt;cpp&amp;gt;struct Face&lt;br /&gt;
{&lt;br /&gt;
  unsigned int Start;&lt;br /&gt;
  unsigned int Count;&lt;br /&gt;
  unsigned int MaterialIndex;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
struct Model&lt;br /&gt;
{&lt;br /&gt;
 Vertex   *Verticelist;&lt;br /&gt;
 Normal   *Normallist;&lt;br /&gt;
 Color    *Colorlist;&lt;br /&gt;
 Texcoord *Texcoordlist;&lt;br /&gt;
 Index    *Indices;&lt;br /&gt;
 string   *MaterialList[32]; //feste Strings sind besser zu laden&lt;br /&gt;
 Face     *Facelist;&lt;br /&gt;
};&amp;lt;/cpp&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Für das Material File könnte z.B. ein Script oder eine XML Datei erstellt werden, die alle benötigten Texturen, Flags und Shader enthält. Wenn man Shader verwendet, dann könnte man die Tangenten mit dazu packen. &lt;br /&gt;
&lt;br /&gt;
Okay, nun müssen wird die Daten auch noch speichern und das so, dass wir sie möglichst schnell wieder laden können. Hier kann man Serialisierung aufgreifen und die Daten und den Loader entsprechend anpassen. Bei diesem Ansatz wird jede dynamische Variable (arrays/pointer) überarbeitet. Alle Daten, die gleich bleiben, werden 1 zu 1 geschrieben, für die dynamischen Daten wird ein Bereich am Ende des Formates zur Verfügung gestellt und dorthin verschoben. Die Differenz zwischen Position des Pointers/Array und der Stelle der abgelegten Daten nennt man Offset. Dieser wird an der entsprechenden Stelle in die Liste geschrieben. &lt;br /&gt;
Ein Beispiel kann das wohl besser beschreiben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;cpp&amp;gt;//eigentliche Struktur&lt;br /&gt;
struct Data&lt;br /&gt;
{&lt;br /&gt;
  unsigned int VerticeCount;&lt;br /&gt;
  Vertex* Vertice; //Array durch verticecount korrekt nutzbar (Delphi pVertex(Vertice+i)^ oder bei c++/freepascal Vertice[i])&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
//gut speicherbare und ladbare Version&lt;br /&gt;
struct SpeicherbareDaten&lt;br /&gt;
{&lt;br /&gt;
  unsigned int VerticeCount;&lt;br /&gt;
  #if defined(64BIT)//Pointer sind 64bit groß, der Offset liegt vor relocate an der Pointerstelle&lt;br /&gt;
    Vertex* Vertice;&lt;br /&gt;
  #else&lt;br /&gt;
    #if defined(32BIT)//Pointer sind 32bit groß, der offset=pointer und die anderen 4 Byte sind toter speicher&lt;br /&gt;
      Vertex* Vertice;&lt;br /&gt;
      unsigned int unused;&lt;br /&gt;
    #else&lt;br /&gt;
      Die Bitarchitektur ist nicht vorgesehen.&lt;br /&gt;
    #endif&lt;br /&gt;
  #endif&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void relocate(SpeicherbareDaten* Data)&lt;br /&gt;
{&lt;br /&gt;
  Data-&amp;gt;Vertice=(Vertex*)((char*)Data+(unsigned int)Data-&amp;gt;Vertice);&lt;br /&gt;
}&amp;lt;/cpp&amp;gt;&lt;br /&gt;
Aktuell hat keine Console oder PC eine größere Speicheradressierung als 64Bit.&lt;br /&gt;
Also werden die dynamischen Elemente mit offsets von 4byte und 4byte ungenutzt besetzt. Wir könnten die Daten nun mit einem read Aufruf laden und das relocate korrigiert den offset zu einem Pointer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Probleme der meisten Formate liegen im Aufbau, wenn oft noch geparsed und in mehreren Etappen geladen werden muss (braucht CPU Zeit und verschwendet Zeit beim Festplattenzugriff) und in der unpassenden Datenbeschaffenheit (eventuell konvertieren oder noch schlimmer, Speicherreservierung und konvertieren). Das oben beschriebene Speicher- und Ladesystem braucht nur einen einzigen Read Aufruf und hat danach die Daten komplett im Speicher. Dann noch ein relocate und wir haben die fertigen Daten. &lt;br /&gt;
Der Vorteil des relocate ist, dass man lediglich für dynamische Elemente einmal eine Addition ausführt (10 Arrays = 10 Additionen).&lt;br /&gt;
Durch die Anpassung an das von OpenGL gewollte Datenformat kann man ganz einfach die Daten in den VRam laden lassen (VBO Streams lassen grüssen) und leitet das Laden des Materials an die entsprechende Stelle weiter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Meine Umsetzung ist hier zu finden.&lt;br /&gt;
*[https://svn.linuxprofessionals.org/filedetails.php?repname=karmarama&amp;amp;path=%2Ftrunk%2Finclude%2Fkar_model.hpp kar_model.hpp]&lt;br /&gt;
*[https://svn.linuxprofessionals.org/filedetails.php?repname=karmarama&amp;amp;path=%2Ftrunk%2Fsrc%2Fkar_model.cpp kar_model.cpp]&lt;br /&gt;
*[https://svn.linuxprofessionals.org/filedetails.php?repname=karmarama&amp;amp;path=%2Ftrunk%2Fdemos%2Fdata%2Fexporter.py exporter.py(Blender exporter Script)]&lt;br /&gt;
Ein weiterer Vorteil ist der Codeumfang, denn dieser ist in meiner Implementierung gerademal 205 Zeilen lang.&lt;br /&gt;
Mein Testmodel hatte ~15k Vertice, Normals, Texcoords, ~46k Indices, 15k Faces, 1Material und keine Properties.&lt;br /&gt;
Die Dateigröße betrug 1,5MB und wurde in 7ms ungecached (erster Aufruf der Datei) und 3ms gecached(die Datei wurde seit dem Start von Windows schonmal angefasst) geladen, Pointer angepasst, VBOs für alle Daten erstellt und der Ladeprozess für die Textur angestoßen (alles in stolzen 7ms).&lt;br /&gt;
Das Laden des ganzen Models mit der einer Textur (512x512 dxt5) hat knapp 20ms gedauert.&lt;br /&gt;
[http://karmarama.developer-alliance.org/upload/model.PNG Ein nicht ganz aktuelles Screenshot.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei Fragen, Verbesserungsvorschlägen oder ähnlichem, mich([[Benutzer:TAK2004|TAK2004]]) einfach per PM im Forum ansprechen.&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=20744</id>
		<title>DGL Projekte</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=20744"/>
				<updated>2007-09-07T12:41:30Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; hinzugefügt, plus neue Kategorie &amp;quot;Strategie&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=DGL Projects Corner=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
Willkommen in der '''[[DelphiGL|DGL]] Projekte Ecke'''!&lt;br /&gt;
[[Bild:ProjekteEcke.jpg|center]]&lt;br /&gt;
Auf dieser Seite findet ihr Projekte von '''Mitgliedern von [http://DelphiGL.com DelphiGL.com]''' welche als '''abgeschlossen''' gewertet wurden.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Spiele==&lt;br /&gt;
Viele, um nicht zu sagen die meisten, DGL-Mitglieder widmen sich dem Thema Spiele. Was dabei an respektablen Ergebnissen entstanden ist könnt ihr in dieser Rubrik sehen.&lt;br /&gt;
&lt;br /&gt;
===3D Shooter und Labyrinth Spiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Action===&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_asteroids.jpg|framed|center|Link: '''[[Projekt_Asteroids|Asteroids]]''']]&lt;br /&gt;
&lt;br /&gt;
|Asteroids ist ein Remake des alten Klassikers &amp;quot;Comet&amp;quot;. Ziel des Spiels ist es so viel Asteroiden wie möglich zu zerstören um dadurch möglichst viele Punkte zusammeln, ohne dabei von den herum fliegenden Trümmern getroffen zu werden. &lt;br /&gt;
&lt;br /&gt;
An einem Spiel können bis zu 4 Spieler gleichzeitig teilnehmen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Magellan|Magellan]]&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_napalmbomber.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=90 Napalmbomber3D Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|NapalmBomber3D ist wie der Titel schon vermuten lässt ein 3D-Klon des bekannten Bombermanspielprinzips.Dieses hochbrisante und fesselnde Spiel besticht durch seine tolle Grafik die natürlich mittels OpenGL realisiert wurde.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zum Spiel gibt es natürlich auch noch einen Karteneditor mit dem sich in Windeseile eigenen Maps erstellen lassen.&lt;br /&gt;
&lt;br /&gt;
Neben inzwischen über 50.000 Downloads (im Schnitt sind es immernoch &amp;gt; 400 pro Monat) und diversen sehr guten Reviews hat es das Spiel sogar auf die PC-Action Ausgabe 07/2004 geschafft.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Brett-, Denk- und Kartenspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Projekt_Hex_Change_Screenshot.jpg|thumb|center|168px|Link: '''[[Projekt_Hex-Change|Hex-Change]]''']]&lt;br /&gt;
|2 Spieler konkurrieren um die Felder auf einer Hexagon Fläche. Das Spiel enthält einen Einzelspieler- (gegen KI) und einen &amp;quot;Hot-Seat&amp;quot;-Mehrspielermodus.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:H.A.S.E.|H.A.S.E.]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Reaktions- und Geschicklichkeitsspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_confusingball.jpg|framed|center|Link: '''[[Projekt_ConfusingBall|Confusing Ball]]''']]&lt;br /&gt;
&lt;br /&gt;
|In &amp;quot;Confusing Ball&amp;quot; steuert man einen Ball durch ein 3D Labyrinth, in dem die Gesetze der Physik neu definiert werden müssen. Um ins Ziel eines Levels zu gelangen benötigt man einen gewissen Orientierungssinn und ein gutes räumliches Vorstellungsvermögen.&lt;br /&gt;
Nebenher muss man ja auch noch die Münzen einsammeln, und den Bomben aus dem Weg gehen. Frei verschiebbare Steine erhöhen den Schwierigkeitsgrad.  &lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:MatReno|MatReno]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_beanmachine.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=86 Bean Machine Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Bean Machine&amp;quot; basiert auf dem Sega MegaDrive-Klassiker &amp;quot;Dr.Robotnik's Mean Bean Machine&amp;quot; (ausserhalb Europas auch als &amp;quot;Puyo Puyo&amp;quot; bekannt) und spielt sich somit ähnlich wie Tetris.&lt;br /&gt;
Auch dieses Klassikerremake spielt sich fast genauso wie die Vorlage, allerdings gibt es dank OpenGL recht aufwendige Grafiken, natürlich gewohnt komplett in 3D.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Heiliger Damm.jpg|thumb|center|168px|Link: '''[[Projekt Heiliger_Damm|Heiliger Damm]]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Heiliger Damm&amp;quot; ist ein Geschicklichkeitsspiel passend zum G8-Treffen 2007 in Heiligendamm. Der Spieler übernimmt die Aufgabe, den &amp;quot;heiligen Damm&amp;quot; (eine Oase in der Wüste) vor den Globalisierungsgegner zu schützen. Dies erreicht er, indem er mit der Maus Linien (Zäune) zieht.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:GTA-Place|Fabian Gärtner / GTA-Place]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Manager===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:PBM2_Kdr.jpg|thumb|center|168px|Link: '''[[Projekt_PBM2|PBall Manager 2]]''']]&lt;br /&gt;
&lt;br /&gt;
|Der PBall Manager 2 ist ein Sportmanager in welchem man in die Rolle des Trainers/Managers eines von 96 PBall Teams aus ganz Europa schlüpft. PBall selbst ist eine fiktive Sportart welche ähnlich Fußball ist.&lt;br /&gt;
&lt;br /&gt;
Im Spiel hat man die Kontrolle über alle Abläufe: Von der Aufstellung über Spielerkäufe bis hin zum Stadionausbau liegt alles in der Hand des Spielers. Doch auch die eigene Karriere kann voran getrieben werden indem man zu anderen Clubs wechselt.&lt;br /&gt;
&lt;br /&gt;
Das Ziel aller PBaller ist der Liga-Meister-Pokal indem die besten Clubs der 4 Europäischen Ligen um den Titel spielen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Flash|Kevin Fleischer alias Flash]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Simulationen===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Strategie===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:projektw_wiki_projektecke.jpg|thumb|center|168px|Link: '''[http://www.saschawillems.de/?page_id=114 Projekt &amp;quot;W&amp;quot;]''']]&lt;br /&gt;
&lt;br /&gt;
|Projekt &amp;quot;W&amp;quot; ist ein runden-basierendes Strategiespiel, dessen Ziel die Erlangung der Weltherrschaft ist. Der Spieler kann sich für eine der fünf neuen großen Nationen entscheiden, und muss diese dann zum Sieg über alle anderen Nationen führen.&lt;br /&gt;
&lt;br /&gt;
Dazu muss man seine Regionen verwalten, dort Gebäude bauen und auf wichtige Faktoren achten. Man baut zudem militärische Einheiten und gliedert diese in Divisionen um damit das eigene Territorium zu verteidigen, bzw. gegnerische Regionen einzunehmen. Zusätzlich kann man Technologien erforschen, die u.A. neue Gebäude und Militäreinheiten freischalten. Auch Spionage und Sabotage spielen eine wichtige Rolle, so kann man z.B. mit Hilfe eines eingeschleusten Spions an wichtige Informationen gelangen oder die Stromversorgung einer Region lahmlegen.&lt;br /&gt;
&lt;br /&gt;
Neben dem Einzelspielermodus, in dem man gegen die KI bestehen muss, gibt es auch einen Hotseatmodus, bei dem mehrere Spieler an einem Rechner gegeneinander antreten können. Präsentiert wirds wie gewohnt in schicker 3D-Grafik, und auf passender Hardware wird das Ganze noch mit Shadern garniert.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:projektw_wiki_projektecke.jpg&amp;diff=20743</id>
		<title>Datei:projektw wiki projektecke.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:projektw_wiki_projektecke.jpg&amp;diff=20743"/>
				<updated>2007-09-07T12:32:59Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Projekt &amp;quot;W&amp;quot; Vorschaubild für die Projektecke&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Projekt &amp;quot;W&amp;quot; Vorschaubild für die Projektecke&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Selektion&amp;diff=20735</id>
		<title>Diskussion:Selektion</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Selektion&amp;diff=20735"/>
				<updated>2007-08-25T18:50:01Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Die Seite wurde neu angelegt: Das Selektionsproblem besteht seit dem Release90 Treiber, und NVidia hat bisher nicht auf Anfragen bzw. Hinweise bezgl. dieser Problematik reagiert. Inzwischen sind wir...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das Selektionsproblem besteht seit dem Release90 Treiber, und NVidia hat bisher nicht auf Anfragen bzw. Hinweise bezgl. dieser Problematik reagiert. Inzwischen sind wir beim Release160 (aktuell ist 163.44) und dort ist es immernoch enthalten. Anscheinend wird das also nicht mehr &amp;quot;gefixt&amp;quot; (Selektion läuft ja eh in Software), so dass man auf OpenGLs Selektionsfunktionen besser ganz verzichtet.&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 20:50, 25. Aug. 2007 (CEST)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Bomberman2&amp;diff=20550</id>
		<title>Tutorial Bomberman2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Bomberman2&amp;diff=20550"/>
				<updated>2007-05-24T22:20:37Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Schlusswort */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Bomberman.gif|left]]&lt;br /&gt;
=Wir programmieren einen Bombermanklon! &amp;lt;br&amp;gt; &amp;lt;br&amp;gt; Teil 1 : Die Codebasis und der Editor=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
Ave, und willkommen zum zweiten Tutorial der Bombermanserie!&lt;br /&gt;
Nachdem wir uns im ersten Tutorial mit der Programmierung eines Editor und der grundlegenden Codebasis beschäftigt haben, gehts nun ans Eingemachte, nämlich den 3D-Bombermanklon.&lt;br /&gt;
&lt;br /&gt;
Da der Quellcode unseres Klons recht umfangreich ist, und in diesem Tutorial viele neue Techniken behandelt werden, wirds vielleicht etwas langatmig. Aber keine Angst, denn zum einen versuche ich alles recht ausführlich und auch für Neulinge verständlich zu erklären, und zum anderen werdet ihr am Ende dieses Tutorials einen kompletten Bombermanklon programmiert haben der euch (und eure Bekannten) mit stundenlangem Spielspaß belohnt!&lt;br /&gt;
&lt;br /&gt;
Deshalb gibts zum Ansporn erstmal zwei nette Screenshots direkt aus dem Spiel :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;[[Bild:Tutorial Bomberman2 nbomber1.jpg]][[Bild:Tutorial Bomberman2 nbomber2.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
Wie schon im ersten Tutorial vorausgesetzt, solltet ihr recht '''gute Kenntnisse in Object Pascal und OpenGL''' mitbringen.&lt;br /&gt;
Des Weiteren werde ich in unserem Quellcode starken Gebrauch von '''dynamischen Arrays''' machen, deren Nutzung und Verwaltung besonders für Personen die sich damit noch nicht beschäftigt haben recht verwirrend sein kann. Deshalb sind gute Kenntnisse zum Thema dynamische Arrays unentbehrlich. Aber keine Angst, denn alles was man zu diesem Thema braucht, findet sich in der Delphi-Hilfe.&lt;br /&gt;
&lt;br /&gt;
Neben der programmiertechnischen Seite, erfordert das Erschaffen eines Spiels natürlich auch den Umgang mit diversen Anwendungen. Einige davon sind kleine Tools, die sich mit einem Klick bedienen lassen während andere Programme eine nicht unerheblich Einarbeitungszeit voraussetzen. Die von mir genutzten Anwendungen und Tools im Überblick :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!colspan=&amp;quot;2&amp;quot;|Komerzielle Anwendungen&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Tutorial Bomberman2 app 3dsmax.jpg]]&lt;br /&gt;
|'''3D Studio MAX'''&lt;br /&gt;
Dieses 3D-Modellierungs und Renderprogramm dürfte wohl jedem ein Begriff sein, ist es doch eines der meistgenutzten Programme in der Spielebranche, und man wird wohl kaum ohne grundlegende Kenntnisse in diesem Programm auskommen.&lt;br /&gt;
&lt;br /&gt;
Wenn man sich erstmal (mittels des sehr gute Handbuches/mitgelieferten Tuts) eingearbeitet hat, dann geht das Erstellen von 3D-Modellen sehr leicht von der Hand. Den Hauptaktor unseres Bombermanklons hab ich in knapp 5 Min. erstellt.&lt;br /&gt;
&lt;br /&gt;
''Alternativen :''&amp;lt;br&amp;gt;&lt;br /&gt;
Als Alternative kommen eigentlich alle Programme in Frage, die in der Lage sind in das 3DS-Format zu exportieren, wie z.B. :&amp;lt;br&amp;gt;&lt;br /&gt;
Blender, Milksphape3D, Maya&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Tutorial Bomberman2 app photoshop.jpg]]&lt;br /&gt;
|'''Adobe Photoshop'''&lt;br /&gt;
Zu diesem Bildbearbeitungsprogramm muß ich wohl auch kaum was erzählen. Für alle die es nicht kennen : Das momentan wohl mächtigste Bildbearbeitungsprogramm. Die Einarbeitung ist nicht gerade einfach, doch wenn man sich mit diesem Programm erstmal auskennt, ist das Erstellen von guten Grafiken und Texturen schnell erledigt.&lt;br /&gt;
&lt;br /&gt;
''Alternativen :''&amp;lt;br&amp;gt;&lt;br /&gt;
Micrografx Picture Publisher, Gimp, JASC Paintshop Pro&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;2&amp;quot;|Kostenlose Tools&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Tutorial Bomberman2 tools explosion generator.jpg|center]]&lt;br /&gt;
|'''Explosion Generator'''&lt;br /&gt;
Dieses sehr praktische Tool rendert eine komplette Explosion in eine Textur, so daß man diese als Grundlage für eine Explosionsanimation ins einer Anwendung nutzen kann.&lt;br /&gt;
Nachteil der Sache ist, das sich das Erscheinungsbild der Explosion nur manuell über eine Textdatei anpassen lässt.&lt;br /&gt;
&lt;br /&gt;
Link : www.positech.co.uk&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Tutorial Bomberman2 tools bitmapfont builder.jpg]]&lt;br /&gt;
|'''Bitmapfont Builder'''&lt;br /&gt;
Mit diesem Programm lassen sich in Windeseile die für Bitmapfonts benötigten Fonttexturen auf Basis der in Windows verfügbaren Schriftarten erstellen.&lt;br /&gt;
&lt;br /&gt;
Link : www.lmnopc.com &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soviel also zu den (von mir) genutzten Anwendungen und Tools. Natürlich steht euch die Wahl frei, und ihr könnt die Tools und Programme eurer Wahl nutzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Ziel==&lt;br /&gt;
Wie schon kurz im Vorwort erwähnt, werden wir in diesem Tutorial einen kompletten Bombermanklon programmieren. Ziel dabei ist es, eine saubere Codebasis zu schreiben und euch grundlegende Techniken der Spieleprogrammierung beizubringen.&lt;br /&gt;
&lt;br /&gt;
Außerdem möchte ich euch einen recht sauberen Programmierstil beibringen, der bei vielen missen lässt und Programmcodes für andere oft unnutzbar macht.&lt;br /&gt;
&lt;br /&gt;
Folgendes wird euch im Tutorial erwarten, und euch auch bei zukünftigen Ausflügen in die Welt der Spieleprogrammierung von Nutzen sein :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 superbomberman help.gif|left]]&lt;br /&gt;
:::::* Timebased Movement (Frameunabhängige Bewegungen)&lt;br /&gt;
:::::* Texturenfonts&lt;br /&gt;
:::::* Statemachine&lt;br /&gt;
:::::* Kollisionsabfrage&lt;br /&gt;
:::::* Sound (via [http://www.fmod.de FMOD])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Projektstruktur==&lt;br /&gt;
Widmen wir uns nun kurz der Projektstruktur. Gemeint sind damit die genutzten Units, deren Funktion und Inhalt. Was genau wo gemacht wird, darüber werden wir uns später unterhalten.&lt;br /&gt;
&lt;br /&gt;
Bei eurer Projektstruktur solltet ihr vor allem darauf achten, nicht alles in eine Unit zu packen. Zum einen kann das später nämlich eingige Probleme machen (ich sage nur Kreuzbezüge) und zum anderen schadet es der Portabilität. Damit sind z.B. wiederverwendbare Programmteile wie der Texturenmanager oder das Soundsystem gemeint, die wenn sie in eine externe Unit ausgelagert werden, später ohne großen Aufwand in andere Projekte eingebunden werden können. Dadurch spart man sich über die Zeit sehr viel Arbeit und baut sich nach und nach mit jedem Projekt eine größere Codebasis auf.&lt;br /&gt;
&lt;br /&gt;
Wichtig ist natürlich (wie auch bei euren Variablen) die Namensgebung. Es scheint zwar verlockend, Objekt- oder Unitnamen so kurz wie möglich zu halten (besonders dann wenn man schreibfaul ist), aber das wird sich früher oder später rächen. Wenn man dann nämlich dutzende Units mit kryptischen Namen in denen dutzende Objekte mit noch kryptischeren Namen verteilt sind quer auf der Platte verteilt hat, fällt die Wiederverwendung und Zuordnung recht schwer!&lt;br /&gt;
&lt;br /&gt;
===Projektunits===&lt;br /&gt;
Nachfolgend gebe ich einen kurzen Überblick über alle dem Projekt zugehörigen Units und deren Inhalt.&lt;br /&gt;
&lt;br /&gt;
{{Unit|NapalmBomber3D_1.pas}}&lt;br /&gt;
:In dieser Unit befindet sich das Hauptformular unseres Bombermanklons. Hier findet neben der Initialisierung einiger wichtiger Variablen und Objekte nichts wirklich Interessantes statt.&lt;br /&gt;
&lt;br /&gt;
{{Unit|BombermanGlobal.pas}}&lt;br /&gt;
:Dies ist wie der Name schon vermuten lässt der Sitz unserer Codebasis und somit auch die wichtigste Unit unseres Projektes. Im letzten Tutorial hieß sie noch global.pas, wurde jedoch aufgrund der besseren Übersicht umbenannt.&lt;br /&gt;
&lt;br /&gt;
{{Unit|BombermanTextureManager.pas}}&lt;br /&gt;
:Naja, ich glaube es ist ein Einfaches anhand der Namensgebung herauszufinden was sich hinter dieser Unit versteckt. Im letzten Tutorial befand sich unser Texturenmanager noch in der globalen Unit. Allerdings will unser 3DS-Lader diesen Texturenmanager auch nutzen, und um Kreuzbezüge zu vermeiden habe ich ihn deshalb in eine extra Unit ausgelagert.&lt;br /&gt;
:Vorteil ist, neben der Tatsache das er nun von mehrern Units genutzt werden kann, auch noch die praktische Tatsache das man diese Unit unverändert für seine anderen Projekte nutzen kann. Also quasi ein Texturenmanager mit Zukunft. &lt;br /&gt;
&lt;br /&gt;
{{Unit|BombermanSoundSystem.pas}}&lt;br /&gt;
:Auch hier sollte die Unitfunktion anhand der Namensgebung recht einfach zu erkennen sein. Hier befindet sich das (momentan noch recht einfache) Soundsystem. Vorteil der Auslagerung in eine estra Unit ist auch hier die Portabilität.&lt;br /&gt;
&lt;br /&gt;
{{Unit|BombermanFont.pas}}&lt;br /&gt;
:In dieser Unit befindet sich unser Fontsystem zur Ausgabe von Bitmapfonts.Mehr dazu später. &lt;br /&gt;
&lt;br /&gt;
{{Unit|BombermanLoad3DS.pas}}&lt;br /&gt;
:Diese Unit bietet einige einfache Methode um 3D-Modelle im 3DS-Format zu laden und in eine unter OpenGL darstellbare DisplayListe zu wandeln.&lt;br /&gt;
:Die Unit basiert ursprünglich auf dem 3DS-Loader von [http://www.lischke-online.de Mike Lischke], und wurde von mir vereinfacht. Deshalb wirds hierzu keine genaue Erklärung geben. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Fremdunits===&lt;br /&gt;
Nachdem ich vorher alle dem Projekt zugehörigen Units aufgezählt habe, gibts hier noch einen ganz kurzen Überblick über die Fremdunits, die vom Projekt benötigt werden.&lt;br /&gt;
&lt;br /&gt;
{{Unit|Utils3DS.pas,Const3DS.pas,File3DS.pas,Types3DS.pas}}&lt;br /&gt;
:Diese Units werden von unserem 3DS-Lader benötigt und stammen auch aus Mike Lischkes 3DS-Packet. &lt;br /&gt;
&lt;br /&gt;
{{Unit|fmod.pas,fmodtypes.pas,fmoddyn.pas,fmoderros.pas,fmodpresets.pas}}&lt;br /&gt;
:Auch hier lässt die Namensgebung recht schnell auf die Units für die FMOD-Library schliessen, die als Grundlage für unser Soundsystem dient. &lt;br /&gt;
&lt;br /&gt;
{{Unit|GLBmp.pas}}&lt;br /&gt;
:Zu dieser Unit muß ich wohl kaum noch viele Worte verlieren, haben wir diese doch schon im Editor zum Laden der Texturen genutzt.&lt;br /&gt;
:Quelle : http://delphigl.cfxweb.net &lt;br /&gt;
&lt;br /&gt;
{{Unit|OpenGL12.pas}}&lt;br /&gt;
:Auch zu dieser Unit gibts nicht viel zu sagen. Sie beinhaltet alle nötigen Deklarationen und Funktionen zur Nutzung von OpenGL (1.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Verwendete Techniken==&lt;br /&gt;
Bevor wir uns also in den Quellcode stürzen, werde ich hier kurz die verwendeten Techniken, deren Nutzen und deren Umsetzung erklären. Alle hier erwähnten Dinge werdet ihr in weiteren Projekten verwenden können und sind für das Gelingen größerer Projekte fast unerlässlich, also lest aufmerksam!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 bombermanbomb.gif|left]]&lt;br /&gt;
===Timebased Movement=== &lt;br /&gt;
Bisher werden viele von euch (wenn sie denn schonmal ein kleines Spiel programmiert haben) die Ereignisse wie z.B. Spielerbewegung oder das aktualisieren einer Animation am Ende eines jeweiligen Frames abgearbeitet haben. Das ist zwar eine einfache Lösung, hat jedoch den riesigen Nachteil, dass Bewegungen und Animationen je nach Rendergeschwindigkeit (sprich Anzahl der pro Sekunde berechneten Bilder) verschieden sind.&lt;br /&gt;
Daraus resultiert z.B., das sich eine Spielfigur auf einem schnellen Rechner unkontrollierbar schnell nach vorne bewegt, während sie auf einem langsamen Rechner kaum von der Stelle kommt. Besonders schlecht ist sowas in einem Netzwerkspiel, da der Spieler am langsamen Rechner durch die langsamere Bewegung einen großen Nachteil hat.&lt;br /&gt;
Abhilfe schafft hier das sog. &amp;quot;Timebased Movement&amp;quot; (zu Deutsch : Zeitbasierte Bewegung), welches für gleichmäßige Bewegungen bzw. Animationen sorgt, in dem es (im Gegensatz zum &amp;quot;Framebased Movement&amp;quot;) diese mittels Zeitmessung auf einen festen Faktor angleicht.&lt;br /&gt;
&lt;br /&gt;
Die Implementation dieser Technik ist zum Glück recht einfach, bietet uns Windows doch netterweise (über einen im Chipsatz integrierten Timer) einen Hochpräzisionstimer dessen Auflösung um ein Tausendfaches höher ist als die eines Systemtimers.&lt;br /&gt;
Damit wird es uns möglich die oft nur sehr geringen Zeitabstände zwischen dem Rendern der Frames zu berechnen. Ein kleines Beispiel :&lt;br /&gt;
Ein moderner Rechner schafft heute in einer nicht besonders Aufwendigen 3D-Szene ohne Probleme an die 300-400 Bilder pro Sekunde. Dies bedeutet, das er zum Berechnen und Ausgeben eines Bildes 2,5ms (=1000ms/400fps) benötigt. Ein normaler Systemtimer würde uns eine solche Messung mit seiner &amp;quot;Genauigkeit&amp;quot; von ~55ms gänzlich unmöglich machen.&lt;br /&gt;
&lt;br /&gt;
Windows bietet uns nun zwei Funktionen zur Nutzung dieses Hochpräzisionstimer an :&lt;br /&gt;
&lt;br /&gt;
*function QueryPerformanceFrequency(var lpFrequency : TLargeInteger): Bool;&lt;br /&gt;
:Diese Funktion liefert uns in ''lpPerformanceCount'' die Anzahl der Takte pro Sekunde zurück, also die Auflösung des Timers. Dieser Wert variiert von Chipsatz zu Chipsatz und '''muß''' deshalb unbedingt beim Programmstart abgefragt und in einer Variable abgelegt werden.&lt;br /&gt;
:Meine Hauptplatine auf Basis des nVidia nForce2-Chipsatz liefert z.B. den Wert 3579545, d.h. dass der Hochpräzisionstimer genau 3.579.545 mal pro Sekunde taktet.&lt;br /&gt;
&lt;br /&gt;
*function QueryPerformanceCounter(var lpPerformanceCount : TLargeInteger): Bool;&lt;br /&gt;
:Obige Funktion liefert uns in ''lpPerformanceCount'' den aktuellen Stand des Hochpräzisionscounter, gemessen in Systemtakten zurück, und wird von uns zur genauen Zeitmessung genutzt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Ermitteln der Counterfrequenz====&lt;br /&gt;
Wie schon in der Funktionsbeschreibung erwähnt müssen wir vor der Nutzung des Hochpräzisionscounters erstmal dessen Frequenz ermitteln. Dies tun wir direkt beim Start unseres Programms im '''OnCreate'''-Ereignis des Hauptfensters :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TBomberManForm.FormCreate(Sender: TObject);&lt;br /&gt;
begin&lt;br /&gt;
QueryPerformanceFrequency(PerfCounterFreq);&lt;br /&gt;
[...]&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Variable ''PerfCounterFreq'' wird in der Unit ''BombermanGlobal.pas'' deklariert und ist vom Typ ''Int64''. In dieser ist von nun an die Frequenz unseres Hochpräzisionstimers hinterlegt. Sofern dieser Wert größer 0 ist, läuft alles nach Plan. Solltet ihr hier wider Erwarten den Wert Null zurückgeliefert bekommen, unterstützt die Hardware dieses Timingverfahren nicht, was jedoch nur bei sehr alten CPUs so ist.&lt;br /&gt;
&lt;br /&gt;
====Die Zeitmessung====&lt;br /&gt;
Nach der recht langen Präambel widmen wir uns nun dem eigentlich Kern des Timebased Movements, nämlich der Zeitmessung. Diese wird in in der ''DrawScene''-Prozedur unseres ''TBombermanGame''-Objektes (BombermanGlobal.pas) umgesetzt :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TBomberManGame.DrawScene;&lt;br /&gt;
var&lt;br /&gt;
 QPCStartCount, QPCEndCount : Int64;&lt;br /&gt;
begin&lt;br /&gt;
QueryPerformanceCounter(QPCStartCount);&lt;br /&gt;
[...]&lt;br /&gt;
// Szene zeichnen&lt;br /&gt;
[...]&lt;br /&gt;
QueryPerformanceCounter(QPCEndCount);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Quellcode spricht eigentlich für sich. Wir ermitteln insgesamt zwei Zeitwerte, zum einen '''vor''' dem Zeichnen der Szene und zum anderen '''nach''' dem Zeichnen der Szene, und speichern diese ab.&lt;br /&gt;
Danach berechnen wir über eine recht einfache Formel unseren Zeitfaktor :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;BomberManGame.TimeFactor := (QPCEndCount-QPCStartCount)/PerfCounterFreq*100;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Zeitfaktor entspricht dann der zum Rendern benötigten Zeit in ms/10 und kann dann beim aktualisieren der Bewegungen bzw. Animationen als Faktor genutzt werden.&lt;br /&gt;
&lt;br /&gt;
====Kleine Rechenkunde====&lt;br /&gt;
Um denn Sinn und die Funktion des Timebased Movement besser verstehen zu können, gibts hier ein paar kleine Rechenbeispiele, die darlegen dass der Code nun frameunabhängig Funktioniert :&lt;br /&gt;
&lt;br /&gt;
Rechner 1 braucht 7 ms um die Szene zu Rendern&lt;br /&gt;
:Zeitfaktor = 0.7&lt;br /&gt;
:Bewegung des Spieler = 0.05*0.7 = 0,035 Einheiten&lt;br /&gt;
:Bewegungen werden 142 mal pro Sekunde aktualisiert (142fps)&lt;br /&gt;
:Gesamtbewegung/s = 142*0,035 = 4,97 Einheiten&lt;br /&gt;
:Ohne Timebased Movement : Gesamtbewegung = 142*0,05 = 7,1 Einheiten&lt;br /&gt;
&lt;br /&gt;
Rechner 2 braucht 11 ms um die Szene zu Rendern&lt;br /&gt;
:Zeitfaktor = 1.1&lt;br /&gt;
:Bewegung des Spieler = 0.05*1.1 = 0,055 Einheiten&lt;br /&gt;
:Bewegungen werden 90 mal pro Sekunde aktualisiert (90fps)&lt;br /&gt;
:Gesamtbewegung/s = 90*0,055 = 4,95 Einheiten&lt;br /&gt;
:Ohne Timebased Movement : Gesamtbewegung = 90*0,05 = 4,5 Einheiten&lt;br /&gt;
&lt;br /&gt;
Ich hoffe mal, dass diese beiden Beispiele verdeutlichen, das sich der Spieler unter Zuhilfenahme des Timebased Movements auf verschieden schnellen Rechner (und in verschieden komplexen Szenen) mit gleicher Geschwindigkeit bewegt. Die Diskrepanz vin 0,02 Einheiten bei obigen Werten ist darauf zurückzuführen, dass ich mit abgerundeten Werten gerechnet habe.&lt;br /&gt;
&lt;br /&gt;
Auch wenn dieser Teil des Tuts etwas theoretisch und trocken war, so ist das Timebased Movement, wie ihr sicher schon aus dem Text herauslesen konntet unerlässlich für moderne Spieletitel, und zwar ganz besonders dann wenn diese später auch im Netzwerk bzw. über das Internet spielbar sein sollen. Allerdings wird sich Bomberman drüber freuen, das er sich jetzt auf jedem System gleichschnell fortbewegen kann... [[Bild:Bomberman wait.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 bombermanbomb.gif|left]]&lt;br /&gt;
===Statemachine===&lt;br /&gt;
&lt;br /&gt;
Auch diesen Begriff dürften einige von euch schonmal irgendwo aufgeschnappt haben. Vermutlich war das aber in einem anderen und weitaus komplexerem Zusammenhang als dies bei unserer (recht primitiven) Statemachine der Fall ist.&lt;br /&gt;
&lt;br /&gt;
Spiele bestehen ja bekannterweise aus verschiedenen Szene (=States) wie z.B. dem Hauptmenü und der 3D-Ansicht. Die Statemachine macht in unserem Falle nichts anderes als den in TBombermanGame.CurrentState gesetzten Status abzufragen und dann in die entsprechende Zeichenroutine zu verzweigen. So hat man die für die einzelnen Szenen erforderlichen Zeichneroutinen in verschiedene Prozeduren separiert und kann später bequem und ohne großen Aufwand neue Szenen hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Für jede Szene deklarieren wir in der Konstantensektion der globalen Unit eine eigene Konstanten, anhand derer sie eindeutig identifiziert werden kann :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;      const&lt;br /&gt;
       GSMainMenu  = $00;&lt;br /&gt;
       GSNewGame   = $01;&lt;br /&gt;
       GSInGame    = $02;&lt;br /&gt;
       GSMatchEnd  = $03;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Statemachine prüft dann in der Zeichenprozedur '''TBombermanGame.DrawScene''' in welchem Status sie sich befindet und verzweigt dann mittels einer einfachen Case-Anweisung zur entsprechenden Zeichneroutine :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;      procedure TBomberManGame.DrawScene;&lt;br /&gt;
      [...]&lt;br /&gt;
      case CurrentState of&lt;br /&gt;
       GSMainMenu : DrawScene_GSMainMenu;&lt;br /&gt;
       GSNewGame  : DrawScene_GSNewGame;&lt;br /&gt;
       GSInGame   : DrawScene_GSInGame;&lt;br /&gt;
       GSMatchEnd : DrawScene_GSMatchEnd;&lt;br /&gt;
      else&lt;br /&gt;
       DrawScene_GSMainMenu;&lt;br /&gt;
      end;&lt;br /&gt;
      [...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Den Status unserer Statemachine setzen wir dann mittels der Prozedur '''TBombermanGame.SetState'''. Aber warum tun wir das nicht direkt über die Variable '''TBombermanGame.CurrentState'''? Dafür gibts einen ganz einfachen Grund : Es ist möglich, dass beim Wechsel zwischen zwei Zuständen verschiedene Variablen geändert oder gesetzt werden müssen. Wechseln wir den Status also über oben genannte Prozedur, so können wir vor dem finalen Wechsel noch prüfen in welchen Status gewechselt wird, und eventuell noch benötigte Variablen setzen oder verändern.&lt;br /&gt;
&lt;br /&gt;
Auch wenn oben beschriebenes recht banal erscheinen mag, so ist eine Statemachine (egal wie primitiv) ein einfaches Mittel zur Verwaltung des Spielzustandes, die sich dazu noch recht leicht erweitern lässt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 bombermanbomb.gif|left]]&lt;br /&gt;
===Texturenfonts===&lt;br /&gt;
&lt;br /&gt;
Was vielen ein Dorn im Auge ist, und sich hoffentlich bald ändert, ist das Fehlen von Routinen zur Fontdarstellung in OpenGL. Aber zum Glück haben sich einige findige Programmierer zu diesem Thema Gedanken gemacht und Methoden zur Schriftdarstellung mittels OpenGL entwickelt die recht einfach zu nutzen und gleichzeitig schnell sind. Eine davon sind Texturenfonts, die wie deren Name schon vermuten lässt, ihre Schriftzeichen aus einer Textur herausholen.&lt;br /&gt;
&lt;br /&gt;
Ein Tool das diese Texturen erstellen kann, wurde von mir bereits am Anfang dieses Tutorials vorgestellt, nämlich der Bitmap Font Builder. Dieser erstellt auf der Basis einer Windowsschriftart eine Textur die alle nötigen Schriftzeichen enthält, und z.B. so aussehen könnte :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 texfont.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Das Erstellen und Ausgeben dieser Schrift erledigt für uns die Klasse '''TTexFont''' in der Unit '''TBombermanFont.pas'''. Dort finden sich am Anfang in der Konstantesektion die vorgenerierten Texturenkoordinaten für die einzelnen Buchstaben. Da grundlegende Kenntnisse zum Thema Texturemapping eine Voraussetzung für dieses Tut sind, gehe ich davon aus das ihr wisst was diese zu bedeuten haben und wie sie funktionieren.&lt;br /&gt;
&lt;br /&gt;
Unsere '''TTexFont'''-Klasse tut jetzt bei der Initialiserung nichts anderes, als für jedes in der Textur hinterlegte Schriftzeichen anhand der in der Konstantesektion festgelegten Texturkoordinate eine Displayliste zu erstellen, die beim Ausgeben des Textes dann nur noch aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 bombermanbomb.gif|left]]&lt;br /&gt;
===Animierte Texturen===&lt;br /&gt;
&lt;br /&gt;
In unserem Bombermanklon nutzen wir für die Explosionen animierte Texturen. Diese animierten Explosionen lassen sich auf zwei Arten realisieren :&lt;br /&gt;
&lt;br /&gt;
====Verschiedene Texturen====&lt;br /&gt;
Wir laden für jede Explosionsphase eine eigene Textur. Dazu benötigen wir also 16 Texturen, die auf der Festplatte recht viel Speicher beanschlagen. Je nach Explosionsphase binden wir nun vor dem Zeichnen des Explosionsquad die zur aktuellen Explosionsphare gehöhrende Textur.&lt;br /&gt;
&lt;br /&gt;
Diese Methode ist zwar recht einfach zu implementieren, hat jedoch einige Nachteile : Da jede Animationsphase in einer eigenen Textur liegt wird sowohl auf der Festplatte als auch im Grafikspeicher recht viel Overhead erzeugt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Eine Textur====&lt;br /&gt;
Dies ist die Lösung die wir verwenden werden, da sie recht viele Vorteile beherbergt. Wir erstellen uns mittels eines Tools (z.b. den am Anfang des Tuts erwähnten [[Tutorial Bomberman2#Voraussetzungen|ExplosionsGenerator]]) '''eine Textur''' auf der in Reihen und Spalten '''alle Animationsphasen''' der Explosion dargestellt sind.&lt;br /&gt;
&lt;br /&gt;
Nun binden wir für jedes Explosionsquad '''dieselbe Textur''' und verändern entsprechend der Animationsphase nur unsere '''Texturkoordinaten''', die wir in einem speziellen Array abgelegt haben :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;ExpTexCoord : array[0..15, 0..3] of Single =&lt;br /&gt;
  ((0, 0,    0.25, 0.25), (0.25, 0,     0.5, 0.25), (0.5, 0,    0.75, 0.25), (0.75, 0,    1, 0.25),&lt;br /&gt;
   (0, 0.25, 0.25, 0.5),  (0.25, 0.25,  0.5, 0.5),  (0.5, 0.25, 0.75, 0.5),  (0.75, 0.25, 1, 0.5),&lt;br /&gt;
   (0, 0.5,  0.25, 0.75), (0.25, 0.5,   0.5, 0.75), (0.5, 0.5,  0.75, 0.75), (0.75, 0.5,  1, 0.75),&lt;br /&gt;
   (0, 0.75, 0.25, 1),    (0.25, 0.75,  0.5, 1),    (0.5, 0.75, 0.75, 1),    (0.75, 0.75, 1, 1));&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn man sich dieses Array genauer betrachtet, dann kann man schon erahnen das unsere Explosionstextur in 4x4 Zellen aufgeteilt ist, und von links nach rechts verläuft. Links seht ihr die vom Explosionsgenerator erstellte Textur, und rechts selbige mit ein paar von mir eingetragenen Texturkoordinaten, die euch das Verständnis dieser Technik ein wenig erleichtern sollten :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;[[Bild:Tutorial Bomberman2 explosion.jpg]][[Bild:Explosion det.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer also weiß wie man mit Texturkoordinaten umgeht dürfte hier absolut keine Verständnisprobleme haben. Unser Quad zeichnen wir dann wie folgt (siehe '''TMap.Draw''') :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glBegin(GL_QUADS);&lt;br /&gt;
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][0], -ExpTexCoord[Round(ExplosionPhase)][3]);  glVertex3f(0, 0, 0);&lt;br /&gt;
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][2], -ExpTexCoord[Round(ExplosionPhase)][3]);  glVertex3f(2, 0, 0);&lt;br /&gt;
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][2], -ExpTexCoord[Round(ExplosionPhase)][1]);  glVertex3f(2, 2, 0);&lt;br /&gt;
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][0], -ExpTexCoord[Round(ExplosionPhase)][1]);  glVertex3f(0, 2, 0);&lt;br /&gt;
glEnd;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie leicht zu erkennen nehmen wir unsere Texturkoordinaten anhand der aktuellen Explosionsphase aus unserem vorher in der Konstantensektion deklariertem Koordinatenarray. Bei ExplosionPhase=0 sieht unser Quad also so aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glBegin(GL_QUADS);&lt;br /&gt;
 glTexCoord2f(0,    -0.75); glVertex3f(0, 0, 0);&lt;br /&gt;
 glTexCoord2f(0.25, -0.75); glVertex3f(2, 0, 0);&lt;br /&gt;
 glTexCoord2f(0.25,  0);    glVertex3f(2, 2, 0);&lt;br /&gt;
 glTexCoord2f(0,     0);    glVertex3f(0, 2, 0);&lt;br /&gt;
glEnd;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der offensichtliche Vorteil dieser Methode ist die Tatsache, das die komplette Animation in einer Textur abgelegt ist, und somit nur eine Textur auf der Festplatte sowie im Grafikkartenspeicher Platz verbraucht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 bombermanbomb.gif|left]]&lt;br /&gt;
&lt;br /&gt;
===Soundsystem===&lt;br /&gt;
&lt;br /&gt;
Zu einer intensiven Spielumgebung gehören natürlich nicht nur aufwendige Grafiken, sondern auch Soundeffekte die dem Spieler das Gefühl vermitteln, er bewege sich inmitten einer dreidimensionalen Umgebung.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hier springt unser Soundsystem ein ('''BombermanSoundSystem.pas'''), welches einfache Routinen zur Initialiserung und Ausgabe von Soundateien mitbringt.&lt;br /&gt;
&lt;br /&gt;
Auf dem Markt gibt es inzwischen einige sehr gute Soundlibraries, die vor allem für Freewareprogramme kostenlos nutzbar sind. Deshalb machen wir von einer dieser Soundbibliotheken gebrauch, nämlich [http://www.fmod.de fmod], dessen Vorteile ein riesiger Funktionsumfang und die Nutzung aller gängigen Soundformate ist.&lt;br /&gt;
&lt;br /&gt;
Unser Soundsystem tut deshalb nichts anderes als diese (sowieso schon einfach nutzbare) Bibiliothek zu kapseln. So kann man später einfach auf eine andere Bibliothek umsteigen, oder sein Soundsystem komplett selbst z.B. unter Verwendung von DirectSound programmieren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auf die Funktionsweise bzw. Implementation von fmod werde ich hier jedoch nicht genauer eingehen. Die mit dieser Bibliothek gelieferten Hilfedateien und Beispiele sind so ausführlich, dass jede weitere Dokumentation Zeitverschwendung wäre.&lt;br /&gt;
&lt;br /&gt;
Unsere Implementation der FMOD-Library ins Soundsystem werden wir später aber noch genauer betrachten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So viel also zu den verwendeten Techniken. Fehlen tut in der Liste zwar der Texturenmanager, diesen haben wir allerdings schon im letzten Tutorial besprochen, das ihr ja alle bestimmt aufmerksam gelesen habt ;-)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Verwendete Dateiformate==&lt;br /&gt;
Natürlich sollte man sich bei der Programmierung eines Spiels Gedanken über die verwendeten Dateiformate machen. Hier braucht man das Rad nicht neu zu erfinden und sollte wenn möglich auf bereits bestehende Formate und Editoren zurückgreifen. Ich werde jetzt alle in unserem Bombermanklon verwendeten Formate auflisten, kurz begründen warum wir diese verwenden und auch Alternativen nennen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===3D-Modelle===&lt;br /&gt;
Für unsere 3D-Modelle (Spieler, Bomben) nutzen wir das sehr weit verbreitet '''3DS-Format''', in das fast alle gängigen 3D-Modellierprogramme exportieren können. Ein weiterer Vorteil neben der breiten Unterstützung durch gängige Programme ist die Existenz diverser 3DS-Laderoutinen in allen möglichen Programmiersprachen.&lt;br /&gt;
Großer Nachteil dieses Formates sind Animationen, die auf Keyframe-Basis gesichert werden und deshalb recht schlecht zu implementieren sind, weshalb der genutzte 3DS-Loader diese auch nicht lädt.&lt;br /&gt;
Als Alternative (vielleicht gibts dazu etwas im nächsten Tutorial) schlage ich deshalb das Milkshapeformat vor, zu dem es auf DGL übrigens eine praktische Ladebibliothek gibt.&lt;br /&gt;
&lt;br /&gt;
Weitere Infos zum 3DS-Format gibts auf [www.wotsit.org www.wotsit.org].&lt;br /&gt;
&lt;br /&gt;
Auf der Suche nach 3D-Modellen sollten vor allem folgende Seiten gute Anlaufstellen sein :&lt;br /&gt;
*http://www.planetquake.com/polycount (Die Netzweit wohl größte Datenbank an Modellen für Q2/Q3/UT/UT2003/HL&lt;br /&gt;
*http://www.3dcafe.com (Recht große Sektion mit frei downloadbaren Modellen im 3DS-Format)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sounds===&lt;br /&gt;
Soundformate exisitieren inzwischen reichlich, und dank der FMOD-Library sind wir in dieser Hinsicht auch sehr flexibel. Da wir unser Spiel aber im Netz vertreiben wollen, nutzen wir für größere Sounds (also z.B. die Hintergrundmusik) das '''OGG-Vorbis-Format'''. Nicht nur das es ggü. dem MP3-Format bessere Qualität bei gleicher Komprimierung bietet, nein es ist sogar ein komplett gebührenfreies Format und kann deshalb selbst in kommerziellen Anwendungen ohne Copyrightprobleme genutzt werden.&lt;br /&gt;
Für kleinere Sounds wie z.B. die Bombenexplosion nutzen wir weiterhin das altbewährte '''Wave-Format'''.&lt;br /&gt;
&lt;br /&gt;
Sounds finden sich im Netz leider weitaus schwerer als 3D-Modelle und Texturen, ein guter Anfang bildet allerdings folgende Page : http://www.findsounds.com&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Texturen===&lt;br /&gt;
Auch hier sind wir bei der Wahl des Formates dank glBMP.pas recht flexibel. Allerdings wollen wir auch Alphamasking unterstützen, eine Technik bei der man vorher im Bildbearbeitungsprogramm markierte Bereiche durchsichtig machen kann. Deshalb benötigen wir ein Format das die Speicherung des Alphakanals unterstützt.Dazu kämen entweder TGA oder PNG in Frage.&lt;br /&gt;
Da PNG jedoch recht neu ist und es für Delphi kaum Loader gibt, verwenden wir für unsere Texturen das TGA-Format.&lt;br /&gt;
&lt;br /&gt;
Texturen für Spiele in Hülle und Fülle, und dazu noch in der Public Domain gibts übrigens beim [http://www.planethalflife.com/wadfather/index-new.htm WadFather].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Karten===&lt;br /&gt;
Natürlich müssen wir auch ein Format für unsere selbsterstellten Karten wählen. Dieses Kapitel haben wir ja schon hinreichend im ersten Tutorial durchgekaut, weshalb ich hier nicht weiter drauf eingehen werde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Quellcode==&lt;br /&gt;
So Leute, jetzt gehts ans Eingemachte. Während der Quellcode zum Editor noch leicht überschaubar, recht kurz und die Anzahl der Objekte/Klassen sehr gering war, gehts jetzt etwas heftiger zur Sache, da unser Projekt bereits auf weit über 1000 Zeilen angewachsen ist.&lt;br /&gt;
&lt;br /&gt;
Ich werde aber mein Bestes geben und versuchen alle wichtigen Codestellen, Variablen und Prozeduren möglichst detailliert und leicht nachvollziehbar zu erklären. Wenns doch noch irgendwo happert und selbst die Kommentare im Quellcode keine Lösung bringen, dann gibts ja immer noch das DGL-Forum in dem ich dann auf eure Fragen gerne eingehe... [[Bild:Bomberman Right.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Grundgedanken===&lt;br /&gt;
Bevor ihr wild drauflos programmiert, solltet ihr euch natürlich über die in eurem Spiel benötigten Klassen, Objekte und Variablen Gedanken machen. Bei einem bereits vorgegebenem Spielprinzip wie Bomberman ist das natürlich eine recht einfache Sache. Hier brauchen wir Klassen (bzw. Objekte) die unser Spielfeld, die Spieler und gelegte Bomben repräsentieren. Des weiteren gibts noch die Klasse '''TBombermanGame''', welche das eigentliche Spiel kapselt und neben Routinen zur Initialisierung auch zur Verwaltung der globalen Spiellogik dient.&lt;br /&gt;
&lt;br /&gt;
Wie ihr seht, ist es also essentiell sich über seine Objekte und Klassen Gedanken zu machen, denn besonders in der OOP sind dies mächtige Werkzeuge um den Code leichter nutzbar und übersichtlicher zu machen. In größeren Projekten spielt diese Planung natürlich eine weit wichtiger Rolle, kann man sich doch viel Arbeit mittels Vererbung sparen.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr nun z.B. KI-gesteuerte Monster in unseren Bombermanklon integrieren wollt, so könntet ihr euch eine TActor-Klasse schreiben, die sich um Kollsionsabfrage und das Zeichnen der Figur kümmert und davon sowohl die menschlich gesteuerten Figuren (TPlayer) als auch die KI-Aktoren (TKIActor) ableiten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Auslagern von Klassen/Objekten===&lt;br /&gt;
Ich hab es im Verlaufe dieses Tuts bereits kurz angeschnitten (bei der Unitauflistung). Klassen bzw. Objekte die nicht spezifisch auf das Spiel zugeschnitten sind (wie z.B. der Texturenmanager oder das Soundsystem) sollten am besten in eine externe Unit ausgelagert werden.&lt;br /&gt;
&lt;br /&gt;
Dies hat den Vorteil, das man sich so nach und nach eine große Codebasis schafft die man dann später in anderen Projekten nutzen kann. So werdet ihr dann nur noch einen Texturenmanager programmieren müssen, den ihr von nun an in jedes andere Projekt einbinden und sofort nutzen könnt. Ein weiterer Vorteil dieser Methode ist die Tatsache, dass eine Erweiterung des Texturenmanagers z.B. direkt in jedem eurer Projekte verfügbar ist. Deshalb wäre es keine schlechte Idee, wenn ihr euch für solche Units einen eigenen Ordner erstellt und in euren Projekten direkt auf die dort befindlichen Units linkt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===BombermanGlobal.pas===&lt;br /&gt;
&lt;br /&gt;
Zu aller erst kümmen wir uns um unsere stark erweiterte Codebasis, zu der sich einige neue Objekte und Klassen gesellen. Im Folgenden werde ich euch zu jedem Objekt bzw. jeder Klasse die Deklaration liefern und wichtige Codestellen und Prozeduren detailliert erläutern :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Das Spielfeld (TMap)====&lt;br /&gt;
Dieses Objekt haben wir ja bereits im ersten Tutorial besprochen. Hier ist nichts dazugekommen, weshalb wir uns mit diesem nicht weiter beschäftigen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Die Spielfigur (TPlayer)====&lt;br /&gt;
Dieses Objekt repräsentiert die Spieler und kümmert sich um deren Verwaltung. Die Liste der Spieler wird in dem dynamischen Array '''Player''' verwaltet, so daß es in der Anzahl der Spieler rein theoretisch keine Grenzen gibt. Einige der Eigenschaften dieses Objektes wie z.B. Size verändern sich im Verlaufe des Spielgeschehens nicht. Der Grund warum ich diese dennoch implementiert habe liegt darin, das unser Klon später mit aufsammelbaren Extras erweitert wird, die einige Eigenschaften des Spielers ähnlich dem Original beinflussen. Außerdem lässt sich über diese Eigenschaften das Gameplay recht einfach anpassen, ohne das man diverse Stellen im Quellcode nachträglich verändern muß.&lt;br /&gt;
&lt;br /&gt;
Das Objekt '''TPlayer''' bringt folgende Eigenschaften und Funktionen mit :&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Position : TVector3f;&amp;lt;/nowiki&amp;gt; : Die aktuelle Spielerposition auf dem Spielfeld .Hierzu verwenden wir einen Fließkommavektor, da sich der Spieler frei und nicht nur Feld für Feld bewegen soll. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ExplosionRadius : Integer;&amp;lt;/nowiki&amp;gt; : Gibt den Explosionsradius der vom Spieler gelegten Bomben an. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;MaxBombs : Integer;&amp;lt;/nowiki&amp;gt; : Die Anzahl der von diesem Spieler maximal gleichzeitig platzierbaren Bomben. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Direction : Integer;&amp;lt;/nowiki&amp;gt; : Die Blickrichtung des Spielers.Diese Variable wird nur genutzt um das 3D-Modell in die korrekte Richtung zu drehen. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Wins : Integer;&amp;lt;/nowiki&amp;gt; : Anzahl der von diesem Spieler gewonnenen Spiele. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;IsDead : Boolean;&amp;lt;/nowiki&amp;gt; : Wie fast alle anderen Variablen ist auch diese selbstredend. Wenn diese True ist, dann hats den Spieler erwischt und er kann nicht mehr am Spiel teilnehmen. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Speed : Single;&amp;lt;/nowiki&amp;gt; : Bewegungsgeschwindigkeit des Spielers. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Size : Single;&amp;lt;/nowiki&amp;gt; : Die Ausmaße der Spielfigur. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Model3DS : String;&amp;lt;/nowiki&amp;gt; : Der Name des zu diesem Spieler gehörenden 3D-Modells. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;KeyUp, KeyDown, KeyLeft, KeyRight, KeyFire : Word&amp;lt;/nowiki&amp;gt; : Die Tastenbelegung des Spielers. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;function IsPositionValid(pNewPosX, pNewPosZ : Single) : Boolean;&amp;lt;/nowiki&amp;gt; : Diese Funktion implementiert die (zum Glück recht einfache) Kollisionsabfrage, und prüft ob die Position an die sich der Spieler bewegen will auch begehbar ist. Dabei wird geprüft, ob das Feld unter der neuen Position begehbar ist, ob Kollision mit anderen Spielern stattfindet und ob Bomben im Weg liegen.&amp;lt;br&amp;gt; Wenn die neue Position gültig ist, dann liefert diese Funktion den Wert TRUE zurück. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure UpDate;&amp;lt;/nowiki&amp;gt; : In dieser Version unseres Bombermanklons hat diese Prozedur nur den einzigen Zweck zu prüfen ob sich der Spieler in einer Explosion befindet. Ist dies der Fall, so stirbt er und es wird ein entsprechender Sound abgespielt. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure Draw;&amp;lt;/nowiki&amp;gt; : Wie der Name bereits vermuten lässt kümmert sich diese Prozedur um das Zeichnen der Spielfigur und deren Schattens. Die hier verwendeten Schatten sind jedoch von der Sorte &amp;quot;Ganzbillig&amp;quot; und sind nichts anderes als auf den Boden geblendete Texturen. Für unseren Bombermanklon sind sie jedoch ausreichend und geben der Szene etwas mehr an Realismus. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure DropBomb;&amp;lt;/nowiki&amp;gt; : Auch dieser Prozedurnamen lässt bereits auf ihre Funktion schliessen. Sie prüft, ob die Zahl der vom Spieler gelegten Bomben nicht die maximale Anzahl an legbaren Bomben überschreitet und legt platziert eine Bombe auf dem Spielfeld. &lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure ProcessInput;&amp;lt;/nowiki&amp;gt; : Auch hier gibts nix besonderes. Mittels '''GetAsyncKeyState''' prüfen wir auf Hardwareebene ob eine Taste im gedrückten Zustand ist und führen dann die damit verbundene Aktion aus. Ist die übergebene Taste gedrückt, wird das höchstwertige Bit des zurückgegebenen Wertes gesetzt. &amp;lt;br&amp;gt;Im Falle einer Bewegung prüfen wir natürlich nach, ob die neue Position des Spielers auch gültig ist. &amp;lt;br&amp;gt; Einzige Besonderheit ist hier die Nutzung unseres vorher berechneten Zeitfaktors '''BomberManGame.TimeFactor''' als Faktor für die Bewegungsgeschwindigkeit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Bomben (TBomb)====&lt;br /&gt;
Auch die von den Spielern legbaren Bomben habe ich in einer Klasse gekapselt um deren Verwaltung und Aktualisierung zu erleichtern. Hier gibts eigentlich nix Spektakuläres, weshalb ich direkt zu den Eigenschaften und Prozeduren übergehe :&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Position : TVector3i;&amp;lt;/nowiki&amp;gt; : Die Position der Bombe als '''Integer'''-Vektor, da Bomben nur genau in der Feldmitte abgelegt werden (wie beim original Bomberman). &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Owner : ^TPlayer;&amp;lt;/nowiki&amp;gt; : Zeiger auf den Besitzer dieser Bombe.Diese Eigenschaft wird benötigt um herauszufinden wie viele Bomben dieser Spieler bereits gelegt hat, und um die Explosionsreichweiter der Bombe (die auch spielerabhängig ist) zu ermitteln. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;CountDown : Single;&amp;lt;/nowiki&amp;gt; : Wie der Eigenschaftsname bereits vermuten lässt ist hier der Countdown bis zur Explosion der Bombe gespeichert. Sinkt dieser Wert auf &amp;gt;= 0, so wird die Explosion eingeleteitet und die Bombe aus der dynamischen Liste entfernt. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;AnimPhase : Single;&amp;lt;/nowiki&amp;gt; : Die Animationsphase wird als Grundlage für die sinusförmigen Skalierung der Bombe genutzt und lässt so den Eindruck entstehen als würde die Bombe sich strecken und wieder zusammenziehen. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure Draw;&amp;lt;/nowiki&amp;gt; : Kümmert sich um das Zeichnen der Bombe sowie deren Schattens. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure Explode;&amp;lt;/nowiki&amp;gt; : Startet die lineare Explosion in vier Richtungen. Wie im Original wird die Explosion in die jeweilige Richtung durch einen Block gestoppt. Ist dieser Block sprengbar, so wird er vom Spielfeld entfernt. &amp;lt;br&amp;gt;Trifft die Explosion auf ihrem Weg auf eine andere Bombe, so wird der Countdown dieser Bombe auf einen Wert nahe 0 gesetzt, so daß eine Kettenrekation stattfindet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Das Spiel (TBomberManGame)====&lt;br /&gt;
Wie bereits erwähnt repräsentiert dieses Objekt unser Spiel und kümmert sich neben der Verwaltung dynamischer Listen und der Spiellogik auch um die Initialisierung wichtiger Listen bzw. OpenGL und implementiert unsere bereits ausgiebig beschriebene Statemachine. Bei Erweiterung solltet ihr hier alles was global geschieht und nicht von den Objekten selbst getan werden kann unterbringen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;'''Private Deklarationen'''&amp;lt;/u&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ShakeScreen : Single;&amp;lt;/nowiki&amp;gt; : In dieser Eigenschaft wird die Restdauer gespeichert während der der Bildschirm nach einer Bombenexplosion erschüttert wird. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure DrawScene_GSMainMenu/DrawScene_GSNewGame/DrawScene_GSInGame/DrawScene_GSMatchEnd;&amp;lt;/nowiki&amp;gt; :             Wie bereits im Kapitel zur Statemachine angesprochen sind dies die Unterprozeduren die von der Statemachine zum Zeichnen der verschiedenen Spielstadien (sprich Szenen) genutzt werden. &lt;br /&gt;
&amp;lt;u&amp;gt;'''Öffentliche Deklarationen'''&amp;lt;/u&amp;gt;&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;gsMainMenu_Selected : Integer;&amp;lt;/nowiki&amp;gt; : Wie am Präfix dieser Variable zu erkenne, gibt sie den im Hauptmenü ausgewählten Menüpunkt wieder. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;gsMainMenu_Rotation : Single;&amp;lt;/nowiki&amp;gt; : Die Rotation der im Hintergrund des Menüs dargestellten Karte. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;gsNewGame_Selected : Integer;&amp;lt;/nowiki&amp;gt; : Im Menü &amp;quot;Neues Spiel&amp;quot; gewählter Menüpunkt. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;gsNewGame_Players : Integer;&amp;lt;/nowiki&amp;gt; : Anzahl der im Menü &amp;quot;Neues Spiel&amp;quot; eingestellten Spieler. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;MapList : TStringList;&amp;lt;/nowiki&amp;gt; : In dieser Stringlist werden mit der Prozedur '''CreateMapList''' alle Namen der in einem bestimmten Ordner gefundene Karten abgelegt, so daß diese im Spielmenü bequem ausgewählt werden können. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ExtremeMode : Boolean;&amp;lt;/nowiki&amp;gt; : Der Name lässts wohl bereits vermuten. Hiermit wird dem Spiel mitgeteilt das es sich im Extremmodus befindet, in dem sowohl Anzahl der legbaren Bomben als auch deren Reichweite und die Geschwindigkeit der Spielfigur stark erhöht werden. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;MapListPos : Integer;&amp;lt;/nowiki&amp;gt; : Position der gewählten Karte in '''MapList''' &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;TimeFactor : Single;&amp;lt;/nowiki&amp;gt; : Diese Variable wurde bereits im Kapitel zum Thema &amp;quot;Timebased Movement&amp;quot; besprochen und behinhaltet den Zeitfaktor der für eine gleichmäßige Bewegung/Animation sorgt. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;OwnerForm : ^TForm;&amp;lt;/nowiki&amp;gt; : Zeiger auf die Form in der das Spiel dargestellt wird. Dieser Zeiger muß einen Wert besitzen und darf nicht ins Leere zeigen. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;CurrentState : Word;&amp;lt;/nowiki&amp;gt; : Aktueller Status der Statemachine. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure SetState(pNewState : Word);&amp;lt;/nowiki&amp;gt; : Versetzt die Statemachine in einen neuen Status. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure CreateMapList(pMapDir : String);&amp;lt;/nowiki&amp;gt; : Erstellt eine Liste aller in ''pMapDir''' befindlichen Karten, so daß auf diese einfach und schnell zugegriffen werden kann. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure Create3DSList(p3DSDir : String);&amp;lt;/nowiki&amp;gt; : Erstellt eine Liste aller in '''p3DSDir''' befindlichen 3DS-Modelle und generiert auch gleichzeitig deren Displaylisten. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure InitOpenGL;&amp;lt;/nowiki&amp;gt; : Erstellt den OpenGL-Rendercontext und initialisiert einige OpenGL-Parameter. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure DrawScene;&amp;lt;/nowiki&amp;gt; : Diese Prozedur verzweigt je nach Zustand der Statemachine in die entsprechende Zeichenprozedur. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure UpDateBombs;&amp;lt;/nowiki&amp;gt; : Aktualisiert die dynamische Bombenliste und entfernt ggf. explodierte Bomben. Diese Aktion muß außerhalb des TBomb-Objektes getätigt werden, da sich ein Objekt nicht selbst aus einer dynamischen Liste entfernen kann. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure StartNewMatch(pMapName : String);&amp;lt;/nowiki&amp;gt; : Wie der Prozedurname vermuten lässt starte diese eine neues Match auf der in '''pMapName''' angegeben Karte. Dabei wird die Bombenliste geleert und es werden alle Spieler wieder auf die Grundwerte zurückgesetzt. &lt;br /&gt;
&lt;br /&gt;
Soviel also zur Deklaration unserer Objekte bzw. Klassen. Wie ihr sehen könnt habe ich hier eine sehr saubere Namensgebung verwendet, durch die viele Eigenschaften bzw. Prozeduren selbsterklärend sind.&lt;br /&gt;
&lt;br /&gt;
Wenden wir uns nun einigen interessanten Stellen im Quellcode zu, die eine genauere Erklärung notwendig machen.&lt;br /&gt;
&lt;br /&gt;
====Interessante Codestellen====&lt;br /&gt;
&lt;br /&gt;
=====Zeichnen der InGame-Action (TBomberManGame.DrawScene_GSInGame)=====&lt;br /&gt;
Die wichtigste Funktion der TBombermanGame-Klasse bedarf natürlich einer kleinen Erklärung, enthält sie doch recht viele Anweisungen. Deshalb werde ich den Quellcode hier detailliert durchgehen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
glClear(GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
glViewport(0, 0, OwnerForm^.ClientWidth, OwnerForm^.ClientHeight);&lt;br /&gt;
glMatrixMode(GL_PROJECTION);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
gluPerspective(45, OwnerForm^.ClientWidth/OwnerForm^.ClientHeight, 1, 1024);&lt;br /&gt;
glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glTranslatef(0,0,-30*Length(Map.PlayGround)/24);&lt;br /&gt;
glRotatef(45, 1, 0 ,0);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Ganze fängt erstmal recht gemütlich mit OpenGL-Standardkost an. Zuert löschen wir den Tiefenpuffer. Ein Löschen des Farbpuffers ist aufgrund der Tatsache das sich unser Spielfeld über den kompletten Bildschirm erstreckt nicht nötigt.&lt;br /&gt;
Danach werden Viewport und Perspektive unserer Fenstergröße angepasst, bevor wir unsere Kamera zuguter Letzt in einem 45°-Winkel über dem Spielfeld ausrichten. Die Höhe der Kamera (wie sich aus der Formel in [[glTranslate]]f herbeileiten lässt) wird je nach Größe des Spielfelds in einer anderen Höhe positioniert, so daß man immer das komplette Spielfeld im Sichtbereich hat.Die 24 am Ende der Formel besagt, das sich die Kamera bei einer Kartengröße von 24 Feldern genau 30 Einheiten über dem Spielfeld befindet, bei einer Größe von 48 Spielfeldern würde sie also 60 Einheiten über dem Spielfeld schweben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
if ShakeScreen &amp;gt; 0 then&lt;br /&gt;
 begin&lt;br /&gt;
 glTranslatef(-Length(Map.PlayGround)/2-Random+Random, Random-Random, -Length(Map.PlayGround)/2-Random+Random);&lt;br /&gt;
 ShakeScreen := ShakeScreen-1*TimeFactor;&lt;br /&gt;
 end&lt;br /&gt;
else&lt;br /&gt;
 glTranslatef(-Length(Map.PlayGround)/2, 0, -Length(Map.PlayGround)/2);&lt;br /&gt;
Map.Draw;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieses Quellcodesubstrakt sorgt dafür, dass unsere Karte auf dem Bildschirm zentriert wird. Wenn gerade eine Bombe explodiert ist ('''ShakeScreen = True''') verändern wir per Zufall die Position der Karte, so daß der Eindruck entsteht als würde das Spielfeld aufgrund der Bombenexplosion erzittern. Besonders bei einer längeren Kettenreaktion trägt dies nicht unerheblich zu einem dichteren Spielgefühl bei.&lt;br /&gt;
Nach der Zentrierung müssen wir natürlich noch unser Spielfeld zeichnen. Die dazu genutzte Prozedur '''TMap.Draw''' kümmert sich übrigens auch um das Zeichnen der Spielfiguren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
for i := Low(Player) to High(Player) do&lt;br /&gt;
 Player[i].ProcessInput;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mittels dieser Zeilen verarbeiten wir die Eingaben der Spieler (sprich Tastendrücke). Dies könnne wir jetzt getrost in jedem Frame machen, da wir die Bewegung des Spielers ja mittels unseres errechneten Zeitfaktors an die Rendergeschwindigkeit angleichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
glPushAttrib(GL_ALL_ATTRIB_BITS);&lt;br /&gt;
if Length(Bomb) &amp;gt; 0 then&lt;br /&gt;
 for i := Low(Bomb) to High(Bomb) do&lt;br /&gt;
  Bomb[i].Draw;&lt;br /&gt;
UpDateBombs;&lt;br /&gt;
glPopAttrib;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor wir nun unsere Bomben zeichnen können, sichern wir alle OpenGL-Attribute, damit wir diese für den Fall, das sie durch das Zeichnen der 3DS-Modelle verändert wurden, später wiederherstellen können.Täten wir das nicht, so würden folgende Zeichneoperationen nicht so ausgeführt wie wir das wollten.&lt;br /&gt;
Mittels '''UpDateBombs''' lassen wir alle Bomben aktualisieren und die dynamische Bombenliste falls nötig aktualisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
glMatrixMode(GL_PROJECTION);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glOrtho(0,640,0,480,-2000,2000);&lt;br /&gt;
glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun alles in unserer 3D-Ansicht gezeichnet haben schalten wir in die orthogonale Ansicht, also den 2D-Modus von OpenGL um unsere Informationsleiste mit den Spielerpunktständen zu zeichnen. Dies geschieht mittels [[glOrtho]].Mit den ersten vier Parametern legen wir die Ausmaße der 2D-Ansicht fest, während die letzten zwei der Near- und Far-Wert für das Viewclipping sind.Diese Werte sind deshalb so groß, damit die 3D-Modelle der Spielerköpfe nicht geclippt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
for i := 0 to 3 do&lt;br /&gt;
 begin&lt;br /&gt;
 glPushMatrix;&lt;br /&gt;
  glTranslatef(128+i*128, 455, 20);&lt;br /&gt;
  glScalef(0.5, 0.5, 0.5);&lt;br /&gt;
  if Player[i].IsDead then&lt;br /&gt;
   Draw3DSModel('bomberhead'+IntToStr(i+1)+'d')&lt;br /&gt;
  else&lt;br /&gt;
   Draw3DSModel('bomberhead'+IntToStr(i+1));&lt;br /&gt;
  glColor3f(1,1,1);&lt;br /&gt;
 glPopMatrix;&lt;br /&gt;
 end;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nun zeichnen wir in einer Schleife die 3D-Modelle der Spielerköpfe in dieser 2D-Ansicht. Dabei wird mittels der ''If-Anweisung'' je nach Status des Spielers (tot oder lebendig) ein anderes Modell gezeichnet. Da wir uns ja im 2D-Modus befinden können wir die Positionen mittels ''glTranslatef'' pixelgenau angeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
for i := 0 to 3 do&lt;br /&gt;
 begin&lt;br /&gt;
 glPushMatrix;&lt;br /&gt;
  glTranslatef(128+i*128, 455, 20);&lt;br /&gt;
  glScalef(1,-1,1);&lt;br /&gt;
   TextureFont.Print2D(IntToStr(Player[i].Wins), [16,-3,0], [1,1,1], 1, 1);&lt;br /&gt;
  glScalef(1,-1,1);&lt;br /&gt;
 glPopMatrix;&lt;br /&gt;
 end;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zu dieser Schleife gibts eigentlich auch nicht viel zu sagen. Hier geben wir neben den Köpfen die Punktzahlen der einzelnen Spieler aus. Einzige Besonderheit ist hier das [[glScale]]f(1,-1,1) vor der Textausgabe.Dies ist deshalb nötig, da ich bei der Definition des 2D-Modus mittels glOrtho die Werte für Oben/Unten aus beleuchtungstechnischen Gründen getauscht habe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
PlayersAlive := 0;&lt;br /&gt;
for i := 0 to High(Player) do&lt;br /&gt;
 begin&lt;br /&gt;
 Player[i].UpDate;&lt;br /&gt;
 if not Player[i].IsDead then&lt;br /&gt;
  inc(PlayersAlive);&lt;br /&gt;
 end;&lt;br /&gt;
case PlayersAlive of&lt;br /&gt;
 0 : begin&lt;br /&gt;
     BomberManGame.StartNewMatch(Map.FileName);&lt;br /&gt;
     end;&lt;br /&gt;
 1 : begin&lt;br /&gt;
     for i := 0 to High(Player) do&lt;br /&gt;
     if not Player[i].IsDead then&lt;br /&gt;
      inc(Player[i].Wins);&lt;br /&gt;
     BomberManGame.StartNewMatch(Map.FileName);&lt;br /&gt;
     end;&lt;br /&gt;
end;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit der Schleife in diesem Codekonstrukt prüfen wir (neben dem Aktualisieren der Spieler, siehe dazu das Kapitel zum Objekt TPlayer) wie viele Spieler noch lebendig sind, erhöhen bei einem überlebendem Spieler dessen Punktzahl bzw und starten das Spiel neu. Ein Neustart des Spiels geschieht natürlich auch wenn alle Spieler tot sind, dann gibts aber natürlich keine Punkte.&lt;br /&gt;
&lt;br /&gt;
Soviel also zur wichtigsten Zeichenroutine. Hier dürftet ihr eigentlich keine Probleme gehabt haben, aber dennoch wars mir wichtig einige Dinge anzuschneiden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Zeichnen des Hauptmenüs (TBomberManGame.DrawScene_GSMainMenu)=====&lt;br /&gt;
Auch in dieser Zeichenprozedur gibts ein paar Besonderheiten die eventuell einer Erklärung bedürfen, weshalb wir uns auch diesen Quellcode vornehmen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
const&lt;br /&gt;
 EntryName : array[0..2] of String = ('Neues Spiel', 'Credits', 'Spiel beenden');&lt;br /&gt;
 EntryPos  : array[0..2] of Single = (160,240,320);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Statt die Menüeinträge und deren Bildschirmposition zu &amp;quot;hardcoden&amp;quot; (also für jeden Menüeintrag eine eigene Textausgabe) ists weitaus praktischer die Menüeinträge sowie deren Positionen (in unserem Falle nur die auf der Y-Achse) am Anfang der Zeichenprozedur in einem Konstantenarray vorzubelegen, so dass wir diese später einfach in einer Schleife zeichnen können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
TextureManager.BindTexture('gamewindow');&lt;br /&gt;
glEnable(GL_ALPHA_TEST);&lt;br /&gt;
glEnable(GL_BLEND);&lt;br /&gt;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);&lt;br /&gt;
glColor4f(1,1,1,0.7);&lt;br /&gt;
glBegin(GL_QUADS);&lt;br /&gt;
 glTexCoord2f(0,1); glVertex3f(224, 112, 0);&lt;br /&gt;
 glTexCoord2f(1,1); glVertex3f(416, 112, 0);&lt;br /&gt;
 glTexCoord2f(1,0); glVertex3f(416, 368, 0);&lt;br /&gt;
 glTexCoord2f(0,0); glVertex3f(224, 368, 0);&lt;br /&gt;
glEnd;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem wir in den 2D-Modus gewechselt haben, binden wir die Textur für unser Hauptmenü, aktivieren Alphamasking um die Ränder der Textur loszuwerden und aktivieren auch noch Blending, damit die im Hintergrund rotierende Karte durch das Menü hindurch sichtbar ist.&lt;br /&gt;
Danach müssen wir nur noch ein zentriertes Quad mit den Ausmaßen der Textur auf den Bildschirm bringen und schon ist unser Menühintergrund sichtbar.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
for i := Low(EntryName) to High(EntryName) do&lt;br /&gt;
 if i = gsMainMenu_Selected then&lt;br /&gt;
  TextureFont.Print2D(EntryName[i], [230,EntryPos[i],0],[1,0.3,0.3],1,1)&lt;br /&gt;
 else&lt;br /&gt;
  TextureFont.Print2D(EntryName[i], [230,EntryPos[i],0],[1,1,1],1,1);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Schleife gibt dann unsere vorher definierten Menüpunkte an den im Array '''EntryPos''' festgelegten Bildschirmpositionen aus. Falls der Eintrag markiert ist, wird er rot hervorgehoben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Zeichnen der Spielfiguren (TPlayer.Draw)=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
glTranslatef(Position.x+0.5, Position.y, Position.z+0.5);&lt;br /&gt;
glRotatef(Direction, 0, 1, 0);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit diesen beiden Zeilen werden wir zum einen das 3D-Modell des Spielers zentrieren, und des zum anderen in die aktuelle Blickrichtung ausrichten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
glPushMatrix;&lt;br /&gt;
 if IsDead then&lt;br /&gt;
  begin&lt;br /&gt;
  glTranslatef(0,0,-0.5);&lt;br /&gt;
  glRotatef(90,1,0,0);&lt;br /&gt;
  end;&lt;br /&gt;
 glScalef(0.0085, 0.0085, 0.0085);&lt;br /&gt;
 Draw3DSModel(Model3DS);&lt;br /&gt;
glPopMatrix;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nun kommt der interessante Teil dieser Prozedur. Natürlich sichern wir zuerst unsere Matrix, um sie später wieder schnell herstellen zu können. Dann prüfen wir ob der Spieler tot ist. Ist dies der Fall, so &amp;quot;legen&amp;quot; wir die Spielfigur mit einer Translation und Rotation auf die Stelle an der der Spieler gestorben ist.&lt;br /&gt;
&lt;br /&gt;
Die dann folgende Skalierung ist deshalb so &amp;quot;überdimensioniert&amp;quot;, da die Maßeinheiten im 3D-Studio relativ groß sind, und auf unsere Maßeinheit angepasst werden müssen.&lt;br /&gt;
&lt;br /&gt;
Letztendlich rufen wir noch mit Hilfe der Prozedur '''Draw3DSModel''' die vom 3D-Modell des Spielers generierte Displayliste auf. Mehr dazu gibts in der Dokumentation zur '''BombermanLoad3DS.pas'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
glColor3f(1,1,1);&lt;br /&gt;
glDisable(GL_LIGHTING);&lt;br /&gt;
glDepthFunc(GL_LEQUAL);&lt;br /&gt;
glEnable(GL_BLEND);&lt;br /&gt;
glBlendFunc(GL_ZERO, GL_SRC_COLOR);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun zur &amp;quot;Schattendarstellung&amp;quot;. Dieses Wort steht mit Absicht in Anführungszeichen, da es keine realistischen Schatten sind, sondern einfache mittels Blending auf den Boden gezeichnete &amp;quot;schwarze Kreise&amp;quot;, die den Eindruck eines grade nach unten geworfenen Schattens entstehen lassen.Dies ist jedoch für den Anfang ausreichend und auf jeden Fall besser als gar keine Schatten.Eventuell werden wir uns im nächsten Tutorial mit echten Schattenwürfen beschäftigen.&lt;br /&gt;
Die Schattentextur wurde übrigens auf recht einfache Art und Weise mit Hilfe des Farbverlauftools in einem Bildbearbeitungsprogramm erstellt. Links seht ihr die Schattentextur, und rechts das Endergebnis im Spiel :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial Bomberman2 shadowtex.jpg]][[Bild:Tutorial Bomberman2 shadowplayer.jpg]]&lt;br /&gt;
&lt;br /&gt;
Obige Zeilen dienen also erstmal der Intialisierung. Hier wird nichts weiter getan als den Tiefentest so einzustellen, das der Schatten auf jeden Fall gezeichnet wird, und das Blending wird aktiviert.Außerdem setzen wir noch einen additiven Blendingmodus.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
TextureManager.BindTexture('shadow_player.tga');&lt;br /&gt;
glBegin(GL_QUADS);&lt;br /&gt;
 glTexCoord2f(0,1); glVertex3f(-0.5, 0.01, -0.5);&lt;br /&gt;
 glTexCoord2f(1,1); glVertex3f( 0.5, 0.01, -0.5);&lt;br /&gt;
 glTexCoord2f(1,0); glVertex3f( 0.5, 0.01,  0.5);&lt;br /&gt;
 glTexCoord2f(0,0); glVertex3f(-0.5, 0.01,  0.5);&lt;br /&gt;
glEnd;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Zeilen dürften selbsterklärend sein. Nach dem Binden unserer Schattentextur zeichnen wir unter die Spielerposition noch ggü. dem Boden leicht erhöht das Schattenquad. Die minimale Erhöhung auf der Z-Achse dient dazu das sog. Z-Fighting zu verhindern, bei dem es je nach Kameraentfernung durch die Ungenauigkeit des Z-Puffers zum Überlappen von Poylgonen kommen kann.&lt;br /&gt;
&lt;br /&gt;
Auch in der Zeichenprozedur unserer Spielfiguren eigentlich nur Standardkost. Die Zeichenprozedur für unsere Bomben sieht genauso aus, weshalb ich diese nicht besprechen werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=====Verarbeiten der Benutzereingaben (TPlayer.ProcessInput)=====&lt;br /&gt;
Auch wenn diese Prozedur schon kurz angesprochen wurde, werde ich hier nochmal auf die Besonderheiten eingehen, da wir die Benutzereingaben nicht wie die meisten von euch mittels der entsprechenden '''OnKeyDown/OnKeyUp/OnKeyPress'''-Ereignisse der Form, sondern direkt auf Hardwareebene abfragen. Allerdings reicht es wenn wir hier exemplarisch nur eine Tastenabfrage besprechen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
if Hi(GetAsyncKeyState(KeyUp)) = 128 then&lt;br /&gt;
 begin&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie schon angesprochen prüft die Funktion '''GetAsyncKeyState''' auf Hardwareebene ob die übergebene Taste bzw. der übergebene Mausbutton (was in unserem Falle ohne Interesse ist) gedrückt sind. Ist dies der Fall, so liefert uns diese Funktion im höchstwertigen Bit (also das Bit das ganz links &amp;quot;sitzt&amp;quot;) eine 1. Mit der Delphifunktion ''Hi'' lassen wir uns also das höherwertige Byte (nicht Bit!) liefern und bekommen als Ergebnis ein Oktett (in dem sich die linken 8 Bits einer 16Bittigen Integervariable befinden). Das Bitmuster von 128 ist ja bekannterweise 1000 0000 und euch sollte sofort aufgefallen sein das bei diesem Bitmuster das von uns gesuchte höchstwertige Bit gesetzt ist .Ein kleiner Vergleich liefert uns nun also TRUE, falls diese Taste gedrückt ist. Das hat sich jetzt wahrscheinlich mächtig kompliziert angehört, war aber mehr als kleine Verständnishilfe Gedacht, und muß nicht unbedingt bekannt sein.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
if IsPositionValid(Position.x, Position.z-0.05*BomberManGame.TimeFactor*Speed-Size/2) then&lt;br /&gt;
 Position.z := Position.z-0.05*BomberManGame.TimeFactor*Speed;&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nun kommen wir zum Kern der Sache.Zuerst prüfen wir im If-Statement, ob die Position an die sich der Spieler bewegen will auch gültig ist. '''Nur wenn dies der Fall ist, wird die Spielerposition auch gesetzt.''' Ansonsten ändert sich nichts an seiner Position.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===BombermanSoundSystem.pas===&lt;br /&gt;
&lt;br /&gt;
Wenn euch das vorherige Kapitel nicht erschlagen hat, dann habt ihrs jetzt eigentlich geschafft, denn das Schwerste liegt hinter euch. Als nächstes werden wir uns dann dem weitaus weniger komplexem Soundsystem widmen.&lt;br /&gt;
&lt;br /&gt;
Kommen wir zuerst zur Typendeklaration :&lt;br /&gt;
&lt;br /&gt;
====Das SoundSystem (TSoundSystem)====&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;SampleHandle : array of PFSOUNDSample;&amp;lt;/nowiki&amp;gt; : Wie in der Dokumentation zu FMOD nachzulesen (die ihr euch unbedingt ansehen solltet) greift diese Bibliothek auf seine Sounds (ähnlich wie Windows auf seiner Fenster) über Handles zu, die wir in diesem dynamischen Array ablegen werden. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;SampleList : TStringList;&amp;lt;/nowiki&amp;gt; : Hier legen wir die Namen der in obigem array abgelegten Sounds zwecks schnellen Zugriffs ab. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;constructor Create;&amp;lt;/nowiki&amp;gt; : Naja, der Konstuktor eben.Hier tun wir eigentlich nix anderes als FMOD zu initialiseren. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;destructor Destroy;&amp;lt;/nowiki&amp;gt; : Hier passiert genau das Gegenteil ;-). &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure AddSample(pFileName, pSampleName : String);&amp;lt;/nowiki&amp;gt; : Fügt unserem Samplepool das in der Datei pFileName abgelegte Soundfile unter dem Namen pSampleName hinzu. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure PlaySample(pSampleName : String;pLoop : Boolean);&amp;lt;/nowiki&amp;gt; : Sucht das Soundsample mit dem Name pSampleName und spielt dies ab.Per pLoop kann man angeben ob es kontinuierlich wiederholt wird. &lt;br /&gt;
&lt;br /&gt;
====Interessante Codestellen====&lt;br /&gt;
&lt;br /&gt;
In unserem momentan noch recht simplen Soundsystem gibts eigentlich nur recht wenige Interessante Codestellen. Fangen wir aber troztdem an, und schauen uns die Initialsierung der FMOD-Library in Konstruktor '''Create''' an :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
FSOUND_Init(44100, 32, 0);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Simpel, nicht wahr =). Als Parameter müssen wir der FMOD-Library zur Initialisierung nur die Mixrate (44,1kHz) und die Anzahl der Soundkanäle übergeben (in unserem Falle 32).&lt;br /&gt;
&lt;br /&gt;
Das wars schon mit der Initialisierung. Gehen wir also gleich über zum Abspielen eines Sounds in '''PlaySample''' :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
Index := SampleList.IndexOf(pSampleName);&lt;br /&gt;
[...]&lt;br /&gt;
Channel := FSOUND_PlaySound(FSOUND_FREE, SampleHandle[Index]);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Abspielen von Sounds unter FMOD geschieht immer auf einem Kanal, den das Sample von FMOD zugeteilt bekommt. Die Zuteilung dieses Parameters geschieht entweder fest oder dynamisch durch FMOD, indem der Parameter FSOUND_FREE angegeben wird.&lt;br /&gt;
Als zweiter Parameter wird noch das Handle des Samples übergeben, dessen Index wir vorher über die StringList ermittelt haben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;[...]&lt;br /&gt;
if pLoop then&lt;br /&gt;
 FSOUND_SetLoopMode(Channel, FSOUND_LOOP_NORMAL);&lt;br /&gt;
[...]&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit diesen beiden Zeilen setzten wir (falls dies gewünscht wird) den Kanal auf dem das Sample abgespielt wird in den Loopmodus, so daß der Sound kontinuierlich wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
So, daß war eigentlich alles Wissenswerte zu unserem einfachen Soundsystem. Mehr Infos gibts in der Doku zu FMOD.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===BombermanLoad3DS.pas===&lt;br /&gt;
Nachdem wir nun eigentlich alle relevanten Stellen und Deklarationen unseres Quellcodes abgeklappert haben gibts noch ein paar Worte zur 3DS-Ladeunit. Das Groß des dort enthaltenen Quelltextes stammt nicht von mir, sondern aus dem Beispiel-3DS-Lader zu Mike Lischkes 3DS-Library.&lt;br /&gt;
&lt;br /&gt;
Meine Arbeit an dieser Unit &amp;quot;beschränkt&amp;quot; sich auf das einfache Laden und Zeichnen der 3DS-Modelle, weshalb ich hier auch nur kurz auf die dafür von mir gebastelte Klasse und Routine eingehe.&lt;br /&gt;
&lt;br /&gt;
====Kapselung des 3DS-Models (TModel3DS)====&lt;br /&gt;
Diese Klasse kapselt das 3DS-Model und bietet mit der Routine '''LoadFromFile''' eine einfache Möglichkeit dies in eine OpenGL-Displayliste zu konvertieren. Die 3D-Modelle werden im dynamischen array '''List3DS''', und ihre Namen (zum schnellen Zugriff) in '''Names3DS''' verwaltet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;nowiki&amp;gt;ListIndex : TGLUInt;&amp;lt;/nowiki&amp;gt; : Index der OpenGL-Displayliste dieses 3D-Modells. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;Name : String;&amp;lt;/nowiki&amp;gt; : Der Dateiname. &lt;br /&gt;
;&amp;lt;nowiki&amp;gt;procedure LoadFromFile(pFileName : String);&amp;lt;/nowiki&amp;gt; : Lädt das 3DS-Model aus der in ''pFileName'' angegebenen Datei und erstellt eine DisplayListe, deren Kennung in ''ListIndex'' abgelegt wird.&lt;br /&gt;
&lt;br /&gt;
====Aufrufen der DisplayListe (Draw3DSModel)====&lt;br /&gt;
Mit Hilfe dieser Prozedur kann man die DisplayListe eines vorher bereits geladenen 3D-Models bequem über dessen Namen zeichnen.&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
&lt;br /&gt;
BOOOOOM...ich hoffe dieser Knall holt euch wieder zurück in die harte Realität. Ich weiß, dieses Tut war ein harter Brocken, aber wenn ihr alles hier angesprochene begriffen habt, habt ihr ne Menge dazugelernt und solltet von nun an wissen wie man die Programmierung eines Spiels angeht, und welche Techniken man dabei nutzt.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr dieses Tut dann endgültig verdaut habt, wäre ich über Feedback sehr erfreut. Denn das lässt leider (nicht nur bei meinen Tuts) zu wünschen übrig...'''aber diesmal hängt der Umfang des nächsten Tuts, in dem wir unseren Bombermanklon um einige tolle Effekte und Funktionen erweitern von eurem Feedback ab!''' Also gebts mir, und am besten im Forum, so das Alle was davon haben!&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:'''Sascha Willems'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Bomberman1]]|[[Tutorial_Softwareentwicklung1]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Bomberman2]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=20549</id>
		<title>Tutorial glsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_glsl&amp;diff=20549"/>
				<updated>2007-05-24T22:20:27Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Die Zukunft */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Präambel=&lt;br /&gt;
Ave und willkommen bei meiner &amp;quot;Einführung&amp;quot; in die recht frische und mit OpenGL1.5 eingeführte Shadersprache &amp;quot;glSlang&amp;quot;. In diesem umfangreichen Dokument werde ich versuchen, sowohl auf die Nutzung (sprich das Laden und Anhängen von Shadern im Quellcode), als auch auf die Programmierung von Shadern selbst einzugehen, inklusive aller Sprachelemente der OpenGL Shadersprache. Es wird also auch recht viele Informationen zu der C-ähnlichen Programmstruktur und den von glSlang angebotenen Variablen und Attributen gehen. Am Ende dieser Einführung sollten alle die, die sich für das Thema interessieren, in der Lage sein, zumindest einfach Shader zu schreiben und auch in ihren Programmen zu nutzen. Ausserdem soll dieses Dokument gleichzeitig als ein deutsches &amp;quot;Pendant&amp;quot; zu den von 3DLabs veröffentlichten Shaderspezifikationen, und damit als alltägliches Nachschlagewerk, dienen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vorkenntnisse==&lt;br /&gt;
Wie auch schon mein ARB_VP-Tutorial richtet sich auch diese Einführung aufgrund ihrer Thematik eher an die fortgeschritteneren GL-Programmierer und neben sehr guten GL-Kenntnissen sollten sich alle, die sich daran versuchen wollen, mit den technischen Hintergründen der GL, wie z.B. dem Aufbau der Renderpipeline auskennen. Weiterhin sind C-Kenntnisse absolut erforderlich, da die Shader ja in einer an ANSI-C angelehnten Syntax geschrieben werden. Auch Begriffsdefinitionen zu Vertex oder Fragment werden zum Verständis dieser Einführung benötigt. Wer also noch am Anfang seiner GL-Karriere steht, dem wird dieses Dokument nicht viel nützen. Ganz nebenbei solltet ihr auch noch eine gehörige Portion Zeit (am besten nen kompletten Nachmittag) mitbringen, denn die folgende Kost ist nicht nur umfangreich, sondern auch manchmal recht schwer verdaulich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Was ist glSlang?=&lt;br /&gt;
Wie Eingangs kurz angesprochen handelt es sich bei glSlang um eine Shadersprache, also um eine Hochsprache, in der man die programmierbaren Teile aktueller Grafikbeschleuniger nach eigenem Belieben programmieren kann. Sie stellt quasi den Nachfolger zu den in Assembler geschriebenen Vertex- und Fragmentprogrammen ([[GL_ARB_Vertex_Program]]/[[GL_ARB_Fragment_Program]]) dar und basiert auf ANSI C, erweitert um Vektor- und Matrixtypen sowie einige C++-Mechanismen.&lt;br /&gt;
&lt;br /&gt;
Die in glSlang geschriebenen Programme nennen sich, angepasst an die Terminologie von RenderMan und DirectX, [[Shader]] (im Gegensatz zu &amp;quot;Programme&amp;quot; bei ARB_VP/FP) und werden entweder auf Vertexe (VertexShader) oder Fragmente (FragmentShader) angewendet, andere noch nicht programmierbare Teile der GL-Pipeline wie z.B. die Rasterisierung können momentan noch nicht über Shader beeinflusst werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
glSlang ist ein recht neues Feature, dass mit OpenGL1.5 eingeführt wurde, weshalb eine entsprechend moderne Grafikkarte (DX9-Generation) inklusive aktuellster Treiber von Nöten ist. &lt;br /&gt;
''Aktueller Stand (November 2005) ist wie folgt :''&lt;br /&gt;
&lt;br /&gt;
[http://www.ati.com ATI] haben bereits seit fast 2 Jahren (Catalyst 3.10) glSlang-fähige Treiber, allerdings kommt es besonders mit neueren Treibern hier und da immernoch zu Fehlern (oder es werden gar neue Fehler eingführt) und ATI zeigt momentan kein sehr starkes Interesse am fixen dieser Fehler.&lt;br /&gt;
&lt;br /&gt;
[http://www.nvidia.com NVidia] haben sich etwas mehr Zeit gelassen, allerdings ist deren glSlang-Implementation inzwischen recht ausgereift. Bugs gibts allerdings trotzdem hier und da, aber NVidias Entwicklersupport ist da recht offen für Fehlerberichte. Die aktuellen Treiber der 80er Reihe sind daher für glSlang-Nutzer bestens geeignet.&lt;br /&gt;
&lt;br /&gt;
[http://www.3dlabs.com 3DLabs], die glSlang quasi erfunden haben, haben natürlich hervorragenden glSlang Support in ihren Treiber, allerdings sind deren Wildcat-Karten kaum verbreitet.&lt;br /&gt;
&lt;br /&gt;
Natürlich benötigt ihr auch einen passenden OpenGL-Header der die für glSlang nötigen Extensions und Funktionen exportiert. Ich verweise dazu auf unseren internen OpenGL-Header [[DGLOpenGL.pas]] der da einwandfrei seine Dienste verrichtet und auch in der Beispielanwendung Verwendung findet.&lt;br /&gt;
&lt;br /&gt;
==Neue Extensions==&lt;br /&gt;
Die GL-Shadersprache &amp;quot;besteht&amp;quot; in ihrer aktuellen Version aus folgenden Extensions, fürs Verständnis wäre es nicht schlecht, wenn ihr euch zumindest die Einleitungen dazu durchlest :&lt;br /&gt;
* [[GL_ARB_Shader_Objects]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shader_objects.txt Orginal Spezifikation])&lt;br /&gt;
: Definiert die API-Aufrufe die zum Erstellen, Kompilieren, Linken, Anhängen und Aktivieren von Shader- und Programmobjekten nötig sind. &lt;br /&gt;
* [[GL_ARB_Vertex_Shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_shader.txt Orginal Spezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Vertexebene hinzu. &lt;br /&gt;
* [[GL_ARB_Fragment_Shader]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/fragment_shader.txt Orginal Spezifikation])&lt;br /&gt;
: Fügt der OpenGL Programmierbarkeit auf Fragmentebene hinzu. &lt;br /&gt;
* [[GL_ARB_Shading_Language_100]] ([http://oss.sgi.com/projects/ogl-sample/registry/ARB/shading_language_100.txt Orginal Spezifikation])&lt;br /&gt;
: Gibt die unterstützte Version von glSlang an, momentan 1.00.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Objekte==&lt;br /&gt;
Im Zuge der Vereinheitlichung der GL wird immer häufiger in Objekte gekapselt, deren API dann auch aneinander angelehnt ist. Ziel ist, dabei die Programmierung der GL uniform zu machen, so dass z.B. zwischen dem Erstellen und Verwalten eines Vertex-Buffer-Objektes oder eines Shader-Objektes kaum ein Unterschied besteht (demnächst kommen dann auch Pixel-Buffer-Objekte dazu). Mit glSlang wurden dann im Zuge dieser Aktion zwei neue Objekte eingeführt, deren Definition ihr euch unbedingt einprägen solltet :&lt;br /&gt;
&lt;br /&gt;
* '''Programmobjekt'''&lt;br /&gt;
:Ein Objekt, an das die Shader später angebunden werden. Bietet Funktionalität zum Linken der Shader und prüft dabei die Kompatibilität zwischen Vertex- und Fragmentshader.&lt;br /&gt;
&lt;br /&gt;
* '''Shaderobjekt'''&lt;br /&gt;
:Dieses Objekt verwaltet den Quellcodestring eines Shaders und ist entweder vom Typ '''GL_VERTEX_SHADER_ARB''' oder '''GL_FRAGMENT_SHADER_ARB'''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Resourcen==&lt;br /&gt;
Die Shadersprache ist keinesfalls final und es wurden bereits diverse Ausdrücke für zukünftige Verwendung reserviert, denn ein Ziel bei ihrer Entwicklung war es, sie so zukunftsorientiert zu gestalten, dass auch Grafikkarten der nächsten und übernächsten Generation voll ausgenutzt werden können. Damit einher geht die Tatsache, dass sich die Spezifikationen in Zukunft ändern/erweitern werden, weshalb man da immer einen Blick hineinwerfen sollte. Die Anlaufstelle dafür ist natürlich die [http://www.3dlabs.com/support/developer/ogl2/index.htm GL2-Seite von 3D-Labs], wo u.a. auch ein OGL2-SDK und diverse Whitepapers als PDFs angeboten werden, in denen auch stattgefundene Änderungen an glSlang dokumentiert sind.&lt;br /&gt;
&lt;br /&gt;
=glSlang im Programm=&lt;br /&gt;
Bevor wir uns mit der Syntax von glSlang beschäftigen, zeige ich euch erstmal, wie ihr Shader in euer Programm einbindet und nutzt. Warum das zuerst? Ganz einfach deshalb, weil ihr dann das, was ihr im glSlang-Syntaxteil lernt, direkt in eurer Testanwendung verwenden könnt. Hoffe diese Entscheidung klingt logisch und findet Anklang.&lt;br /&gt;
&lt;br /&gt;
Zuerst benötigen wir natürlich unsere Objekte. Zum einen ein ''Programmobjekt'', an das unsere Shader gebunden werden, und zwei ''Shaderobjekte'', die den Quellcode unseres Vertex bzw. Fragment Shaders aufnehmen. Dazu wurde eigens der neue &amp;quot;Datentyp&amp;quot; {{INLINE_CODE|glHandleARB}} eingeführt, der ein Objekthandle repräsentiert. Wir deklarieren also wie folgt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        : GLhandleARB;&lt;br /&gt;
 VertexShaderObject   : GLhandleARB;&lt;br /&gt;
 FragmentShaderObject : GLhandleARB;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dieser Deklaration können wir dann damit beginnen unsere Objekte zu erstellen. Den Anfang macht das Programmobjekt :&lt;br /&gt;
&lt;br /&gt;
 ProgramObject        := glCreateProgramObjectARB;&lt;br /&gt;
&lt;br /&gt;
Die Funktion [[glCreateProgramObjectARB]] erstellt uns oben ein leeres Programmobjekt und gibt ein gültiges Handle darauf zurück.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Erstellung unseres Vertex bzw. Fragment Shaders :&lt;br /&gt;
&lt;br /&gt;
 VertexShaderObject   := glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);&lt;br /&gt;
 FragmentShaderObject := glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);&lt;br /&gt;
&lt;br /&gt;
[[glCreateShaderObjectARB]] dient zur Generierung eines leeren Shaderobjektes. Momentan unterstützt diese Funktion VertexShader und FragmentShader.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun also zwei gültige Shaderobjekte haben, wollen wir diese auch mit entsprechendem Quellcode versorgen :&lt;br /&gt;
&lt;br /&gt;
 glShaderSourceARB(VertexShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
 glShaderSourceARB(FragmentShaderObject, 1, @ShaderText, @ShaderLength);&lt;br /&gt;
&lt;br /&gt;
Via [[glShaderSourceARB]] setzen wir den Quellcode eines Shaderobjektes ''komplett'' neu. Zum Laden des Quellcodes bietet sich unter Delphi übrigens eine TStringList geradezu an. Es sollte beachtet werden, dass der Quellcode zu diesem Zeitpunkt ''nicht geparst'' wird, also keine Fehleruntersuchung stattfindet.&lt;br /&gt;
&lt;br /&gt;
Der Quellcode wurde jetzt also an unsere Shaderobjekte gebunden und sollte dann natürlich auch noch kompiliert werden :&lt;br /&gt;
&lt;br /&gt;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 glCompileShaderARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
Der glSlang-Compiler des Treibers wird bei einem Aufruf von [[glCompileShaderARB]] versuchen, unsere Shader zu kompilieren. Sofern diese keine Fehler aufweisen, sollte dies auch erfolgreich sein. Wenn nicht, dann spuckt uns der ShaderKompiler je nach Treiber recht detaillierte Infos aus. Wie man an diese Infos kommt könnt ihr gleich nachlesen.&lt;br /&gt;
&lt;br /&gt;
Wenn unsere Shader dann kompiliert werden konnten, ist es Zeit, diese an unser anfangs erstelltes Programmobjekt anzuhängen :&lt;br /&gt;
&lt;br /&gt;
 glAttachObjectARB(ProgramObject, VertexShaderObject);&lt;br /&gt;
 glAttachObjectARB(ProgramObject, FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachdem die Shaderobjekte nun an das Programmobjekt angehangen wurden, werden diese nicht mehr benötigt und ihre Resourcen können freigegeben werden :&lt;br /&gt;
&lt;br /&gt;
 glDeleteObjectARB(VertexShaderObject);&lt;br /&gt;
 glDeleteObjectARB(FragmentShaderObject);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Am Schluß müssen wir dann noch unsere ans Programmobjekt gebundenen Shader linken :&lt;br /&gt;
&lt;br /&gt;
 glLinkProgramARB(ProgramObject);&lt;br /&gt;
&lt;br /&gt;
Während [[glCompileShaderARB]] unsere Shader auf syntaktische Fehler innerhalb ihres lokalen Raums geprüft hat, werden beim Linken durch [[glLinkProgramARB]] die angehangenen Shader zu einem ausführbaren Shader gelinkt. Folgende Bedingungen führen zu einem '''Linkerfehler''':&lt;br /&gt;
&lt;br /&gt;
* Die Zahl der von der Implementation unterstützten Attributvariablen wurde überschritten&lt;br /&gt;
* Der Speicherplatz für Uniformvariablen wurde überschritten&lt;br /&gt;
* Die Zahl der von der Implementation angebotenen Sampler wurde überschritten&lt;br /&gt;
* Die main-Funktion fehlt&lt;br /&gt;
* Die Liste der Varying-Variablen des Vertexshaders stimmt nicht mit der des Fragmentshaders überein&lt;br /&gt;
* Funktions- oder Variablenname nicht gefunden&lt;br /&gt;
* Eine gemeinsame Globale ist mit unterschiedlichen Werten oder Typen initialisiert worden&lt;br /&gt;
* Zwei Sampler unterschiedlichen Typs zeigen auf die selbe Textureneinheit&lt;br /&gt;
* Ein oder mehrere angehangene(r) Shader wurden nicht erfolgreich kompiliert&lt;br /&gt;
&lt;br /&gt;
Die Nutzung von glSlang im eigenen Programm ist wie oben erkennbar also nicht wirklich schwer und innerhalb kurzer Zeit realisiert. Natürlich ist es auch möglich z.B. nur einen VertexShader oder nur einen FragmentShader an ein Programmobjekt zu binden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fehlererkennung==&lt;br /&gt;
Natürlich wird es ohne Fehlerausgabe recht schwer, etwaige Probleme in einem Vertex- oder Fragmentshader zu finden. Doch auch in diesem Bereich wurde glSlang recht gut durchdacht und es wurden zwei Funktionen eingeführt, welche im Zusammenspiel die Fehlersuche recht einfach machen, nämlich [[glGetInfoLogARB]] und [[glGetObjectParameterivARB]] mit dem Argument {{INLINE_CODE|GL_OBJECT_INFO_LOG_LENGTH_ARB}}. Erstere Funktion liefert uns einen Logstring, während uns letztere Funktion dessen Länge angibt. Der Logstring wird verändert, sobald ein Shader kompiliert oder ein Programm gelinkt wird.&lt;br /&gt;
&lt;br /&gt;
Um die Ausgabe dieses Logs so einfach wie möglich zu machen, bietet es sich an beide in einer einfach Funktion unterzubringen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;function glSlang_GetInfoLog(glObject : GLHandleARB) : String;&lt;br /&gt;
var&lt;br /&gt;
 blen,slen : GLInt;&lt;br /&gt;
 InfoLog   : PGLCharARB;&lt;br /&gt;
begin&lt;br /&gt;
glGetObjectParameterivARB(glObject, GL_OBJECT_INFO_LOG_LENGTH_ARB , @blen);&lt;br /&gt;
if blen &amp;gt; 1 then&lt;br /&gt;
 begin&lt;br /&gt;
 GetMem(InfoLog, blen*SizeOf(GLCharARB));&lt;br /&gt;
 glGetInfoLogARB(glObject, blen, slen, InfoLog);&lt;br /&gt;
 Result := PChar(InfoLog);&lt;br /&gt;
 Dispose(InfoLog);&lt;br /&gt;
 end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist recht leicht erklärt : Zuerst lassen wir uns über {{INLINE_CODE|glGetObjectParameterivARB}} mitteilen wie lang der aktuelle Infolog ist. Sollte dort tatsächlich etwas drinstehen (blen &amp;gt; 1), dann lassen wir uns dessen Inhalt via {{INLINE_CODE|glGetInfoLogARB}} in {{INLINE_CODE|InfoLog}} ausgeben und liefern diesen als Ergebnis zurück.&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt wird nur nach dem Kompilieren eines Shaders bzw. dem Linken eines Programmobjektes ein Infolog erstellt. Es bietet sich dadurch an, direkt danach einen solchen Aufruf zu machen :&lt;br /&gt;
&lt;br /&gt;
 glCompileShaderARB(VertexShaderObject);&lt;br /&gt;
 ShowMessage(glSlang_GetInfoLog(VertexShaderObject));&lt;br /&gt;
&lt;br /&gt;
Wenn unser Vertex Shader komplett fehlerfrei kompiliert werden konnte, dann sehen wir als Ergebnis nur einen leeren Dialog. Ist dies nicht der Fall, so werden wir vom Treiber mit recht detaillierten Fehlerinformationen &amp;quot;belohnt&amp;quot;, z.B. so :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL_error_vshader.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Auch das Infolog nach dem Linken des Programmobjektes dürfte, selbst wenn keine Fehler vorkommen, recht interessant sein, das sieht dann nämlich so aus :&lt;br /&gt;
&lt;br /&gt;
[[Bild:GLSL info programobject.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wie zu sehen, wird uns nach dem erfolgreichen Linken auch gesagt, ob und welcher Shader in Hardware bzw. Software läuft. Für Debuggingzwecke sicherlich eine mehr als brauchbare Information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Parameterübergabe==&lt;br /&gt;
Uniformparameter (mehr dazu später) stellen die Schnittstelle zwischen eurem Programm und dem Shader dar, werden also genutzt um Daten aus dem Programm heraus an einen Shader zu übergeben. Zur Übergabe dieser Parameter bietet OpenGL diverse Funktionen, die alle Abkömmlinge von [[glUniformARB]] sind. Während mit {{INLINE_CODE|glUniform4fARB}} z.B. ein Vier-Komponentenvektor an das Programmobjekt übergeben wird, kann man mittels {{INLINE_CODE|glUniformMatrix4fvARB}} ganze Matrizen schnell und einfach übergeben. Ausserdem gibt es nun die Möglichkeit Uniformparameter direkt über ihren Namen, statt wie unter ARB_FP/VP über einen festen Index zu adressieren. Die Funktion [[glGetUniformLocationARB]] gibt anhand des übergebenen Parameternamens dessen Position zurück. Man kann also ganz einfach über den Namen drauf zugreifen :&lt;br /&gt;
&lt;br /&gt;
 glUniform3fARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('LightPosition')), LPos[0], LPos[1], LPos[2]);&lt;br /&gt;
 glUniform1iARB(glGetUniformLocationARB(ProgramObject, PGLCharARB('texSamplerTMU3')), 3);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wichtig ist hier, das man je nach Parametertyp auch die passende Anzahl von Argumenten übergibt. Also für einen 4-Komponenten Floatvektor {{INLINE_CODE|glUniform4fARB}} und für einen einfachen Integerwert (z.B. Textureinheit für einen Sampler) glUnifrom1iARB. Auch nicht vergessen dürft ihr, das die Namen der Parameter genauso wie im Shader geschrieben werden müssen, also Groß- und Kleinschreibung beachtet werden muß.&lt;br /&gt;
&lt;br /&gt;
=Die Shadersprache=&lt;br /&gt;
&lt;br /&gt;
Nachdem wir uns mit der Einbindung der glSlang-Shader in unser Programm beschäftigt haben, wollen wir uns in den folgenden Kapiteln um die Sprachelemente von glSlang kümmern. Wie schon gesagt basiert glSlang auf ANSI-C, wurde allerdings um speziell auf den Zielbereich angepasste Vektor- und Matrixtypen und einige C++-Features wie das freie deklarieren von Variablen an jeder Stelle und das Funktionsüberladen auf Basis des Argumenttyps erweitert. Wer sich ein wenig mit C/C++ auskennt sollte also in der nun folgenden Materie keine Probleme bekommen.&lt;br /&gt;
&lt;br /&gt;
'''Obligatorische Hinweise für verwöhnte Delphi-Nutzer : '''&lt;br /&gt;
*Wie von C/C++ her gewohnt, spielt auch in glSlang die Groß- und Kleinschreibung eine wichtige Rolle, also bitte achtet darauf. gl_Position ist eine komplett andere Variable als z.B. gl_position.&lt;br /&gt;
*Es findet keine automatische Typenkonvertierung statt. Das bedeutet also das float MyFloat = 1 ungültig ist und es in dem Falle float MyFloat = 1.0 heissen muss. Typecasts müssen also immer manuell stattfinden, z.B. MyFloat = float(MyInt).&lt;br /&gt;
&lt;br /&gt;
'''Kleine Programmstrukturkunde für C-Unkundige :'''&amp;lt;br&amp;gt;&lt;br /&gt;
Da sicherlich einige Delpher nie richtig was mit C gemacht haben, zeige ich mal anhand eines kleinen Beispieles (das auf keinen Fall nen brauchbaren Shader darstellt) den grundlegenden Aufbau eines glSlang-Shaders, der natürlich dem Aufbau eines C-Programmes stark ähnelt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform vec4 VariableA;&lt;br /&gt;
float VariableB;&lt;br /&gt;
vec3  VariableC;&lt;br /&gt;
const float KonstanteA = 256.0;&lt;br /&gt;
&lt;br /&gt;
float MyFunction(vec4 ArgumentA)&lt;br /&gt;
 {&lt;br /&gt;
 float FunktionsVariableA = float(5.0);&lt;br /&gt;
&lt;br /&gt;
 return float(ArgumentA * (FunktionsVariableA + KonstanteA));&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
// Ich bin ein Kommentar&lt;br /&gt;
/* Und ich auch */&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sieht doch recht bekannt aus, unser Programmaufbau. Delphi und C haben ja so einige Grundlagen gleich, darunter auch der ungefähre Programmaufbau. Ausserhalb jeglicher Funktionen legen wir am Programmanfang unsere Variablen, Konstanten und Attribute fest, die dann ''global'' nutzbar sind, also in jeder Funktion.&lt;br /&gt;
&lt;br /&gt;
Darunter deklarieren wir dann eine kleine Funktion. Wie auch bei den Variablendeklarationen wird hier der Rückgabetyp nicht wie bei Pascal nach dem Funktionsnamen untergebracht, sondern davor. Innerhalb der Funktion können dann wieder Variablen deklariert werden, die dann allerdings ''lokal'', also nur in dieser Funktion nutzbar sind. Vorteil dieser Deklaration ist die Tatsache, dass je nach Grafikkarte nur bestimmt viele globale Variablen deklariert werden können. Wenn möglich sollte man also mit lokalen Vorlieb nehmen. Unsere Funktion gibt dann natürlich noch via return einen Wert zurück, ''was gemacht werden muss'', sofern man diese nicht als void deklariert hat (entspräche dann einer Prozedur in Pascal). Wird dies nicht getan, so spuckt der Compiler einen Fehler aus.&lt;br /&gt;
&lt;br /&gt;
Auch wichtig sind natürlich Kommentare. Erste Variante (Doppelslash) ist auch in der Pascalwelt verfügbar und kommentiert eine einzelne Zeile aus. Die Variante darunter kann man für Kommentarblöcke nutzen (/* .. */) und entspricht den Kommentaren in geschweiften Klammern in Delphi.&lt;br /&gt;
&lt;br /&gt;
Danach kommt dann die '''wichtigste Funktion''' des Shaders, nämlich '''main''', die in keinem Shader fehlen darf. Sie stellt quasi den Programmkörper dar und ist oft auch die einzige Funktion in einem Shader. Sie erhält weder ein Argument, noch gibt sie einen Wert zurück.&lt;br /&gt;
&lt;br /&gt;
Soviel also zum grundlegenden Aufbau eines Shader. Hoffe das jetzt alle die in C nicht so bewandert sind damit klar kommen, und dann bald ihre ersten glSlang-Shader schreiben können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Datentypen==&lt;br /&gt;
&lt;br /&gt;
Obwohl einige Datentypen aus C übernommen wurden, sieht man der Typenliste an, das diese speziell auf den 3D-Bereich zugeschnitten wurde. Variablen müssen vor ihrer Nutzung eindeutig deklariert sein, Typecasting erfolgt über Konstruktoren (dazu später mehr). Folgende Datentypen stehen sowohl im Vertex- als auch Fragmentshader zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Datentyp  	&lt;br /&gt;
!Erklärung&lt;br /&gt;
|-&lt;br /&gt;
|void 	&lt;br /&gt;
|Für Funktionen die keinen Wert zurückgeben&lt;br /&gt;
|-&lt;br /&gt;
|bool 	&lt;br /&gt;
|Konditionaler Typ, entweder true (wahr) oder false (falsch)&lt;br /&gt;
|-&lt;br /&gt;
|int 	&lt;br /&gt;
|Vorzeichenbehafteter Integerwert&lt;br /&gt;
|-&lt;br /&gt;
|float 	&lt;br /&gt;
|Fließkommaskalar mit Singlegenauigkeit (32 Bit)&lt;br /&gt;
|-&lt;br /&gt;
|vec2 	&lt;br /&gt;
|2-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec3 	&lt;br /&gt;
|3-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|vec4 	&lt;br /&gt;
|4-Komponenten Fließkommavektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec2 	&lt;br /&gt;
|2-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec3 	&lt;br /&gt;
|3-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|bvec4 	&lt;br /&gt;
|4-Komponenten Booleanvektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec2 	&lt;br /&gt;
|2-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec3 	&lt;br /&gt;
|3-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|ivec4 	&lt;br /&gt;
|4-Komponenten Integervektor&lt;br /&gt;
|-&lt;br /&gt;
|mat2 	&lt;br /&gt;
|2x2 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat3 	&lt;br /&gt;
|3x3 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|mat4 	&lt;br /&gt;
|4x4 Fließkommamatrix&lt;br /&gt;
|-&lt;br /&gt;
|sampler1D 	&lt;br /&gt;
|Zugriff auf 1D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler2D 	&lt;br /&gt;
|Zugriff auf 2D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|sampler3D 	&lt;br /&gt;
|Zugriff auf 3D-Textur&lt;br /&gt;
|-&lt;br /&gt;
|samplerCube 	&lt;br /&gt;
|Zugriff auf Cubemap&lt;br /&gt;
|-&lt;br /&gt;
|sampler1DShadow 	&lt;br /&gt;
|Zugriff auf 1D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|sampler2DShadow 	&lt;br /&gt;
|Zugriff auf 2D-Tiefentextur mit Vergleichsoperation&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Die sampler-Typen stellen eine besondere Klasse dar und werden im Kapitel 6.7 genauer erklärt, inklusive einiger Anwendungsbeispiele.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Arrays===&lt;br /&gt;
&lt;br /&gt;
Natürlich unterstützt glSlang auch Arrays, die wie in C deklariert werden und deren Index bei 0 beginnt. Folgendes Array im Shader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
float temp[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
beginnt also bei Index 0 und endet bei Index 2. Im Gegensatz zu C lassen sich Arrays in glSlang allerdings ''nicht bei der Initialisierung vorbelegen''. Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Strukturen===&lt;br /&gt;
&lt;br /&gt;
Neu ggü. ARB_FP/VP ist nun auch die Möglichkeit, Strukturen in einem Shader zu deklarieren. Vor allem die Übersicht komplexerer Shader kann dadurch stark verbessert werden. Strukturen werden wie gewohnt mit dem Schlüsselwort {{INLINE_CODE|struct}} eingeleitet und können dann zur Typisierung von Variablen genutzt werden. Folgendes Beispiel dürfte die Nutzung verdeutlichen :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct light&lt;br /&gt;
 {&lt;br /&gt;
 bool active;&lt;br /&gt;
 float intensity;&lt;br /&gt;
 vec3 position;&lt;br /&gt;
 vec3 color;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Im Shader können dann neue Variablen von diesem Typ ganz einfach deklariert werden :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
 light LightSource[3];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Der Zugriff auf die Elemente der Struktur erfolgt dann wie gewohnt über den Punkt :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
LightSource[3].position = vec3(1.0, 1.0, 5.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Typenqualifzierer==&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zur Typendeklaration kann eine Variable noch einen Typenqualifizerer vorangestellt bekommen, der an den Anfang der Deklaration gehört.&lt;br /&gt;
&lt;br /&gt;
* '''const'''&lt;br /&gt;
: Festgelegte (nur lesen) Konstante bzw. nur lesbarer Funktionsparameter.&lt;br /&gt;
&lt;br /&gt;
* '''uniform'''&lt;br /&gt;
: Ein den ganzen Shader über gleichbleibender Wert, der eine Schnittstelle zwischen dem Shader und der OpenGL-Anwendung darstellt. Ein Uniformwert wird in der Hauptanwendung an den entsprechenden Shader übergeben und kann dort dann genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* '''attribute'''&lt;br /&gt;
: Nur lesbare Werte die eine Verbindung zwischen dem Shader und der OpenGL-VertexAPI darstellen (z.B. VertexParameter eines VertexArrays). Natürlich nur in einem Vertex Shader nutzbar.&lt;br /&gt;
&lt;br /&gt;
* '''varying'''&lt;br /&gt;
: Stellt die Verbindung zwischen einem Vertex- und einem FragmentShader dar. Werden im VertexShader geschrieben und dann perspektivisch korrekt über die Primitive interpoliert, um dann im Fragment Shader gelesen werden zu können. Nutzbar sind hier nur die Typen float, vec2, vec3, vec4, mat2, mat3 und mat4, Strukturen und andere Datentypen können nicht varying sein. Die Namen einer varying-Variable müssen sowohl im VertexShader als auch im FragmentShader gleich sein.&lt;br /&gt;
&lt;br /&gt;
* '''in'''&lt;br /&gt;
: Für Variablen die an eine Funktion übergeben und dort ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* '''out'''&lt;br /&gt;
: Für Variablen die von einer Funktion nach aussen zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
* '''inout'''&lt;br /&gt;
: Für Variablen die sowohl an eine Funktion übergeben als auch von dieser zurückgegeben werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um obige Auflistung nicht leer im Raum stehen zu lassen zeige ich ein paar Beispiele die hoffentlich zum Verständnis beitragen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Vertexnormale soll an einen FragmenShader (interpoliert) übergeben werden :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
VertexNormal = normalize(MV_IT * gl_Normal);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
:Im FragmentShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
varying vec3 VertexNormal;&lt;br /&gt;
...&lt;br /&gt;
TempVector = VertexNormal*...&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Uniformparameter zur nachträglichen Farbänderung der Szene wird im Programm übergeben :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = GlobalColor * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
:Im Programm :&lt;br /&gt;
&lt;br /&gt;
 glUniform4fARB(glSlang_GetUniLoc(ProgramObject, 'GlobalColor'), Col[0], Col[1], Col[2], Col[3]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Beispiel C=== &lt;br /&gt;
Konstante zur festen Farbänderung :&lt;br /&gt;
&lt;br /&gt;
:Im VertexShader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
const vec4 ColorBias = vec4(0.2, 0.3, 0.0, 0.0);&lt;br /&gt;
...&lt;br /&gt;
gl_FrontColor = ColorBias * gl_Color;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
==Konstruktoren==&lt;br /&gt;
&lt;br /&gt;
Um in einem Shader ''Vektoren'' oder ''Matrizen'' mit Werten zu belegen, gibt es sogenannte Konstruktoren (nicht zu verwechseln mit z.B. Klassenkonstruktoren unter Delphi), die im Endeffekt nichts anderes als Funktionen zur Vorbelegung von Vektoren oder Matrizen darstellen. Dabei trägt der Konstruktor den selben Namen wie die Typendeklaration, also lässt sich eine Variable vom Typ {{INLINE_CODE|vec4}} mit dem Konstruktor {{INLINE_CODE|vec4(float, float, float, float)}} initialisieren.&lt;br /&gt;
&lt;br /&gt;
Allerdings hat man sich recht viel Mühe bei dieser Konstruktorgeschichte gemacht, so dass man einen vec4 nicht unbedingt mit einem {{INLINE_CODE|vec4}}-Konstruktor vorbelegen muss, sondern es vielseitige Möglichkeiten gibt. Um dies zu verdeutlichen gibts ein paar Beispiele :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(1.0, 0.0, 0.0, 0.0);&lt;br /&gt;
vec4 Color = vec4(MyVec3, 1.0);&lt;br /&gt;
vec4 Color = vec4(MyVec2_A, MyVec2_B);&lt;br /&gt;
&lt;br /&gt;
vec3 LVec  = vec3(MyVec4);&lt;br /&gt;
vec2 Tmp   = vec2(MyVec3);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trotz der recht wenigen Beispiele sollte schnell erkennbar sein, das man hier wirklich sehr viele Kombinationsmöglichkeiten hat, die dann gültig sind ''wenn man mindestens auf die benötigte Anzahl der Argumente kommt''. Im vorletzten Beispiel wird z.B. ein 3-Komponentenvektor aus einem 4-Komponentenvektor initialisiert. Das erzeugt keinen Fehler, sondern führt dazu das {{INLINE_CODE|vec3.x, vec3.y, vec3.z}} aus MyVec4 übernommen werden und MyVec4.w einfach ignoriert wird.&lt;br /&gt;
&lt;br /&gt;
Das Umkehrbeispiel, also&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
vec4 Color = vec4(MyVec3)&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
funktioniert allerdings nicht, da hier die Zahl der benötigten Argumente nicht erreicht wird. In diesem Falle müsste es dann&lt;br /&gt;
&amp;lt;glsl&amp;gt; &lt;br /&gt;
vec4 Color = vec4(MyVec3, 0.0)&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
heissen.&lt;br /&gt;
&lt;br /&gt;
Obiges gilt natürlich auch für ''Matrixkonstruktoren'', hier sind z.B. folgende Konstuktoren denkbar, obwohl eigentlich alle Möglichkeiten nutzbar sind, ''solange die benötigte Zahl an Argumenten erreicht wird'' :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
mat4 MyMatrix = mat4(MyVec4, MyVec4, MyVec4, MyVec4);&lt;br /&gt;
mat2 MyMatrix = mat4(1.0, 0.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 1.0, 0.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 1.0, 0.0,&lt;br /&gt;
                     0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixkomponenten==&lt;br /&gt;
&lt;br /&gt;
Was natürlich in keiner Shadersprache fehlen darf, ist der leichte Zugriff auf die einzelnen Komponenten eines Vektors. glSlang bietet, je nach Anwendungsgebiet gleich drei Namensets für den Zugriff auf die Komponenten eines solchen Vektors, welches Set man nutzen will bleibt natürlich frei und ist unabhängig von der Deklaration eines Vektors. Man sollte nur darauf achten, beim gleichzeitigen Zugriff auf mehrere Komponenten im gleichen Namenset zu verbleiben :&lt;br /&gt;
&lt;br /&gt;
* {x, y, z, w}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Punkte, Normale oder sonstige Vertexdaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {r, g, b, a}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Farbwerte repräsentieren.&lt;br /&gt;
&lt;br /&gt;
* {s, t, p, q}&lt;br /&gt;
:Für den Zugriff auf Vektoren die Texturkoordinaten repräsentieren.&lt;br /&gt;
&lt;br /&gt;
Ein paar Beispiele zur Unterstreichung des oben gesagten :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
v4.rgba = vec4(1.0, 0.0, 0.0, 0.0);  // gültig&lt;br /&gt;
v4.rgzw = vec4(1.0, 1.0, 1.0, 2.0);  // Ungültig, da verschiedenen Namensets&lt;br /&gt;
v2.rgb  = vec3(1.0, 2.0, 1.0);       // Ungültig, da vec2 nur r+g besitzt&lt;br /&gt;
v2.xx   = vec2(5.0, 3.0);            // Ungültig, da 2 mal gleiche Komponente&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch der Zugriff auf die Komponenten einer Matrix geht leicht von der Hand. Namensets wie bei den Vektoren gibt es hier natürlich keine, aber folgende Beispiele sollen den Zugriff aufzeigen :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
MyMat4[2]    = vec4(1.0); // Setzt die 3.Zeile der Matrix komplett auf 1.0&lt;br /&gt;
MyMat4[3][3] = 3.5;       // Setzt das Element unren rechts auf 3.5&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Zugriff auf Matrixelemente ausserhalb ihrer Dimension (also z.B. MyMat4[4][4]) liefert unvorhersehabre Ergebnise, also sollte man auf diese Fälle prüfen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektor- und Matrixoperationen==&lt;br /&gt;
&lt;br /&gt;
Wie von C gewohnt sind in glSlang so ziemlich alle Operatoren die man auf Matrizen oder Vektoren anwenden kann überladen, so das man nicht umständlich über selbstgeschriebene Funktionen kombinieren muss. Darüber hinaus ist es in den meisten Fällen auch möglich ohne Konvertierung Fließkommawerte mit kompletten Matrizen oder Vektoren zu kombinieren. Folgende Beispiele zeigen einige der vielfältigen Kombinationsmöglichkeiten auf :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
float factor;&lt;br /&gt;
&lt;br /&gt;
vec3 dest = source + factor; &lt;br /&gt;
&lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = source.x + factor;&lt;br /&gt;
dest.y = source.y + factor;&lt;br /&gt;
dest.z = source.z + factor;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Matrix * Vektor ist auch ohne manuelle Konvertierung möglich :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
vec3  dest;&lt;br /&gt;
vec3  source;&lt;br /&gt;
mat3  MyMat;&lt;br /&gt;
 &lt;br /&gt;
dest = source * MyMat; &lt;br /&gt;
 &lt;br /&gt;
// Ist gleich&lt;br /&gt;
dest.x = dot(source, MyMat[0]);&lt;br /&gt;
dest.y = dot(source, MyMat[1]);&lt;br /&gt;
dest.z = dot(source, MyMat[2]);&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier sind die Möglichkeiten fast unbeschränkt und zeigen wieder wie flexibel glSlang ausgelegt ist. &lt;br /&gt;
&lt;br /&gt;
==Operatoren==&lt;br /&gt;
&lt;br /&gt;
glSlang bietet (momentan) folgende Operatoren, die Liste ist nach ihrer Gewichtung sortiert (Anfang = höchste). Alle ''reservierten'' Operatoren werden erst in kommender Hardware/glSlang-Versionen nutzbar sein :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div  align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Operatorklasse  	&lt;br /&gt;
!Operatoren  	&lt;br /&gt;
!Assoziation&lt;br /&gt;
|-&lt;br /&gt;
|Gruppering 	&lt;br /&gt;
|() 	&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
|Arrayindizierung&amp;lt;br&amp;gt;Funktionsaufrufe und Konstruktoren&amp;lt;br&amp;gt;Strukturfeldwahl und Swizzle&amp;lt;br&amp;gt;Postinkrement und -dekrement&amp;lt;br&amp;gt; 	&lt;br /&gt;
|[]&amp;lt;br&amp;gt;()&amp;lt;br&amp;gt;.&amp;lt;br&amp;gt;++ -- 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Prefixinkrement- und dekrement&amp;lt;br&amp;gt;Einheitlich (~ reserviert) 	&lt;br /&gt;
| ++ --&amp;lt;br&amp;gt; + - ~ ! 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Mulitplikation (% reserviert) 	&lt;br /&gt;
|* / % 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Additiv 	&lt;br /&gt;
| + - 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises Verschieben (reserviert) 	&lt;br /&gt;
|&amp;lt;&amp;lt;  &amp;gt;&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Relation 	&lt;br /&gt;
|&amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;= 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Vergleich 	&lt;br /&gt;
|==  != 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises AND (reserviert) 	&lt;br /&gt;
|&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises XOR (reserviert) 	&lt;br /&gt;
|^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Bitweises OR (reserviert) 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches AND 	&lt;br /&gt;
|&amp;amp;&amp;amp; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches XOR 	&lt;br /&gt;
|^^ 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Logisches OR 	&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|Auswahl 	&lt;br /&gt;
|?: 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Zuweisung&amp;lt;br&amp;gt;Arithmetrische Zuweisung&amp;lt;br&amp;gt;(Modulis, Shift und bitweise Op. reserviert) 	&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;+= -=  *=  /=  %=&amp;lt;/nowiki&amp;gt; &amp;lt;br&amp;gt; &amp;lt;nowiki&amp;gt;&amp;lt;&amp;lt;=  &amp;gt;&amp;gt;= &amp;amp;=  ^=  |=&amp;lt;/nowiki&amp;gt; 	&lt;br /&gt;
|Rechts n. Links&lt;br /&gt;
|-&lt;br /&gt;
|Aufzählung 	&lt;br /&gt;
|, 	&lt;br /&gt;
|Links n. Rechts&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Funktionen==&lt;br /&gt;
&lt;br /&gt;
Ein großer Vorteil von Hochsprachen ist u.A. die Möglichkeit oft genutzte Codeteile in Funktionen (bzw. auch Prozeduren unter Pascal) zu verpacken um so Flexibilität als auch Übersichtlichkeit zu steigern. Wer schonmal was in C geschrieben hat, der wird sich jetzt sicherlich kein Kopfzerbrechen machen müssen. Funktionen werden in glSlang genauso nach folgendem Prinzip deklariert :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
RückgabeTyp FunktionsName(Typ0 Argument0, Typ1, Argument1, ... , TypN, ArgumentN)&lt;br /&gt;
 {&lt;br /&gt;
 return RückgabeWert;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funktionen die ''nichts zurückgeben'' müssen mit dem RückgabeTyp {{INLINE_CODE|void}} deklariert werden, ausserdem entfällt dann logischerweise das {{INLINE_CODE|return}}. Falls die Funktion eines ihrere Argumente nach aussen übergeben soll, muss dieses Argument mit dem Typenqualifizierer out (Siehe Kapitel 4.2) versehen werden. ''Arrays'' können nur als Eingabeargumente übergeben werden und dürfen nich dimensioniert als Argument verwendet werden, sondern müssen mit leeren Klammern argumentiert werden.&lt;br /&gt;
Ein paar Beispiele :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void MeineFunktion(float EingabeWert; out float AusgabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 AusgabeWert = EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktion gibt ''nichts'' zurück, aber gibt EingabeWert*MyConstValue im Ausgabeargument AusgabeWert nach aussen.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
float MeineFunktion(float EingabeWert)&lt;br /&gt;
 {&lt;br /&gt;
 return EingabeWert*MyConstValue;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bietet genau die selbe Funktionalität wie das Beispiel darüber. Allerdings wird hier der berechnete Wert als Ergebnis der Funktion zurückgeliefert.&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
float VektorSumme(float v[])&lt;br /&gt;
 {&lt;br /&gt;
 return v[0]+v[1]+v[2]+v[3];&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt darf ein Array als Argument keine Dimensionierung enthalten. Wenn man der Funktion also ein Array übergibt, sollte man vorher drauf achten das es entsprechend der in der Funktion genutzten Indizes dimensioniert wurde.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==if-Anweisung==&lt;br /&gt;
&lt;br /&gt;
Selektion über eine if-Anweisung darf auch in keiner Hochsprache fehlen. Genauso wie in C oder Delphi erwartet auch hier die If-Anweisung einen boolschen Ausdruck (Wahr oder Falsch) und wird dann ausgeführt (wahr) bzw. verzweigt auf ein (wenn vorhanden) else (falsch). Verschachtelung ist wie erwartet auch möglich.&lt;br /&gt;
&lt;br /&gt;
'''Hinweis : ''' &lt;br /&gt;
Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten im Fragmentshader kein Early-Out, was zur Folge hat das bei einer If-Anweisung immer alle Zweige ausgeführt werden. Am Ende wird dann aber nur ein Ergebnis geschrieben, die anderen verworfen. Auf solchen Karten bringen If-Anweisungen also im Normalfall keine Geschwindigkeitssteigerung, sondern oft eher das Gegenteil.&lt;br /&gt;
Neuere SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall, da hier dynamische Verzweigungen und auch Early-Out von der Hardware implementiert werden.&lt;br /&gt;
&lt;br /&gt;
==Schleifen==&lt;br /&gt;
&lt;br /&gt;
Auch Schleifen, ein wichtiges Konzept jeder Hochsprache haben ihren Weg in glSlang gefunden. Unterstützt werden folgende Schleifentypen :&lt;br /&gt;
&lt;br /&gt;
* '''for'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
for (Startausdruck; Durchlaufbedingung; Wiederholungsausdruck;)&lt;br /&gt;
  {&lt;br /&gt;
   statement&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''while'''-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
while (Durchlaufbedingung)&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''do'''-while-Schleife&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
do&lt;br /&gt;
 {&lt;br /&gt;
  statement&lt;br /&gt;
 }&lt;br /&gt;
 while (Durchlaufbedingung)&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hinweis :''' Grafikkarten auf dem Stand des Shadermodells 2.0 (Radeon 9x00, Radeon X8x0, GeForceFX 5x00) unterstüzten Schleifen nicht in Hardware. Schleifen werden dann beim Kompilieren vom Treiber entrollt, wodurch natürlich Shader mit weitaus mehr Instruktionen als erwartet generiert werden. Von daher sollte man auf solchen Karten möglichst auf Schleifen verzichten, oder diese nur recht kurz halten. Bei SM3.0-Karten (Radeon X1x00, GeForce6x00 und höher) ist dass nicht mehr der Fall.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Variablen, Attribute und Konstanten=&lt;br /&gt;
Nachdem wir uns nun lange genug mit den minderinterssanten Elementen der glSlang-Syntax beschäftigt haben, gehts jetzt endlich an die wirklich interessanten Dinge. Wie schon ARB_VP/ARB_FP bringt auch glSlang jede Menge eingabauter Variablen, Attribute und Konstanten mit, deren Aliase sie recht leicht identifizierbar machen (ganz im Gegensatz zum Indexgewusel bei den DX-Shadern).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Vertex Shader==&lt;br /&gt;
Exklusiv im Vertex Shader stehen die folgenden Variablen zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Position    muss geschrieben werden&lt;br /&gt;
:Dieser Variable '''muss''' im Vertexshader ein Wert zugewiesen werden, wird dies nicht getan ist das Ergebnis (sprich die Position des Vertex) undefiniert. Vorgesehen ist diese Variable für die ''homogene Position des Vertex'' und wird u.a. zum Clipping und Culling verwendet. Sie darf natürlich auch (mehrfach) geschrieben und ausgelesen werden.&lt;br /&gt;
&lt;br /&gt;
* float gl_PointSize    kann geschrieben werden&lt;br /&gt;
:Diese Variable wurde dazu vorgesehen um dort im VertexShader die Punktgröße in Pixeln hineinzuschreiben.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_ClipVertex    kann geschrieben werden&lt;br /&gt;
:Falls genutzt, sollten hier die Vertexkoordinaten die im Zusammenhang mit benutzerdefinierten Clippingplanes genutzt werden abgelegt werden. Wichtig ist, das gl_ClipVertex im selben Koordinatenraum wie die Clippingplane definiert ist.&lt;br /&gt;
&lt;br /&gt;
==Attribute im Vertex Shader==&lt;br /&gt;
&lt;br /&gt;
Folgende Attribute stehen nur im Vertex Shader zur Verfügung und '''können nur gelesen werden''' :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_Color&lt;br /&gt;
: Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_SecondaryColor&lt;br /&gt;
:Sekundärer Farbwert des Vertex.&lt;br /&gt;
* vec4 gl_Normal&lt;br /&gt;
:Normale des Vertex.&lt;br /&gt;
* vec4 gl_Vertex&lt;br /&gt;
:Koordinaten des Vertex;&lt;br /&gt;
* vec4 gl_MultiTexCoord0..7&lt;br /&gt;
:Texturkoordinaten auf Textureinheit 0..7.&lt;br /&gt;
* float gl_FogCoord&lt;br /&gt;
:Nebelkoordinate des Vertex. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Variablen im Fragment Shader==&lt;br /&gt;
&lt;br /&gt;
Im Fragment Shader sind folgende Variablen exklusiv nutzbar :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragColor&lt;br /&gt;
: Speichert den Farbwert des Fragmentes, der von folgenden Funktionen der festen Pipeline genutzt wird. Wird dieser Variable nichts zugewiesen, so ist ihr Inhalt undefiniert und darauf aufbauende Ergebnisse ebenfalls.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragData[0..15]&lt;br /&gt;
: Ersetzt gl_FragColor bei der Verwendung von multiplen Rendertargets. &lt;br /&gt;
&lt;br /&gt;
* float gl_FragDepth&lt;br /&gt;
: Durch schreiben dieser Variable kann man den von der festen Funktionspipeline ermittelten Tiefenwert überspringen, der mit {{INLINE_CODE|gl_FragCoord.z}} ausgelesen werden kann. Wird dieser Wert nicht geschrieben, nutzen folgende Funktionen der Pipeline den vorher fest berechneten Wert.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FragCoord    nur lesen&lt;br /&gt;
: In dieser Variable ist die Position des Fragmentes relativ zur Fensterposition im Format x,y,z,1/w abgelegt, wobei z den von der festen Funktionspipeline berechneten Tiefenwert enthält.&lt;br /&gt;
&lt;br /&gt;
* bool gl_FrontFacing    nur lesen&lt;br /&gt;
: Gibt an ob das Fragment zu einer nach vorne zeigenden Primitive gehört (=true). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Im Bezug auf {{INLINE_CODE|gl_FragColor}} und {{INLINE_CODE|gl_FragDepth}} sei noch anzumerken das diese ''nicht'' in den Wertebereich 0..1 gebracht werden müssen, da dies später durch die feste Funktionspipeline automatisch gemacht wird.&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Varyings==&lt;br /&gt;
&lt;br /&gt;
Wie bereits in Kapitel 4.2 erwähnt, stellen Varyings eine Schnittstelle zwischen dem Vertex und dem Fragment Shader dar. Sie werden im Vertex Shader geschrieben und können dann im Fragment Shader ausgelesen werden, ohne das die folgenden Varyings dafür explizit deklariert werden müssen :&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontColor&lt;br /&gt;
: Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackColor&lt;br /&gt;
: Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_FrontSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Vorderseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_BackSecondaryColor&lt;br /&gt;
: Sekundäre Farbe der Rückseite des Vertex.&lt;br /&gt;
&lt;br /&gt;
* vec4 gl_TexCoord[x]&lt;br /&gt;
: Texturkoordinaten des Vertex auf Textureinheit x, wobei x die von der Hardware zur Verfügung gestellte Zahl der Textureinheiten-1 nicht überschreiten darf.&lt;br /&gt;
&lt;br /&gt;
* float gl_FogFragCoord&lt;br /&gt;
: Nebelkoordinate des Fragmentes. &lt;br /&gt;
&lt;br /&gt;
Die Varyings {{INLINE_CODE|gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor}} und {{INLINE_CODE|gl_BackSecondaryColor}} können im FragmentShader nur unter den Aliases gl_Color bzw. gl_SecondaryColor gelesen werden. Welcher Wert des Vertex Shaders im Fragment Shader dort eingesetzt wird ist abhängig davon ob das Fragment zu einer nach vorne oder nach hinten zeigenden Primitive gehört.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Konstanten==&lt;br /&gt;
Auch diverse Konstanten wurden definiert um darauf schnell im Shader zugreifen zu können. In den Klammern stehen die von einer GL-Implementation als Mindestanforderung anzubietenden Werte. Alle Konstanten sind sowohl im Vertex als auch im Fragment Shader abrufbar :&lt;br /&gt;
&lt;br /&gt;
: OpenGL 1.0/1.2 :&lt;br /&gt;
* int gl_MaxLights (8)&lt;br /&gt;
* int gl_MaxClipPlanes (6)&lt;br /&gt;
* int gl_MaxTextureUnits (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: ARB_Fragment_Program :&lt;br /&gt;
* int gl_MaxTextureCoordsARB (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Vertex_Shader :&lt;br /&gt;
* int gl_MaxVertexAttributesGL2 (16)&lt;br /&gt;
* int gl_MaxVertexUniformFloatsGL2 (512)&lt;br /&gt;
* int gl_MaxVaryingFloatsGL2 (32)&lt;br /&gt;
* int gl_MaxVertexTextureUnitsGL2 (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: Fragment_Shader :&lt;br /&gt;
* int gl_MaxFragmentTextureUnitsGL2 (2)&lt;br /&gt;
* int gl_MaxFragmentUniformFloatsGL2 (64)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eingebaute Uniformvariablen==&lt;br /&gt;
&lt;br /&gt;
Um den Zugriff auf OpenGL-Staten zu vereinfachen wurden in glSlang diverse Uniformvariablen zur direkten Verwendung im Shader eingebaut. Wie gewohnt wurden auch hier sinnvolle Namen verwendet, so dass eine tiefere Erklärung unnötig sein dürfte :&lt;br /&gt;
&lt;br /&gt;
* mat4 gl_ModelViewMatrix&lt;br /&gt;
* mat4 gl_ProjectionMatrix&lt;br /&gt;
* mat4 gl_ModelViewProjectionMatrix&lt;br /&gt;
* mat3 gl_NormalMatrix&lt;br /&gt;
* mat4 gl_TextureMatrix[gl_MaxTextureCoordsARB]&lt;br /&gt;
:{{INLINE_CODE|gl_NormalMatrix}} repräsentiert die inversen oberen 3x3 Werte der Modelansichtsmatrix. {{INLINE_CODE|gl_TextureMatrix[x]}} adressiert maximal Anzahl Textureinheiten-1-Texturmatrizen.&lt;br /&gt;
&lt;br /&gt;
* float gl_NormalScale&lt;br /&gt;
: Gibt den unter OpenGL festgelegten Faktor zur Skalierung der Normalen zurück.&lt;br /&gt;
&lt;br /&gt;
* struct gl_DepthRangeParameters&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_DepthRangeParameters&lt;br /&gt;
{&lt;br /&gt;
 float near;&lt;br /&gt;
 float far;&lt;br /&gt;
 float diff;&lt;br /&gt;
};&lt;br /&gt;
gl_DepthRangeParameters gl_DepthRange;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
: Clippingplanes : &lt;br /&gt;
* vec4 gl_ClipPlane[gl_MaxClipPlanes]&lt;br /&gt;
  &lt;br /&gt;
*struct gl_PointParameters&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_PointParameters&lt;br /&gt;
{&lt;br /&gt;
 float size;&lt;br /&gt;
 float sizeMin;&lt;br /&gt;
 float sizeMax;&lt;br /&gt;
 float fadeThresholdSize;&lt;br /&gt;
 float distanceConstantAttenuation;&lt;br /&gt;
 float distanceLinearAttenuation;&lt;br /&gt;
 float distanceQuadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_PointParameters gl_Point;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
*struct gl_MaterialParameters&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_MaterialParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 emission;&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 float shininess;&lt;br /&gt;
};&lt;br /&gt;
gl_MaterialParameters gl_FrontMaterial;&lt;br /&gt;
gl_MaterialParameters gl_BackMaterial;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightSourceParameters&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_LightSourceParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
 vec4 position;&lt;br /&gt;
 vec4 halfVector;&lt;br /&gt;
 vec3 spotDirection;&lt;br /&gt;
 float spotExponent;&lt;br /&gt;
 float spotCutoff;&lt;br /&gt;
 float spotCosCutoff;&lt;br /&gt;
 float constantAttenuation;&lt;br /&gt;
 float linearAttenuation;&lt;br /&gt;
 float quadraticAttenuation;&lt;br /&gt;
};&lt;br /&gt;
gl_LightSourceParameters gl_LightSource[gl_MaxLights];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelParameters&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_LightModelParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelParameters gl_LightModel;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightModelProducts&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_LightModelProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 sceneColor;&lt;br /&gt;
};&lt;br /&gt;
gl_LightModelProducts gl_FrontLightModelProduct;&lt;br /&gt;
gl_LightModelProducts gl_BackLightModelProduct;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
*struct gl_LightProducts&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_LightProducts&lt;br /&gt;
{&lt;br /&gt;
 vec4 ambient;&lt;br /&gt;
 vec4 diffuse;&lt;br /&gt;
 vec4 specular;&lt;br /&gt;
};&lt;br /&gt;
gl_LightProducts gl_FrontLightProduct[gl_MaxLights];&lt;br /&gt;
gl_LightProducts gl_BackLightProduct[gl_MaxLights];&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
* vec4 gl_TextureEnvColor[gl_MaxFragmentTextureUnitsGL2]&lt;br /&gt;
* vec4 gl_EyePlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_EyePlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneS[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneT[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneR[gl_MaxTextureCoordsARB]&lt;br /&gt;
* vec4 gl_ObjectPlaneQ[gl_MaxTextureCoordsARB]&lt;br /&gt;
&lt;br /&gt;
*struct gl_FogParameters&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
struct gl_FogParameters&lt;br /&gt;
{&lt;br /&gt;
 vec4 color;&lt;br /&gt;
 float density;&lt;br /&gt;
 float start;&lt;br /&gt;
 float end;&lt;br /&gt;
 float scale;&lt;br /&gt;
};&lt;br /&gt;
gl_FogParameters gl_Fog;&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Diese recht umfangreiche GL-Stateliste sollte eigentlich jeden Bedarf decken und momentan gibts kaum einen OpenGL-Status den man so nicht in einem Shader abfragen bzw. nutzen kann.&lt;br /&gt;
&lt;br /&gt;
=Eingebaute Funktionen=&lt;br /&gt;
glSlang ist mit diversen Skalar- und Vektorfunktionen ausgestattet, die teilweise (idealerweise) sogar direkt in der Hardware ausgeführt werden, weshalb einer fertigen Funktion ggü. gleichwertigen eigenen Berechnungen immer der Vorzug zu geben ist.&lt;br /&gt;
{{Hinweis| ''genType'' kann vom Type float, vec2, vec3 oder vec4 sein, ''mat'' vom Typ mat2, mat3 oder mat4.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Trigonometire und Winkel==&lt;br /&gt;
Alle übergebenen Winkel sollten, soweit nicht anders vermerkt, in Radien angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* genType radians (genType degrees)&lt;br /&gt;
: Wandelt von Grad nach Radien. &lt;br /&gt;
* genType degrees (genType radians)&lt;br /&gt;
: Wandelt von Radien nach Grad.&lt;br /&gt;
* genType sin (genType angle)&lt;br /&gt;
: Gibt den Sinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType cos (genType angle)&lt;br /&gt;
: Gibt den Cosinus von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType tan (genType angle)&lt;br /&gt;
: Gibt den Tangens von Angle zurück, wobei Angle in Radien angegeben wird.&lt;br /&gt;
* genType asin (genType x)&lt;br /&gt;
: Liefert den Arcsinus von x zurück, also den Winkel dessen Sinus x ergeben würde.&lt;br /&gt;
* genType acos (genType x)&lt;br /&gt;
: Liefert den Arccosinus von x zurück, also den Winkel dessen Cosinus x ergeben würde.&lt;br /&gt;
* genType atan (genType y, genType x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x/y ergeben würde.&lt;br /&gt;
* genType atan (genType y_over_x)&lt;br /&gt;
: Liefert den Winkel zurück, dessen Tangens x über y ergeben würde. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Exponentiell==&lt;br /&gt;
* genType pow (genType x, genType y)&lt;br /&gt;
: Gibt x hoch y zurück.&lt;br /&gt;
* genType exp2 (genType x)&lt;br /&gt;
: Gibt 2 hoch x zurück.&lt;br /&gt;
* genType log2 (genType x)&lt;br /&gt;
: Gibt den Logarithmus zur Basis 2 von x zurück.&lt;br /&gt;
* genType sqrt (genType x)&lt;br /&gt;
: Gibt die Wurzel von x zurück.&lt;br /&gt;
* genType inversesqrt (genType x)&lt;br /&gt;
: Gibt die umgekehrte Wurzel von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Standardfunktionen==&lt;br /&gt;
* genType abs (genType x)&lt;br /&gt;
: Liefert den absoluten Wert von x zurück.&lt;br /&gt;
* genType sign (genType x)&lt;br /&gt;
: Gibt -1.0 zurück, wenn x &amp;lt; 0.0, 0.0 wenn x = 0.0 und 1.0 wenn x &amp;gt; 0.0.&lt;br /&gt;
* genType floor (genType x)&lt;br /&gt;
: Gibt denn nächsten Integerwert zurück, der kleiner oder gleich x ist.&lt;br /&gt;
* genType ceil (genType x)&lt;br /&gt;
: Gibt den nächsten Integerwert zurück, der größer oder gleich x ist.&lt;br /&gt;
* genType fract (genType x)&lt;br /&gt;
: Gibt den Nachkommateil von x zurück.&lt;br /&gt;
* genType mod (genType x, float y) &lt;br /&gt;
* genType mod (genType x, genType y)&lt;br /&gt;
: Gibt den Modulus zurück. (=x-y * floor(x/y)) &lt;br /&gt;
* genType min (genType x, genType y) &lt;br /&gt;
* genType min (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn y &amp;lt; x, ansonsten x. &lt;br /&gt;
* genType max (genType x, genType y) &lt;br /&gt;
* genType max (genType x, float y)&lt;br /&gt;
: Liefert y zurück wenn x &amp;lt; y, ansonsten x. &lt;br /&gt;
* genType clamp (genType x, genType minVal, genType maxVal) &lt;br /&gt;
* genType clamp (genType x, float minVal, float maxVal)&lt;br /&gt;
: Zwängt x in den Bereich minVal..maxVal. &lt;br /&gt;
* genType mix (genType x, genType y, genType a)&lt;br /&gt;
* genType mix (genType x, genType y, float a)&lt;br /&gt;
: Liefert den linearen Blend zwischen x und y zurück. (= x * (1-a) + y * a) &lt;br /&gt;
* genType step (genType edge, genType x)&lt;br /&gt;
* genType step (float edge, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge, ansonsten 1.0. &lt;br /&gt;
* genType smoothstep (genType edge0, genType edge1, genType x)&lt;br /&gt;
* genType smoothstep (float edge0, float edge1, genType x)&lt;br /&gt;
: Liefert 0.0 zurück, wenn x &amp;lt;= edge und 1.0 wenn x &amp;gt;= edge. Dabei wird eine weiche Hermite Interpolation zwischen 0 und 1 durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Geometrie==&lt;br /&gt;
* float length (genType x)&lt;br /&gt;
: Gibt die Länge des Vektors x (= sqrt(x[0]² + x[1]² + ... + x[n]²) zurück. &lt;br /&gt;
* float distance (genType p0, genType p1)&lt;br /&gt;
: Gibt die Distanz zwischen den zwei Vektoren p0 un p1 (= length(p0-p1)) zurück. &lt;br /&gt;
* float dot (genType x, genType y)&lt;br /&gt;
: Gibt das Punktprodukt von x und y zurück (=x[0]*y[0] + x[1]*y[1] + ... + x[n]*y[n]). &lt;br /&gt;
* vec3 cross (vec3 x, vec3 y)&lt;br /&gt;
: Gibt das Kreuzprodukt von x und y zurück. &lt;br /&gt;
* genType normalize (genType x)&lt;br /&gt;
: Normalisiert den Vektor x auf die Länge 1. &lt;br /&gt;
* vec4 ftransform()&lt;br /&gt;
: Nur im Vertex Shader. Die Funktion stellt sicher, das das eingehende Vertex haargenau so transformiert wird wie in der festen Funktionspipeline. gl_Position = ftransform() wird dann also gebraucht, wenn in mehreren Durchgängen sowohl im Shader als auch in der festen Pipeline gerendert wird, um sicherzustellen das in beiden Fällen die gleiche Vertexposition herauskommt. &lt;br /&gt;
* genType faceforward (genType N, genType I, genType Nref)&lt;br /&gt;
: Gibt einen nach vorne zeigenden Vektor N zurück. (If dot(NRef, I) &amp;lt; 0 return N else return -N) &lt;br /&gt;
* genType reflect (genType I, genType N)&lt;br /&gt;
: Gibt den an der Flächenausrichtung N reflektierten Vektor I zurück. (=I-2 * dot(N,I) * N) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Matrixfunktionen==&lt;br /&gt;
* mat matrixCompMult (mat x, mat y)&lt;br /&gt;
: Multipliziert Matrix X mit Matrix Y komponentenweise. Um eine normale lineare Matrixmultiplikation durchzuführen, sollte der &amp;quot;*&amp;quot;-Operator genutzt werden. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vektorvergleiche==&lt;br /&gt;
Die meisten Vektorvergleichsfunktionen liefern als Ergebnis einen boolvektor zurück, da die Vergleiche per Komponente stattfinden. Wenn man also x = vec4(1.0, 3.0, 0.0, 0.0) mit y = vec4(2.0, 1.5, 1.5, 0.0) via lessThan(x, y) vergleicht, erhält man als Ergebnis bvec(true, false, true, false).&lt;br /&gt;
&lt;br /&gt;
* bvec lessThan (vec x, vec y)&lt;br /&gt;
* bvec lessThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt; y zurück. &lt;br /&gt;
* bvec lessThanEqual (vec x, vec y)&lt;br /&gt;
* bvec lessThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;lt;= y zurück. &lt;br /&gt;
* bvec greaterThan (vec x, vec y)&lt;br /&gt;
* bvec greaterThan (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt; y zurück. &lt;br /&gt;
* bvec greaterThanEqual (vec x, vec y)&lt;br /&gt;
* bvec greaterThanEqual (ivec x, ivec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x &amp;gt;= y zurück. &lt;br /&gt;
* bvec equal (vec x, vec y)&lt;br /&gt;
* bvec equal (ivec x, ivec y)&lt;br /&gt;
* bvec equal (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x == y zurück. &lt;br /&gt;
* bvec notEqual (vec x, vec y)&lt;br /&gt;
* bvec notEqual (ivec x, ivec y)&lt;br /&gt;
* bvec notEqual (bvec x, bvec y)&lt;br /&gt;
: Gibt den komponentenweisen Vergleich x != y zurück. &lt;br /&gt;
* bool any (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn mindestens eine der Komponenten von x true ist.&lt;br /&gt;
* bool all (bvec x)&lt;br /&gt;
: Liefert true zurück, wenn alle Komponenten von x true sind. &lt;br /&gt;
* bvec not (bvec x)&lt;br /&gt;
: Liefert die logische Negation von x zurück. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Texturenzugriffe==&lt;br /&gt;
&lt;br /&gt;
Diese wichtige Funktionskategorie dient dazu, Werte aus einer an eine Textureinheit gebundenen Textur zu ermitteln. Die Texturenzugriffe können sowohl im Vertex (!) als auch im Fragment Shader ausgeführt werden, wobei der optionale Parameter bias im Vertex Shader ignoriert wird. Allerdings gibt es zusätzlich Funktionen die auf &amp;quot;Lod&amp;quot; enden und nur im Vertex Shader genutzt werden dürfen um eben dieses Manko zu umgehen. Funktionen mit dem Suffix &amp;quot;Proj&amp;quot; geben einen projizierten Texturenwert zurück.&lt;br /&gt;
&lt;br /&gt;
: '''1D-Texturen :'''&lt;br /&gt;
* vec4 texture1D (sampler1D sampler, float coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture1DProj (sampler1D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 texture1DLod (sampler1D sampler, float coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture1DProjLod (sampler1D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''2D-Texturen :'''&lt;br /&gt;
* vec4 texture2D (sampler2D sampler, vec2 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture2DProj (sampler2D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''3D-Texturen :'''&lt;br /&gt;
* vec4 texture3D (sampler3D sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 texture3DProj (sampler3D sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
* vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 texture3DProjLod (sampler3D sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Cubemap :'''&lt;br /&gt;
* vec4 textureCube (samplerCube sampler, vec3 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader : &lt;br /&gt;
*vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: '''Tiefentextur (Shadowmap) :'''&lt;br /&gt;
* vec4 shadow1D (sampler1DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow2D (sampler2DShadow sampler, vec3 coord [, float bias])&lt;br /&gt;
* vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
* vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord [, float bias])&lt;br /&gt;
: Nur im Vertex Shader :&lt;br /&gt;
* vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod)&lt;br /&gt;
* vec4 shadow1DProjLod (sampler1DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
* vec4 shadow2DProjLod (sampler2DShadow sampler, vec4 coord, float lod)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie bereits eingangs gesagt ist dieses Kapitel ein sehr wichtiges, denn eine 3D-Szene ohne Texturen ist heute kaum denkbar. Darüber hinaus lassen sich durch Texturenzugriffe recht viele interessante Sachen machen, z.B. ein einfacher Blurfilter oder das freie überblenden bestimmter Texturenteile. Deshalb führe ich hier kurz ein paar Beispiele an, welche die Nutzung dieser Funktionen verdeutlichen sollen :&lt;br /&gt;
&lt;br /&gt;
===Beispiel A=== &lt;br /&gt;
Eine Textur gebunden die einfach ausgegeben werden soll&lt;br /&gt;
&lt;br /&gt;
''Im Vertex Shader'' :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt; &lt;br /&gt;
Der Vertex Shader ist recht minimal. Neben der homogenen Vertexposition leiten wir hier nur die im OpenGL-Programm angegebenen Texturkoordinaten weiter. ''Dies ist aber unbedingt nötig!'' Ohne die letzte Zeile hätten wir im Fragment Shader keine gültigen Texturkoordinaten auf TMU0, was in einer Fehldarstellung enden würde.&lt;br /&gt;
&lt;br /&gt;
''im Fragment Shader'' :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D texSampler;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_FragColor = texture2D(texSampler, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
Zuerst deklarieren wir hier einen 2D-Texturensampler, wichtig : '''Texturensampler müssen IMMER als uniform deklariert werden!''' In der Hauptfunktion weisen wir dann einfach den über die Funktion texture2D aus unserer gebundenen Textur ausgelesenen Farbwert, anhand der vom Vertex Shader übergebenen Texturkoordinaten, zu.&lt;br /&gt;
&lt;br /&gt;
===Beispiel B=== &lt;br /&gt;
Zwei Texturen, jeweils auf TMU0 und TMU1. Fragmentfarbe soll eine Multiplikation der beiden Texturen darstellen.&lt;br /&gt;
&lt;br /&gt;
In diesem Beispielfall (der recht häufig vorkommt) müssen wir im Programm festlegen, ''welcher Sampler welche Textureinheit adressiert'', genau deshalb müssen die Texturensampler auch als uniform deklariert werden. Die Standardtextureneinheit eines Samplers ist TMU0, was in unserem Falle natürlich nicht brauchbar ist. Also müssen wir unserem zweiten Textursampler im Programm mitteilen das er seine Daten aus TMU1 beziehen soll :&lt;br /&gt;
&lt;br /&gt;
 glUniform1iARB(glSlang_GetUniLoc(ProgramObject, 'texSamplerTMU1'), 1);&lt;br /&gt;
&lt;br /&gt;
Dies ist also unbedingt zu machen, sobald ein Texturensampler eine Textureinheit &amp;gt; GL_TEXTURE_0 adressieren will. Die Textureneinheit des Samplers lässt sich also nicht im Shader selbst festlegen. Der Fragment Shader ist nun allerdings schnell hergeleitet (Vertex Shader verändert sich nicht, da TMU1 die Texturkoordinaten auch von TMU0 bezieht) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
im Fragment Shader :&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D texSamplerTMU0;&lt;br /&gt;
uniform sampler2D texSamplerTMU1;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
    gl_FragColor = texture2D(texSamplerTMU0, vec2(gl_TexCoord[0])) *&lt;br /&gt;
                   texture2D(texSamplerTMU1, vec2(gl_TexCoord[0]));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Noisefunktionen==&lt;br /&gt;
Sowohl im Vertex als auch im Fragment Shader lassen sich Noisefunktionen nutzen, mit deren Hilfe sich einge Gewisse &amp;quot;Zufälligkeit&amp;quot; simulieren lässt (wirklich zufällige Werte sind es natürlich nicht). Ein zurückgegebener Wert liegt dabei immer im Bereich [-1..1] und ist immer bei gleichem Eigabewert auch immer gleich.&lt;br /&gt;
&lt;br /&gt;
* float noise1 (genType x)&lt;br /&gt;
* vec2 noise2 (genType x)&lt;br /&gt;
* vec3 noise3 (genType x)&lt;br /&gt;
* vec4 noise4 (genType x)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Discard==&lt;br /&gt;
Eigentlich keine Funktion, sondern eine Abbruchbedingung '''nur im Fragment Shader'''. Das Schlüsselwort {{INLINE_CODE|discard}} verwirft das aktuell bearbeitete Fragment und beendet gleichzeitig den Shader. Es kann z.B. genutzt werden um Alphamasking manuell durchzuführen.&lt;br /&gt;
Man sollte dabei jedoch beachten dass ein Großteil der aktuellen Hardware kein &amp;quot;early-out&amp;quot; (frühes Beenden) im Fragmentshader unterstützt. Wenn dort also ein {{INLINE_CODE|discard}} auftaucht, wird trotzdem auch der Code danach ausgeführt und einfach verworfen. Einen Geschwindigkeitsvorteil durch diesen Befehl wird man also erst auf neueren Karten feststellen, die dieses Faeature auch so unterstützen wie es angedacht war. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Beispielshader=&lt;br /&gt;
Wen bis hierhin nicht der Mut verlassen hat, und wer aufmerksam gelesen hat, dürfte jetzt also zumindest in der Lage sein kleinere Shader in glSlang zu schreiben und diese auch im Programm zu nutzen. Ich habe im Themenbereich &amp;quot;glSlang&amp;quot; versucht alle Bereiche der Shadersprache selbst anzusprechen und hoffe das auch brauchbar rübergebracht zu haben. Um oben erlerntes (hoffe ich doch mal) nochmal zu vertiefen werde ich jetzt (wie ich das bereits bei meinem ARB_VP-Tutorial getan habe) einen simplen Beispielshader (Vertex und Fragment Shader) auseinanderpflücken um so u.a. auch die Programmstruktur für alle die in C nicht so bewandert sind zu erörtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Vertex Shader==&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform vec4 GlobalColor;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;
 gl_FrontColor   = gl_Color * GlobalColor;&lt;br /&gt;
 gl_TexCoord[0]  = gl_MultiTexCoord0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie gesagt recht simpel. Angefangen wird mit der Deklaration einer globalen Uniformvariable namens {{INLINE_CODE|GlobalColor}}. Wie wir uns erinnern gibt der Typenqualifizierer uniform an, das wir den Wert dieser Variable (ein 4-Komponentenvektor, da Farbwerte aus R,G,B und A bestehen) in unserem Programm an den Shader übermitteln.&lt;br /&gt;
&lt;br /&gt;
Danach gehts ohne Umwege direkt in unsere Hauptfunktion, da wir im Vertex Shader keine anderen Funktionen benötigen. Dort berechnen wir zuerst die homogene Position unseres Vertex, die sich aus der eingehenden Vertexposition multipliziert mit der Modelansichtsmatrix ergibt. Wie schonmal gesagt '''muss diesem Wert etwas zugewiesen werden''', da sonst alle darauf aufbauenden Funktionen unvorhersehbare Ergebnisse liefern.&lt;br /&gt;
Ausserdem wollen wir die Frontfarbe unseres Vertex jedesmal mit der im Programm übergebenen GlobalColor multiplizieren, so dass wir den Farbwert der gesamten Szene aus unserem Programm heraus manipulieren können. Zu guterletzt geben wir dann noch unsere aus der festen Funktionspipeline erhaltenen Texturkoordinaten auf Textureinheit 0 weiter. Wenn im Fragmentshader Texturkoordinaten verwendet werden, '''muss das getan werden'''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Fragment Shader==&lt;br /&gt;
&amp;lt;glsl&amp;gt;&lt;br /&gt;
uniform sampler2D Texture0;&lt;br /&gt;
uniform sampler2D Texture1;&lt;br /&gt;
uniform sampler2D Texture2;&lt;br /&gt;
uniform sampler2D Texture3;&lt;br /&gt;
&lt;br /&gt;
void main(void)&lt;br /&gt;
{&lt;br /&gt;
 vec2 TexCoord = vec2( gl_TexCoord[0] );&lt;br /&gt;
 vec4 RGB      = texture2D( Texture0, TexCoord );&lt;br /&gt;
&lt;br /&gt;
 gl_FragColor  = texture2D(Texture1, TexCoord) * RGB.r +&lt;br /&gt;
                 texture2D(Texture2, TexCoord) * RGB.g +&lt;br /&gt;
                 texture2D(Texture3, TexCoord) * RGB.b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/glsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier passiert nicht wirklich viel Großartiges. Wir deklarieren beim Shaderanfang zuerst vier Texturensampler, da wir insgesamt vier verschiedene Texturen im Shader auslesen wollen, eine Verlaufstextur und drei Oberflächentexturen. Auch hier sei wieder gesagt das man Sampler '''immer als uniform deklarieren muss'''. In der Hauptfunktion deklarieren wir dann einen Farbvektor, der auch direkt einen Farbwert aus Textureinheit 0 zugewiesen bekommt. Auf Textureinheit 0 haben wir ihm Hauptprogramm eine Verlaufstextur gebunden, die angibt wie die drei folgenden Texturen ineinander geblendet werden.&lt;br /&gt;
Danach schreiben wir dann den Farbwert des Fragmentes, der '''im Fragment Shader ausgegeben werden muss'''. Der besteht wie einfach zu erkennen aus Farbwert von Textureinheit 1 * Rotwert von Textureinheit 0 + Farbwert von Textureinheit 2 * Grünwert von Textureinheit 0 + Farbwert von Textureinheit 3 * Blauwert von Textureinheit 0. So ist z.B. an Stellen an denen in der Verlaufstextur reines blau liegt nur die dritte Textur sichtbar.&lt;br /&gt;
&lt;br /&gt;
So viel also zu unserem kleinen Beispielshader. Er ist weder besonders toll noch besonders sinnvoll, sollte aber auch eher dazu dienen euch glSlang ein wenig zu veranschaulichen, was mir hoffentlich gelungen ist.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr in den vorangegangenen Kapiteln zumindest ein wenig aufgepasst habt, dann könnt ihr euch vor eurem inneren Auge hoffentlich vortstellen was der Shader macht : Er blendet drei Texturen weich anhand der Verlaufstextur ineinander über. Sowas kann man z.B. für ein Terrain nutzen, um dieses anhand einer Farbtextur zu texturieren. Für alle, die damit Probleme haben hier zwei Bilder die den Shader veranschaulichen. Links die Verlaufstextur, die angibt wo welche Textur wie stark gewichtet wird und rechts dann das Ergebnis :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt; [[BILD:GLSL_sample_shader_a.jpg]] [[BILD:GLSL_sample_shader_b.jpg]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Post Mortem=&lt;br /&gt;
Das wars also, meine &amp;quot;Einführung&amp;quot; in die OpenGL Shader Sprache. Ich hoffe es hat euch nicht gelangweilt und auch die von mir zur Verfügung gestellten Informationen haben euch hoffentlich ausgereicht. Mit der Veröffentlichung dieser Einführung geht übrigens auch die Eröffnung eines Shaderforums hier auf der DGL einher, in der ihr dann also fleissig Fragen zum Thema stellen oder eure Shader präsentieren könnt. In diesem Post Mortem gehe ich jetzt noch kurz auf die Zukunft von glSlang ein und zeige ein paar Screenshots (damit die Augen entspannen können), bevor ihr euch dann selbst in die Shaderwelt stürzen könnt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Screenshots=&lt;br /&gt;
&lt;br /&gt;
Um eure Augen ein wenig zu verwöhnen und zu zeigen was man mit glSlang alles machen, v.a. da man jetzt Shader schön lesbar in einer Hochsprache verfassen kann, mal ein paar Screens. Besonders der zweite Shot sieht animiert noch besser aus :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;[[BILD:GLSL_sample_Kugel.jpg]] [[BILD:GLSL_sample_Alien.jpg]] &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Zahl möglicher Effekte ist bei einer so flexiblen Shadersprache natürlich nahezu unbegrenzt, und besonders auf kommender Hardware werden bisher ungesehen Effekte den Einzu in die Echtzeitgrafik finden. Man darf also mehr als gespannt sein.&lt;br /&gt;
&lt;br /&gt;
=Die Zukunft=&lt;br /&gt;
Viele werden sich sicherlich fragen, warum sie z.B. statt ARB_VP/FP oder Nvidias cG denn überhaupt auf glSlang setzen sollen. Doch solche Zweifel dürften bei einem genauen Blick auf die neue Shadersprache schnell verworfen sein. Zum einen steckt hinter glSlang dank des ARBs fast die komplette 3D-Industrie und zum anderen hat man beim Entwurf der Shadersprache, wie z.B. an vielen reservierten Wörtern/Funktionen erkennbar versucht so weit wie möglich in die Zukunft zu planen. So sollen auch Karten der nächsten und übernächsten Generation mit glSlang ausnutzbar sein, und was danach kommt wird durch Spracherweiterungen erreicht. Sich also jetzt (besonders da es krachneu ist) mit glSlang zu befassen, um nicht ganz den Anschluss an kommende Entwicklungen im 3D-Bereich zu verlieren, ist der beste Weg.&lt;br /&gt;
&lt;br /&gt;
Also viel Spaß beim Experimentieren und Shaderschreiben! Und nicht vergessen : Wir wollen sehen was ihr so treibt,&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_glsl2]]}}&lt;br /&gt;
[[Kategorie:Tutorial|GLSL]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Bomberman1&amp;diff=20548</id>
		<title>Tutorial Bomberman1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Bomberman1&amp;diff=20548"/>
				<updated>2007-05-24T22:20:05Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Schlusswort */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Bomberman.gif|left]]&lt;br /&gt;
=Wir programmieren einen Bombermanklon! &amp;lt;br&amp;gt; &amp;lt;br&amp;gt; Teil 1 : Die Codebasis und der Editor=&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Ave, und willkommen zu meinem zweiten Tutorial, dem Anfang einer Tutorialserie!&lt;br /&gt;
&lt;br /&gt;
Neben Tetris gehört ''Bomberman'' wohl zu einem der erfolgreichsten Spielkonzepte der Videospielgeschichte, wurde es doch auf fast jede Plattform und dazu noch in diversen Varianten (es existieren über 30 Bombermanspiele) umgesetzt. Der Erfolg dieses Spielkonzepts liegt (wie auch bei Tetris) in seinem recht einfachen, aber dennoch fesselndem Spielprinzip in dem es darum geht die Mitspieler durch geschicktes Platzieren von Bomben aus den Rennen zu werfen und als letzter auf dem Spielfeld zu stehen. (Mehr Infos zum Thema Bomberman gibts u.a. hier : [http://www.bomberman.info http://www.bomberman.info])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
[[Bild:Bomberman nes 1985.jpg|NES (1985)]][[Bild:Bomberman snes 1993.jpg|MegaDrive (1993)]][[Bild:Bomberman neogeo 1997.jpg|NeoGeo (1997)]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und gerade wegen der Einfachheit dieses Spielprinzips ist ein Bombermanklon gradezu prädestiniert um als Grundlage für eine kleine Tutorialserie zum Thema Spieleprogrammierung zu dienen. Während Anfängern ein recht einfacher Einstieg in die Spieleprogrammierung geboten wird, bietet es fortgeschritteneren Programmierern sehr viel Freiraum zur Weiterentwicklung.&lt;br /&gt;
In dieser mehrteiligen Serie werde ich von Anfang an und auf auch für Einsteiger (für die die Tutorials auch gedacht sind) geeignete Art und Weise zeigen wie man einen Bombermanklon und den dazugehörenden Editor von Grund auf programmiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In diesem ersten Teil der Serie werden wir die vom Editor und dem Spiel verwendete Codebasis erstellen und widmen uns dann später im dem Editor und seinen Eigenheiten.&lt;br /&gt;
&lt;br /&gt;
Am Ende wird der geneigte Leser einen vollständen Karteneditor zum Erstellen einfacher Bombermankarten fertiggestellt haben, mit dessen Hilfe wir dann die Karten für den im zweiten Tutorial entwickelten Bombermanklons erstellen können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Realisiert wird das Ganze natürlich in Delphi und OpenGL. Später wird dann noch FMOD als Soundlibrary zu den beiden stoßen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
Was ich in diesem Tutorial allerdings nicht erklären werde, und was natürlich benötigt wird, sind zum einen '''Kenntnisse in Object Pascal''' (dazu gibts nicht nur sehr viele gute Tuts, sondern v.a. auch die Anleitung zu Delphi bzw. dessen Hilfedatei), und '''grundlegende OpenGL-Kenntnisse''' zu Themen wie Rotation und Bewegung, Zeichnen von geometrischen Objekten und Texturemapping. Zu diesen Themen gibts hier auf DGL ja jede Menge guter Tutorials.&lt;br /&gt;
Wer mit diesen Voraussetzungen ausgestattet ist, der sollte in dieser Tutorialserie auf keine Problem stoßen und kann sich schonmal auf einen brauchbaren Bombermanklon freuen, den er im Anschluß dann fleißig verbessern und erweitern kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Das Ziel==&lt;br /&gt;
&lt;br /&gt;
Am Ende dieser Tutorialserie wird ein ausgewachsener 3D-Bombermanklon mit diversen Spezieleffekten wie Alphamasking, Partikelsystemen, fulminanten Explosionen und Soundausgabe stehen, der sich vor seinen Vorbildern nicht zu verstecken braucht.&lt;br /&gt;
Und praktisch nebenbei (oder vornedran ;-)) wird dann noch ein leistungsstarker Editor mit einem einfach zu nutzenden Dateiformat entwickelt, mit dessen Hilfe in Windeseile neue Karten erstellt werden können.&lt;br /&gt;
Ziel dieser Tutorialserie ist nicht unbedingt der perfekte Bombermanklon, sondern es geht mir eher darum den Einsteigern unter den Leser neben einem guten Programmierstil auch noch wichtige Grundlagen für die Entwicklung eines Spiels mitzugeben. Denn was bei einem kleinen Projekt schon nützlich ist, kann sich bei einem großen Projekt schnell als große Hilfe erweisen.&lt;br /&gt;
&lt;br /&gt;
Eventuell (hängt zum großen Teil auch vom Feedback der Leser ab) werde ich sogar noch ein Tutorial hinterherschieben, das unseren Klon noch im Mehrspielerfähigkeiten mittels LAN erweitert.&lt;br /&gt;
&lt;br /&gt;
Viel Spaß also beim Bombenlegen...[[Bild:Bomberman anim.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Die Codebasis==&lt;br /&gt;
&lt;br /&gt;
Wie die Überschrift es schon erahnen lässt, widmen wir uns zu allererst der Codebasis. Die Codebasis nennt sich deshalb so, weil sie grundlegende Funktionen und Klassen zur Verfügung stellt die sowohl vom Editor als später auch vom Spiel genutzt werden. Bezeichnen kann man das natürlich auch als Engine, doch dieser Begriff ist in meinen Augen falsch, da ich unter Engine ein viel komplexeres Grundgerüst verstehe, als dies bei einem Bombermanklon benötigt wird.&lt;br /&gt;
&lt;br /&gt;
Diese Codebasis besteht zu Beginn nur aus einigen wenigen Dingen, wird aber im Verlaufe der Tutorialserie ständig erweitert und ist Dreh- und Angelpunkt unseres Bombermanklons.&lt;br /&gt;
In diesem Tut stellt unsere Codebasis (die sich in der Datei '''global.pas''' befindet) folgende Objekte zur Verfügung :&lt;br /&gt;
&lt;br /&gt;
===Einen Texturenmanager (TTextureManager)===&lt;br /&gt;
Viele von euch werden ihre Texturen bisher wohl auf einfache Art und Weise über ein (meist dynamisches) {{INLINE_CODE|array of glUInt}} &amp;quot;verwaltet&amp;quot; haben, und haben dann beim Programmstart alle Texturen per Hand in dieses array eingelesen haben. Nicht nur das dass Laden der Texturen auf diese Art und Weise recht umständlich war und bei jeder neuen Textur der Quellcode geändert werden musste, nein auch der Zugriff auf die Texturen beim Zeichnen der Szene war umständlich und geschah auf die Weise {{INLINE_CODE|[[glBindTexture]](GL_TEXTURE_2D, Textur[3])}}. Dadurch war man immer gezwungen, sich zu vergewissern dass Textur Nr.3 auch die richtige Textur war.&lt;br /&gt;
&lt;br /&gt;
Bei unserem Bombermanklon wollen wir diesen Fehler nicht machen, und haben auch nicht vor bei jeder neuen Textur den Quellcode ändern zu müssen. Das ist nicht nur für den Programmierer selbst komfortabler, sondern auch für die Spieler, die die Karten mit eigenen Texturen verschönern wollen.&lt;br /&gt;
&lt;br /&gt;
Deshalb schreiben wir uns einen kleinen aber sehr nützlichen Texturenmanager, mit dessen Hilfe wir alle Texturen in einem Verzeichnis zur Laufzeit in den Texturenpool laden können, und der Texturen nicht anhand ihrer Position im array bindet, sondern auf diese mit einer Stringlist über deren Namen zugreift. So wird z.b. aus dem {{INLINE_CODE|glBindTexture(GL_TEXTURE_2D, Textur[3])}} ein einfaches und leichter durchschaubares {{INLINE_CODE|TextureManager.BindTexture('steinwand1.tga')}}.&lt;br /&gt;
&lt;br /&gt;
Um uns nicht mit dem Laden verschiedener Formate herumschlagen zu müssen, benutzen wir zum Umwandeln der Texturen die '''glBMP-Bibliothek''' von [http://delphigl.cfxweb.net http://delphigl.cfxweb.net] in einer von mir um einige nützliche Dinge erweiterten Variante (ist im Download zu diesem Tutorial natürlich enthalten).&lt;br /&gt;
&lt;br /&gt;
Unser Texturmanager besteht aus folgenden Prozeduren und Variablen:&lt;br /&gt;
&lt;br /&gt;
*Texture : array of TglBMP&lt;br /&gt;
:In diesem dynamischen array werden alle geladenen Texturen abgelegt.&lt;br /&gt;
&lt;br /&gt;
*TextureName : THashedStringList&lt;br /&gt;
:In dieser StringList werden die Texturennamen abgelegt, über die der Texturenmanager später die Texturen im {{INLINE_CODE|Texturearray}} addressiert. Hier wird statt einer herkömmlichen {{INLINE_CODE|TStringList}} eine {{INLINE_CODE|THashedStringList}} verwendet, da diese bei häufigen Suchvorgängen (was bei vielen Texturenwechseln der Fall ist) und besonders bei großen Datenmengen schneller als die herkömmliche {{INLINE_CODE|TStringList}} ist.&lt;br /&gt;
:'''Hinweis für Nutzer von Delphiversionen &amp;lt; 6:'''&lt;br /&gt;
:In diesen Delphiversionen existiert der Typ {{INLINE_CODE|THashedStringList}} nicht. Dadruch seid ihr gezwungen doch eine normale {{INLINE_CODE|TStringList}} zu verwenden. &lt;br /&gt;
&lt;br /&gt;
*constructor Create&lt;br /&gt;
:Erstellt und initialisiert den Texturenmanager.&lt;br /&gt;
&lt;br /&gt;
*destructor Destroy&lt;br /&gt;
:Deinitialisiert und entfernt den Texturenmanager aus dem Speicher.&lt;br /&gt;
&lt;br /&gt;
*procedure AddTexturesInDir(pDirName, pFileMask : String)&lt;br /&gt;
:Fügt dem Texturenpool alle im Verzeichnis {{INLINE_CODE|pDirName}} liegenden Texturen mit der in {{INLINE_CODE|pFileMask}} angegebenen Endung hinzu.&lt;br /&gt;
&lt;br /&gt;
*procedure AddTexture(pFileName, pTextureName : String)&lt;br /&gt;
:Fügt dem Texturenpool die aus der Datei {{INLINE_CODE|pFileName}} geladene Textur unter dem Namen {{INLINE_CODE|pTextureName}} hinzu.&lt;br /&gt;
&lt;br /&gt;
*procedure BindTexture(pTextureName : String)&lt;br /&gt;
:Sucht die Textur mit dem Namen {{INLINE_CODE|pTextureName}} im Texturenpool und bindet diese an das {{INLINE_CODE|GL_TEXTURE_2D}}-Ziel. Wurde die Textur nicht gefunden, wird für das Texturemapping deaktiviert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wie man also sehen kann steckt hinter einem Texturenmanager nicht sonderlich viel Arbeit, er erleichtert einem das Leben allerdings erheblich. Besonders wenn man später Dinge wie Alphamasking einbringen will, muss man nicht mehr umständlich im Zeichencode rumwühlen, sondern man muss einfach nur noch die {{INLINE_CODE|BindTexture}}-Routine ein wenig abändern. Alles in allem also ein nützliches Hilfsmittel das in keinem OpenGL-Projekt fehlen sollte.&lt;br /&gt;
&lt;br /&gt;
===Das Spielfeld (TMap)===&lt;br /&gt;
Der nächste Baustein unserer Codebasis repräsentiert das Spielfeld auf dem die Aktion stattfindet. Viel zu bieten hat diese Klasse momentan, ausser einer Zeichenprozedur und einige Editorprozeduren noch nicht viel, was sich aber in naher Zukunft noch ändern wird.&lt;br /&gt;
&lt;br /&gt;
Hier also Prozeduren und Variablen des Spielfelds :&lt;br /&gt;
&lt;br /&gt;
*PlayGround : array of array of TFieldType&lt;br /&gt;
:Diese Variable repräsentiert das eigentliche Spielfeld und ist ein zweidimensionales array vom Typ {{INLINE_CODE|TFieldType}}, dessen Definition die Eigenschaften eines Spielfelds festlegt und so aussieht :&lt;br /&gt;
&amp;lt;pascal&amp;gt;TFieldType = record&lt;br /&gt;
  Texture  : String;&lt;br /&gt;
  FType    : Byte;&lt;br /&gt;
  FSpecial : Byte;&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
:{{INLINE_CODE|Textur}} steht für den Namen der diesem Feld zugewiesenen Textur, während {{INLINE_CODE|FType}} angibt ob es sich um ein Bodenteil, einen festen Block oder einen zerstörbaren Block handelt. Natürlich ist diese Variable frei erweiterbar (was später auch noch ausgiebig getan wird), und man könnte hier quasi unendlich viele Feldtypen mit den tollsten Eigenschaften (z.B. bewegliche Blöcke) definieren. {{INLINE_CODE|FSpecial}} gibt letztendlich noch an, ob dieses Feld noch eine besondere Eigenschaft, wie z.B. einen Spielerstart enthält.&lt;br /&gt;
&lt;br /&gt;
*DefaultFieldTexture : String&lt;br /&gt;
:In dieser Variable wird die Standardtextur festgelegt, die einem Feld zugewiesen wird, nachdem ein darauf befindlicher sprengbarer Block zerstört wurde.&lt;br /&gt;
&lt;br /&gt;
*procedure SetSize(pSize : Integer)&lt;br /&gt;
:Legt die in {{INLINE_CODE|pSize}} angegebene Spielfeldgröße fest, und tut nichts anderes als das dynamisches {{INLINE_CODE|PlayGround}}-array in seiner Größe mittels {{INLINE_CODE|SetLength}} zu verändern.&lt;br /&gt;
&lt;br /&gt;
*procedure FillBorder(pTexture : String;pFieldType : Integer)&lt;br /&gt;
:Füllt den Rand des Spielfelds mit der in {{INLINE_CODE|pTexture}} angegebenen Textur und dem in {{INLINE_CODE|pFieldType}} angegebenen Feldtyp.&lt;br /&gt;
&lt;br /&gt;
*procedure FillGround(pTexture : String;pFieldType : Integer)&lt;br /&gt;
:Füllt das Spielfeld (exklusive dem Rand) mit der in {{INLINE_CODE|pTexture}} angegebenen Textur und dem in {{INLINE_CODE|pFieldType}} angegebenen Feldtyp&lt;br /&gt;
&lt;br /&gt;
*procedure Draw;&lt;br /&gt;
:Wie der Prozedurenname bereits erahnen lässt, wird in dieser Prozedur das komplette Spielfeld gezeichnet. Diese Prozedur spielt daher also ein Hauptrolle in unserem Bombermanprojekt.&lt;br /&gt;
:Da in der Grundversion unseres Editors nichts weiter getan wird, als die Felder in einer {{INLINE_CODE|for..do}}-Schleife zu zeichnen, bedarf der Quellcode wohl kaum detaillierter Beschreibungen. Eine Zeile dürfte den Anfänger in der Leserschaft jedoch etwas unbekannt vorkommen, weshalb ich diese hier etwas detaillierter erkläre :&lt;br /&gt;
:*glLoadName(OpenGLID)&lt;br /&gt;
::Mit dieser Zeile legen wir einen &amp;quot;Namen&amp;quot; (Eine Variable vom Typ Cardinal, und nicht etwa wie der leicht irreführende Titel Name zu vermuten lässte einen String) auf den {{INLINE_CODE|NameStack}} von OpenGL, der dann dem nächsten gezeichneten geometrischen Objekt zugewiesen wird. Damit wird dann jedem Feld ein einzigartiger OpenGL-Name zugewiesen.&lt;br /&gt;
::Mit Hilfe dieses OpenGL-Namens kann man dann später mit einer {{INLINE_CODE|[[Selection]]}} genannten Methode herausfinden auf welches Feld der Mauszeiger gerade zeigt. Benötigt wird das Ganze natürlich nur für den Editor. Wie genau dieses Selektionsverfahren realisiert wird, dazu gibts später im Editorkapitel mehr.&lt;br /&gt;
&lt;br /&gt;
*procedure SaveToFile(pFileName : String)&lt;br /&gt;
:Diese Prozedur sichert die Karte in die mit {{INLINE_CODE|pFileName}} angegebene Datei. Dabei wird ein einfach zu lesendes und leicht erweiterbares ASCII-Format verwendet :&lt;br /&gt;
          Dateiversion&lt;br /&gt;
          Größe Der Karte&lt;br /&gt;
          Name der Standardtextur&lt;br /&gt;
          Textur von Feld [1,0]&lt;br /&gt;
          FeldTyp von Feld [1,0]&lt;br /&gt;
          SpezialInfo von Feld [1,0]&lt;br /&gt;
          .&lt;br /&gt;
          .&lt;br /&gt;
          .&lt;br /&gt;
          Textur von Feld [Größe Der Karte-1,Größe Der Karte-1]&lt;br /&gt;
          FeldTyp von Feld [Größe Der Karte-1,Größe Der Karte-1]&lt;br /&gt;
          SpezialInfo von Feld [Größe Der Karte-1,Größe Der Karte-1]&lt;br /&gt;
:Ein binäres Format hätte hier natürlich den Vorteil, das zum einen der Platzbedarf geringer wäre, und es zum anderen auch vor Veränderungen sicher wäre, allerdings wären die alten Karten nach jeder Änderung unbrauchbar.Für ein reines ASCII-Format kann man sich jedoch schnell mal einen Importer schreiben, der ältere Karten in eine neuere Version konvertiert.&lt;br /&gt;
&lt;br /&gt;
*procedure LoadFromFile(pFileName : String)&lt;br /&gt;
:Lädt die Karte aus der in {{INLINE_CODE|pFileName}} angegebene Datei. &lt;br /&gt;
&lt;br /&gt;
Soviel also zu unserer aktuellen Codebasis, die als Grundlage für unseren Editor sowie das Spiel an sich dienen wird. Bis jetzt war ja noch nichts spektakuläres dabei, und selbst die unerfahreneren unter euch sollten bis hierhin keine Probleme gehabt haben.&lt;br /&gt;
Der größte Teil unserer zukünftigen Änderungen werden an der Codebasis stattfinden und vor allem das Kartenobjekt betreffen. Natürlich werden später noch neue Klassen u.a. zur Spielerverwaltung (und evtl. Gegnerverwaltung) hinzukommen, dazu aber mehr in den folgenden Tutorials.&lt;br /&gt;
&lt;br /&gt;
Doch wenden wir uns jetzt dem Editor zu... [[Bild:Bomberman happy.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Der Editor==&lt;br /&gt;
&lt;br /&gt;
Ein Spiel ist ja bekannterweise nur so gut wie sein Inhalt, der mit Hilfe der entwickelten Tools wie einem Leveleditor erstellt wird. Was nützen die tollsten und modernsten Features oder die ausgeglügelste künstliche Intelligenz, wenn die Level in denen man sich bewegt einfach mies sind...deshalb sollte man sich bei der Entwicklung eines Spiels immer auf seine Tools konzentrieren, und diese so intuitiv und gleichzeitig leistungsfähig wie möglich gestalten, damit man später schnell und einfach guten Gamecontent erstellen kann.&lt;br /&gt;
&lt;br /&gt;
Zum Glück ist diese Thematik bei einem Bombermanklon nicht so brisant wie bei einem Egoshooter á la Doom3, dessen Editor sich vor 3DStudio MAX nicht zu verstecken braucht, aber trotzdem geht einem der Levelbau viel leichter von der Hand wenn man einen einfach zu nutzenden Mapeditor zur Hand hat, statt die Karten für die erste Betaversion seines Spiels mittels Notepad zusammenzubasteln.&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werden wir uns deshalb um einen leicht zu bedienenden Editor kümmern, der grundlegende Fähigkeiten zum Erstellen der Karten und einige brauchbare Tools mitbringt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Natürlich wird der Editor mittels der Delphi-VCL realisiert, ist sie doch schliesslich dass was Delphi so groß gemacht hat, und die Entwicklungszeit von Windowsanwendungen signifikant verringert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Bomberman editor1.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wie auf obigem Screenshot zu erkennen basiert die Grundversion unseres Editors auf zwei Fenstern. Im linken Fenster wird das Spielfeld dargestellt, und im rechten befinden sich zum einen Einstellungen bezüglich des zu setztenden Feldes und einige Tools die dem Kartenbauer das Leben erleichtern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Quellcode des Editors bietet ansich nichts unbekanntes und dürfte recht leicht verständlich sein. Dennoch werde ich einige relevante Codestellen erläutern :&lt;br /&gt;
&lt;br /&gt;
===OpenGL initialisieren (TForm1.FormCreate)===&lt;br /&gt;
Der Einfachheit halber verwende ich in unserem Bombermanprojekt die {{INLINE_CODE|OpenGL12.pas}} von [http://www.lischke-online.de/ Mike Lischke] in einer minimal abgeänderten Form (betrifft nur das Erstellen des Rendercontext), die dem Projektquellcode natürlich beiliegt.&lt;br /&gt;
&lt;br /&gt;
Diese macht das erstellen eines Rendercontextes zu einem Kinderspiel :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;DC := GetDC(Handle);&lt;br /&gt;
RC := CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 8, 0, 0, 0, DummyPal);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der ersten Zeile erstellen wir uns vom Handle unseres Fensters einen gültigen DeviceContext vom Typ {{INLINE_CODE|HDC}}, der dann genutzt wird um den OpenGL-Rendercontext zu erstellen.&lt;br /&gt;
&lt;br /&gt;
In der zweiten Zeile erstellen wir einen OpenGL-Context mit Doublebuffering, 32Bit Farbtiefe, 24bittigem Tiefenpuffer und einem 8Bit großen Stencilpuffer, mit dessen Hilfe wir in einem späteren Tutorial Schattenwürfe realisieren werden. Die {{INLINE_CODE|DummyPal}}-Variable ist wie ihr Name schon sagt nur ein Dummy, der nicht benötigt wird, da unser Rendercontext keinen Palettenmodus (256 Farben) nutzt.&lt;br /&gt;
&lt;br /&gt;
Einige Zeilen später werden wir dann einige OpenGL-Werte initialisieren :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glEnable(GL_TEXTURE_2D);&lt;br /&gt;
glEnable(GL_DEPTH_TEST);&lt;br /&gt;
glDepthFunc(GL_LESS);&lt;br /&gt;
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion dieser Zeilen dürfte bekannt sein : Zeile 1 aktiviert zweidimensionales Texturemapping, die Zeilen 2 und 3 legen den Tiefentest fest (aktiviert, und nur Fragmente die weiter vorne liegen durchlassen). Zeile 4 sagt der Grafikkarte dann noch, das sie die best aussehendste Perspektivenkorrektur verwenden soll.&lt;br /&gt;
&lt;br /&gt;
Danach laden wir noch die benötigten Texturen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;TextureManager.AddTexturesInDir('textures', '*.tga');&lt;br /&gt;
for i := 0 to TextureManager.TextureName.Count-1 do&lt;br /&gt;
 Form2.TextureCombo.Items.Add(TextureManager.TextureName[i]);&lt;br /&gt;
ChDir(ExtractFilePath(Application.ExeName));&lt;br /&gt;
&lt;br /&gt;
SetLength(SpecialTex, Length(SpecialTexName));&lt;br /&gt;
for i := Low(SpecialTexName) to High(SpecialTexName) do&lt;br /&gt;
 begin&lt;br /&gt;
 SpecialTex[i] := TglBMP.Create('textures\special\'+SpecialTexName[i]);&lt;br /&gt;
 SpecialTex[i].GenTexture(False, False);&lt;br /&gt;
 end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Block sagen wir dem Texturenmanager das er alle TGA-Dateien im Unterordner {{INLINE_CODE|textures}} in den Texturenpool laden soll. Ich verwende das TGA-Format deshalb, da es eines der wenigen Formate (neben PNG) ist, das einen Alphakanal unterstützt. Mehr zu diesem Alphakanal und seiner Anwendung gibts ineinem späteren Tutorial (Kleiner Hinweis : Alphamasking). Gleichzeitig fügen wir noch alle Texturennamen in die ComboBox im Toolfenster ein, damit wir diese später bequem zuweisen können.&lt;br /&gt;
&lt;br /&gt;
Im zweiten Block laden wir die in der Konstantensektion festgelegten Spezialtexturen die später z.B. genutzt werden um die Startpunkte der Spieler zu kennzeichnen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ich hoffe ihr seit nach diesem etwas langweiligen und nicht besonders anspruchsvollem Ausflug in die Initialisierung des Editors noch wach, denn jetzt kommt etwas schwierigeres...[[Bild:Bomberman wait.gif]]&lt;br /&gt;
&lt;br /&gt;
===Spielfelder mittels des Mauszeigers auswählen (aka Selection)===&lt;br /&gt;
Im Kapitel zur Codebasis hab ich dieses Thema schonmal kurz angeschnitten und euch gezeigt, wie man ein Objekt mittels des Namestacks unter OpenGL &amp;quot;bekannt&amp;quot; macht. Wer mehr zum Thema Selection erfahren will, kann sich ja das Tutorial dazu auf meiner Hompage durchlesen : [http://www.delphigl.de/tutorials/selection_de.html Selection-Tutorial]. (Oder das [[Tutorial_Selection]] hier im Wiki)&lt;br /&gt;
&lt;br /&gt;
Nun stelle ich euch eine (recht kurze, aber knackige) Prozedur vor, die prüft ob und wenn ja, welches dieser auf dem Namestack befindlichen Objekte unter dem Mauszeiger ist. Gemeint ist die Funktion '''GetSelectBufferHit''', die ich euch hier häppchenweise erläutern werde :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;var&lt;br /&gt;
 SelectBuffer : array[0..512] of TGLUInt;&lt;br /&gt;
 Viewport     : TVector4i;&lt;br /&gt;
 Hits,i       : Integer;&lt;br /&gt;
 HitZValue    : TGLUInt;&lt;br /&gt;
 Hit          : TGLUInt;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Variablendeklaration dieser Funktion bedarf erstmal einer fundierten Erklärung : Im {{INLINE_CODE|SelectBuffer}}-array werden alle Objekttreffer gespeichert. Jeder Objekttreffer besteht aus vier Werten : Anzahl der Objekte auf dem Namestack zum Zeitpunkt des Treffers, kleinste Z-Koordinate aller Eckpunkte des Objektes, größte Z-Koordinate aller Eckpunkte des Objektes und Name des getroffenen Objektes. Deshalb kann unser SelectBuffer bis zu 128 (512/4) Objekttreffer beinhalten.&lt;br /&gt;
In der Variable Viewport wird der aktuelle OpenGL-Viewport gespeichert, den wir später noch brauchen werden.&lt;br /&gt;
Und mit den Variablen {{INLINE_CODE|Hits, HitZValue}} und {{INLINE_CODE|Hit}} stellen wir am Ende der Funktion in einer Schleife fest welches Objekt nun letztendlich unter dem Mauszeiger liegt.&lt;br /&gt;
&lt;br /&gt;
Kommen wir nun zur eigentlichen Funktion und der in ihr enthaltenen erwähnenswerten Codezeilen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glGetIntegerv(GL_VIEWPORT, @viewport);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mittels dieser Zeile speichern wir den aktuellen Viewport in die vorher dafür definierte Variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glSelectBuffer(512, @SelectBuffer);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hiermit teilen wir OpenGL zum einen die Größe des SelectBuffers und zum anderen dessen Adresse im Speicher mit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glRenderMode(GL_SELECT);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt schalten wir in den SelectModus, in dem nichts auf den Bildschirm gerendert wird, aber unser SelectBuffer gefüllt wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glInitNames;&lt;br /&gt;
glPushName(0);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese zwei Zeilen sind unabdingbar, denn sie dienen dazu den Namestack zu initialisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glMatrixMode(GL_PROJECTION);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
gluPickMatrix(MousePos.x, viewport[3]-MousePos.y, 3.0, 3.0, Viewport);&lt;br /&gt;
gluPerspective(45.0, Form1.ClientWidth/Form1.ClientHeight, 0.1, 2048);&lt;br /&gt;
Form1.DrawScene;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Teil ist sehr wichtig. Hier setzen wir die Ansichtsmatrix so, das (wenn wir im normalen Rendermodus wären) nur der Bereich im 3 Pixel Umkreis um die Mausposition herum gerendert werden würde. Dies dient dazu das nur Objekte im direkten Umkreis der Mausposition in den Selectbuffer gerendert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;Hits      := glRenderMode(GL_RENDER);&lt;br /&gt;
Hit       := High(TGLUInt);&lt;br /&gt;
HitZValue := High(TGLUInt);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zeile schaltet jetzt wieder in den normalen Rendermodus. Allerdings liefert uns OpenGL jetzt (da wir uns vorher im Selectmodus befanden) die Anzahl der getroffenen Objekte zurück. Die zwei nachfolgenden Zeilen initialisieren die Variablen vor, mit deren Hilfe wir später herausfinden welches Objekt dem Mauszeiger am nächsten liegt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;for i := 0 to Hits-1 do&lt;br /&gt;
 if SelectBuffer[(i*4)+1] &amp;lt; HitZValue then&lt;br /&gt;
  begin&lt;br /&gt;
  Hit       := SelectBuffer[(i*4)+3];&lt;br /&gt;
  HitZValue := SelectBuffer[(i*4)+1];&lt;br /&gt;
  end;&lt;br /&gt;
Result := Hit;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mittels der Schleife prüfen wir ob die Z-Koordinaten des neuen Objektes niedriger als die bereits gespeicherte ist (wir erinnern uns : in {{INLINE_CODE|SelectBuffer[(n*4)+1]}} steht die kleinste Z-Koordinate der Eckpunkte dieses Objekts, sprich der dem Betrachter nächste Z-Wert). Wenn dies der Fall ist, übernehmen wir dessen Z-Koordinaten in {{INLINE_CODE|HitZValue}} und dessen Namen in {{INLINE_CODE|Hit}}.&lt;br /&gt;
Am Ende dieser Schleife haben wir dann endlich das Objekt, welches der Kamera am nächsten ist und geben dies im Resultat der Funktion zurück.&lt;br /&gt;
&lt;br /&gt;
Wenns dir jetzt besser geht als unserem kleine Bomberman, dann hast du das Schlimmste bereits überstanden, bei Nichtverstehen nochmal das von mir erwähnte Tut durchlesen...&lt;br /&gt;
&lt;br /&gt;
===Zeichnen der Szene (TForm1.ApplicationEvents1Idle)===&lt;br /&gt;
Bekannterweise gibt es ja jede Menge Möglichkeiten und Stellen an denen man seine Szene zeichnen könnte. Entweder man schreibt sich nen eigenen Loop mittels {{INLINE_CODE|repeat..until}}, machts mit einem Timer (ist übrigens eine sehr schlechte Lösung) oder nimmt ganz einfach den {{INLINE_CODE|OnIdle}}-Event der Form, der über die {{INLINE_CODE|ApplicationEvents}}-Komponente (siehe Komponenten-Tab &amp;quot;Zusätzlich&amp;quot;) zur Vefügung gestellt wird.&lt;br /&gt;
Dieses Ereignis wird eigentlich nicht periodisch aufgerufen, sondern immer nur nach der Abarbeitung einer Fensternachricht. Allerdings kann man dies mit einem kleinen Trick umgehen :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;Done := False;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn diese Zeile im {{INLINE_CODE|OnIdle}}-Ereignis aufgerufen wird, verschweigt man Windows ganz einfach das die Anwendung die Nachrichtenschleife durchlaufen hat. Als Folge dessen wird diese Routine permanent durchlaufen, und das OpenGL-Programm hat fast die komplette CPU-Zeit zum Zeichnen der Szene.&lt;br /&gt;
Weitere interessante Zeilen im {{INLINE_CODE|OnIdle}}-Ereignis sind folgende :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;DrawScene;&lt;br /&gt;
SBufferHit := GetSelectBufferHit;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nachdem in der ersten Zeile die Szene gezeichnet wurde, wird der Variable {{INLINE_CODE|SBufferHit}} die Kennung des unter der Maus befindlichen Feldes zugeweisen, so dass man dieses Feld dann in der Zeichneroutine der Karte farblich hervorheben kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;if MouseLeft then&lt;br /&gt;
 if Assigned(SelField) then&lt;br /&gt;
  begin&lt;br /&gt;
  SelField^.Texture := Form2.TextureCombo.Items[Form2.TextureCombo.ItemIndex];&lt;br /&gt;
  SelField^.FType   := Form2.FieldTypeCombo.ItemIndex;&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieser Codehappen weist dem ausgewählten Feld ({{INLINE_CODE|SelField &amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt; @TFieldType}}) bei gedrückter linker Maustaste die im Toolfenster ausgewählte Textur und den ausgewählten Feldtyp zu. Ist kein Feld unter dem Cursor ({{INLINE_CODE|SelField &amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt; nil}}) dann geschieht nichts, da {{INLINE_CODE|Assigned()}} diesen Fall abfängt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So, geschafft!Das war alles Wichtige zum Quellcode des Editors.Der Rest des Codes ist recht einfach und aufgrund der Dokumentation und ausgiebieger Kommentare im Quelltext dürfte er auch keine Probleme machen... [[Bild:Bomberman cheer.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Abschliessend gibts noch ein paar Worte zur Bedienung des Editors :&lt;br /&gt;
&lt;br /&gt;
:Im 3D-Fenster :&lt;br /&gt;
::Cursortasten : Auf dem Spielfeld scrollen&lt;br /&gt;
::Mausrad : Rein- bzw. rauszoomen&lt;br /&gt;
::Bild rauf/Bild runter : Kamerawinkel verändern&lt;br /&gt;
::Linke Maustaste : Feld unter dem Mauscursor mit der Textur und dem in Form2 gewählten Feldtyp belegen&lt;br /&gt;
::Rechte Maustaste : Kontextmenü mit Spezialfeldern aufrufen&lt;br /&gt;
::+/- : Spielfeld rotieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
&lt;br /&gt;
Das wars fürs Erste, und ich hoffe das Tutorial hat euch gefallen. Weiterhin hoffe ich natürlich das ihr meiner Tutorialserie bis zum Ende treu bleibt und mich mit Feedback (am besten direkt ins Forum) überschüttert. Anregungen und Kritik (solange konstruktiv) sehe ich nämlich gerne und motivieren mich auch...&lt;br /&gt;
Außerdem interessieren mich eure Modifikationen zum Editor und eure Levelkonstrukte, postet also fleissig Neuerungen, Verbesserungen und gebastelte Level ins Forum, und '''freut euch auf den zweiten Teil der Tutorialreihe!!!'''&lt;br /&gt;
&lt;br /&gt;
Euer&lt;br /&gt;
:'''Sascha Willems'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
{{TUTORIAL_NAVIGATION| - | [[Tutorial_Bomberman2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Bomberman1]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Modellierung_eines_Low-Poly_Menschen_Teil_2&amp;diff=20547</id>
		<title>Tutorial Modellierung eines Low-Poly Menschen Teil 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Modellierung_eines_Low-Poly_Menschen_Teil_2&amp;diff=20547"/>
				<updated>2007-05-24T22:19:37Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Nachwort */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Ave!==&lt;br /&gt;
&lt;br /&gt;
Und willkommen zum Nachfolger meines ersten Low-Poly-Tutorials.Nachdem wir in diesem gelernt haben aus möglichst wenigen Dreiecken eine menschliche Figur zu modellieren,beschäftigen wir uns nun mit der Texturierung eben dieses Polygoniers.&lt;br /&gt;
&lt;br /&gt;
Wie bekannt tragen gerade die Texturen sehr viel zum Aussehen eines 3D-Modelles bei und können leicht zum simulieren von Details genutzt werden,ohne das dadurch die Anzahl der genutzten Polygone steigt.&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial werden wir unseren fertigen Polygonhelden also mit '''einer''' selbstgemachten Textur versehen.Wenn ihr aufmerksam ward,dann habt ihr sicher bemerkt das ich im lezten Satz &amp;quot;einer&amp;quot; betont habe.Das hat auch einen Grund,denn wir belegen nicht jeden Mesh unserer Figur mit einer eigenen Textur,sondern nutzen nur eine einzige Textur für alle Meshes des Modelles.Diese eine Textur wird im Fachjargon auch &amp;quot;Skin&amp;quot; genannt und hat im Groben zwei Vorteile ggü. der Nutzung mehrere Texturen.Texturenwechsel (via glBindTexture) sind ja bekannterweise recht zeitintensiv und können bei häufigem Autreften schonmal nen Flaschenhals darstellen.Durch die Nutzung einer einzigen Textur für das komplette Modell sparen wir also ganz einfach diverse Texturenwechsel und machen der GPU das Leben leichter.Ein weiterer,vielleicht sogar besserer Grund für die Nutzung eines einzigen Skins für unser Modell ist die Tatsache das man anhand eines einfachen Texturenwechsel innerhalb seines Spiels das komplette Aussehen des 3D-Helden darüber verändern kann.Diese Technik findet auch in professionellen Spielen (u.a. UT2003) häufig Anwendung,und ein gutes Beispiel ist z.B. ein 2.WK-Shooter.Statt ein Modell für einen Wehrmachtssoldaten und eins für einen allierten Soldaten zu erstellen (und damit zwei Modelle im Speicher zu halten) wird nur ein Grundmodell erstellt,dessen Zugehörigkeit oder Spezialfähigkeit (z.B. Mediziner) dann über sein Skin sichtbar ist. &lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
Für dieses Tutorial benötigt ihr unbedingt einen 3D-Modeller der euch einen visuellen Editor zum Verändern der UVW-Koordinaten auf Vertexbasis und einen UVW-Unwrap-Modifikator anbietet,da ihr sonst Probleme haben werdet das im Tutorial gemachte nachzuvollziehen.&lt;br /&gt;
Ansonsten solltet ihr wie im ersten Tutorial zumindest grundlegende Kenntnisse in Sachen 3D-Modellierung und Nutzung eurer 3D-Software mitbringen.&lt;br /&gt;
&lt;br /&gt;
In Sachen Bildbearbeitungssoftware ist eigentlich alles erlaubt und ich habe zum Erstellen der Textur auch &amp;quot;nur&amp;quot; Picture Publisher 9 gentutzt,welches bei meinem Webspacepaket dabei war.Photoshop,PaintShop Pro oder Gimp (kostenlos) sollten also auch ausreichen.&lt;br /&gt;
&lt;br /&gt;
==Erstellen der Textur==&lt;br /&gt;
&lt;br /&gt;
Beginnen wollen wir also mit dem Erstellen der Textur die unsere Figur später schmücken soll.Da wir für das komplette Modell nur eine Textur verwenden,sollten wir uns erstmal Gedanken um die Einteilung eben dieser machen und dafür sorgen das alle Meshes Platz darauf haben.Unser Polygonmensch besteht aus zwei Armen,zwei Beinen,einem Becken,dem Rumpf,einem Hals und seinem Kopf.Aufgrund der Symetrie des Körpers können wir übrigens die beiden Arme und Beine auf jeweils auf ein Exemplar beschränken.Summa Sumarum sind das also 6 Körperteile,wobei man einige davon aus den anderen heraus texturieren könnte.Für das Tutorial erstelle ich nämlich einen uniformierten Soldaten,der deshalb an Beinen und Armen (bis auf Hände und Stiefel) gleich texturiert werden kann,also brauche ich keine extra Textur für das Beinkleid.Genausowenig braucht der Hals eine eigene Textur,da sich in der Textur für den Kopf garantiert genug Haut findet um sie über den Hals zu legen.&lt;br /&gt;
&lt;br /&gt;
Im Endeffekt bräuchten wir jetzt also nur noch Platz für vier Körperteile auf unserer Textur (Arm,Rumpf,Becken,Kopf).Allerdings sollte man sich auch vor dem Erstellen eben dieser Überlegen,ob man nicht doch noch irgendwelche Stellen besonders behandeln will.Ist dies der Fall,sollte man das natürlich beim Einteilen des Platzes mitberücksichtigen.So hat mein Soldat auf den Schultern noch ein paar Abzeichen,also kann ich für diese nicht einfach die Textur des Rumpfes nutzen.Aber diese Besonderheiten sind abhängig von dem was ihr machen wollt,also müsst ihr euch da auch selbst was einfallen lassen.&lt;br /&gt;
&lt;br /&gt;
Da sich eine solche Einteilung recht schlecht in Schrift und Wort erklären lässt,zeige ich euch mal wie ich das bei meinem Soldaten mit der Texturunterteilung gehandhabt habe.Folgend seht ihr die farblich eingeteilten Bereiche :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_skin1_col2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ich hoffe mal das diese Einteilung zumindest halbwegs nachvollziehbar erscheint,und rate euch sowas auch zuerst mit farbigen Blöcken durchzuspielen,bevor ihr beim Basteln der Textur plötlich merkt das kein Platz mehr für ein bestimmtes Körperteil da ist und wieder von vorne anfangen müsst.&lt;br /&gt;
Im Bezug auf die Texturengröße gibts auch keinen allgemeingültigen Rat,denn diese hängt von mehreren Faktoren ab.Zum einen wie nahe der Spieler dem Modell je kommt,wie detailliert das Modell an sich ist und wie viele Details ihr gerne über die Textur realisieren wollt.Ich habe für mein Modell ganz einfach eine 256x256 Pixel große Textur genommen,damit ich hier und da ein Detail einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Da es nicht Gegenstand dieses Tutorials ist euch das Erstellen einer Textur beizubringen,überlasse ich euch mal euren Bildbearbeitungskünsten (Kleiner Tipp falls ihr v.a. Details für die Textur sucht : Die google Bildsuche hilft ungemein) und präsentiere euch direkt meine fertige Textur (etwas verkleinert) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_skin1_prev.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das sollte bei euch zumindest ähnlich aussehen und wenn nicht,dann nehmt halt die Farbtextur und nutzt diese zum Texturieren des Modelles.Der Rest kann ja später noch gemacht werden.&lt;br /&gt;
&lt;br /&gt;
==UVW-Mapping==&lt;br /&gt;
&lt;br /&gt;
Da wir jetzt sowohl eine fertige Textur (oder etwa nicht?) sowie ein fertiges 3D-Modell haben,wollen wir diese natürlich auch gerne zusammenführen.Dazu machen wir uns die Möglichkeit zu Nutze,das ein halbwegs brauchbares 3D-Modellierungsprogramm in der Lage ist die UVW-Koordinaten für jedes Vertex zu verändern.Wers noch nicht weis : UVW sind die Texturkoordinaten eines Vertexes und werden in OpenGL allgemein auch als STQ referenziert,wobei uns die letzte Koordinate (W) nichts angeht.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_01.jpg|right]]Wir laden also unser im letzten Tut gebasteltes 3D-Modell und holen uns (sofern möglich) den perspektivischen Viewport auf den kompletten Schirm.Nun öffnen wir den Materialeditor (Shortcut m) und laden in die Diffuse-Map des ersten Materials unsere Textur zu,bevor wir diese dann dem kompletten Modell zuweisen.Ausserdem sollte natürlich &amp;quot;Map im Viewport zeigen&amp;quot; aktiv sein,da wir unsere Textur später sonst nicht sehen.Momentan sehen wir natürlich noch nicht viel von der Textur,da kein einziger Mesh UVW-Koordinaten besitzt.&lt;br /&gt;
&lt;br /&gt;
Anfangen wollen wir mit dem Arm und nutzen ein nettes Feature von 3DSMax um diesen einzeln bearbeiten zu können,nämliches das Isolationstool.Dazu selektieren wir den Arm und drücken '''ALT+Q''' (oder im Hauptmenü über den Eintrag Tools-&amp;gt;Selektion isolieren) und schon wird der Rest des Models ausgeblendet,während ein kleines Fenster erscheint das uns über den Isolationsmodus informiert.&lt;br /&gt;
Dem Arm,allein auf dem Schirm und noch selektiert,weisen wir jetzt aus der Modifikatorliste den '''Unwrap UVW'''-Modifikator zu (befindet sich recht weit unten),der auch automatisch UVW-Koordinaten für den selektieren Mesh erstellt,die wie zu sehen allerdings keinesfalls brauchbar sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_02.jpg|right]]Als nächstes wollen wir uns endlich ins UVW-Mappen stürzen.Dabei gehen wir beim Arm Seite-für-Seite vor,und selektieren deshalb alle Faces der Vorderseite.Dazu öffnen wir den UVW-Unwarp-Modifikator des Arms und klicken auf &amp;quot;Face selektieren&amp;quot;,bevor wir dann im Viewport alle Faces der Vorderseite des Armes selektieren (Um mehrere Objekte zu selektieren STRG gedrückt halten).Wenn ihr das gemacht habt,dann sollte eure perspektivische Ansicht in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_03.jpg]]&lt;br /&gt;
&lt;br /&gt;
Nun öffnen wir durch einen Klick auf '''&amp;quot;Bearbeiten...&amp;quot;''' in den Eigenschaften des UVW-Modifikators den UVW-Editor,der danach ungefähr so auf eurem Bildschirm erscheinen sollte :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_04.jpg]]&lt;br /&gt;
&lt;br /&gt;
Was euch evtl. direkt auffällt (und den ein oder anderen evtl. auch schon ein paar nerven gekostet hat),ist die Tatsache das dort wo eure Textur sein sollte nur ein schwarzes Quadrat ist.Das liegt ganz einfach daran das dass 3DStudio die Textur aus einem mir unerklärlichen Grund mit einer Helligkeit von 0 anzeigt.Wollt ihr also was von eurer zugewiesenen Textur sehen,dann öffnet mit bem Button ganz unten rechts (Show options) eine kleine Zusatzleiste am unteren Fensterrand und setzt die Helligkeit dort auf 1.Ausserdem solltet ihr auch den Haken vor &amp;quot;Bitmap wiederholen&amp;quot; (Tile Bitmap) entfernen.&lt;br /&gt;
Nun sind wir also endlich bereit unserem Arm die passenden UVs zuzuordnen.Ein kleiner Tipp für die Produktivität : Wenn ihr eure Fenster so anordnet wie ich (links UVW-Editor und das zu editierende Objekt rechts daneben),dann lässt sich nicht nur bequem arbeiten,sondern die Änderungen im UVW-Editor auch in Echtzeit auf dem Modell verfolgen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_05.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_06.jpg|right]]Immernoch die Frontfaces unseres Armes selektiert klicken wir in den Eigenschaften des Modifikators jetzt also auf '''Planar Map''' um die Texturkoordinaten der gewählten Vertexe auf die Textur zu projezieren.Bei den Frontfaces wird die Notwendigkeit dieser Aktion noch nicht so recht sichtbar,aber spätestens bei den Seiten des Armes wird euch dies klar werden.Ausserdem aktivieren wir &amp;quot;Filter selected Faces&amp;quot;,damit nur die gewählten Faces im UVW-Editor sichtbar sind.Habt ihr dieses Prozedere korrekt nachvollzogen,dann sollte euer UVW-Editor in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_07.jpg]]&lt;br /&gt;
&lt;br /&gt;
Nun sehen wir ein korrektes Abbild unserer Armgeometrie auf der Textur,allerdings passen die Texturkoordinaten noch absolut nicht.Wir schnappen uns also die Vertices des Armes und verschieben diese so,das sie den Bereich einnehmen den wir auf unserer Textur für den Arm vorgesehen haben.Ich mach das übrigens lieber über die Eingabefelder,denn das blosse Verschieben mit der Maus ist nicht gerade genau.Danach sollte die Vorderseite des Armes so auf der Textur zugewiesen sein und wie rechts zu erkennen aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_08.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch2_09.jpg]]&lt;br /&gt;
&lt;br /&gt;
Diese Prozedur müsst ihr jetzt natürlich für alle vier Seiten des Armes,sowie die Unterseite der &amp;quot;Hand&amp;quot; anwenden.Wer dann auch noch mitgedacht hat,wird sich nicht blindlinks auf den zweiten Arm stürzen,sondern diesen durch eine Kopie unseres bereits UVW-Gemappten Armes ersetzen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts jetzt mit dem Torso unseres Polygonators.Nachdem wir diesen angewählt haben,gehen wir wieder in den Isolationsmodus und selektieren wie gewohnt alle Frontfaces.Allerdings werden wir jetzt direkt sehen dass das Mapping (welches momentan auf &amp;quot;Averaged Normals&amp;quot; steht) nicht &amp;quot;korrekt&amp;quot; ist,denn das gelbe Mappingquadrat steht schief (siehe Links).Um das zu korrigieren (damit die Frontfaces des Torsos auch auf der Textur richtig liegen) wählen wir diesmal bei den Sub object Parametern &amp;quot;Z&amp;quot; und sofort sollte das Mappingquadrat in der richtigen Position liegen (siehe Rechts).Hier könnt ihr also je nach Bedarf mit den Optionen rumprobieren und sobald ihr die richtige Einstellung gefunden habt wieder auf '''Planar Map''' klicken :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_10.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch2_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auch diesmal skaliert und verschiebt ihr die Vertices der Vorderseite des Torus solange im UVW-Editor,bis diese alle im dafür vorgesehen Bereich der Textur liegen.Evtl. müsst ihr an einigen Stellen noch ein wenig rumschieben bis alles so aussieht wie es soll :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_12.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch2_13.jpg]]&lt;br /&gt;
&lt;br /&gt;
Zur Texturierung der Rückseite bzw. der beiden anderen Seiten könnt ihr übrigens ganz einfach den Teil der Textur nutzen in dem keine Medallien abgelegt sind.Folgend seht ihr den gemappten Rücken (oben) und eine Seite (unten) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_14.jpg]]&lt;br /&gt;
&lt;br /&gt;
amit wären wir eigentlich auch schon am Ende des Tutorials angelangt.Euch jetzt noch bebildert zu erzählen wie die restlichen Körperteile texturiert werden würde,wäre in meinen Augen Schwachsinn.Die Grundlagen und evtl. auftretende Schwierigkeiten hab ich ja bereits angesprochen,und den Rest des Modells solltet ihr ohne Problem fertigtexturieren können.&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Wenn ihr meinen Beschreibungen folgen konntet,dann sollte euer Polygonsoldatn nun in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch2_15.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das ist doch die Mühe wert,oder?Zumal ihr nun behaupten könnt neben dem Modell auch noch die Textur für euer Modell komplett selbst erstellt zu haben.Ausserdem bietet sich euch jetzt durch die Nutzung eines einzigen Skins für unser Modell noch jede Menge Erweiterungsmöglichkeiten,von der andersfarbigen Uniform bis hin zu einer total anderen Bekleidung.&lt;br /&gt;
&lt;br /&gt;
Wie immer hoffe ich,das euch dieses Tut so viel Spaß gemacht hat wir mir das Verfassen eben dieses und bin auf euer Feedback und eure Modellierergebnisse mehr als gespannt!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Modellierung eines Low-Poly Menschen Teil 1]] | - }} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Modellierung eines Low-Poly Menschen Teil 2]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Modellierung_eines_Low-Poly_Menschen_Teil_1&amp;diff=20546</id>
		<title>Tutorial Modellierung eines Low-Poly Menschen Teil 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Modellierung_eines_Low-Poly_Menschen_Teil_1&amp;diff=20546"/>
				<updated>2007-05-24T22:19:21Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Nachwort */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Ave!==&lt;br /&gt;
&lt;br /&gt;
Und hallo zu meinem ersten Tutorial das direkt weder was mit Delphi noch was mit OpenGL zu tun hat.Hört sich zwar verwirrend an,aber im Endeffekt geht es diesmal um ein Thema mit dem sich jeder der ein 3D-Spiel entwickelt früher oder später einmal auseinandersetzen muss.&lt;br /&gt;
&lt;br /&gt;
Es geht nämlich um das Erstellen eines 3D-Modelles,genauer gesagt um ein 3D-Modell mit einer geringen Polygonanzahl.Wie jeder der sich mit 3D-Grafiken in Echtzeit auseinander setzt weis,hängt die Geschwindigkeit einer 3D-Anwendung u.a. stark von der Anzahl der darzustellenden Polygone ab und selbst auf modernen Grafikkarten sollte man es damit nicht übertreiben.&lt;br /&gt;
&lt;br /&gt;
Und genau deshalb beschäftigen wir uns in diesem Tutorial mit dem Erstellen eines menschlichen 3D-Modelles unter Nutzung möglichst weniger (genauer gesagt 360) Dreiecke.Für eine Hauptfigur in einem Egoshooter wäre das natürlich viel zu undetailliert,allerdings ziele ich eher auf ein Modell für ein Strategiespiel o.Ä. ab,bei denen sich oft hunderte von Einheiten gleichzeitig auf dem Bildschirm tummeln.Allerdings lässt sich die Polygonanzahl des Modells leicht erhöhen und den eigenen Bedürfnissen anpassen.Mir gehts in diesem Tutorial eher um die Grundlagen als um den endgültigen Polycount.&lt;br /&gt;
&lt;br /&gt;
==Voraussetzungen==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial verwende ich 3DStudio MAX (wie zu sehen in einer englischen Version),aber eigentlich sollte es sich ohne größere Umstände auf alle 3D-Modellierer die nach einem ähnlichen Prinzip arbeiten und das Modifizieren auf Vertexebene ermöglichen,übertragbar sein.&lt;br /&gt;
&lt;br /&gt;
Grundlegende Kenntnisse der genutzten 3D-Software sollten euch allerdings bekannt sein bevor ihr euch ins Tut stürzt.Damit meine ich solche Aktionen wie Markieren,Verschieben,Skalieren,Erstellen von Primitiven und das Verändern eines Viewports.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Grundlagen==&lt;br /&gt;
&lt;br /&gt;
Da sich menschliche Formen nur schlecht aus dem Gedächtnis mit ein paar Boxen modellieren lassen,brauchen wir natürlich eine Vorlage die einem Menschen ähnlich kommt.Da das Ganze auch noch 3D ist,vorzugsweise auch von zwei Seiten (Vorne und Links oder Rechts).Entschieden hab ich mich dann für die Grundlage eines jeden Menschen,nämlich ein Skelett.(zum vergrößern klicken)&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_bones1.jpg|100px]]  [[Bild:Tutorial_Low-Poly-Mensch1_bones2.jpg|100px]]&lt;br /&gt;
&lt;br /&gt;
3DStudio MAX bietet uns jetzt die tolle Möglichkeit eben diese Vorlagen als Hintergrund für einen Viewport anzugeben.Wir beginnen mit dem Modellieren unserer Figur in der Frontansicht,und wählen deshalb auch diesen Viewport an.Nun wechseln wir in den Dialog der uns diesen Hintergrund festlegen lässt :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_01.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_02.jpg]]&lt;br /&gt;
&lt;br /&gt;
In obigem Dialog wählen wir über &amp;quot;File&amp;quot; zuerst unser Hintergrundbild für den aktuell selektierten Viewport aus. Danach müssen wir den Aspekratio via &amp;quot;Match Bitmap&amp;quot; an das Bild anpassen,da es sonst verzerrt im Hintergrund angezeigt werden würde.Die Checkbox &amp;quot;Lock Zoom/Pan&amp;quot; muss auch aktiviert werden,damit das Bild beim Verschieben/Zoomen des Viewports auch angepasst wird.&lt;br /&gt;
&lt;br /&gt;
Danach sollte eure Frontansicht ungefähr so aussehen (ich hab ihn mir auf den ganzen Schirm geholt und auch passen gezoomt bzw. verschoben) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_03.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Der Brustkorb===&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun unseren Viewport an unsere Bedürfnisse angepasst und mit einem Hintergrundbild ausgesttatet haben,auf dessen Basis wir unser Modell erstellen,können wir auch schon mit dem eigentlichen Modelliervorgang loslegen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_04a.jpg|right]]Wie schon kurz angesprochen werden wir unsere Figur komplett aus '''Boxen''' erstellen. Also wählen wir die Boxprimitive aus und erstellen eine 3x3x1 unterteilte Box die ungefähr den Ausmassen des Skelettbrustkorbes entspricht, allerdings ein wenig größer ist, da ein Mensch ja bekannterweise noch Haut und Fleisch besitzt :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_04.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_05.jpg|right]]Die Box kommt zwar vom Umfang her schonmal nah ran, allerdings passt die Form absolut nicht.Dazu gibts aber den &amp;quot;Mesh bearbeiten&amp;quot;(Edit Mesh)-Modifikator,den wir auch gleich auf die Box anwenden. Danach selektieren wir die Vertices '''immer''' so wie auf folgendem Screen zu sehen mit dem Auswahlrechteck :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_06.jpg]]&lt;br /&gt;
&lt;br /&gt;
Das Auswahlrechteck deshalb,weil bei einem einfachen Klick auf das sichtbare Vertex nur dieses ausgewählt werden würde,und nicht auch wie beim Auswahlrechteck alle dahinterliegenden Vertices.Bitte behaltet euch diesen Satz das ganze Tut über im Hinterkopf,denn er ist '''wichtig!'''.&lt;br /&gt;
&lt;br /&gt;
Nun selektiert und verschiebt ihr also die Vertices (Auswahlrechteck!) solange in der Vorderansicht,bis der Brustkorb in etwa dem des Skelettes entspricht.Das muss nicht 1:1 sein,man kann hier natürlich nach Lust und Laune variieren.Euer Ergebnis sollte nun in etwa so aussehen (rechts seht ihr das Ergebnis in der 3D-Ansicht) :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_07.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_08.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dank unserer Vorlage in Form des Skelettes sollte euch diese Aktion eigentlich recht leicht gefallen sein.Kleiner Hinweis falls ihr ein detaillierters Modell erstellen wollt : Die 3x3x1-unterteilte Box kann natürlich nach Belieben unterteilt und somit mit mehr Dreicken versehen werden,wodurch ihr leicht mehr Details ausarbeiten könnt!&lt;br /&gt;
&lt;br /&gt;
===Die Arme===&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit den Armen unseres Protagonisten.Da die Grundsätze des Modellierens der Körperteile (Vertexauswahl,Modifikatoranwendung) bereits im vorigen Kapitel beschrieben wurden,spar ich mir das jetzt und in den folgenden Absätzen und komme direkter auf den Punkt.&lt;br /&gt;
&lt;br /&gt;
Wir erstellen also wieder eine Box,die ungefähr den Dimensionen des Armes entspricht.Diesmal allerdings 3x1x1 unterteilt (Oberarm,Unterarm,Hand).Diesmal verändern wir diese Box allerdings '''nicht''' entsprechend der Armposition,sondern so wie ein menschlicher Arm im Normalfall bei lässigem Stehen positioniert wäre :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_09.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_09a.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_10.jpg|right]]Nun nutzen wir die Tatsache das ein menschlicher Körper symetrisch ist schamlos aus und erstellen den anderen Arm durch ein Spiegeln als Kopie :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_11.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Anschliessend müssen wir den neu erstellten Arm nur noch an die passende Stelle auf der gegenüberliegenden Seite des Brustkorbs schieben.&lt;br /&gt;
&lt;br /&gt;
===Das Becken===&lt;br /&gt;
&lt;br /&gt;
Wer sich in Sachen Anatomie ein wenig auskennt (oder wer schonmal in den Spiegel geschaut hat),wird feststellen das es eine Verbindung zwischen Rumpf und den Beinen gibt,auch das Becken genannt.Rein theoretisch hätten wir diesen im selben Mesh wie den Rumpf modellieren können,aber für eine evtl. später folgende Animation unseres Recken ist ein seperater Mesh dafür besser geeignet.&lt;br /&gt;
&lt;br /&gt;
Da das Prozedere dem der Erstellung des Brustkorbes wie ein Ei dem anderen gleicht,gibts hier nur die Screencaps von der Box und dem fertigen Rumpf.Einziger Unterschied zum Brustkorb ist natürlich die Form und die Tatsache das man einen Übergang zu eben diesem im Becken schaffen sollte,sowie Ansätze für die gleich folgenden Beine :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_12.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_13.jpg]]&lt;br /&gt;
&lt;br /&gt;
Kurzer Tipp für Polygonsparer : Hier würde eigentlich auch eine 2x2x1-unterteilte Box reichen (28 Polygone weniger),die dann allerdings natürlich nicht so organisch aussähe.&lt;br /&gt;
&lt;br /&gt;
===Die Beine===&lt;br /&gt;
&lt;br /&gt;
Damit sich unser Polygonheld auch etwas besitzt auf das er sich in seiner virtuellen Umgebung stützen kann,geben wir ihm auch zwei Beine mit (dank der Symetrie müssen wir allerdings nur eines modellieren).Wie auch schon bei den Armen erstellen wir wieder eine 3x1x1-unterteilte Box die in etwa die Beine unseres Viewporthintergrunds umschliesst und passen diese Box dann anhand des Skeletts in ihren Unterteilungen an.Danach bringen wir das Bein noch in eine natürlichere Position :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_14.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_15.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ist unser Bein fertiggestellt,so wird dieses wieder als eine Kopie gespiegelt um anschliessend an die passende Position geschoben zu werden.Beim &amp;quot;basteln&amp;quot; der Beine solltet ihr übrigens drauf achten,das die Stelle an der diese aus dem Becken treten auch recht &amp;quot;flüssig&amp;quot; überläuft um einen natürlichen Eindruck zu gewährleisten.Solltet ihr das zumindest halbwegs hinbekommen haben,dann dürfte euer Modell in der 3D-Ansicht in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_16.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Der Hals===&lt;br /&gt;
&lt;br /&gt;
Dem Hals müssen wir besonders bei einem Modell mit so wenigen Polygonen kaum Beachtung schenken,tut er doch nichts weiter als den Rumpf und den Kopf zu verbinden.Wir verwenden eine einfache 2x1x1 Box die etwas höher als breit ist :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_17.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Der Kopf===&lt;br /&gt;
&lt;br /&gt;
Der Kopf gillt allgemein hin als das wichtigste Körperteil des modernen Menschen,wird er doch manchmal zum Denken genutzt.Bei uns nimmt er auch eine &amp;quot;wichtige&amp;quot; Funktion ein,denn er ist der einzige Mesh den wir auch in die Tiefe hinein unterteilen (dazu gleich mehr).Wir erstellen also eine 3x3x3-unterteilte Box die in etwa den kompletten Schädel umschliesst.Auch diese passen wir wie gewohnt den Gegebenheiten des zugrundeliegenden Körperteils an,machen sie allerdings ein wenig runder (und damit organischer) als dies beim Schädel der Fall ist.Natürlich könnt ihr euch beim Kopf freien Lauf lassen und evtl. noch Hörner oder sonstige Accessoirs wie Haare,Helme oder Hüte direkt in den Kopf miteinbringen.Solche Details wie Augenhöhlen,Nase oder Mund können wir bei einem Low-Poly-Model natürlich nicht über die Geometrie einbinden,sondern müssen später über eine Textur realisiert werden :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_21.jpg]]&lt;br /&gt;
&lt;br /&gt;
Was natürlich sofort auffällt ist die Flachheit unseres Avatars.Da wir allerdings in 3 Dimensionen sehen und leben,werden wir uns diesem Problem natürlich auch sofot annehmen.&lt;br /&gt;
&lt;br /&gt;
==Die 3.Dimension==&lt;br /&gt;
&lt;br /&gt;
Wie bereits gesagt,ist unser Modell zwar schon menschlich geformt,würde so aber in keiner 3D-Anwendung ne gute Figur machen.Begeben wir uns nun also in die 3.Dimension.Dazu aktivieren wir die linke Seitenansicht und laden dort als Hintergrund dann die Datei bones2.jpg.Mit großer Wahrscheinlichkeit wird euch jetzt allerdings genau dasselbe passieren wie mir : Das Hintergrundbild passt größen- und positionstechnisch nicht zu unserem 3D-Modell.Das macht aber nichts,denn da wir in der Frontansicht fertig sind werden wir unsere Figur komplett markieren und solange skalieren bzw. verschieben bis sie in etwa auf unser neues Hintergrundbild passt.Eure linke Seitenansicht sollte nun in etwa so aussehen :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_22.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Der Brustkorb===&lt;br /&gt;
&lt;br /&gt;
Besonders bei diversen Filmschauspielern und Superhelden ist es gerade der markante Brustkorb der ihnen das gewisse etwas verleiht.Das soll bei unserem Polygonier auch so sein,weshalb wir den Brustkorb jetzt leicht in die nach vorne und leicht nach hinten verbreitern.Das sollte dann in etwa so aussehen,und wie rechts zu sehen macht sich der Effekt auch gleich bemerkbar.Wer sich übrigens beim &amp;quot;Brustkorb&amp;quot; an die Skelettvorlage gehalten hat,der hat einen netten Durschnittspolygonier gebastelt :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_23.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_24.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Der Kopf===&lt;br /&gt;
&lt;br /&gt;
Auch dem Kopf sollten wir eine natürliche Form in allen 3 Dimensionen verpassen.Diesmal müssen wir allerdings auch kurz mal in die von-oben Ansicht wechseln,um die äusseren Ecken des Kopfes ein wenig nach Innen zu ziehen.Das ist deshalb nötig,da unser Polygonprolet sonst ein leicht eingedelltes und damit recht befremdliches Gesicht (und auch Hinterkopf) hätte.In Pixel ausgedrückt sollte das im Endeffekt so aussehen und in der 3D-Ansicht ist gut zu erkennen was ein paar verschobene Vertices so ausmachen können :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_25.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_26.jpg]]  [[Bild:Tutorial_Low-Poly-Mensch1_27.jpg]]&lt;br /&gt;
 &lt;br /&gt;
===Die Beine===&lt;br /&gt;
&lt;br /&gt;
Auch die Beine (und v.a. der Fuß) unseres Modelles sollten leicht in die 3.Dimension transportiert werden um es realistischer erscheinen zu lassen.Zu diesem Zeck knicken wir das Bein dort wo eigentlich die Kniekehle ist ein wenig nach vorne und ziehen die vorne und ganz unten sitzenden Vertices recht weit nach vorne um einen Fuß zu bilden.Natürlich müsst ihr das nicht an beiden Beinen machen.Vor dem Bearbeiten solltet ihr deshalb ein Bein entfernen und das bearbeitet nach dem Ende dieser Aktion wieder als gespiegelte Kopie verschieben :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_28.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Da steht er nun (mehr oder weniger ähnliche),unser 360 Polygone leichter Paul Pixel und er wartet nur darauf in irgendeinem Spiel in die virtuelle Schlacht geschickt zu werden :&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Low-Poly-Mensch1_28.jpg]]&lt;br /&gt;
&lt;br /&gt;
Was ihm natürlich noch fehlt ist ein passende Textur.Dazu wirds in Zukunft bei brauchbarem Feedback dann auch evtl. ein Tutorial geben,aber bis dahin könnt ihr euch ja schonmal selbst daran verdingen.&lt;br /&gt;
&lt;br /&gt;
Ich hoffe mit diesem Tutorial übrigens eine kleine Lücke geschlossen zu haben,welche teamintern schon besprochen wurde : Content.Denn viele haben zwar die programmiertechnischen Voraussetzungen um ein Spiel zu programmieren,aber beim Erstellen des Inhalts (v.a. 3D-Modelle) haperts oft.Ich hoffe deshalb dass durch dieses Tutorial nun einige von euch in der Lage sind eigene Figuren zu erstellen.Deshalb gibts allerdings auch kein fertiges 3D-Modell zum Download.Um den Lerneffekt dieses Tutorials zu verstärken müsst ihr diesmal vom Anfang bis zum Ende durchhalten!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sascha Willems&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| - | [[Tutorial Modellierung eines Low-Poly Menschen Teil 2]]}} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Modellierung eines Low-Poly Menschen Teil 1]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=20516</id>
		<title>DGL Projekte</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Projekte&amp;diff=20516"/>
				<updated>2007-05-02T10:00:40Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Links zu meinen Projekte aktualisiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=DGL Projects Corner=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
Willkommen in der '''[[DelphiGL|DGL]] Projekte Ecke'''!&lt;br /&gt;
[[Bild:ProjekteEcke.jpg|center]]&lt;br /&gt;
Auf dieser Seite findet ihr Projekte von '''Mitgliedern von [http://DelphiGL.com DelphiGL.com]''' welche als '''abgeschlossen''' gewertet wurden.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Spiele==&lt;br /&gt;
Viele, um nicht zu sagen die meisten, DGL-Mitglieder widmen sich dem Thema Spiele. Was dabei an respektablen Ergebnissen entstanden ist könnt ihr in dieser Rubrik sehen.&lt;br /&gt;
&lt;br /&gt;
===3D Shooter und Labyrinth Spiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Action===&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_asteroids.jpg|framed|center|Link: '''[[Projekt_Asteroids|Asteroids]]''']]&lt;br /&gt;
&lt;br /&gt;
|Asteroids ist ein Remake des alten Klassikers &amp;quot;Comet&amp;quot;. Ziel des Spiels ist es so viel Asteroiden wie möglich zu zerstören um dadurch möglichst viele Punkte zusammeln, ohne dabei von den herum fliegenden Trümmern getroffen zu werden. &lt;br /&gt;
&lt;br /&gt;
An einem Spiel können bis zu 4 Spieler gleichzeitig teilnehmen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Magellan|Magellan]]&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_napalmbomber.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=90 Napalmbomber3D Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|NapalmBomber3D ist wie der Titel schon vermuten lässt ein 3D-Klon des bekannten Bombermanspielprinzips.Dieses hochbrisante und fesselnde Spiel besticht durch seine tolle Grafik die natürlich mittels OpenGL realisiert wurde.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zum Spiel gibt es natürlich auch noch einen Karteneditor mit dem sich in Windeseile eigenen Maps erstellen lassen.&lt;br /&gt;
&lt;br /&gt;
Neben inzwischen über 50.000 Downloads (im Schnitt sind es immernoch &amp;gt; 400 pro Monat) und diversen sehr guten Reviews hat es das Spiel sogar auf die PC-Action Ausgabe 07/2004 geschafft.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Brett-, Denk- und Kartenspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Projekt_Hex_Change_Screenshot.jpg|thumb|center|168px|Link: '''[[Projekt_Hex-Change|Hex-Change]]''']]&lt;br /&gt;
|2 Spieler konkurrieren um die Felder auf einer Hexagon Fläche. Das Spiel enthält einen Einzelspieler- (gegen KI) und einen &amp;quot;Hot-Seat&amp;quot;-Mehrspielermodus.&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:H.A.S.E.|H.A.S.E.]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Reaktions- und Geschicklichkeitsspiele===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_confusingball.jpg|framed|center|Link: '''[[Projekt_ConfusingBall|Confusing Ball]]''']]&lt;br /&gt;
&lt;br /&gt;
|In &amp;quot;Confusing Ball&amp;quot; steuert man einen Ball durch ein 3D Labyrinth, in dem die Gesetze der Physik neu definiert werden müssen. Um ins Ziel eines Levels zu gelangen benötigt man einen gewissen Orientierungssinn und ein gutes räumliches Vorstellungsvermögen.&lt;br /&gt;
Nebenher muss man ja auch noch die Münzen einsammeln, und den Bomben aus dem Weg gehen. Frei verschiebbare Steine erhöhen den Schwierigkeitsgrad.  &lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:MatReno|MatReno]]&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:Thumb_beanmachine.jpg|framed|center|Link: '''[http://www.saschawillems.de/?page_id=86 Bean Machine Projektseite]''']]&lt;br /&gt;
&lt;br /&gt;
|&amp;quot;Bean Machine&amp;quot; basiert auf dem Sega MegaDrive-Klassiker &amp;quot;Dr.Robotnik's Mean Bean Machine&amp;quot; (ausserhalb Europas auch als &amp;quot;Puyo Puyo&amp;quot; bekannt) und spielt sich somit ähnlich wie Tetris.&lt;br /&gt;
Auch dieses Klassikerremake spielt sich fast genauso wie die Vorlage, allerdings gibt es dank OpenGL recht aufwendige Grafiken, natürlich gewohnt komplett in 3D.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Sascha Willems|Sascha Willems]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Manager===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|[[Bild:PBM2_Kdr.jpg|thumb|center|168px|Link: '''[[Projekt_PBM2|PBall Manager 2]]''']]&lt;br /&gt;
&lt;br /&gt;
|Der PBall Manager 2 ist ein Sportmanager in welchem man in die Rolle des Trainers/Managers eines von 96 PBall Teams aus ganz Europa schlüpft. PBall selbst ist eine fiktive Sportart welche ähnlich Fußball ist.&lt;br /&gt;
&lt;br /&gt;
Im Spiel hat man die Kontrolle über alle Abläufe: Von der Aufstellung über Spielerkäufe bis hin zum Stadionausbau liegt alles in der Hand des Spielers. Doch auch die eigene Karriere kann voran getrieben werden indem man zu anderen Clubs wechselt.&lt;br /&gt;
&lt;br /&gt;
Das Ziel aller PBaller ist der Liga-Meister-Pokal indem die besten Clubs der 4 Europäischen Ligen um den Titel spielen.&lt;br /&gt;
&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|[[Benutzer:Flash|Kevin Fleischer alias Flash]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Simulationen===&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Name&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Beschreibung&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Macher&lt;br /&gt;
|-&lt;br /&gt;
|''Noch keine Programme''&lt;br /&gt;
|Hast du ein fertiges Projekt, was du bei DGL vorgestellt hast? Dann nichts wie her damit!&lt;br /&gt;
|''Hier könnte dein Name stehen''&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Skyboxen&amp;diff=20228</id>
		<title>Tutorial Skyboxen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Skyboxen&amp;diff=20228"/>
				<updated>2007-02-21T11:58:22Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Skyboxen */ + Hinweise&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Skyboxen=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Teil 1: Die Texturen mit Terragen erzeugen==&lt;br /&gt;
Dieser Teil des Tutorials beschäftigt sich mit dem Erstellen der für eine Skybox benötigten Texturen mit Hilfe des Programms [http://www.planetside.co.uk/terragen Terragen]. Sie sollten jedoch grundlegende Kenntnisse über dieses Programm besitzen, da ich nicht zu sehr ins Detail gehen werde. Ich werde nur die Schritte erklären, die nötig sind, um ein grundlegendes Terrain zu erstellen und die Skybox zu rendern. Sie sollten also zuerst besser das Online-Tutorial zu Terragen lesen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn Terragen gestartet wird, erscheint die Oberfläche wie abgebildet:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox01.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wir bechäftigen uns zuerst mit dem rechten Fenster, um unsere Landschaft zu generieren. Wählen Sie es aus und klicken sie auf den &amp;quot;Generate Terrain&amp;quot;-Button, um den folgenden Dialog zu öffnen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox02.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In der Auswahlbox &amp;quot;Method&amp;quot; kann die zur Landschaftsgenerierung genutzte Methode gewählt werden, die mit den Optionen auf der rechten Seite noch angepasst werden kann. Ich habe mich dazu entschieden, für dieses Tutorial einen Canyon zu generieren. Klicken Sie nach ihrer Wahl auf &amp;quot;Generate Terrain&amp;quot; und Sie werden Ihre neu generierte Landschaft im &amp;quot;Landscape&amp;quot;-Dialog sehen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox03.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn Ihnen das generierte Terrain nicht gefällt, können Sie es mit den oberen drei Buttons nachträglich anpassen.&lt;br /&gt;
&lt;br /&gt;
Der Punkt, von dem drei Linien ausgehen, ist die Position des Betrachters. Mit einem Linksklick kann man dessen Position und mit einem Rechtsklick dessen Blickpunkt ändern.&lt;br /&gt;
Jetzt ist es Zeit die Oberflächentextur zu wählen. Sie könnten zwar selbst eine generieren, da dies jedoch sehr zeitintensiv ist ,habe ich mich dazu entschieden, eine der mit Terragen gelieferten Vorlagen zu öffnen. Klicken Sie dazu auf den &amp;quot;Open...&amp;quot;-Button in der &amp;quot;Surface Map&amp;quot;-Sektion des Dialogs und wählen Sie eine Vorlage aus. Natürlich kann diese im Nachhinein noch abgeändert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und jetzt zum &amp;quot;Rendering&amp;quot;-Dialog:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox04.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Oben links können Sie eine Vorschau Ihrer Landschaft sehen, welche mit dem &amp;quot;Render Preview&amp;quot;-Button aktualisiert werden kann. Aber benutzen Sie nicht die höchste Detailstufe, nur um die Vorschau zu rendern, da dies sonst relativ lange dauern kann. Diese Detailstufe sollte nur zum endgültigen Rendern genutzt werden, während für das Preview die mittlere Stufe ausreicht.&lt;br /&gt;
&lt;br /&gt;
Unter &amp;quot;Image Size&amp;quot; können Sie die Größe Ihrer Skyboxtexturen wählen. Für eine Skybox sollten Höhe und Breite gleich sein. Ich habe 512x512 Pixel gewählt, so das die Skybox später detailliert genug aussieht, um einen realisitschen Eindruck zu vermitteln. Aber vergessen Sie nicht, das größere Texturen mehr Speicher benötigen und Performance kosten.&lt;br /&gt;
Bevor Sie die Skybox rendern können, müssen noch einige Einstellungen geändert werden, um das benötigte 90° Sichtfeld zu erhalten. Klicken Sie auf &amp;quot;Camera Settings&amp;quot; um den folgenden Dialog zu öffnen:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox05.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für das korrekte Sichtfeld müssen Sie den &amp;quot;Zoom&amp;quot;-Wert auf 1 setzen. Danach können Sie diesen Dialog auch schon wieder schliessen und zum &amp;quot;Rendering Control&amp;quot;-Dialog wechseln. Setzen Sie dort alle Werte für die Kameraausrichtung (&amp;quot;Camera orientation&amp;quot;) auf 0.&lt;br /&gt;
Nachdem Sie den Detailschieber auf Maxmimum gesetzt haben- sind Sie Bereit die Texturen zu rendern. Der erste Teil wird bei einer Kopfausrichtung (&amp;quot;head orientation&amp;quot;) von 0° generiert und stellt ihr hinteres Bild dar. Das rechte wird bei 90°, das vordere bei 180° und das linke bei 270° gerendert.&lt;br /&gt;
Setzen Sie die Kopfausrichtung jetzt wieder auf 0° und den &amp;quot;Pitch&amp;quot; auf 90°, um den Himmel zu rendern, also ihr oberes Bild. Die untere Textur für die Skybox wird bei einem &amp;quot;Pitch&amp;quot; von -90° gerendert.&lt;br /&gt;
Die hier von mir gewählten Namen sind natürlich unverbindlich und an das Beispielprogramm angepasst.&lt;br /&gt;
&lt;br /&gt;
Hier die 6 Texturen meiner Skybox:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
{|rules=&amp;quot;all&amp;quot; border = &amp;quot;1&amp;quot;&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox10.jpg]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox06.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox07.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox08.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox09.jpg]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox11.jpg]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Teil 2 - Nutzung der Skybox in OpenGL==&lt;br /&gt;
Nachdem Sie nun ihre Skyboxtexturen generiert haben, ist es Zeit, sie in Ihrer OpenGL-Anwendung zu nutzen. Ich werde hier nicht die Grundschritte zur Erstellung eines Renderkontextes oder zur Darstellung von Dreiecken zeigen. Wenn Sie darüber mehr wissen wollen, suchen sie eine der diversen OpenGL Seiten mit Tutorials zu diesen Themen auf.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 1 - Die Texturen laden===&lt;br /&gt;
Texturen mit der TglBMP Klasse zu laden ist sehr leicht. Der Einfachheit halber bevorzuge ich es, alle Texturen der Skybox in einem Array zu organisieren. Ausserdem nutze ich lokal in der Ladeprozedur ein Array in dem alle Dateinamen abgelegt sind, so dass die Texturen leicht in einer Schleife geladen werden können:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TGLForm.LoadSkyBox;&lt;br /&gt;
const&lt;br /&gt;
 SkyBoxName : array[0..5] of String = ('BK', 'FR', 'DN', 'UP', 'LF', 'RT');&lt;br /&gt;
var&lt;br /&gt;
 i : Integer;&lt;br /&gt;
begin&lt;br /&gt;
for i := 0 to High(SkyBoxTexture) do&lt;br /&gt;
 begin&lt;br /&gt;
 SkyBoxTexture[i] := TGLBmp.Create;&lt;br /&gt;
 SkyBoxTexture[i].LoadImage(SkyBoxName[i]+'.jpg');&lt;br /&gt;
 SkyBoxTexture[i].SetTextureWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);&lt;br /&gt;
 SkyBoxTexture[i].GenTexture(False, False);&lt;br /&gt;
 end;&lt;br /&gt;
GenerateSkyBox(256, 256, 256);&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das global deklarierte SkyBoxTexture-Array beinhaltet unsere sechs Texturen und im lokal deklarierten SkyBoxName-Array befinden sich alle zugehörigen Dateinamen für jede Textur, so dass Sie die Ladeprozedur ganz einfach an Ihre Namenskonventionen anpassen können.&lt;br /&gt;
Zuerst laden wir die Texturen in einer Schleife. Dabei muss jedesmal die TglBMP Klasse erstellt werden, dann wird die Bilddatei geladen und der Texturewrap auf GL_CLAMP_TO_EDGE für die S und die T Koordinate gesetzt. Dies ist nötig damit unsere Kanten passend aneinandergefügt werden.&lt;br /&gt;
&lt;br /&gt;
Beachten Sie auch, dass ich die GenTexture-Prozedur der TglBMP-Klasse abgeändert habe. Ihr werden jetzt zwei Parameter vom Typ BOOLEAN übergeben, wobei der erste angibt, ob die Textur im komprimierten S3-Format geladen gibt und der zweite, ob das anisotropische Filtering genutzt werden soll. Wenn Sie diese Eigenschaften nutzen wollen, müssen Sie sich jedoch zuerst davon versichern, dass die Grafikkarte diese unterstützt.&lt;br /&gt;
&lt;br /&gt;
Sie sollten jedoch davon absehen, Ihre Skybox Texturen komprimiert zu laden weil dadurch die Qualität stark herabgesetzt werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 2 - Die Displayliste erstellen===&lt;br /&gt;
Nachdem die Texturen geladen wurden, generieren wir die Displayliste für unsere Skybox. Wie Sie bereits wissen sollten, sind Displaylisten um ein Vielfaches schneller, als die Quads in jedem Frame neu zu zeichnen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TGLForm.GenerateSkyBox(pWidth, pHeight, pLength : TGLFloat);&lt;br /&gt;
var&lt;br /&gt;
 px,py,pz : TGLFloat;&lt;br /&gt;
begin&lt;br /&gt;
List := glGenLists(1);&lt;br /&gt;
glNewList(List, GL_COMPILE);&lt;br /&gt;
 px := - pWidth  / 2;&lt;br /&gt;
 py := - pHeight / 2;&lt;br /&gt;
 pz := - pLength / 2;&lt;br /&gt;
 SkyBoxTexture[0].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py,           pz);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py,           pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[1].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px,          py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px,          py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px + pWidth, py,           pz + pLength);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[2].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py, pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[3].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[4].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px, py,           pz);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px, py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[5].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px + pWidth, py,           pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
glEndList;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Teil des Quelltextes ist sehr einfach zu verstehen. Die Variablen px, py und pz werden genutzt, um die Skybox zu zentrieren. Dann wird ein Quader mit den Kantenlängen pWidth, pHeight und pLength und den zugehörigen Texturen in unsere Displayliste kompiliert. Der erste Quad ist die hintere Seite, der zweite die vordere Seite, der dritte ist der Boden, der vierte der Deckel, der fünfte die linke Seite und der letzte ist die rechte Seite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 3 - Die Skybox zeichnen===&lt;br /&gt;
Bevor wir die Skybox nun zeichnen '''deaktivieren wir das Schreiben in den Tiefenpuffer''' via [[glDepthMask]]. So vermeiden wir dass später gerenderte Objekte durch den von der Skybox geschriebenen Tiefenwert betroffen werden :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glDepthMask(False);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aufgerufen wird die Skybox nun über ihre Displayliste :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glClear(GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
glRotatef(xrot, 1, 0, 0);&lt;br /&gt;
glRotatef(yrot, 0, 1, 0);&lt;br /&gt;
glCallList(List);&lt;br /&gt;
SwapBuffers(FDC);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einleitend wechseln wir in die Modelansichtsmatrix und laden dort die Grundmatrix. Dann muss nur der Tiefenpuffer gelöscht (und eventuell andere verwendete Puffer) werden, den Farbpuffer müssen Sie nicht mehr löschen, da die Skybox den ganzen Schirm füllt. Jetzt muss unsere Matrix nur noch entsprechend dem Sichtwinkel des Betrachters rotiert werden, bevor unsere Displayliste aufgerufen wird. An die Spielerposition wird hier natürlich nicht transformiert, da die Skybox ja unendlich weit vom Spieler entfernt sein soll.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dem Rendern der Skybox müssen wir das Schreiben in den Tiefenpuffer natürlich wieder aktivieren :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glDepthMask(True);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Kleiner Hinweis :'' Wer möchte kann die beiden [[glDepthMask]]-Aufrufe natürlich auch direkt in der oben erstellten Displayliste ablegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jetzt könnte zusätzlich noch eine animierte Wolkenschicht wie in Quake3 oder Unreal zu sehen hinzugefügt werden. Eine Alternative zu einer Skybox sind übrigens [[Skydome]]s, die mittels passender Formeln (und evtl. auch [[Shader]]n) dynamischer gestaltet werden können.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Hinweise==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Größe der Texturen===&lt;br /&gt;
Je nach Anwendung bzw. Blickrichtung des Betrachters nimmt die Skybox einen recht großen Platz auf dem Schirm bei, wodurch Qualitätsunterschiede hier direkt sichtbar sind. Daher sollte eine entsprechend hohe Auflösung gewählt werden, also 1024x1024 und höher. Man benötigt zwar 6 solch großer Texturen (die untere Textur kann man sich aber evtl. je nach Szenario sparen) die allerdings auch trotz solch hoher Auflösung in den Speicher moderner Grafikkarten passen sollten.&lt;br /&gt;
&lt;br /&gt;
===Texturenkompression===&lt;br /&gt;
Bereits seit mehreren Jahren können 3D-Beschleuniger Texturen in einem Format mit fester Kompressionsrate ablegen und nutzen, wodurch sowohl Grafikkartenspeicher als auch Bandbreite gespart wird. Allerdings wirkt sich diese besonders bei Texturen mit langen Farbverläufen bzw. Übergängen (wie bei Skyboxen oft der Fall) negativ aus und ist i.d.R. auch direkt erkennbar, wie auf folgendem Bild sichtbar ist :&lt;br /&gt;
[[Bild:Tutorial_skyboxen_texcomp.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
Die Verschlechterung des Bildes auf der rechten Seite sollte leicht erkennbar sein. Wenn man die Texturen dann auch noch als JPG abgelegt hat und dort bereits komprimiert hat (auch bei 100% Qualitätseinstellung komprimiert JPG immernoch) verschlechtert sich das Gesamtbild nochmals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprogramm==&lt;br /&gt;
Und zu guter Letzt noch ein Bild unserer Skybox aus dem Demoprogramm:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox12.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
Für diesen Screenshot habe ich 512x512 Pixel große Texturen genutzt, während die Texturen im Download nur 256x256 Pixel groß sind!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
[http://www.delphigl.de/files/skyboxtut.zip Die Skyboxdemo (inklusive Quellcode) herunterladen]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Autor: [[Benutzer:Sascha_Willems|Sascha Willems]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Terrain3]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Tutorial3]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:Tutorial_skyboxen_texcomp.jpg&amp;diff=20227</id>
		<title>Datei:Tutorial skyboxen texcomp.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:Tutorial_skyboxen_texcomp.jpg&amp;diff=20227"/>
				<updated>2007-02-21T11:52:28Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Vergleich der Skyboxtextur ohne und mit Texturkompression&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vergleich der Skyboxtextur ohne und mit Texturkompression&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Skyboxen&amp;diff=20226</id>
		<title>Tutorial Skyboxen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Skyboxen&amp;diff=20226"/>
				<updated>2007-02-21T11:37:48Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: /* Schritt 3 - Die Skybox zeichnen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Skyboxen=&lt;br /&gt;
&lt;br /&gt;
==Teil 1: Die Texturen mit Terragen erzeugen==&lt;br /&gt;
Dieser Teil des Tutorials beschäftigt sich mit dem Erstellen der für eine Skybox benötigten Texturen mit Hilfe des Programms [http://www.planetside.co.uk/terragen Terragen]. Sie sollten jedoch grundlegende Kenntnisse über dieses Programm besitzen, da ich nicht zu sehr ins Detail gehen werde. Ich werde nur die Schritte erklären, die nötig sind, um ein grundlegendes Terrain zu erstellen und die Skybox zu rendern. Sie sollten also zuerst besser das Online-Tutorial zu Terragen lesen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn Terragen gestartet wird, erscheint die Oberfläche wie abgebildet:&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox01.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wir bechäftigen uns zuerst mit dem rechten Fenster, um unsere Landschaft zu generieren. Wählen Sie es aus und klicken sie auf den &amp;quot;Generate Terrain&amp;quot;-Button, um den folgenden Dialog zu öffnen:&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox02.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In der Auswahlbox &amp;quot;Method&amp;quot; kann die zur Landschaftsgenerierung genutzte Methode gewählt werden, die mit den Optionen auf der rechten Seite noch angepasst werden kann. Ich habe mich dazu entschieden, für dieses Tutorial einen Canyon zu generieren. Klicken Sie nach ihrer Wahl auf &amp;quot;Generate Terrain&amp;quot; und Sie werden Ihre neu generierte Landschaft im &amp;quot;Landscape&amp;quot;-Dialog sehen:&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox03.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn Ihnen das generierte Terrain nicht gefällt, können Sie es mit den oberen drei Buttons nachträglich anpassen.&lt;br /&gt;
&lt;br /&gt;
Der Punkt, von dem drei Linien ausgehen, ist die Position des Betrachters. Mit einem Linksklick kann man dessen Position und mit einem Rechtsklick dessen Blickpunkt ändern.&lt;br /&gt;
Jetzt ist es Zeit die Oberflächentextur zu wählen. Sie könnten zwar selbst eine generieren, da dies jedoch sehr zeitintensiv ist ,habe ich mich dazu entschieden, eine der mit Terragen gelieferten Vorlagen zu öffnen. Klicken Sie dazu auf den &amp;quot;Open...&amp;quot;-Button in der &amp;quot;Surface Map&amp;quot;-Sektion des Dialogs und wählen Sie eine Vorlage aus. Natürlich kann diese im Nachhinein noch abgeändert werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und jetzt zum &amp;quot;Rendering&amp;quot;-Dialog:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox04.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Oben links können Sie eine Vorschau Ihrer Landschaft sehen, welche mit dem &amp;quot;Render Preview&amp;quot;-Button aktualisiert werden kann. Aber benutzen Sie nicht die höchste Detailstufe, nur um die Vorschau zu rendern, da dies sonst relativ lange dauern kann. Diese Detailstufe sollte nur zum endgültigen Rendern genutzt werden, während für das Preview die mittlere Stufe ausreicht.&lt;br /&gt;
&lt;br /&gt;
Unter &amp;quot;Image Size&amp;quot; können Sie die Größe Ihrer Skyboxtexturen wählen. Für eine Skybox sollten Höhe und Breite gleich sein. Ich habe 512x512 Pixel gewählt, so das die Skybox später detailliert genug aussieht, um einen realisitschen Eindruck zu vermitteln. Aber vergessen Sie nicht, das größere Texturen mehr Speicher benötigen und Performance kosten.&lt;br /&gt;
Bevor Sie die Skybox rendern können, müssen noch einige Einstellungen geändert werden, um das benötigte 90° Sichtfeld zu erhalten. Klicken Sie auf &amp;quot;Camera Settings&amp;quot; um den folgenden Dialog zu öffnen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox05.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für das korrekte Sichtfeld müssen Sie den &amp;quot;Zoom&amp;quot;-Wert auf 1 setzen. Danach können Sie diesen Dialog auch schon wieder schliessen und zum &amp;quot;Rendering Control&amp;quot;-Dialog wechseln. Setzen Sie dort alle Werte für die Kameraausrichtung (&amp;quot;Camera orientation&amp;quot;) auf 0.&lt;br /&gt;
Nachdem Sie den Detailschieber auf Maxmimum gesetzt haben- sind Sie Bereit die Texturen zu rendern. Der erste Teil wird bei einer Kopfausrichtung (&amp;quot;head orientation&amp;quot;) von 0° generiert und stellt ihr hinteres Bild dar. Das rechte wird bei 90°, das vordere bei 180° und das linke bei 270° gerendert.&lt;br /&gt;
Setzen Sie die Kopfausrichtung jetzt wieder auf 0° und den &amp;quot;Pitch&amp;quot; auf 90°, um den Himmel zu rendern, also ihr oberes Bild. Die untere Textur für die Skybox wird bei einem &amp;quot;Pitch&amp;quot; von -90° gerendert.&lt;br /&gt;
Die hier von mir gewählten Namen sind natürlich unverbindlich und an das Beispielprogramm angepasst.&lt;br /&gt;
&lt;br /&gt;
Hier die 6 Texturen meiner Skybox:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|rules=&amp;quot;all&amp;quot; border = &amp;quot;1&amp;quot;&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox10.jpg]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox06.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox07.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox08.jpg]]&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox09.jpg]]&lt;br /&gt;
|-&lt;br /&gt;
| [[Bild:Tutorial_Skyboxen_skybox11.jpg]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Teil 2 - Nutzung der Skybox in OpenGL==&lt;br /&gt;
Nachdem Sie nun ihre Skyboxtexturen generiert haben, ist es Zeit, sie in Ihrer OpenGL-Anwendung zu nutzen. Ich werde hier nicht die Grundschritte zur Erstellung eines Renderkontextes oder zur Darstellung von Dreiecken zeigen. Wenn Sie darüber mehr wissen wollen, suchen sie eine der diversen OpenGL Seiten mit Tutorials zu diesen Themen auf.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 1 - Die Texturen laden===&lt;br /&gt;
Texturen mit der TglBMP Klasse zu laden ist sehr leicht. Der Einfachheit halber bevorzuge ich es, alle Texturen der Skybox in einem Array zu organisieren. Ausserdem nutze ich lokal in der Ladeprozedur ein Array in dem alle Dateinamen abgelegt sind, so dass die Texturen leicht in einer Schleife geladen werden können:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TGLForm.LoadSkyBox;&lt;br /&gt;
const&lt;br /&gt;
 SkyBoxName : array[0..5] of String = ('BK', 'FR', 'DN', 'UP', 'LF', 'RT');&lt;br /&gt;
var&lt;br /&gt;
 i : Integer;&lt;br /&gt;
begin&lt;br /&gt;
for i := 0 to High(SkyBoxTexture) do&lt;br /&gt;
 begin&lt;br /&gt;
 SkyBoxTexture[i] := TGLBmp.Create;&lt;br /&gt;
 SkyBoxTexture[i].LoadImage(SkyBoxName[i]+'.jpg');&lt;br /&gt;
 SkyBoxTexture[i].SetTextureWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);&lt;br /&gt;
 SkyBoxTexture[i].GenTexture(False, False);&lt;br /&gt;
 end;&lt;br /&gt;
GenerateSkyBox(256, 256, 256);&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das global deklarierte SkyBoxTexture-Array beinhaltet unsere sechs Texturen und im lokal deklarierten SkyBoxName-Array befinden sich alle zugehörigen Dateinamen für jede Textur, so dass Sie die Ladeprozedur ganz einfach an Ihre Namenskonventionen anpassen können.&lt;br /&gt;
Zuerst laden wir die Texturen in einer Schleife. Dabei muss jedesmal die TglBMP Klasse erstellt werden, dann wird die Bilddatei geladen und der Texturewrap auf GL_CLAMP_TO_EDGE für die S und die T Koordinate gesetzt. Dies ist nötig damit unsere Kanten passend aneinandergefügt werden.&lt;br /&gt;
&lt;br /&gt;
Beachten Sie auch, dass ich die GenTexture-Prozedur der TglBMP-Klasse abgeändert habe. Ihr werden jetzt zwei Parameter vom Typ BOOLEAN übergeben, wobei der erste angibt, ob die Textur im komprimierten S3-Format geladen gibt und der zweite, ob das anisotropische Filtering genutzt werden soll. Wenn Sie diese Eigenschaften nutzen wollen, müssen Sie sich jedoch zuerst davon versichern, dass die Grafikkarte diese unterstützt.&lt;br /&gt;
&lt;br /&gt;
Sie sollten jedoch davon absehen, Ihre Skybox Texturen komprimiert zu laden weil dadurch die Qualität stark herabgesetzt werden kann.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 2 - Die Displayliste erstellen===&lt;br /&gt;
Nachdem die Texturen geladen wurden, generieren wir die Displayliste für unsere Skybox. Wie Sie bereits wissen sollten, sind Displaylisten um ein Vielfaches schneller, als die Quads in jedem Frame neu zu zeichnen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TGLForm.GenerateSkyBox(pWidth, pHeight, pLength : TGLFloat);&lt;br /&gt;
var&lt;br /&gt;
 px,py,pz : TGLFloat;&lt;br /&gt;
begin&lt;br /&gt;
List := glGenLists(1);&lt;br /&gt;
glNewList(List, GL_COMPILE);&lt;br /&gt;
 px := - pWidth  / 2;&lt;br /&gt;
 py := - pHeight / 2;&lt;br /&gt;
 pz := - pLength / 2;&lt;br /&gt;
 SkyBoxTexture[0].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py,           pz);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py,           pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[1].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px,          py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px,          py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px + pWidth, py,           pz + pLength);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[2].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py, pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[3].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px,          py + pHeight, pz);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px,          py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[4].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px, py,           pz);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px, py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
 SkyBoxTexture[5].Bind;&lt;br /&gt;
 glBegin(GL_QUADS);&lt;br /&gt;
  glTexCoord2f(0, 0); glVertex3f(px + pWidth, py,           pz);&lt;br /&gt;
  glTexCoord2f(1, 0); glVertex3f(px + pWidth, py,           pz + pLength);&lt;br /&gt;
  glTexCoord2f(1, 1); glVertex3f(px + pWidth, py + pHeight, pz + pLength);&lt;br /&gt;
  glTexCoord2f(0, 1); glVertex3f(px + pWidth, py + pHeight, pz);&lt;br /&gt;
 glEnd;&lt;br /&gt;
glEndList;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dieser Teil des Quelltextes ist sehr einfach zu verstehen. Die Variablen px, py und pz werden genutzt, um die Skybox zu zentrieren. Dann wird ein Quader mit den Kantenlängen pWidth, pHeight und pLength und den zugehörigen Texturen in unsere Displayliste kompiliert. Der erste Quad ist die hintere Seite, der zweite die vordere Seite, der dritte ist der Boden, der vierte der Deckel, der fünfte die linke Seite und der letzte ist die rechte Seite.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schritt 3 - Die Skybox zeichnen===&lt;br /&gt;
Bevor wir die Skybox nun zeichnen '''deaktivieren wir das Schreiben in den Tiefenpuffer''' via [[glDepthMask]]. So vermeiden wir dass später gerenderte Objekte durch den von der Skybox geschriebenen Tiefenwert betroffen werden :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glDepthMask(False);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Aufgerufen wird die Skybox nun über ihre Displayliste :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
glLoadIdentity;&lt;br /&gt;
glClear(GL_DEPTH_BUFFER_BIT);&lt;br /&gt;
glRotatef(xrot, 1, 0, 0);&lt;br /&gt;
glRotatef(yrot, 0, 1, 0);&lt;br /&gt;
glCallList(List);&lt;br /&gt;
SwapBuffers(FDC);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einleitend wechseln wir in die Modelansichtsmatrix und laden dort die Grundmatrix. Dann muss nur der Tiefenpuffer gelöscht (und eventuell andere verwendete Puffer) werden, den Farbpuffer müssen Sie nicht mehr löschen, da die Skybox den ganzen Schirm füllt. Jetzt muss unsere Matrix nur noch entsprechend dem Sichtwinkel des Betrachters rotiert werden, bevor unsere Displayliste aufgerufen wird. An die Spielerposition wird hier natürlich nicht transformiert, da die Skybox ja unendlich weit vom Spieler entfernt sein soll.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nach dem Rendern der Skybox müssen wir das Schreiben in den Tiefenpuffer natürlich wieder aktivieren :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;glDepthMask(True);&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Kleiner Hinweis :'' Wer möchte kann die beiden [[glDepthMask]]-Aufrufe natürlich auch direkt in der oben erstellten Displayliste ablegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jetzt könnte zusätzlich noch eine animierte Wolkenschicht wie in Quake3 oder Unreal zu sehen hinzugefügt werden. Eine Alternative zu einer Skybox sind übrigens [[Skydome]]s, die mittels passender Formeln (und evtl. auch [[Shader]]n) dynamischer gestaltet werden können.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprogramm==&lt;br /&gt;
Und zu guter Letzt noch ein Bild unserer Skybox aus dem Demoprogramm:&lt;br /&gt;
[[Bild:Tutorial_Skyboxen_skybox12.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hinweis:&lt;br /&gt;
Für diesen Screenshot habe ich 512x512 Pixel große Texturen genutzt, während die Texturen im Download nur 256x256 Pixel groß sind!&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
[http://www.delphigl.de/files/skyboxtut.zip Die Skyboxdemo (inklusive Quellcode) herunterladen]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Autor: [[Benutzer:Sascha_Willems|Sascha Willems]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Terrain3]]|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Tutorial3]]&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:TBN_Matrix&amp;diff=19939</id>
		<title>Diskussion:TBN Matrix</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:TBN_Matrix&amp;diff=19939"/>
				<updated>2006-12-13T15:01:09Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Offlinebearbeitung ==&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist bereits seit mehreren Wochen als &amp;quot;Offline in Bearbeitung&amp;quot; markiert und in der Zeit sind keine Änderungen erfolgt. Wird noch dran gearbeitet, oder ist ber bereits fertig. Bei letzterem bitte Offline-Tag entfernen.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Sascha Willems|Sascha Willems]] 16:01, 13. Dez 2006 (CET)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:GLSL_Licht_und_Schatten&amp;diff=19938</id>
		<title>Diskussion:GLSL Licht und Schatten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:GLSL_Licht_und_Schatten&amp;diff=19938"/>
				<updated>2006-12-13T15:00:21Z</updated>
		
		<summary type="html">&lt;p&gt;Sascha Willems: Offlinebearbeitung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ich hoffe du sponserst später noch paar coole Bilder. Du weißt doch: Ich steh auf sowas. ;)&lt;br /&gt;
Und außerdem bietet es sich bei einem Shaderthema immer an. ;)&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Flash|Flash]] 16:47, 12. Sep 2006 (CEST)&lt;br /&gt;
&lt;br /&gt;
== Offlinebearbeitung ==&lt;br /&gt;
&lt;br /&gt;
Der Artikel ist bereits seit mehreren Wochen als &amp;quot;Offline in Bearbeitung&amp;quot; markiert und in der Zeit sind keine Änderungen erfolgt. Wird noch dran gearbeitet, oder ist ber bereits fertig. Bei letzterem bitte Offline-Tag entfernen.&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Sascha Willems|Sascha Willems]] 16:00, 13. Dez 2006 (CET)&lt;/div&gt;</summary>
		<author><name>Sascha Willems</name></author>	</entry>

	</feed>