PDA

View Full Version : Dynamic Allocation and OpenGL



pentagast
07-12-2018, 10:49 AM
Hi. I've been trying to draw a series of triangles to the screen. I generate buffers, bind them correctly, and buffer the arrays of floats using glBufferData. If I use arrays of data created with stack memory, it works fine. The problem occurs when I create dynamically allocated arrays from the heap and pass them to OpenGL. I wrote a test function that emulates exactly what I'm trying to do elsewhere which highlights the problem.

Here's the code that works fine:


void testFunction() {

GLuint vertexBufferId, indexBufferId;
int triangleCount = 3;

float newPositions[] = {
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, 0.5f
};

GLushort vertexIndices[] = {
0, 1, 2,
2, 1, 3,
0, 1, 4
};

glGenBuffers(1, &vertexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
glBufferData(GL_ARRAY_BUFFER, sizeof(newPositions), newPositions, GL_STATIC_DRAW);


glGenBuffers(1, &indexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndices), vertexIndices, GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glDrawElements(GL_TRIANGLES, triangleCount * 3, GL_UNSIGNED_SHORT, 0);
}


When I change the data to use dynamically allocated memory, I get a black screen instead of the triangles which were drawn before.


void testFunction() {
GLuint vertexBufferId, indexBufferId, colourBufferId;
int triangleCount = 3;

float* newPositions = new float[15]{
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, 0.5f
};

GLushort* vertexIndices = new GLushort[9] {
0, 1, 2,
2, 1, 3,
0, 1, 4
};

glGenBuffers(1, &vertexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
glBufferData(GL_ARRAY_BUFFER, sizeof(newPositions), newPositions, GL_STATIC_DRAW);

glGenBuffers(1, &indexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndices), vertexIndices, GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glDrawElements(GL_TRIANGLES, triangleCount * 3, GL_UNSIGNED_SHORT, 0);

delete[] vertexIndices;
delete[] newPositions;
}


I'm still quite new to OpenGL, so if I need to approach it differently with heap memory then please let me know. Thanks for your help.

GClements
07-12-2018, 11:26 AM
When I change the data to use dynamically allocated memory, I get a black screen instead of the triangles which were drawn before.


float* newPositions = new float[15]{
...
glBufferData(GL_ARRAY_BUFFER, sizeof(newPositions), newPositions, GL_STATIC_DRAW);

I'm still quite new to OpenGL, so if I need to approach it differently with heap memory then please let me know. Thanks for your help.

It seems that you're also still quite new to C++. This isn't an OpenGL problem per se. The issue is that in the second case sizeof(newPositions) is equivalent to sizeof(float*); in the first case it was equivalent to sizeof(float[15]).

C++ doesn't provide a mechanism to obtain the size of a dynamically-allocated array. The implementation may not even store this; if it rounds the allocation up to a larger size, there's no reason for it to record the requested size. So you have to keep track of the size yourself. One way to do that is to use std::vector instead.

pentagast
07-12-2018, 11:30 AM
I completely missed that and assumed a problem with OpenGL. Thanks for the help.

ProgrammerX
07-13-2018, 02:56 AM
Additionally it might be beneficial if you try to avoid using raw new calls for dynamic allocation in general and use the standard template library instead. The new operator is the source for a lot of mistakes that can be completely avoided by using the STL.

To do so, replace your c style static array (vertexIndices[] = ...) with a std::array and your dynamically allocated array with a std::vector. Because the STL containers are designed to have mostly equal interfaces your OpenGL call would be the same for both container types. It should look like this:



glBufferData(GL_ARRAY_BUFFER, sizeof(float)*myContainer.size(), myContainer.data(), GL_STATIC_DRAW);


You also get additional functionality that is often needed with arrays.

Greetings

EDIT: Make sure that you compile with c++ 11 support. Use -std=c++11 for clang and gcc. Not sure about msvc, but google will tell you.