\chapter{ARB Program Shader}
    Mit dem bis jetzt erläuterten Wissen ist es uns nun möglich
    die ersten Shader zu schreiben. Hierzu müssen wir unser
    Programm noch um einige Funktionen erweitern:

    \section{Praxis: Extensions mit GLew}
    Um Shader in OpenGL nutzen zu können sind vielfach Extensions
    nötig. Folglich ist es nötig die Fähigkeiten des Hostsystems
    zu testen. Hierzu wollen wir den GLew (\ref{glew}) nutzen, dazu
    erweitern wir die initGL Funktion um den einige Zeilen die der
    Initialisierung dienen:

    \begin{lstlisting}[name=init.cpp: initGL]
    // init GLew
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        ERR("glewInit returned err: " << glewGetErrorString(err));
    } else {
        LOG("using GLEW version: " << glewGetString(GLEW_VERSION));
    }
    \end{lstlisting}

    glewInit initialisiert den GLew, falls dieses fehlschlägt geben
    wir eine Fehlermeldung aus und beenden das Programm, ansonsten
    schreiben wir die GLew-Version auf die Konsole. Nun können wir
    testen ob das Hostsystem die für uns interessanten Extensions 
    unterstützt. Dazu bietet der GLew eine Vielzahl von Möglichkeiten,
    unter anderem definiert er für jede Extension ein Makro das einfach
    auf Wahrheit getestet werden kann, mehr dazu später.

    \section{Praxis: Laden von Shadern}
    Unser Programm soll zur Laufzeit beliebige Shader aus Textdateien laden
    können um nicht jedes mal wenn wir einen Shader ändern unser Programm
    neu compilieren zu müssen. Hierzu definieren wir eine Funktion die
    den Dateinamen des zu ladenden Shaders in einem std::string entgegen nimmt 
    und einen char* zurückgeliefert der den Inhalt der Textdatei enthält.
    \begin{lstlisting}[name=textfile.h]
char* readTextFile(const std::string& fn);
    \end{lstlisting}
    Die Einzelheiten der Implementation sollen dem Leser hier erspart werden,
    sie befindet sich in der Datei textfile.cpp.

    Die Endung der zu ladenden Textdateien haben keinerlei inhärente Bedeutung,
    wir werden uns für dieses Dokument auf folgende Erweiterungen einigen:

    \begin{description}
        \item{.avp} - ARB Vertex Program
        \item{.afp} - ARB Fragment Program
        \item{.avs} - ARB Vertex Shader (GLSL)
        \item{.afs} - ARB Fragment Shader (GLSL)
    \end{description}

    Nun definieren wir eine weitere Funktion welche das eigentlich Laden der Shader
    übernehmen soll.
    \begin{lstlisting}[name=shader.h: loadShader]
void loadShader(const std::string& fn);
    \end{lstlisting}
    Diese Funktion nimmt einen std::string entgegen der den Dateinamen enthält,
    versucht die Endung der Datei zu finden und ruft dann die entsprechende
    Funktion zum Laden des Shaders auf. Auch hier werden wir die Implementationsdetails
    nicht erörtern, der geneigte Leser mag sie in der Datei shader.cpp nachlesen.
    
    \section{ARB Vertex Programs}
    Wie bereits erwähnt nutzt die ARB\_vertex\_program-Extension eine Art
    Assemblersprache, welche in der Spezifikation (auffindbar in der
    Extension Registry \cite{extreg}) definiert wird.

    Um ARB Vertex Programs zu laden wird - wie bereits oben beschrieben - innerhalb
    von \emph{loadShader()} die Funktion \emph{loadVertexProgram()} aufgerufen:
    
    \begin{lstlisting}[name=shader.cpp: loadShader]
// check for ARB_vertex_program extension support
if (!GLEW_ARB_vertex_program) {
    ERR("system doesn't support ARB_vertex_program extension!");
}

char* pgmstr = readTextFile(fn);
unsigned int program;
// bind shader
glGenProgramsARB(1, &program);
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, program);
// load shader
glProgramStringARB(GL_VERTEX_PROGRAM_ARB,
                   GL_PROGRAM_FORMAT_ASCII_ARB,
                   strlen(pgmstr),
                   pgmstr);
// check for errors
if (glGetError() == GL_INVALID_OPERATION) {
    int errorpos;
    const char* errorstr;

    glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
    errorstr = (const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);

    ERR("error while loading ARB_vertex_program from " << fn << " at pos " << errorpos << endl << errorstr);
}

// save handle
AVPHandle = program;
AVPLoaded = true;

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

    Zunächst wird mittels des von GLew gesetzten Makros überprüft ob die Extension
    \emph{ARB\_vertex\_program} unterstützt wird. Danach wird der Shader in ein char-Array
    geladen und auf dem Stack Platz für einen unsigned int geschaffen, welcher mittels
    \emph{glGenProgramsARB} zum Speichern eines Handles für das zu ladende Programm verwandt
    wird. \emph{glBindProgramARB} bewirkt dass das soeben generierte Programm gebunden wird, ähnlich
    wie bei Texturen. Schließlich wird der Shader mittels \emph{glProgramStringARB} geladen, und zwar
    in das gerade gebundene Handle.

    Mittels \emph{glGetError} wird nun geprüft ob beim Laden ein Fehler auftrat, sollte das der
    Fall sein wird der Fehlerstring ausgelesen, ausgegeben und die Anwendung etwas unsanft beendet.

    \section{ARB Fragment Programs}
    Die Assemblersprache der ARB\_fragment\_program-Extension ist in weiten Teilen
    Identisch zu der der ARB\_vertex\_program-Extension.

    Auch das Laden von ARB Fragment Programs läuft nahezu identisch ab, weswegen an dieser Stelle
    kein Sourcecode gezeigt werden soll. Es werden lediglich einige OpenGL-Konstanten verändert,
    genaueres kann in der Datei shader.cpp nachgelesen werden.
    
    \section{Praxis: Binden von Shadern}
    Um ARB Shader auch nutzen zu können ist es nötig OpenGL mitzuteilen welche Shader auf den
    aktuellen Stream angewandt werden sollen. Dies geschieht ganz ähnlich dazu wie man Texturen
    bindet. Hierzu definieren wir eine weitere Funktion, \emph{bindShaders()}:

    \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);
    }

}
    \end{lstlisting}
    In dieser wird geprüft ob Vertex- oder Fragment- Programs geladen sind und je nach Ergebnis
    werden \emph{glBindProgramARB} und \emph{glEnable} mit den jeweiligen Parametern
    aufgerufen. Diese Funktion rufen wir nun innerhalb von \emph{renderScene()} aufgerufen, und
    zwar bevor wir den teapot zeichnen.


