\chapter{OpenGL}
    \section{Einführung}
    OpenGL ist eine plattformübergreifende Umgebung zur Entwicklung von
    sowohl zwei- als auch dreidimensionalen Grafikapplikationen. Seit seiner
    Einführung 1992 hat sich OpenGL zur am weitesten unterstützten und
    weitverbreitetsten API für Grafikprogrammierung entwickelt, und ist
    auf jeder Art von Endgeräten von Desktopcomputern bis hin zu
    eingebetteten Systemen zu finden.
    (siehe auch \cite{opengl.org})

    Seit 1992 wird der OpenGL-Standard vom \emph{Architecture Review Board (ARB)}
    überwacht und erweitert. Das ARB ist ein unabhängiges Konsortium
    bestehend aus führenden Anbietern aus dem Grafiksektor.

    \section{Architektur}
    OpenGL definiert eine sehr einfache API welche nur grundlegende 
    Funktionalität zur Erstellung von 3D-Applikationen bietet.
    Das Hostsystem auf dem eine solche Applikation ausgeführt werden soll
    muss eine Implementation dieser API vorhalten, eine freie Implementation 
    bietet Mesa (\cite{mesa}), allerdings ist diese nicht offiziell zertifiziert,
    Mesa hat sich aber trotzdem zumindest auf unixoiden Betriebssystemen als
    Quasi-Standard etabliert. Die Aufgabe der Implementierenden Bibliothek ist
    es im Grunde nur die Bibliotheksaufrufe des Benutzers an den
    ebenfalls vom System bereitgestellten, herstellerspezifischen Treiber 
    weiterzuleiten, welcher diese dann in einer für die jeweilige GPU
    verständlichen Form an die Grafikkarte weiter gibt. Diese Architektur
    lässt den Grafikkartenherstellern möglichst große Freiheit in Design und 
    Implementierung der nötigen Funktionen, auch lässt sie dem Benutzer
    die freie Wahl der implementierenden Bibliothek.

    \begin{figure}
        \centering
        \includegraphics[width=0.9\textwidth]{images/Flow}
        \caption{Die OpenGL Visualisierungspipeline (aus \cite{opengl.org})}
        \label{fig:pipelines}
    \end{figure}
    
    OpenGL arbeitet sowohl auf Bilddaten als auch auf geometrischen
    Primitiven. Beide Arten von Daten werden über unabhängige, programmierbare
    Pipelines verarbeitet und erst im letzten Schritt auf der Grafikkarte
    zusammengefügt und in den Frame-Buffer geschrieben (Siehe Abbildung \ref{fig:pipelines}).

    \section{Pipeline Schritte}
    Die Applikation setzt zunächst einige interne Variablen (vgl. \ref{sec:kontext}),
    dann sendet sie Informationen über Vertices und deren Verbindungen untereinander
    (connectivity) an die Grafikkarte. Jeder Vertex besitzt bestimmte Attribute
    wie seine Position im Raum, seine Farbe, Texturkoordinaten, Normale usw.

    Im ersten Schritt werden diese Attribute zusammengefasst und es werden Operationen 
    auf ihnen ausgeführt, so zum Beispiel Positionstransformationen, per-Vertex
    Beleuchtungsberechnungen oder die Generierung und Transformation der Texturkoordinaten.

    Dann werden aus den Vertices und den Konnektivitätsdaten Primitive zusammengesetzt.
    Diese werden am Frustum geculled und geclippt, d.h. später nicht sichtbare
    Primitive werden an dieser Stelle schon aus den Berechnungen entfernt. Dann werden
    diese Primitive auf die Projektionsebene projiziert und es werden die Positionen
    der Pixel im späteren Bild berechnet (Rasterisation). Dieser Schritt hat folglich
    zwei Ausgabe-ströme: die oben beschriebenen Positionen der Pixel und die
    interpolierten Farbwerte (Fragmente) derer.

    Die Fragmenten werden im nächsten Schritt weiter behandelt, zum Beispiel mit einer
    Textur versehen oder mittels Nebels aufgehellt. Dieser Schritt ergibt einen
    Farb- und einen Tiefen-wert für jedes Fragment.

    Im letzten Schritt wird schließlich aus den Fragmenten und deren Positionsdaten
    das letztendliche Bild zusammengesetzt, nachdem noch einige Tests auf den
    Fragmenten stattgefunden haben, wie zum Beispiel Alpha-, Stencil, Depth oder
    Scissor-Tests.

    \section{Zustände und der Kontext}
    \label{sec:kontext}
    OpenGL besteht im Grunde aus zwei Gattungen von Funktionen:

    Die einen ändern den Zustand von internen Variablen wie zum Beispiel
    den Transformationsmatrizen, den aktiven Lichtquellen oder der
    gewählten Textur, die anderen schicken Geometriedaten (Streams)
    an die Grafikkarte. Letztere werden im Programm durch
    \begin{lstlisting}[name=glBegin]
    glBegin(GLenum mode);
    \end{lstlisting}
    und 
    \begin{lstlisting}[name=glEnd]
    glEnd();
    \end{lstlisting}
    zu Blöcken zusammengeschlossen um es dem Treiber zu ermöglichen
    Optimierungen auf Geschwindigkeit vorzunehmen. Innerhalb dieser Blöcke
    dürfen keine Änderungen am internen Zustand OpenGLs vorgenommen
    werden.

    Ein vollständiger Satz dieser internen Zustände wird Kontext
    genannt. Um OpenGL überhaupt nutzen zu können muss für ein Fenster
    in welches OpenGL zeichnen soll ein solcher Kontext erzeugt und vorgehalten
    werden. Dies muss ebenfalls vom Hostsystem erledigt werden.

    \section{Bibliotheken}
    Wie bereits angesprochen bietet OpenGL nur eine sehr eingeschränkte
    Menge von Methoden mit die alle nur sehr grundlegende Funktionen abbilden.
    Damit nicht jeder Benutzer aufbauend auf diesen Methoden Standardfunktionalität
    implementieren muss wurden eine Vielzahl von Bibliotheken entwickelt welche
    das Benutzen von OpenGL vereinfachen sollen. 
    Auch stellt OpenGL keinerlei Methoden zur Erzeugung von Fenstern,
    des Kontextes oder zur Behandlung von Benutzereingaben an. 
    Die Abbildungen \ref{fig:apihierunix} und \ref{fig:apihierwin} sollen die 
    Hierarchie der APIs auf verschiedenen Systemen verdeutlichen.
    Im Folgenden sollen drei dieser Bibliotheken vorgestellt werden:

    \begin{figure}
        \includegraphics{images/Hierarchy_UNIX}
        \caption{API-Hierarchie auf einem UNIX System (aus \cite{opengl.org})}
        \label{fig:apihierunix}
    \end{figure}

    \begin{figure}
        \includegraphics{images/Hierarchy_WIN}
        \caption{API-Hierarchie auf einem Windows System (aus \cite{opengl.org})}
        \label{fig:apihierwin}
    \end{figure}

    
        \subsection{GLU}
        GLU ist die \emph{OpenGL Utility Library}. Sie soll Grafikfunktionen
        höherer Ebene wie die Abbildung zwischen Bildschirm- und 
        Weltkoordinaten, die Generierung von Texture-Mipmaps, das Zeichnen
        von Quadriken sowie Transformationen zur einfacheren Erstellung und
        Verwaltung von Projektionsebenen und Kamera anbieten. 
        GLU wird wie auch OpenGL selbst vom ARB spezifiziert
        und ist Teil eines vollständigen OpenGL-Paketes.
        Bis zur Version 1.2 existierte eine Mesa-eigene Implementation \cite{mesa}, 
        welche allerdings ab Version 1.3 zugunsten der SGI-Implementation
        \cite{sgi} aufgegeben wurde.
        
        \subsection{GLut}
        GLut steht für \emph{OpenGL Utility Toolkit}, und ermöglicht es, Aufgaben 
        wie die Erstellung von Fenstern oder Tastaturein- und -Ausgaben 
        plattformunabhängig zu erledigen. Daneben bietet GLUT einige Funktionen zum 
        Zeichnen einfacher geometrischer Objekte wie Würfel, Zylinder, Kugeln oder 
        der Utah-Teekanne.

        GLUT setzt auf OpenGL, GLU und, je nach Betriebssystem, auf den jeweiligen 
        betriebssystemspezifischen Funktionen und Bibliotheken auf, die die Verbindung 
        zu OpenGL herstellen (GLX für X, WGL für Windows und AGL für Mac OS).
        (aus: \cite{wikipedia})
        
        \subsection{GLew}
        \label{glew}
        Die GLew (\emph{The OpenGL Extension Wrangler Library}, \cite{glew}) ist eine 
        plattformunabhängig C/C++ Bibliothek die das Laden und Verwalten von Extensions 
        (vgl. \ref{sec:exts}) vereinfacht. Sie bietet effiziente Methoden um zur Laufzeit
        zu ermitteln welche Extensions vom System unterstützt werden.

    \section{Extensions}
    \label{sec:exts}

    Obwohl die OpenGL-Spezifikation eine bestimmte Grafikpipeline definiert bietet sie
    Herstellern eine einfache Möglichkeit ihre spezifische Implementation um benötigte
    Features zu erweitern: den \emph{Extension Mechanism}. 
    Dieser Mechanismus ist Fluch und Segen zugleich: Segen weil der Spezifizierungsvorgang
    durch das ARB zeitraubend ist und OpenGL durch solche Extensions auf dem neuesten
    Stand der Technik bleiben kann, Fluch weil Hersteller diesen Mechanismus missbrauchen
    um auch das Letzte an Leistung aus ihrer Hardware herauszuholen und der Benutzer
    somit solche Features für verschiedene herstellerspezifische APIs separat
    implementieren muss, was OpenGL ja gerade zu verhindern sucht.

    Zum Glück werden Extensions welche sich bei den Benutzern großer Beliebtheit
    erfreuen und ihre Robustheit im Feld bewiesen haben ständig vom ARB in den
    Standard übernommen, so dass dieser Mechanismus auch der schnelleren Weiterentwicklung
    von OpenGL dient. Bibliotheken wie die GLew vereinfachen zudem den Zugriff und
    helfen einen Weg durch den Extension-Wald zu bahnen.

    Eine komplette Liste der aktuellen Extensions findet man in der 
    \emph{OpenGL Extension Registry} \cite{extreg}.
    
    \section{Praxis: Initialisierung mit GLut}
    Der erste Schritt zur funktionierenden OpenGL-Applikation ist die Erzeugung eines
    Fensters in welches gerendert werden soll, sowie des Kontextes. Wir wollen hierzu
    das GLut nutzen:

    Die Dateien init.h und init.cpp enthalten die wichtigsten Funktionen:
    \begin{lstlisting}[name=init.h]
void initGL(int argc, char *argv[]);
void resize(int w, int h);
void renderScene();
    \end{lstlisting}

    initGL enthält den nötigen Code um ein Fenster zu erstellen, den Kontext zu erzeugen
    und GLut mitzuteilen welche Callbacks es nutzen soll:
    \begin{lstlisting}[name=init.cpp: initGL]
void initGL(int argc, char *argv[]) {

    // initialize glut
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(10, 10);
    glutInitWindowSize(800, 600);
    glutCreateWindow("gltut");

    // set global states 
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0, 0.0, 0.0, 1.0);

    // set callbacks
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(resize);
    glutKeyboardFunc(handleKey);
}
    \end{lstlisting}
    Im ersten Abschnitt initialisieren wir das GLut selbst, erzeugen den Kontext und
    ein Fenster mit einer Größe von 800x600 Pixel, dem Titel \"gltut\" und der
    Position (10,10).
    Der zweite Abschnitt setzt lediglich einige Variablen im Kontext, während im dritten
    Abschnitt Callbacks angegeben werden welche GLut zum rendern bzw. während des Idle-Loops,
    beim Verändern der Größe des Fensters und bei Tastendruck aufgerufen werden sollen.

    resize ist die Callbackfunktion die vom GLut aufgerufen wird sobald sich die Größe
    des Fensters geändert hat.
    \begin{lstlisting}[name=init.cpp: resize]
void resize(int w, int h) {
    // calc width/height ratio
    float ratio = 1.0* w / h;

    // set matrix mode
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // set new viewport and perspective
    glViewport(0, 0, w, h);
    gluPerspective(45, ratio, 1, 1000);

    // restore matrix mode
    glMatrixMode(GL_MODELVIEW);
}
    \end{lstlisting}
    Nachdem das Verhältnis von neuer Breite zu neuer Höhe berechnet wurde wird OpenGL
    mitgeteilt dass nachfolgende Transformationsoperationen auf der Projektionsmatrix
    ausgeführt werden sollen und diese mit einer Identitätsmatrix geladen.
    Hiernach wird der neue Viewport gesetzt und mit der GLU-Funktion gluPerspective
    die Projektionsmatrix gesetzt. Danach wird der Matrixmodus zurückgesetzt.

    renderScene ist die Methode die jeden Frame aufgerufen wird um den Inhalt zu zeichnen.
    \begin{lstlisting}[name=init.cpp: renderScene]
void renderScene() {
    // clear buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // load identity matrix into modelview matrix
    glLoadIdentity();
    // position camera
    gluLookAt(eye[0], eye[1], eye[2],
              cnt[0], cnt[1], cnt[2],
              0.0f,   1.0f,   0.0f);

    // init a light source
    glLightfv(GL_LIGHT0, GL_POSITION, l0pos);

    // draw the teapot
    glutSolidTeapot(1);

    // swap back and framebuffer
    glutSwapBuffers();
}
    \end{lstlisting}
    Zunächst wird der aktuelle Buffer geleert, dann wird die aktuelle (Modelview) Matrix
    mit der Identitätsmatrix überschrieben. Nun wird mittels der GLU-Funktion gluLookAt
    die Kamera positioniert, eine Lichtquelle gesetzt sowie die bekannte Teekanne gezeichnet.
    Zu guter Letzt werden die Buffer ausgetauscht.
  
    Nun wollen wir diese Funktionen zusammenführen:
    \begin{lstlisting}[name=main.cpp]
int main(int argc, char *argv[]) {

    // initialize OpenGL
    initGL(argc, argv);

    // start main loop
    glutMainLoop();

    return EXIT_SUCCESS;
}
    \end{lstlisting} 
    Dies lässt sich nun sehr einfach bewerkstelligen: wir rufen die initGL Methode auf
    um OpenGL zu initialisieren, danach nutzen wir die GLut-Funktion glutMainLoop um
    in die Hauptschleife des Programms zu kommen.
    
    \begin{figure}
        \centering
        \includegraphics{images/prog1}
        \caption{Das erste OpenGL Programm}
        \label{fig:prog1}
    \end{figure}
