Search code examples
c++openglglfwglew

Custom OpenGL buffer class doesn't display anything


I wanted to create a class to handle OpenGL buffers like vertex buffers objects or colorbuffers.

Here is the buffer.h:

#pragma once
#include <GL/glew.h>

class glBuffer
{
public:
    glBuffer(GLenum target);
    void setdata(const void *data, GLenum mode);
    void bind(GLuint index, GLint valuePerVertex, GLenum variableType = GL_FLOAT, GLsizei stride = 0, int offset = 0);
    void unbind();
    GLuint getBufferID() const;
    ~glBuffer();

private:
    bool m_active;
    GLuint m_buffer;
    GLuint m_index;
    GLenum m_target;
};

And buffer.cpp:

#include "buffer.h"
#include <GL/glew.h>
#include <iostream>


glBuffer::glBuffer(GLenum target)
{
    m_target = target;
    m_active = false;
    glGenBuffers(1, &m_buffer);
}

void glBuffer::setdata(const void *data, GLenum mode)
{
    glBindBuffer(m_target, m_buffer);
    glBufferData(m_target, sizeof(data), data, mode);
    glBindBuffer(m_target, 0);
}

void glBuffer::bind(GLuint index, GLint valuePerVertex, GLenum variableType, GLsizei stride, int offset)
{
    m_active = true;
    m_index = index;
    glEnableVertexAttribArray(m_index);
    glBindBuffer(m_target, m_buffer);
    glVertexAttribPointer(
        m_index,
        valuePerVertex,     
        variableType,       
        GL_FALSE,           //normalized?
        stride,             
        (void*)offset       //buffer offset
    );
}

void glBuffer::unbind()
{   
    m_active = false;
    glBindBuffer(m_target, 0);
    glDisableVertexAttribArray(m_index);
}

GLuint glBuffer::getBufferID() const
{
    return m_buffer;
}


glBuffer::~glBuffer()
{
    if (!m_active){
        unbind();
    }
    glDeleteBuffers(1, &m_buffer);
}

Here is how I use it in my application, where I #include "buffer.h" :

glBuffer vbo(GL_ARRAY_BUFFER);
vbo.setdata(color_buffer_data, GL_STATIC_DRAW);
vbo.bind(0, 3);

Replaces :

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer_data), vertex_buffer_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(
    0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
    3,                  // size
    GL_FLOAT,           // type
    GL_FALSE,           // normalized?
    0,                  // stride
    (void*)0            // array buffer offset
);

When I compile and run it, I get a black window without anything drawn.

What is happening?

PS: I'm using vs, glfw3, glew.


Solution

  • Here is your working code for setting the buffer data

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer_data), vertex_buffer_data, GL_STATIC_DRAW);
    

    I am assuming that your vertex_buffer_data is an array which is why this works. Since you cast this to a void* you cannot simple call sizeof on the pointer. What you need is the size of the entire array in bytes.

    Here is your function in your class that does not work

    void glBuffer::setdata(const void *data, GLenum mode)
    {
        glBindBuffer(m_target, m_buffer);
        glBufferData(m_target, sizeof(data), data, mode);
        glBindBuffer(m_target, 0);
    }
    

    This is because the sizeof(data) is not the same as in first case. It is either 4 (32-bit) or 8 (64-bit) as pointed out by @genpfault. The simple solution would be to change your function as below.

    void glBuffer::setdata(const void *data, int numElements, size_t elementSize, GLenum mode)
    {
        glBindBuffer(m_target, m_buffer);
        glBufferData(m_target, numElements * elementSize, data, mode);
        glBindBuffer(m_target, 0);
    }
    

    in this function 'numElements' is the number of elements in the array that your void* data points to and 'elementSize' is the size of each element.

    Here is an example code for the above function

    float vertex_buffer_data[9] = {0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f};
    glBuffer vbo(GL_ARRAY_BUFFER);
    vbo.setdata(vertex_buffer_data, 9, sizeof(float), GL_STATIC_DRAW);
    vbo.bind(0, 3); 
    

    And it should work. If you are still confused, here is a small example program to demonstrate why your code did not work.

    #include "stdafx.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int a[5] = {1, 2, 3, 4, 5};
        void* ptr = a;
        printf( " sizeof(a) = %d \n", sizeof(a));
        printf( " sizeof(a[0]) = %d \n", sizeof(a[0]));
        printf( " sizeof(ptr) = %d \n", sizeof(ptr));
        getchar();
    
        return 0;
    }
    

    Output :

    sizeof(a) = 20 
    sizeof(a[0]) = 4 
    sizeof(ptr) = 4
    

    Note: this was compiled on windows 32-bit in visual studio, hence the pointer size is 4 bytes. It would be 8 if I compiled it in 64-bit.