Cannot render Mesh

Hello OpenGL Community,

I am currently working on my first OpenGL project where i am rendering a rectangle using a mesh class to encapsulate the vertex and index data, as well as handle rendering. However, I’ve encountered an issue where the mesh object does not render, and I’m receiving a GL_INVALID_ENUM (1280) error in my shader’s use() method.

Problem Description
When trying to render the mesh object, I get the following OpenGL error:

OpenGL Error in shader::use(): 1280
OpenGL Error in render: 1282

The 1280 error occurs before the glDrawElements call, indicating that the problem lies somewhere in the preparation phase of rendering. the 1282 error occurs after glDrawElements.

What I Have Tried
I can render a VAO directly in the main function using the same shader, and it works without any problems. This leads me to believe that the issue is within my mesh class implementation.

Vertex and Index Data
Here is the vertex and index data I am using:

Vertex Data:

Vertex 0: Position(-0.5, 0.5, 0) Color(1, 0, 0) TexCoord(0, 1) Normal(0, 0, 1)
Vertex 1: Position(-0.5, -0.5, 0) Color(0, 1, 0) TexCoord(0, 0) Normal(0, 0, 1)
Vertex 2: Position(0.5, -0.5, 0) Color(0, 0, 1) TexCoord(1, 0) Normal(0, 0, 1)
Vertex 3: Position(0.5, 0.5, 0) Color(1, 1, 0) TexCoord(1, 1) Normal(0, 0, 1)

Index Data:

Index 0: 0
Index 1: 1
Index 2: 2
Index 3: 0
Index 4: 2
Index 5: 3

Relevant Code Snippets

Mesh Class Definition:

mesh.h:

#include <iostream>
#include <vector>

#include "../headers/vertex.hpp"
#include "../headers/shader.hpp"
#include "../headers/material.hpp"
#include "../headers/texture.hpp"

using namespace std;

class mesh
{
private:
    unsigned m_nr_of_vertices;
    unsigned m_nr_of_indices;

    GLuint m_VAO;
    GLuint m_VBO;
    GLuint m_EBO;

    glm::vec3 m_position;
    glm::vec3 m_rotation;
    glm::vec3 m_scale;
    glm::mat4 m_model_matrix;

    // Private functions
    void init_VAO(Vertex* vertex_array, const unsigned& nr_of_vertices, GLuint* index_array, const unsigned& nr_of_indices);
    void update_uniform(shader* shader);
    void update_model_matrix();

public:
    mesh(Vertex* vertex_array, const unsigned& nr_of_vertices, GLuint* index_array, const unsigned& nr_of_indices,
            glm::vec3 position = glm::vec3(0.f), glm::vec3 rotation = glm::vec3(0.f), glm::vec3 scale = glm::vec3(1.f));
    ~mesh();

    // Accessors

    // Modifiers
    void set_position(glm::vec3 new_position);
    void set_rotation(glm::vec3 new_rotation);
    void set_scale(glm::vec3 new_scale);

    // Public functions
    void move(glm::vec3 new_direction);
    void rotate(glm::vec3 new_direction);
    void scale(glm::vec3 new_direction);

    void update();
    void render(shader* shader);
};

mesh.cpp:

#include "../headers/mesh.hpp"

// ! Con- / Destructor
mesh::mesh(Vertex* vertex_array, const unsigned& nr_of_vertices, GLuint* index_array, const unsigned& nr_of_indices,
            glm::vec3 position, glm::vec3 rotation, glm::vec3 scale)
: m_position(position), m_rotation(rotation), m_scale(scale)
{
    init_VAO(vertex_array, nr_of_vertices, index_array, nr_of_indices);
    update_model_matrix();
}

mesh::~mesh()
{
    glDeleteVertexArrays(1, &m_VAO);
    glDeleteBuffers(1, &m_VBO);
    glDeleteBuffers(1, &m_EBO);
}

// ! Accessors


// ! Modifers
void mesh::set_position(glm::vec3 new_position)
{
    m_position = new_position;
}

void mesh::set_rotation(glm::vec3 new_rotation)
{
    m_rotation = new_rotation;
}

void mesh::set_scale(glm::vec3 new_scale)
{
    m_scale = new_scale;
}

// ! Public functions
void mesh::move(glm::vec3 new_direction)
{
    m_position += new_direction;
}

void mesh::rotate(glm::vec3 new_direction)
{
    m_rotation += new_direction;
}

void mesh::scale(glm::vec3 new_direction)
{
    m_scale += new_direction;
}

void mesh::update()
{

}

void mesh::render(shader* shader)
{
    update_model_matrix();
    update_uniform(shader);

    shader->use();

    // Bind vertex array object
    glBindVertexArray(m_VAO);
    // Debugging: Check for OpenGL errors
    GLenum error2 = glGetError();
    if (error2 != GL_NO_ERROR) {
        std::cerr << "OpenGL Error in render: " << error2 << std::endl;
    } 

    // Draw
    glDrawElements(GL_TRIANGLES, m_nr_of_indices, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

}

// ! Private functions
void mesh::init_VAO(Vertex* vertex_array, const unsigned& nr_of_vertices, GLuint* index_array, const unsigned& nr_of_indices)
{
    // Init variables
    m_nr_of_vertices = nr_of_vertices;
    m_nr_of_indices = nr_of_indices;

    // VAO
    glGenVertexArrays(1, &m_VAO);
    glBindVertexArray(m_VAO);

    // VBO
    glGenBuffers(1, &m_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, m_nr_of_vertices * sizeof(Vertex), vertex_array, GL_STATIC_DRAW);
  
    // EBO
    glGenBuffers(1, &m_EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);                 // Binding means seting it to active
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_nr_of_indices * sizeof(GLuint), index_array, GL_STATIC_DRAW);

    // Set the VertexAttributPointers and enable (Input assembly)
    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::position));       // 0 = location / amount of floats / type / not normed / stride step to the next vertex / offset of pos
    glEnableVertexAttribArray(0);   // 0 = Location
    // Color
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::color));          // 0 = location / amount of floats / type / not normed / stride step to the next vertex / offset of color
    glEnableVertexAttribArray(1);   // 1 = Location
    // Texcoords 
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::texCoord));       // 0 = location / amount of floats / type / not normed / stride step to the next vertex / offset texcoords
    glEnableVertexAttribArray(2);   // 2 = Location
    // normal
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::normal));       // 0 = location / amount of floats / type / not normed / stride step to the next vertex / offset texcoords
    glEnableVertexAttribArray(3);

    // Bind VAO 0
    glBindVertexArray(0);

    // Debugging: Check for OpenGL errors
    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        std::cerr << "OpenGL Error in init_VAO: " << error << std::endl;
    }
}

void mesh::update_uniform(shader* shader)
{
    shader->setMat4fv(m_model_matrix, "modelMatrix");
}

void mesh::update_model_matrix()
{
    m_model_matrix = glm::mat4(1.f);
    m_model_matrix = glm::translate(m_model_matrix, m_position);
    m_model_matrix = glm::rotate(m_model_matrix, glm::radians(m_rotation.x), glm::vec3(1.f, 0.f, 0.f));
    m_model_matrix = glm::rotate(m_model_matrix, glm::radians(m_rotation.y), glm::vec3(0.f, 1.f, 0.f));
    m_model_matrix = glm::rotate(m_model_matrix, glm::radians(m_rotation.z), glm::vec3(0.f, 0.f, 1.f));
    m_model_matrix = glm::scale(m_model_matrix, m_scale);
}

shader.cpp

#include "shader.hpp"

// ! Constructor / Destructor
shader::shader(const char* vertexFile, const char* fragmentFile, const char* geometryFile)
{
    GLuint vertexShader = 0;
    GLuint geometryShader = 0;
    GLuint fragmentShader = 0;

    vertexShader = loadShader(GL_VERTEX_SHADER, vertexFile);
    if (vertexShader == 0) return;  // Check for shader compilation error

    // if (geometryFile != "")
    // {
    //     geometryShader = loadShader(GL_GEOMETRY_SHADER, geometryFile);
    //     if (geometryShader == 0) return;  // Check for shader compilation error
    // }

    fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentFile);
    if (fragmentShader == 0) return;  // Check for shader compilation error

    linkProgram(vertexShader, geometryShader, fragmentShader);

    // Clean up shaders (they are no longer needed once linked into a program) and deactivate the program
    glDeleteShader(vertexShader);
    // if (geometryFile != "")
    //     glDeleteShader(geometryShader);
    glDeleteShader(fragmentShader);
}

shader::~shader()
{
    glDeleteProgram(m_id);
}

// ! Public functions
// Sets the shader program as active program
void shader::use()
{
    glUseProgram(m_id);
    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        std::cerr << "OpenGL Error in shader::use(): " << error << std::endl;
    }
}

// Sets 0 as active program (a program has always an id bigger than 0) and deactivates the shader program
void shader::unUse()
{
    glUseProgram(0);
}

// * Setter
// Sets 1 int for uniform / texture
void shader::set1i(GLint value, GLchar* name)
{
    use();
    glUniform1i(glGetUniformLocation(m_id, name), value);
    unUse();
}

// Sets 1 float for uniform
void shader::set1f(GLfloat value, GLchar* name)
{
    use();
    glUniform1f(glGetUniformLocation(m_id, name), value);
    unUse();
}

// Sets the vec 2 floats for uniform
void shader::setVec2f(glm::fvec2 value, GLchar* name)
{
    use();
    glUniform2fv(glGetUniformLocation(m_id, name), 1, glm::value_ptr(value));
    unUse();
}

// Sets the vec 3 floats for uniform
void shader::setVec3f(glm::fvec3 value, GLchar* name)
{
    use();
    glUniform3fv(glGetUniformLocation(m_id, name), 1, glm::value_ptr(value));
    unUse();
}

// Sets the vec 4 floats for uniform
void shader::setVec4f(glm::fvec4 value, GLchar* name)
{
    use();
    glUniform4fv(glGetUniformLocation(m_id, name), 1, glm::value_ptr(value));
    unUse();
}

// Sets the mat3 for uniform
void shader::setMat3fv(glm::mat3 value, GLchar* name, GLboolean transpose)
{
    use();
    glUniformMatrix3fv(glGetUniformLocation(m_id, name), 1, transpose, glm::value_ptr(value));
    unUse();
}

// Sets the mat4 for uniform
void shader::setMat4fv(glm::mat4 value, GLchar* name, GLboolean transpose)
{
    use();
    glUniformMatrix4fv(glGetUniformLocation(m_id, name), 1, transpose, glm::value_ptr(value));
    unUse();
}

// ! Private functions
std::string shader::loadShaderSource(const char* fileName)
{
    std::string temp = "";
    std::string src = "";
    std::ifstream inFile;

    // Vertex shader
    inFile.open(fileName);

    if (inFile.is_open())
    {
        while (std::getline(inFile, temp))
            src += temp + "\n";
        inFile.close();
    }
    else
    {
        std::cout << "ERROR::SHADER::COULD_NOT_OPEN_SHADER_FILE: " << fileName << std::endl;
    }

    return src;
}

GLuint shader::loadShader(GLenum type, const char* fileName)
{
    char infoLog[512];
    GLint success = false;

    GLuint shader = glCreateShader(type);
    std::string strSrc = loadShaderSource(fileName);
    const GLchar* src = strSrc.c_str();
    glShaderSource(shader, 1, &src, nullptr);
    glCompileShader(shader);

    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(shader, 512, nullptr, infoLog);
        std::cout << "ERROR::SHADER::COULD_NOT_COMPILE_SHADER: " << fileName << std::endl;
        std::cout << infoLog << std::endl;
        glDeleteShader(shader);  // Delete the shader if compilation fails
        return 0;  // Return 0 to indicate failure
    }

    return shader;
}

void shader::linkProgram(GLuint vertexShader, GLuint geometryShader, GLuint fragmentShader)
{
    char infoLog[512];
    GLint success = false;

    // Creating the program
    m_id = glCreateProgram();

    // Attach shaders to the program
    glAttachShader(m_id, vertexShader);
    //if (geometryShader)
       // glAttachShader(m_id, geometryShader);
    glAttachShader(m_id, fragmentShader);

    // Link the program
    glLinkProgram(m_id);

    // Checks the status of linking the program
    glGetProgramiv(m_id, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(m_id, 512, nullptr, infoLog);
        std::cout << "ERROR::SHADER::COULD_NOT_LINK_PROGRAM" << std::endl;
        std::cout << infoLog << std::endl;
        glDeleteProgram(m_id);  // Delete the program if linking fails
    }

    // "Unuse" the program
    glUseProgram(0);
}

main.cpp:

#include "../headers/libs.h"

#define WINDOW_WIDTH  1400      //1400
#define WINDOW_HEIGHT  720        //720


using namespace std;


// Handles the viewport resize
void framebuffer_resize_callback(GLFWwindow* window, int fbW, int fbH)
{
    glViewport(0, 0, fbW, fbH);
}


// updates input for the given window
void updateInput(GLFWwindow* window, mesh mesh, glm::vec3& position)
{
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    {
        mesh.move(glm::vec3(0.f, 0.f, -0.01f));
    }
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    {
        mesh.move(glm::vec3(0.f, 0.f, 0.01f));
    }
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    {
        mesh.move(glm::vec3(-0.01f, 0.f, 0.f));
        position.x += -0.01f;
    }
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    {
        mesh.move(glm::vec3(0.01f, 0.f, 0.f));
    }
    if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
    {
        //mesh.rotate(glm::vec3(0.f, 1.f, 0.f));
        //rotation.y -= 1.f;
    }
    if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
    {
       // rotation.y += 1.f;
    }
    if (glfwGetKey(window, GLFW_KEY_V) == GLFW_PRESS)
    {
        //scale.x += 0.001;
        //scale.y += 0.001;
    }
    if (glfwGetKey(window, GLFW_KEY_B)== GLFW_PRESS)
    {
        //scale.x -= 0.001;
        //scale.y -= 0.001;
    }
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

int main()
{

    Vertex vertices [] =
    {
        // Position                       // Color                             // Texture coords            // Normals
        glm::vec3(-0.5f, 0.5f, 0.f),      glm::vec3(1.f, 0.f, 0.f),            glm::vec2(0.f, 1.f),         glm::vec3(0.f, 0.f, 1.f),
        glm::vec3(-0.5f, -0.5f, 0.f),     glm::vec3(0.f, 1.f, 0.f),            glm::vec2(0.f, 0.f),         glm::vec3(0.f, 0.f, 1.f),
        glm::vec3(0.5f, -0.5f, 0.f),      glm::vec3(0.f, 0.f, 1.f),            glm::vec2(1.f, 0.f),         glm::vec3(0.f, 0.f, 1.f),
        glm::vec3(0.5f, 0.5f, 0.f),       glm::vec3(1.f, 1.f, 0.f),            glm::vec2(1.f, 1.f),         glm::vec3(0.f, 0.f, 1.f)
    };
    unsigned nrOfVertices = sizeof(vertices) / sizeof(Vertex);

    GLuint indicies [] =
    {
        0, 1, 2,    // First triangle
        0, 2, 3     // Secound triangle
    };
    unsigned nrOfIndicies = sizeof(indicies) / sizeof(GLuint);

    // Init GLFW
    if (!glfwInit()) 
    {
        cout << "ERROR::MAIN.CPP::GLFW_INIT_FAILED" << endl;
        return -1;
    }

    // Create Window
    int frameBufferWidth = 0;
    int frameBufferHeight = 0;

    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

    GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "We Are Going 3D!", nullptr, nullptr);

    glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight); // for not resizeable windows
    //glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    glfwMakeContextCurrent(window); // Important to set the context
    glfwSetFramebufferSizeCallback(window, framebuffer_resize_callback);

    // Init GLEW (Needs Window and OpenGL context)
    glewExperimental = GL_TRUE;

    // Error with glew
    if (glewInit() != GLEW_OK)
    {
        cout << "ERROR::MAIN.CPP::GLEW_INIT_FAILED" << endl;
        glfwTerminate();
        return -1;
    }

    // OpenGL options
    glEnable(GL_DEPTH_TEST); // Lets us use perspectiv 

    glEnable(GL_CULL_FACE);   // Is used to not render / calculate stuff behind faces
    glCullFace(GL_BACK);      // We dont want to see the back side of the triangle
    glFrontFace(GL_CCW);       // Gives input wich the back side is (CW bcause FrontFace is CCW (Counter Clock Wise))

    glEnable(GL_BLEND);     // Enables blending from colors
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  // Function used to blend colors

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);      // Sets the triangles to polygons and fills them

    // Shader init
    shader core_program("../shader/vertex_core.glsl", "../shader/fragment_core.glsl", "");

    // Model
    mesh test_mesh(vertices, nrOfVertices, indicies, nrOfIndicies, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f));

    GLuint VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLuint EBO;
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicies), indicies, GL_STATIC_DRAW);

    // Set the Vertex Attrib Pointers and enable
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::position));
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::color));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::texCoord));
    glEnableVertexAttribArray(2);

    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Vertex::normal));
    glEnableVertexAttribArray(3);

    glBindVertexArray(0);

    // ! Texture init
    // Texture 0
    texture texture0("../assets/image/texture.png", GL_TEXTURE_2D, 0);
    // Texture 1
    texture texture1("../assets/image/apple.png", GL_TEXTURE_2D, 1);
    
    // ! Material init
    // Material 0
    material material0(glm::vec3(0.1f), glm::vec3(1.f), glm::vec3(1.f), texture0.get_texture_unit(), texture1.get_texture_unit());

    // ! init matrices
    glm::vec3 position(0.f);
    glm::vec3 rotation(0.f);
    glm::vec3 scale(1.f);

    glm::mat4 model_matrix(1.f);
    model_matrix = glm::translate(model_matrix, position);
    model_matrix = glm::rotate(model_matrix, glm::radians(rotation.x), glm::vec3(1.f, 0.f, 0.f));
    model_matrix = glm::rotate(model_matrix, glm::radians(rotation.y), glm::vec3(0.f, 1.f, 0.f));
    model_matrix = glm::rotate(model_matrix, glm::radians(rotation.z), glm::vec3(0.f, 0.f, 1.f));
    model_matrix = glm::scale(model_matrix, scale);

    glm::vec3 camPosition(0.f, 0.f, 1.f);
    glm::vec3 worldUp(0.f, 1.f, 0.f);
    glm::vec3 camFront(0.f, 0.f, -1.f);
    
    glm::mat4 viewMatrix(1.f);
    viewMatrix = glm::lookAt(camPosition, camPosition + camFront, worldUp);

    float fov = 90.f;
    float nearPlane = 0.1f;
    float farPlane = 1000.f;
    glm::mat4 projectionMatrix(1.f);
    projectionMatrix = glm::perspective(glm::radians(fov), static_cast<float>(frameBufferWidth) / frameBufferHeight, nearPlane, farPlane);

    // Lights
    glm::vec3 ligthPos0(0.f, 0.f, 1.f);

    // init uniforms
    core_program.setMat4fv(model_matrix, "modelMatrix");
    core_program.setMat4fv(viewMatrix, "viewMatrix");   // each time the core_program gets activated and deactivated in the func
    core_program.setMat4fv(projectionMatrix, "projectionMatrix");

    core_program.setVec3f(ligthPos0, "lightPos");
    core_program.setVec3f(camPosition, "cameraPos");


    // Main loop
    while (!glfwWindowShouldClose(window))
    {
        // Inputs
        glfwPollEvents();

        // Updates
        updateInput(window, test_mesh, position);

        // Draw setup
        glClearColor(0., 0., 0., 1.);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clearing all three buffers befor drawing again

       
        // Update uniforms
        core_program.set1i(texture0.get_texture_unit(), "texture0");
        core_program.set1i(texture1.get_texture_unit(), "texture1");
        material0.send_to_shader(core_program);

        // Move, Rotate and Scale
        model_matrix = glm::mat4(1.f);
        model_matrix = glm::translate(model_matrix, position);
        model_matrix = glm::rotate(model_matrix, glm::radians(rotation.x), glm::vec3(1.f, 0.f, 0.f));
        model_matrix = glm::rotate(model_matrix, glm::radians(rotation.y), glm::vec3(0.f, 1.f, 0.f));
        model_matrix = glm::rotate(model_matrix, glm::radians(rotation.z), glm::vec3(0.f, 0.f, 1.f));
        model_matrix = glm::scale(model_matrix, scale);

        core_program.setMat4fv(model_matrix, "modelMatrix");

        // Update framebuffer size and projection matrix
        glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight);  // incase window gets resized

        projectionMatrix = glm::mat4(1.f);
        projectionMatrix = glm::perspective(glm::radians(fov), static_cast<float>(frameBufferWidth) / frameBufferHeight, nearPlane, farPlane);
        core_program.setMat4fv(projectionMatrix, "projectionMatrix");

        // Use program
        core_program.use();


        // Activate Texture
        texture0.bind();
        texture1.bind();

        // Draw
        //glDrawArrays(GL_TRIANGLES, 0, nrOfVertices);
        //glDrawElements(GL_TRIANGLES, nrOfIndicies, GL_UNSIGNED_INT, 0);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, nrOfIndicies, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
        test_mesh.render(&core_program);

        // End of Draw
        glfwSwapBuffers(window);
        glFlush();

        glBindVertexArray(0);
        glUseProgram(0);
        glActiveTexture(0);
        glBindTexture(GL_TEXTURE_2D, 0);
    }
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);

    // End of Program
    glfwDestroyWindow(window);
    glfwTerminate();
}

Summary
I can successfully render a rectangle using a VAO directly in the main function with the same shader. However, when I try to render using my mesh class, I get the aforementioned OpenGL errors. I suspect the issue lies in my mesh class implementation, but I’m not sure where.

Any help or pointers would be greatly appreciated!

Thank you in advance.

I’ve not read through your code in detail, but whenever I see wrapper classes without (possibly marked deleted) copy or move constructors and assignment operators I feel compelled to ask: have you seen the wiki page on common pitfalls with OO wrappers?

Thank you for the response. I appreciate your suggestion and will definitely consider implementing it in the class. I have found the issue—it was related to an unbound shader.

// Use program
core_program.use();

// Activate Texture
texture0.bind();
texture1.bind();

// Draw
// glDrawArrays(GL_TRIANGLES, 0, nrOfVertices);
// glDrawElements(GL_TRIANGLES, nrOfIndicies, GL_UNSIGNED_INT, 0);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, nrOfIndicies, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

// <--- Here, adding shader->unUse() (glUseProgram(0)) was the solution
test_mesh.render(&core_program);