\chapter{GLSL}
    Auch für GLSL Shader muss der Programmcode um einige Funktionen erweitert werden:

    \section{GLSL Vertex Shader}
    GLSL Shader werden zwar nicht in Pseudo-Assembler sondern in einer Hochsprache
    verfasst, aber auch sie werden aus Textdateien geladen.
    
    Das Laden von GLSL-Shadern gestaltet sich etwas komplizierter als das Laden von
    ARB Vertex Programs:
    
    \begin{lstlisting}[name=shader.cpp - loadVertexShader]
// check for ARB_vertex_shader extension support
if (!GLEW_ARB_vertex_shader) {
    ERR("system doesn't support ARB_vertex_shader extension!");
}

// create handle
AVSHandle = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
// read program
char* pgmstr = readTextFile(fn);
const GLcharARB* pgms = pgmstr;

// generate shader source
glShaderSourceARB(AVSHandle, 1, &pgms, NULL);
// compile shader
glCompileShaderARB(AVSHandle);

// free text memory
delete[] pgmstr;
    \end{lstlisting}

    Nachdem wir überprüft haben ob der geladene OpenGL-Treiber die \emph{ARB\_vertex\_shader}
    Extension unterstützt wird ein Program-Handle vom Typ \emph{GLhandleARB} erzeugt, und zwar
    mittels \emph{glCreateShaderObjectARB}, welchem der Typ des zu erzeugenden Handles mitgegeben
    wird, in diesem Fall ein Vertex Shader Handle. Das eigentliche Laden der Textdatei gestaltet
    sich identisch zum Laden von ARB Shadern. Sobald der Shader-Source im Speicher ist wird 
    dieser mittels \emph{glShaderSourceARB} an das Handle gebunden und mittels \emph{glCompileShaderARB}
    kompiliert. Hiernach wird brav der Speicher für den Source wieder freigegeben.
    Zur Fehlerbehandlung später mehr.
    
    \section{GLSL Fragment Shader}
    Ähnlich wie bei ARB\_fragment\_programs ist auch bei ARB\_fragment\_shadern
    die Sprache und der Ladevorgang weitgehend identisch. Deswegen soll dem Leser auch 
    hier eine langwierige Erläuterung des hierzu notwendigen Sources erspart bleiben.

    \section{Datentypen und Variablen}
    GLSL bietet verschiedene Möglichkeiten Variablen zu definieren, diese können folgende Typen 
    annehmen:
    
        \subsection{Datentypen}
        Folgende simple Datentypen werden angeboten:
        \begin{itemize}
            \item float
            \item bool
            \item int
        \end{itemize}
        Diese Typen entsprechen den von OpenGL definierten Typen GLfloat, GLint und GLbool und 
        verhalten sich wie erwartet.

        Des weiteren können 2-, 3- oder 4-Komponentige Vektoren dieser Typen definiert werden:
        \begin{itemize}
            \item vec2, vec3, vec4
            \item bvec2, bvec3, bvec4
            \item ivec2, ivec3, ivec4
        \end{itemize}

        Quadratische Matrizen von Fließkommazahlen können in drei verschiedenen Größen definiert werden:
        \begin{itemize}
            \item mat2
            \item mat3
            \item mat4
        \end{itemize}

        Für den Umgang mit Texturen kann auf vier spezielle Typen zurückgegriffen werden:
        \begin{itemize}
            \item[sampler1D] - für eindimensionale Texturen
            \item[sampler2D] - für zweidimensionale Texturen
            \item[sampler3D] - für dreidimensionale Texturen
            \item[samplerCube] - für Cubemaps
        \end{itemize}

        Arrays werden in GLSL genau so definiert wie in C, können allerdings nicht bei der
        Deklaration initialisiert werden.

        Auch Strukturen können definiert werden, auch hier ist die Syntax mit der C-Syntax
        identisch:
        \begin{lstlisting}[name=Strukturen in GLSL Shadern]
struct foobar {
    float foo;
    vec3  bar;
};
        \end{lstlisting}

        \subsection{Variablen}
        \label{sec:vars}
        Einfache Variablen können wie gewohnt deklariert werden
        \begin{lstlisting}[name=einfache Variablen in GLSL]
float foo, bar;
int baz = 5;
bool bla = false;
        \end{lstlisting}

        Allerdings gibt es in GLSL - anders als zum Beispiel in C - keine automatischen
        Typecasts beim initialisieren von Variablen, stattdessen wird stark auf das
        Konzept von Konstruktoren zurückgegriffen, dem von C++ nicht unähnlich:
        \begin{lstlisting}[name=Strukturen in GLSL Shadern]
float a = 2;                // falsch - kein automatisches typecasting
int b = 2;                  // korrekt
float c = float(b);         // korrekt - c = 2.0f
vec2 d = vec2(.5f, 1.0f);   // korrekt
vec3 e = (d, c);            // korrekt
        \end{lstlisting}

        Wie leicht zu sehen ist gibt es eine weite Reihe von Konstruktoren, dies gilt insbesondere 
        für Matrizen. Diese sollen allerdings an dieser Stelle nicht alle aufgeführt werden. 

        Für Variablen gibt es außerdem einige Qualifier die hier kurz erläutert werden sollen:

        \begin{itemize}
            \item[const] - Kompilierzeitkonstante, kann nicht geändert werden
            \item[uniform] - globale Variable welche von der Applikation an den Shader übergeben wird,
                kann in Vertex und Fragment Shadern gelesen, aber nicht geschrieben werden.
            \item[attribute] - globale Variable welche von OpenGL an den Vertex Shader übergeben wird,
                kann nur in Vertex Shadern gelesen, aber nicht verändert werden.
            \item[varying] - Variable zum Austausch interpolierter Daten vom Vertex Shader zum
                Fragment Shader. 
        \end{itemize}

    \section{Praxis: Linken von GLSL Programmen}
    Im Gegensatz zu ARB Programs müssen die Handles von GLSL Shadern nach dem kompilieren
    gelinkt werden, und zwar zu einem weiteren \emph{GLhandleARB}, dem eigentlichen Programm
    welches dann auf der Grafikkarte ausgeführt werden kann. Dies geschieht in einer eigenen
    Funktion - \emph{linkShaders} - welche nach dem Laden der Shader aufgerufen wird:
    
    \begin{lstlisting}[name=shader.cpp - linkShaders]
// genarate shader program handle
if (AVSHandle || AFSHandle)
    ShaderHandle = glCreateProgramObjectARB();
// attach vertex shader
if (AVSHandle)
    glAttachObjectARB(ShaderHandle, AVSHandle);
// attach fragment shader
if (AFSHandle)
    glAttachObjectARB(ShaderHandle, AFSHandle);
// link program
glLinkProgramARB(ShaderHandle);

// print info logs
printInfoLog(AVSHandle);
printInfoLog(AFSHandle);
printInfoLog(ShaderHandle);
    \end{lstlisting}

    Sobald festgestellt wurde dass zumindest ein GLSL Shader geladen wurde wird - diesmal
    mittels \emph{glCreateProgramObjectARB} ein Handle erstellt, an welches mit der Funktion
    \emph{glAttachObjectARB} die jeweiligen Shader gebunden werden. Schließlich wird mit
    \emph{glLinkProgramARB} das Programm erzeugt. Anschließend wird mit der Funktion
    \emph{printInfoLog} zu jedem Handle das so genannte Info Log ausgegeben:

    \begin{lstlisting}[name=shader.cpp - printInfoLog]
void printInfoLog(GLhandleARB obj) {
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

    glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB,
            &infologLength);

    if (infologLength > 0) {
        infoLog = (char *)malloc(infologLength);
        glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
        LOG("Infolog for " << obj);
        printf("%s\n",infoLog);
        free(infoLog);
    }
}
    \end{lstlisting}

    Hier wird mittels der Funktion \emph{glGetObjectParameterivARB} zum übergebenen
    Handle die Länge des entstandenen Info Logs ermittelt. Dann wird Speicher dafür
    reserviert und das Log mit \emph{glGetInfoLogARB} in diesen geschrieben. Nachdem
    das Log ausgegeben wurde wird der reservierte Speicher wieder freigegeben.

    \section{Binden von GLSL Shadern}
    Schließlich müssen wir noch dafür sorgen dass unsere GLSL Shader auch
    angewandt werden. Hierzu müssen wir lediglich die Funktion \emph{bindShaders}
    anpassen:

    \begin{lstlisting}[name=shader.cpp: bindShaders]
void bindShaders() {
    // bind and enable ARB_vertex_shader?
    if (AVPLoaded) {
        glBindProgramARB(GL_VERTEX_PROGRAM_ARB, AVPHandle);
        glEnable(GL_VERTEX_PROGRAM_ARB);
    }
    // bind and enable ARB_fragment_shader?
    if (AFPLoaded) {
        glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, AFPHandle);
        glEnable(GL_FRAGMENT_PROGRAM_ARB);
    }
    
    // use GLSL?
    if (ShaderHandle)
        glUseProgramObjectARB(ShaderHandle);
                
}
    \end{lstlisting}

    Hier wurde lediglich der letzte Block hinzugefügt welcher, nachdem überprüft wurde
    ob ein gültiges Program Handle vorliegt, mittels der Funktion \emph{glUseProgramObjectARB}
    OpenGL anweist dieses auf den aktuellen Stream anzuwenden.
    
    \section{Kommunikation Applikation und Shader}
    \label{sec:glslcom}
    GLSL bietet der Applikation mehrere Möglichkeiten mit dem Shader zu kommunizieren, allerdings
    ist dies immer eine ein-Weg-Kommunikation, der Shader kann also keine Berechnungen an die 
    Applikation zurückgeben. Natürlich gibt es hier Ausnahmen - so gibt es zum Beispiel durchaus 
    Kanäle zum Debuggen - auf diese soll aber im Rahmen dieses Dokumentes nicht eingegangen werden.

    Die einfachste Möglichkeit aus der Applikation mit dem Shader zu kommunizieren ist einfach über
    den OpenGL-Kontext (state). Dieser steht dem Shader in vollem Umfang zur Verfügung, allerdings 
    ist das nicht immer der sinnvollste Weg, zudem der Kontext keine beliebigen Felder hat, und das
    missbrauchen von nicht benötigten Feldern des Kontextes würde wohl von den meisten 
    Programmierern aus äußerst unsauber empfunden werden.

    Glücklicherweise erlaubt GLSL die Definition von Benutzerdefinierten Variablen die die Applikation
    schreiben und auf diese Weise mit dem Shader kommunizieren kann. Hierzu werden zwei der Qualifier
    welche in \ref{sec:vars} beschrieben wurden verwendet, nämlich \emph{attribute} und \emph{uniform}.

    Uniform-Variablen zeichnen sich dadurch aus dass sie innerhalb eines Streams - sprich innerhalb
    eines \emph{glBegin()} und \emph{glEnd()} Blockes - nicht geändert werden können, dies impliziert
    auch dass sie nicht geeignet sind Vertexattribute zu beinhalten. Sie sind deshalb nur geeignet 
    Werte zu halten welche über einen Stream, eine komplette Szene oder gar einen kompletten Frame 
    konstant bleiben.

    Attribute-Variablen hingegen können jederzeit geändert werden, allerdings ist das natürlich
    kostspieliger da der geladene Treiber keinerlei Optimierungen der Stream-Daten vornehmen kann.
    Auch können sie nur innerhalb eines Vertex Shaders gelesen werden da sie sich auf 
    Vertex-Informationen beschränken und folglich im Fragment Shader nutzlos wären.
    
    Ein anderer Weg auf dem die Applikation mit dem Shader kommunizieren kann ist die benötigten
    Daten in Texturen zu laden, da diese nicht unbedingt als Bilddaten vom Shader interpretiert werden
    müssen. Tatsächlich kann man so sehr einfach verschiedene Effekte erzeugen, zum Beispiel kann ein
    Vertex Shader welcher die Bilddaten als Höheninformation interpretiert sehr einfach ein Heightfield
    darstellen, oder ein Fragment Shader kann die Textur als Bump- oder Normalmap interpretieren.
    
    \section{Praxis: Kommunikation Applikation und Shader}
    \label{sec:glslcomprax}
    
    Nun wollen wir wie in \ref{sec:glslcom} beschrieben eine Uniform-Variable von unserer Applikation
    an den Shader weitergeben. Dazu muss erst die Position der Variablen im Speicher gefunden werden,
    dabei müssen wir darauf achten dass dies erst geschieht nachdem wir den Shader übersetzt und
    gelinkt haben, bei einigen Treibern ist es sogar notwendig dass der Shader dazu gebunden ist.

    Ziel ist es dem Shader eine Variable vom Typ GLfloat zukommen zu lassen welche innerhalb einer 
    Sekunde von 0.0f auf 1.0f steigt um dann erneut bei 0.0f zu beginnen. So ist es dem Shader möglich
    sein Verhalten über die Zeit unabhängig von der Ablaufgeschwindigkeit der Applikation
    zu verändern.
    Zu diesem Zweck definieren wir eine neue Funktion - \emph{sendTime()} - und rufen diese
    in \emph{renderScene()} nach dem Binden der Shader mittels \emph{bindShaders} auf:
    
    \begin{lstlisting}[name=shader.cpp - sendTime]
    void sendTime() {
        // determine locate of uniform variable timeElapsed
        GLint loc = glGetUniformLocationARB(ShaderHandle, "timeElapsed");
        // some very basic error handling
        GLenum err = glGetError();
        if (err != GL_NO_ERROR)
            LOG("loc: " << loc << " err " << err << " " << gluErrorString(err));
        // calculate a float value between 0.0f and 1.0f 
        GLfloat sec = (GLfloat)((clock() % CLOCKS_PER_SEC))/CLOCKS_PER_SEC;
        // pass it to the shade
        glUniform1fARB(loc, sec);
    }
    \end{lstlisting}

    Die Variable welche wir dem Shader zur Verfügung stellen soll \emph{timeElapsed} heißen.
    Die Ermittlung der Position dieser Variablen geschieht mittels der Funktion \emph{glGetUniformLocationARB},
    welche ein Handle nimmt in welchem die Variable deklariert wurde und einen nullterminierten
    String der den Namen der Variablen enthält. Nach einiger - zugegebenermaßen sehr rudimentärer - 
    Fehlerbehandlung berechnen wir mittels der in \emph{time.h} definierten Funktion \emph{clock} den
    Wert welchen wir an den Shader übermitteln wollen und sende ihn schließlich mittels
    der Funktion \emph{glUniform1fARB} an den Shader.

    Auf diese und ähnlich Weise können auch andere Typen von Variablen gesetzt werden, das gezeigte
    soll aber an dieser Stelle ausreichen.
    
    
        
