Bisher ist die Implementierung unserer Szene recht einfach gehalten. Insbesondere wird die Größe des Viewports aktuell bei jedem Frame erneut berechnet. Das wollen wir nun etwas sinnvoller gestalten.

Wir ersetzen daher in unserer scene.h die bisherigen Funktionen durch diese neuen:

void loadScene(GLFWwindow* window);
void renderScene();
void unloadScene();

Auf diese Weise können wir unseren Codefluss so abändern, dass beim Starten der App die Szene mit allen Modellen geladen und der Viewport festgelegt wird, und wenn die App beendet wird, alle Ressourcen wieder freigegeben werden.

Hier die Implementierung dieser drei Methoden für den Moment:

void loadScene(GLFWwindow* window)
{
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);
    loadCameraProjectionMatrix((float)(width / height));

    glClearColor(0.29f,0.36f,0.4f,1.0f);
}
void renderScene()
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    loadCameraViewMatrix();

    glBegin(GL_QUADS);
    glColor3f(0.5f, 0.73f, 0.14f);
    glVertex3f(-0.6f, 0.0f, 0.0f);
    glVertex3f(0.0f, -0.6f, 0.0f);
    glVertex3f(0.6f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.6f, 0.0f);
    glEnd();
}
void unloadScene()
{
    //bisher leer
}

Integration in bisherigen Code

Ihr Renderloop in der graphics.c sollte nun in etwa so aussehen:

loadScene(window);
while (!glfwWindowShouldClose(window))
{
    renderScene();
    glfwSwapBuffers(window);
    glfwPollEvents();
    printFps();
}
unloadScene();

Testen Sie ob immer noch alles funktioniert.

Auf Änderung der Fenstergröße reagieren

Sie werden bemerken, dass diese Änderungen dazu führen, dass der Viewport nicht mehr korrekt skaliert wird, wenn Sie die Fenstergröße nachträglich ändern. Beispielsweise beim Drücken der M Taste um das Fenster zu maximieren.

Um automatisch auf diese Änderung zu reagieren, registrieren wir ein weiteres Callback in der graphics.c:

glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);

Außerdem definieren wir oben in der selben Datei eine statische Variable in der wir uns merken ob es zu einer Änderung der Fenstergröße gekommen ist.

static int resized = 0;

Und hier die Implementierung des Callbacks:

static void framebufferSizeCallback(GLFWwindow* window, int width, int height)
{
    resized = 1;
}

Denken Sie daran, dass Sie das Callback auch wieder in der Header Datei definieren. Sobald es nun zu einer Änderung des Fenstergröße und damit zu einer Änderung des Framebuffers kommt, wird dieses Callback aufgerufen und das resized-flag auf 1 gesetzt. Das ist wichtig, da wir nicht einfach direkt unseren Viewport verändern können während unsere Anwendung gerade ein Bild rendert. Wir müssen stattdessen warten bis unser Frame fertig gezeichnet wurde und danach die Änderung vornehmen.

Wir passen daher abermals unseren Loop an:

loadScene(window);
while (!glfwWindowShouldClose(window))
{
    renderScene();
    glfwSwapBuffers(window);
    glfwPollEvents();
    printFps();
    if (resized)
    {
        resized = 0;
        setViewportSize(window);
    }
}
unloadScene();

Nun müssen wir diese Änderungen natürlich auch in der Scene umsetzen:

void loadScene(GLFWwindow* window)
{
    setViewportSize(window);

    glClearColor(0.29f,0.36f,0.4f,1.0f);
}
void setViewportSize(GLFWwindow* window)
{
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);
    loadCameraProjectionMatrix((float)width / (float) height);
}

Denken Sie auch hier daran, die neue Funktion setViewportSize in den Header aufzunehmen.

Finaler Test

Nun sollte alles wieder wie gewohnt funktionieren und der Viewport sollte korrekt skaliert sein.