2
votes

I'm a beginner in OpenGL and I am trying to draw a colored square I followed the tutorial at OpenGL Book and I am using the example to draw here. Since this draws a triangle I modified the code to draw 4 vertices. I made a Rectangle class that can output it's data in array format. This is the data that I am trying to pass into the glBufferData function.

Unfortunately when I use my class's data it does not draw anything on the screen. I'm even checking in gDebugger, I'm looking at my VBO and the data is not correct.

Wrong gDebugger

To test, I extracted the vertices out of my class and used them in a local array instead of the pointer returned from my class.

My data is now :

Vertex Vertices[] =
{
    { { -0.5f, 0.5f, 0.0f, 1.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
    { { 0.5f, 0.5f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
    { { -0.5f, -0.5f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } },
    { { 0.5f, -0.5f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }
};

instead of

Vertex* Vertices = rec->GetVertexData();

(I checked by hand both arrays, they have the exact same values, the problem is not in my Rectangle's code) and now the call glBufferData(GL_ARRAY_BUFFER, BufferSize, Vertices, GL_STATIC_DRAW); works and I see the correct rectangle on screen. With the data in gDebugger being

Correct gDebugger

After some research I realized that sizeof does not report the correct size given a pointer so I fixed that. I hardcoded (for now) BufferSize = 128; in order to test quicker. Point is, it works with the Vertex array and still not with the Vertex pointer from my class.

I've googled examples of the glBufferData and literally none of them shows you how to use the data from a pointer, you'd think that would be a good example.

So how can I pass an array of Vertex to my glBufferData that's being returned as a pointer from another class ? I'm using OpenGL version 4 with GLEW and GLUT.

Update :

So the error was on my part, I'll post my debugging here in hopes it can help other people. I added a Watch of name Vertice, 8. Which showed me that my array had bogus values. Doing a step by step debugging showed me that when glGenBuffers was called it was overwriting my values. I went back and checked my code and I realized that my mistake was calling Vertex vec[4]; instead of Vertex *vec = new Vertex[4]; and the stack's values was overwritten by another function.

1
Hard to say from the little code given. An array is already a pointer so there's really no difference there. If I'm going to take a stab just guessing: How do you pass Verticesto glBufferData? One potential problem is that you have another level of indirection by using &Vertices which would be wrong. Assuming that you're using MSVC, add Vertices,8 to your watch, does it show the correct values? Otherwise your data is not consecutive.Ylisar
Damn, I didn't even know about that Watch test. It really helped me debug my problem. I'm posting an update to my post. If you want to make your comment into an answer I'll mark it as an answer.Tristan Dubé
Glad you found your error and I was able to help :) just hand me an upvote for the comment, I can't think of a descriptive enough answer for you to up vote hehe.Ylisar

1 Answers

5
votes

It is often mistaken that arrays are pointers, when in reality they are not. Array expressions decay into a pointer in many circumstances (sizeof being one of the exceptions to this rule) but there are significant differences between array themselves and pointers. For further information, read this excellent post.

As for the problem in hand, once the array decays into a pointer, it's shape (the first dimension) is lost, which is the reason sizeof returns the size of a pointer and not that of the entire array.

float arr[3] = { 1.0f, 2.0f, 3.0f };    // sizeof(arr) = 3 * sizeof(float)
float *ptr = arr;                       // sizeof(ptr) = sizeof(float*)

how can I pass an array of Vertex to my glBufferData that's being returned as a pointer from another class ?

You've three options to do this. Make the class return the pointer to the array (as you do now) and add another function to expose the count of the elements in it i.e. its length, with which you may calculate the size in bytes. However, this is not a very elegant solution, since in C++ one can have references to array, which brings us to the next solution (live example):

float (&MyClass::GetData()) [3] const
{
    return arr;
}

The sizeof operator on this reference would rightly return the size of the whole array. You might use std::array instead to avoid the arcane expression like so std::array<float, 3>& MyClass::GetData() const;.

Another wiser option is to do away with arrays altogether and use std::vector, to which you can return a reference:

std::vector<float> const& MyClass::GetData() const
{
    return vec;
}

At the other end

auto const &vec = obj->GetData();
float *data = vec.data();
size_t data_len = vec.size() * sizeof(float);

The additional advantage in using std::vector is that the length can vary at runtime; also lesser bugs due to the hairy nature of arrays.