Problem with rendering a cube

OpenGL: Basic Coding

I’ve just started writing my own game engine in C and I’m stuck in the beginning with rendering a cube.

The problem is that the front face of the cube renders at the back of the back face of the cube. (See image below)

Here is the source code (main.c):

#include <stdio.h>

#include "glad/glad.h"
#include "GLFW/glfw3.h"

#include "quantum/QUANTUM_utils.h"
#include "quantum/gfx/QUANTUM_shader.h"
#include "quantum/gfx/QUANTUM_texture.h"

#include "quantum/gfx/objects/QUANTUM_VAO.h"
#include "quantum/gfx/objects/QUANTUM_VBO.h"
#include "quantum/gfx/objects/QUANTUM_EBO.h"

#include "quantum/math/QUANTUM_math.h"

#define QUANTUM_WND_W 1720.0f
#define QUANTUM_WND_H 880.0f
#define QUANTUM_WND_X 100.0f
#define QUANTUM_WND_Y 100.0f

#define QUANTUM_WND_TITLE "Quantum Engine"

#define QUANTUM_OPENGL_VERSION_MAJOR 4
#define QUANTUM_OPENGL_VERSION_MINOR 6

#define QUANTUM_WIREFRAME_RENDERER 0

static void error_callback(GLint error, const GLchar *description) {
    fprintf(stderr, "Error, %i: %s", error, description);
}

static void framebuffer_callback(__attribute__((unused)) GLFWwindow *window, GLint width, GLint height) {
    glViewport(0, 0, width, height);
}

int main() {
    glfwSetErrorCallback(error_callback);

    if (!glfwInit()) {
        QUANTUM_LOG_ERROR("GLFW initialization failed\n");
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, QUANTUM_OPENGL_VERSION_MAJOR);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, QUANTUM_OPENGL_VERSION_MINOR);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *window = glfwCreateWindow(QUANTUM_WND_W, QUANTUM_WND_H, QUANTUM_WND_TITLE, NULL, NULL);

    if (!window) {
        QUANTUM_LOG_ERROR("GLFW window initialization failed\n");
        return -2;
    }

    glfwMakeContextCurrent(window);

    glfwSetWindowPos(window, QUANTUM_WND_X, QUANTUM_WND_Y);

    glfwSetFramebufferSizeCallback(window, framebuffer_callback);

    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        QUANTUM_LOG_ERROR("GLAD initialization failed\n");
        glfwTerminate();
        return -3;
    }

    glEnable(GL_DEPTH_TEST);

    QUANTUM_shader shader = QUANTUM_shader_create("vertex.vert", "fragment.frag");
    QUANTUM_shader_compile(&shader);

    GLfloat vertices[] = {
            /* @formatter:off */

            /* Positions */         /* UV */

            /* Back */
            -0.5f, -0.5f, -0.5f,    0.0f, 0.0f,
             0.5f, -0.5f, -0.5f,    1.0f, 0.0f,
             0.5f,  0.5f, -0.5f,    1.0f, 1.0f,
             0.5f,  0.5f, -0.5f,    1.0f, 1.0f,
            -0.5f,  0.5f, -0.5f,    0.0f, 1.0f,
            -0.5f, -0.5f, -0.5f,    0.0f, 0.0f,

            /* Front */
            -0.5f, -0.5f,  0.5f,    0.0f, 0.0f,
             0.5f, -0.5f,  0.5f,    1.0f, 0.0f,
             0.5f,  0.5f,  0.5f,    1.0f, 1.0f,
             0.5f,  0.5f,  0.5f,    1.0f, 1.0f,
            -0.5f,  0.5f,  0.5f,    0.0f, 1.0f,
            -0.5f, -0.5f,  0.5f,    0.0f, 0.0f,

            /* Left */
            -0.5f,  0.5f,  0.5f,    1.0f, 0.0f,
            -0.5f,  0.5f, -0.5f,    1.0f, 1.0f,
            -0.5f, -0.5f, -0.5f,    0.0f, 1.0f,
            -0.5f, -0.5f, -0.5f,    0.0f, 1.0f,
            -0.5f, -0.5f,  0.5f,    0.0f, 0.0f,
            -0.5f,  0.5f,  0.5f,    1.0f, 0.0f,

            /* Right */
             0.5f,  0.5f,  0.5f,    1.0f, 0.0f,
             0.5f,  0.5f, -0.5f,    1.0f, 1.0f,
             0.5f, -0.5f, -0.5f,    0.0f, 1.0f,
             0.5f, -0.5f, -0.5f,    0.0f, 1.0f,
             0.5f, -0.5f,  0.5f,    0.0f, 0.0f,
             0.5f,  0.5f,  0.5f,    1.0f, 0.0f,

             /* Down */
            -0.5f, -0.5f, -0.5f,    0.0f, 1.0f,
             0.5f, -0.5f, -0.5f,    1.0f, 1.0f,
             0.5f, -0.5f,  0.5f,    1.0f, 0.0f,
             0.5f, -0.5f,  0.5f,    1.0f, 0.0f,
            -0.5f, -0.5f,  0.5f,    0.0f, 0.0f,
            -0.5f, -0.5f, -0.5f,    0.0f, 1.0f,

            /* Up */
            -0.5f,  0.5f, -0.5f,    0.0f, 1.0f,
             0.5f,  0.5f, -0.5f,    1.0f, 1.0f,
             0.5f,  0.5f,  0.5f,    1.0f, 0.0f,
             0.5f,  0.5f,  0.5f,    1.0f, 0.0f,
            -0.5f,  0.5f,  0.5f,    0.0f, 0.0f,
            -0.5f,  0.5f, -0.5f,    0.0f, 1.0f

            /* @formatter:on */
    };

    QUANTUM_VAO VAO = QUANTUM_VAO_create(false);
    QUANTUM_VBO VBO = QUANTUM_VBO_create(false);

    QUANTUM_VAO_bind(&VAO);

    QUANTUM_VBO_bind(&VBO);
    QUANTUM_VBO_upload(&VBO, sizeof(vertices), vertices);

    QUANTUM_VAO_attrib(&VAO, 0, 3, GL_FLOAT, 5 * sizeof(GLfloat), 0);
    QUANTUM_VAO_attrib(&VAO, 1, 2, GL_FLOAT, 5 * sizeof(GLfloat), 3 * sizeof(GLfloat));

    QUANTUM_VAO_unbind(&VAO);

    QUANTUM_VBO_unbind(&VBO);

    QUANTUM_texture texture = QUANTUM_texture_create("cat.png");

#if QUANTUM_WIREFRAME_RENDERER > 0
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#endif

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();

        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        GLint width = 0, height = 0;
        glfwGetWindowSize(window, &width, &height);

        QUANTUM_texture_bind(&texture);
        QUANTUM_shader_bind(&shader);

        QUANTUM_mat4x4f model = QUANTUM_mat4x4f_create_identity_matrix();
        QUANTUM_mat4x4f view = QUANTUM_mat4x4f_create_identity_matrix();
        QUANTUM_mat4x4f projection = QUANTUM_mat4x4f_create_identity_matrix();

        view = QUANTUM_mat4x4f_translate(&view, QUANTUM_vec3f_new(0.0f, 0.0f, -3.0f));
        projection = QUANTUM_mat4x4f_perspective(RAD(45.0f), (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);

        QUANTUM_shader_uniform_mat4x4f(&shader, "u_model", &model);
        QUANTUM_shader_uniform_mat4x4f(&shader, "u_view", &view);
        QUANTUM_shader_uniform_mat4x4f(&shader, "u_projection", &projection);

        QUANTUM_VAO_bind(&VAO);
        glDrawArrays(GL_TRIANGLES, 0, (sizeof(vertices) / sizeof(GLfloat)) / 5);

        glfwSwapBuffers(window);
    }

    QUANTUM_shader_delete(&shader);

    QUANTUM_VAO_delete(&VAO);
    QUANTUM_VBO_delete(&VBO);

    glfwTerminate();

    return 0;
}

I think there is no logic errors. When I was googling about this problem, I found that I should enable depth test, however it is enabled in my program.

Here is my matrix perspective function:

QUANTUM_mat4x4f QUANTUM_mat4x4f_perspective(GLfloat fov, GLfloat aspect, GLfloat far, GLfloat near) {
   return (QUANTUM_mat4x4f) {
           1.0f / (aspect * tanf(fov * 0.5f)), 0, 0, 0,
           0, 1.0f / (tanf(fov * 0.5f)), 0, 0,
           0, 0, -(far + near) / (far - near), -(2 * far * near) / (far - near),
           0, 0, -1, 0
   };
}

And if you need, here is matrix struct defenition:

typedef struct QUANTUM_mat4x4f {
    GLfloat mat[4][4];
} QUANTUM_mat4x4f;

Here are my shader programs, in case there’s something wrong with them, but I don’t think so.

Vertex:

#version 460 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 uv;

out vec2 v_uv;

uniform mat4x4 u_model, u_view, u_projection;

void main() {
    gl_Position = u_projection * u_view * u_model * vec4(position, 1.0f);

    v_uv = uv;
}

Fragment:

#version 460 core

out vec4 frag_color;

in vec2 v_uv;

uniform sampler2D u_texture;

void main() {
    frag_color = texture(u_texture, v_uv);
}

P.S Sorry for my english, I’m not a native speaker.