Um Echtzeitgrafik anzuzeigen muss der Computer viele Einzelbilder generieren und in schneller Folge anzeigen. Würde man dafür ein einfaches while(true) verwenden, wäre die Anwendung vollkommen ausgelastet und nicht mehr in der Lage beispielsweise auf Maus oder Tastatur zu reagieren.

Aus diesem Grunde implementiert man einen sogeannnen Message loop. Unsere Anwendung wird in einer Endlosschleife immer wechselseitig ein Bild rendern und dann beim Betriebssystem nachfragen ob eine Nachricht vorliegt. Eine solche Nachricht könnte z.B. sein “Benutzer möchte Fenster maximieren”. Solange Nachrichten vorliegen werden diese abgearbeitet und anschließend ein weiteres Bild gezeichnet.

Translation Units in C

Wir wollen alle Grafikfunktionen kapseln. Da wir unter C aber keine Klassen haben, müssen wir auf sog. Translation Units ausweichen. Diese “Übersetzungseinheiten” sind das was man einem Kompiler gibt um eine Objektdatei zu erstellen. Das beinhaltet jeweils eine .c Datei sowie alle eingebundenen Header Dateien. Aktuell hat unser Programm genau eine Translation Unit: main.c

Wir erstellen nun eine zweite Quellcode Datei mit dem Namen graphics.c und die dazugehörige Header Datei graphics.h

Auf diese Weise können wir alle Grafikfunktionen in der Datei graphics.c implementieren. Die Headerdatei graphics.h wird benötigt, damit wir auf diese Funktionen aus der main.c zugreifen können.

Header Datei

Beginnen wir mit der Header Datei graphics.h

#include <GLFW/glfw3.h>

int startGraphics(int, int);

Eine Header Datei enthält alle Funktionssignaturen die wir gleich anschließend in der Quellcode Datei implementieren wollen.

Quellcode Datei

Hier nun die Implementierung der graphics.c

#include <stdio.h>
#include "graphics.h"


static GLFWwindow* window;

int startGraphics(int width, int height)
{
    glfwSetErrorCallback(errorCallback);
    
    if (!glfwInit())
    {
        printf("Error initilizing graphics.");
        return 1;
    }
    
    window = glfwCreateWindow(width, height, "Engine", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        printf("Error opening window.");
        return 1;
    }

    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, keyCallback);

    while (!glfwWindowShouldClose(window))
    {
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

Graphics aufrufen

Aktuell gibt unser Programm noch Hello World aus. Damit es nun Gebrauch von den Grafikfunktionen machen kann müssen wir entsprechende Anpassungen in der main.c vornehmen:

#include <stdio.h>
#include "graphics.h"

int main(void)
{
    printf("Engine starting...\n");

    int result = startGraphics(1280, 720);
    
    printf("Engine terminated.\n");

    return result;
}

Makefile anpassen

Unser makefile benötigt zwei Anpassungen. Wir müssen eine neue Regel für die Translation Unit graphics.o hinzufügen. Idealerweise steht das bei Ihnen direkt unter dem Eintrag für die main.o. Und außerdem müssen wir die graphics.o auch als Abhängigkeit für unsere Hauptregel hinzufügen.

bin/engine: obj/main.o obj/graphics.o bin
	gcc -g obj/*.o -o bin/engine $(LIB) $(LNK) $(OPT)

obj/main.o: main.c obj
	gcc -g -c main.c -o obj/main.o $(INC) $(OPT)

obj/graphics.o: graphics.c obj
	gcc -g -c graphics.c -o obj/graphics.o $(INC) $(OPT)

Wenn wir zukünftig weitere Translation Units zu unserem Projekt hinzufügen, dann wissen Sie nun, wie Sie diese im Makefile einbinden.

Starten Sie die Anwendung und prüfen Sie ob sich ein Fenster öffnet und ob es sich ohne Probleme schließen lässt.