Dima Maligin
Dima Maligin

Reputation: 1482

openGL Unhandled exception on glDrawArrays(GL_TRIANGLES, 0, model.indicesCount); call

So I'm trying to write a simple 3D rendering engine using GLFW and GLEW in C++. However the program crashes on glDrawArrays(GL_TRIANGLES, 0, model.indicesCount); call. I'm pretty sure I'm doing something wrong but I can't figure out where or what needs to be changed/altered. I'm actually rewriting a perfectly working engine from Java.

My code:

common.h:

#ifndef _COMMON
#define _COMMON

// standard stuff
#include <iostream>
#include <list>

// openGL stuff
#include "GL\glew.h"
#include "GLFW\glfw3.h"

// my stuff
#include "DisplayManager.h"
#include "RawModel.h"
#include "Loader.h"
#include "Renderer.h"

#endif

DisplayManager.h:

#pragma once

#include "common.h"

class DisplayManager{
private:
    GLFWwindow* window;
public:
    void create(int width = 1280, int height = 720, std::string title = "Untitled"){
        if(!glfwInit()){
            std::cerr << "GLFW init failed\n";
            system("pause");
            exit(EXIT_FAILURE);
        }

        glfwWindowHint(GLFW_SAMPLES, 4);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
        glfwMakeContextCurrent(window);

        if(!window){
            std::cerr << "Failed to create a window\n";
            system("pause");
            exit(EXIT_FAILURE);
        }

        glewExperimental = GL_TRUE;
        if(glewInit() != GLEW_OK){
            std::cerr << "GLEW init failed\n";
            system("pause");
            glfwTerminate();
            exit(EXIT_FAILURE);
        }
    }

    void update(){
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    int isCloseRequested(){
        return glfwWindowShouldClose(window);
    }

    void close(){
        glfwDestroyWindow(window);
        glfwTerminate();
    }

};

RawModel.h:

#pragma once

struct RawModel{

public:
    GLuint vaoID;
    GLuint indicesCount;

    RawModel(GLuint vaoID, GLuint indicesCount){
        this->vaoID = vaoID;
        this->indicesCount = indicesCount;
    }

};

Loader.h:

#pragma once

#include "common.h"

#define VERTEX_ATTRIB_INDEX 0
#define VERTEX_SIZE 3

class Loader{
public:
    // functions
    RawModel loadModel(const GLfloat vertices[], GLuint verticesCount){
        GLuint vaoID = createAndBindVao();
        storeFloatDataInVAO(VERTEX_ATTRIB_INDEX, vertices, verticesCount, VERTEX_SIZE);
        unbindVAO();
        return RawModel(vaoID, verticesCount);
    }

    void cleanUp(){
        std::list<GLuint>::iterator vao_it = vaos.begin();
        for(; vao_it != vaos.end(); ++vao_it){
            const GLuint vao = *vao_it;
            glDeleteVertexArrays(1, &vao);
        }

        std::list<GLuint>::iterator vbo_it = vbos.begin();
        for(; vbo_it != vbos.end(); ++vbo_it){
            const GLuint vbo = *vbo_it;
            glDeleteBuffers(1, &vbo);
        }
    }
private:
    // variables
    std::list<GLuint> vaos;
    std::list<GLuint> vbos;

    // functions
    GLuint createAndBindVao(){
        GLuint vaoID; 
        glGenVertexArrays(1, &vaoID);
        vaos.push_back(vaoID);
        glBindVertexArray(vaoID);
        return vaoID;
    }

    void storeFloatDataInVAO(const GLuint attributeIndex, const GLfloat data[], const GLuint dataLength, const GLuint chunkSize){
        GLuint vboID;
        glGenBuffers(1, &vboID);
        vbos.push_back(vboID);
        glBindBuffer(GL_VERTEX_ARRAY, vboID);
        glBufferData(GL_VERTEX_ARRAY, sizeof(GLfloat) * dataLength * chunkSize, data, GL_STATIC_DRAW);
        glVertexAttribPointer(attributeIndex, chunkSize, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glBindBuffer(GL_VERTEX_ARRAY, 0);
    }

    void unbindVAO(){
        glBindVertexArray(0);
    }
};

Renderer.h:

#pragma once

#include "common.h"

#define BLACK   0.0f, 0.0f, 0.0f, 1.0f
#define WHITE   1.0f, 1.0f, 1.0f, 1.0f
#define RED     1.0f, 0.0f, 0.0f, 1.0f
#define GREEN   0.0f, 1.0f, 0.0f, 1.0f
#define BLUE    0.0f, 0.0f, 1.0f, 1.0f
#define YELLOW  1.0f, 1.0f, 0.0f, 1.0f

class Renderer{
public:
    void prepare(){
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(YELLOW);
    };

    void render(RawModel model){
        glBindVertexArray(model.vaoID);
        glEnableVertexAttribArray(VERTEX_ATTRIB_INDEX);
        glDrawArrays(GL_TRIANGLES, 0, model.indicesCount);
        glDisableVertexAttribArray(VERTEX_ATTRIB_INDEX);
        glBindVertexArray(0);
    }
};

and the Source.cpp with the main function:

#include "common.h"

static const GLfloat VERTICES[] = {
//  X       Y       Z
   -0.5f,   0.5f,   0,
   -0.5f,  -0.5f,   0,
    0.5f,   0.5f,   0
};

int main(){

    DisplayManager display;
    display.create();

    Loader loader;
    RawModel model = loader.loadModel(VERTICES, 3);

    Renderer renderer;

    // main loop
    while(!display.isCloseRequested()){
        renderer.prepare();
        renderer.render(model);
        display.update();
    }

    loader.cleanUp();
    display.close();
    return EXIT_SUCCESS;
}

If I comment out the glDrawArrays(GL_TRIANGLES, 0, model.indicesCount); it seams to be working and I get a green window.

Upvotes: 0

Views: 699

Answers (1)

derhass
derhass

Reputation: 45342

The error is here:

    glBindBuffer(GL_VERTEX_ARRAY, vboID);
    glBufferData(GL_VERTEX_ARRAY, sizeof(GLfloat) * dataLength * chunkSize, data, GL_STATIC_DRAW);
    glVertexAttribPointer(attributeIndex, chunkSize, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glBindBuffer(GL_VERTEX_ARRAY, 0);

GL_VERTEX_ARRAY is not a valid buffer target in OpenGL, the correct one is GL_ARRAY_BUFFER. As a consequence, these commands all should generate a GL error. The attrib pointer function will should generate GL_INVALID_OPERATION, since no GL_ARRAY_BUFFER is bound at the time of the call, the others should just generate GL_INVALID_ENUM. Now you have basically an uninitialized vertex attribute pointer, you later enable that attribute array and try to draw from it, resulting in the crash.

Another thing: I don't see any shaders in your code. Shaders are mandatory in the core profile, which you use. Now glDrawElements() actually should fail, although some implementors ignore that and use some trivial shaders in that scenario.

Upvotes: 3

Related Questions