0

I am learning OpenGL with c++ right now using SDL, glew, and glm. I have gotten to the "VAO and VBO" stage. However, I am getting an error. When I run my program, I get a exception: Unhandled exception at 0x74DECB49 in LearningOpenGL.exe: 0xC0000005: Access violation executing location 0x00000000. There is an arrow pointing to the line glGenVertexArrays I initialized SDL, made an OpenGL Context, and am using OpenGL 3.0+.

Here is Display.cpp (initializing everything)

    #include "Display.h"

    Display::Display(int width, int height, std::string title)
    {
        _displayWidth = width;
        _displayHeight = height;
        _displayTitle = title;
        _window = nullptr;
    }

    Display::Display()
    {

    }

    Display::~Display()
    {

    }

    void Display::createDisplay()
    {
        // Initialize SDL
        SDL_Init(SDL_INIT_EVERYTHING);
        // Setting attributes to our window
        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

        // Create Window
        _window = SDL_CreateWindow((_displayTitle.c_str()), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _displayWidth, _displayHeight, SDL_WINDOW_OPENGL);
        // Error Check Window
        if (_window == nullptr)
        {
            std::cerr << "Window could not be created!" << std::endl;
        }
        else
        {
            std::cout << "Window Created Successfully With SDL!" << std::endl;
        }
        // Create OpenGL Context
        _glContext = SDL_GL_CreateContext(_window);

        // Initialize GLEW
        glewExperimental = GL_TRUE;
        GLenum status = glewInit();

        if (glewExperimental)
        {
            std::cout << "Glew Experimental: On" << std::endl;
        }
        else
        {
            std::cout << "Glew Experimental: Off" << std::endl;
        }
        // Error Check GLEW
        if (status != GLEW_OK)
        {
            std::cerr << "GLEW could not be initialized!" << std::endl;
        }
        else
        {
            std::cout << "GLEW Was Initilized Successfully!" << std::endl;
        }

        // Log OpenGL Version Number
        std::cout << "Using OpenGL Version: " << glGetString(GL_VERSION) << std::endl;

        _closed = false;
    }

    void Display::destroyDisplay()
    {
        SDL_GL_DeleteContext(_glContext);
        SDL_DestroyWindow(_window);
        SDL_Quit();
    }

    void Display::update()
    {
        SDL_GL_SwapWindow(_window);

        // Check for Input
        while (SDL_PollEvent(&_sdlEvent))
        {
            if (_sdlEvent.type == SDL_QUIT)
            {
                _closed = true;
            }
        }

    }

    bool Display::isClosed()
    {
        return _closed;
    }

Here is Mesh.cpp

#include "Mesh.h"

Mesh::Mesh(Vertex* vertices, unsigned int numVertices)
{
    _renderCount = numVertices;

    // Create VAO
    glGenVertexArrays(1, &_vaoID);
    glBindVertexArray(_vaoID);

    // Create VBO
    glGenBuffers(1, _vboID);
    glBindBuffer(GL_ARRAY_BUFFER, _vboID[POSITION_VB]);

    // Put data into the VBO
    glBufferData(GL_ARRAY_BUFFER, (numVertices * sizeof(vertices[0])), vertices, GL_STATIC_DRAW);

    // Enable the first attibute of the VAO
    glEnableVertexAttribArray(0);

    // Put the data in the VAO
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Unbind the VAO and VBO and disable attribute 0
    glDisableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

Mesh::Mesh()
{

}

Mesh::~Mesh()
{
    cleanUp();
}

void Mesh::render()
{
    glBindVertexArray(_vaoID);
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_TRIANGLES, 0, _renderCount);

    glDisableVertexAttribArray(0);
    glBindVertexArray(0);
}

void Mesh::cleanUp()
{
    glDeleteBuffers(1, _vboID);
    glDeleteVertexArrays(1, &_vaoID);
}

Here is Game.cpp

#include "Game.h"

Game::Game()
{
    _display = Display(_displayWidth, _displayHeight, _displayTitle);

    // TODO: Fix Hardcoded 3 below

    _vertices[0] = Vertex(glm::vec3(-1.0f, -1.0f, 0.0f));
    _vertices[1] = Vertex(glm::vec3(1.0f, -1.0f, 0.0f));
    _vertices[2] = Vertex(glm::vec3(0.0f, 1.0f, 0.0f));

    _mesh = Mesh(_vertices, 3);

}

Game::~Game()
{

}

void Game::init()
{
    _display.createDisplay();
}

void Game::gameLoop()
{
    while (!_display.isClosed())
    {
        glClearColor(0.0f, 0.15f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        _mesh.render();

        _display.update();
    }
    _display.destroyDisplay();
}

void Game::start()
{
    init();
    gameLoop();
}

I have read other posts on this problem, and the solution for them seemed to be "set glewExperimental = GL_TRUE." As you can see, I did this, but still, exception. When I used the old graphics pipeline with OpenGL, it worked. Now however, it does not. I am using OpenGL 3.0+, so what is the problem?

resueman
  • 10,572
  • 10
  • 31
  • 45
Java Man Tea Man
  • 242
  • 3
  • 15
  • Well, from the code posted so far, I is not at all clear that you use OpenGL >= 3.0. You certainly don't request it anywhere. So make sure you actually got it. Another option would be that your mesh constructor is called before the context was created (and glew initialized). – derhass Jul 15 '15 at 20:16
  • I do call getString(Gl_VERSION) in display.cpp. It outputs this: 3.1.0 Build 8.15.10.2618 ; I will also update my question above to display my game class. – Java Man Tea Man Jul 15 '15 at 20:24

2 Answers2

2

The crash data suggests that the glGenVertexArrays() function is not available, which would most likely be a problem with your GLEW/SDL setup.

However, there's also a subtle but very critical problem in your code. I don't think it should cause a crash, but it would definitely keep it from working. The harmful line is here:

_mesh = Mesh(_vertices, 3);

Here you assign a (newly constructed) Mesh instance to a variable. What happens on this line is the following:

  1. A new Mesh object is created.
  2. The constructor is invoked. In the constructor you create the VAO and other OpenGL object.
  3. The new object is assigned to the _mesh variable. Since your Mesh class does not have an assignment operator defined, default member-wise assignment is used.
  4. Since the newly created Mesh instance only exists within the statement, it is destroyed.
  5. The destructor of the object is invoked. In the destructor, you delete the VAO.

So at the end of this statement, your VAO has been deleted. You still have the VAO id stored in a member of the _mesh variable, but this id is now invalid.

Wrapping OpenGL objects in C++ classes often causes trouble if you don't have a firm grasp of C++, and understand exactly how to implement proper copy and assignment semantics.

I elaborated on some options to fix this type of issue in my answer to a similar problem here: Mesh class called with default constructor not working OpenGL C++. The most straightforward approach is that you do not allow these kinds of objects to be copied, and reference them with (smart) pointers throughout your code.

Community
  • 1
  • 1
Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
0

Do you call the classes procedures in the right order? Like does it really create the context before generating the arrays? I had the same problem and this was the reason. You can also try to update your graphic drivers if you haven't done so for some time ^^

Hitokage
  • 733
  • 8
  • 19