VBOs with std::vector
If you have a std::vector<T> v
, you may obtain a T*
pointing to the start of the contiguous data (which is what OpenGL is after) with the expression &v[0]
.
In your case, this means passing a Vertex*
to glBufferData
:
glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(Vertex),
&vertices[0],
GL_STATIC_DRAW
);
Or like this, which is the same:
glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(Vertex),
&vertices.front(),
GL_STATIC_DRAW
);
You can rely on implicit conversion from Vertex*
to void const*
here; that should not pose a problem.
OpenGL: Using VBO with std::vector
You want to do:
unsigned int vbo;
vector<float> vert;
...
vert.push_back(i*size);
vert.push_back(height*h);
vert.push_back(j*size);
...
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vert.size() * sizeof(float), vert.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
It is always good to read the documentation. Also, I would suggest you pick up a good C++ book, which probably would be a good way for you to avoid doing mistakes like these.
std::vector and VBOs render only the last shape
As I suspected, the problem is with the (lack of) copy constructor. The default one just copies all the members. As a result your VAOs and buffers get deleted multiple times, even before you manage to draw anything (vectors move during reallocation, and if they can't move they copy). As a rule of thumb: if you have a non-default destructor, you must implement also a copy constructor and an assignment operator, or explicitly delete them if your class is not meant to be copyable.
For your concrete case the solutions are:
Quick solution: store pointers to meshes in the vector:
std::vector<Mesh*> meshes;
meshes.emplace_back(&mesh1);
meshes.emplace_back(&mesh2);Correct solution: use proper RAII for resource management. Using the unique_ptr technique from here your MCVE code becomes:
class Mesh
{
public:
Mesh(Vertex* vertices, unsigned int numVertices, const char& flag);
void draw();
private:
//...
GLvertexarray m_vertexArrayObject;
GLbuffer m_vertexArrayBuffers[NUM_BUFFERS];
unsigned int m_drawCount;
char m_flag;
};
Mesh::Mesh(Vertex* vertices, unsigned int numVertices, const char& flag) : m_flag(flag), m_drawCount(numVertices)
{
GLuint id;
glGenVertexArrays(1, &id);
glBindVertexArray(id);
m_vertexArrayObject.reset(id);
for(int i = 0; i < NUM_BUFFERS; ++i)
{
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
m_vertexArrayBuffers[i].reset(id);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(vertices[0]), vertices, GL_STATIC_DRAW);
}
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
void Mesh::draw()
{
switch(m_flag)
{
case 'P':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_POINTS, 0, m_drawCount);
glBindVertexArray(0);
break;
case 'L':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_LINES, 0, m_drawCount);
glBindVertexArray(0);
break;
case 'T':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_TRIANGLES, 0, m_drawCount);
glBindVertexArray(0);
break;
}
}
int main()
{
//...
Mesh mesh1(vertices1, sizeof(vertices1)/sizeof(vertices1[0]), 'L');
Mesh mesh2(vertices2, sizeof(vertices2)/sizeof(vertices2[0]), 'L');
std::vector<Mesh> meshes;
meshes.emplace_back(std::move(mesh1));
meshes.emplace_back(std::move(mesh2));
// ...
return 0;
}Notice how there is no more need for defining a destructor, and your class automatically becomes movable but not copyable. Furthermore, if you have OpenGL 4.5 or
ARB_direct_state_access
then things get even simpler.
std::vector Offset Calculation for VBO?
Simply, you can't.
The vector of vectors is essentially storing a vector of pointers to memory elsewhere, and is therefore not contiguous and cannot be offset.
You will need to use a multi-dimensional array; as you are already.
C++ - OpenGL - glBufferData with std::vector
The answer, seen HERE is:
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_indicesEBO), &m_indicesEBO.front(), GL_STATIC_DRAW);
Using the pointer to the beginning of the vector with .front()
How to properly keep track of VBOs and VAOs for cleanup?
There is missing the address-of (&
) operator
glDeleteVertexArrays(1, (unsigned int*)_vaos[i]);
glDeleteVertexArrays(1, &_vaos[i]);
Alternatively you can do:
glDeleteVertexArrays(1, _vaos.data()+i);
Anyway, you don't need the for loops at all (see std::vector
):
void Model::_cleanup()
{
glDeleteVertexArrays(_vaos.size(), _vaos.data());
glDeleteBuffers(_vbos.size(), _vbos.data());
}
Using OpenGL VBOs with custom classes/datatructures
First of all you have to ensure that the vertex coordinates are in a contiguous and contiguous area in memory and are not fragmented into a lot of little pieces. Use Location bl, br, tr, tl
instead of Location *bl ...
and std::vector<Face>
instead of std::vector<Face*>
. Then you have a consecutive list of vertex coordinates which can be bound to a vertex buffer object:
class Face {
public:
Location bl;
Location br;
Location tr;
Location tl;
};
std::vector<Location> faces;
Create the vetrtex array object and bind the data
GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, faces.size()*sizeof(*faces.data()), faces.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
Draw the mesh:
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glVertexPointer( 3, GL_INT, sizeof(Location), nullptr );
glEnableClientState( GL_VERTEX_ARRAY );
glPushMatrix();
for (int i = 0; i < chunks.size(); i++) {
Chunk* chunk = chunks[i];
for (int j = 0; j < chunk->facesToRender.size(); j++) {
Face* f = chunk->facesToRender[j];
srand(i); // Create a color per chunk
glColor3ub(rand()%255, rand()%255, rand()%255);
glDrawArrays(GL_QUADS, j*4, 4);
}
}
glPopMatrix();
glDisableClientState( GL_VERTEX_ARRAY );
As an alternative you can create a list of vertex coordinates and a list of faces which each contains the 4 indices of the corner coordinates.
std::vector<Location> vertices;
struct Face
{
int bl;
int br;
int tr;
int tl;
};
std::vector<Face> faces;
Indexed vertex cordiaten can be drawn by glDrawElements
.
Related Topics
Cycles in Family Tree Software
How to Pretty-Print Stl Containers in Gdb
Can Openssl on Windows Use the System Certificate Store
What Is the Past-The-End Iterator in Stl C++
How to Hide Strings in a Exe or a Dll
How to Access Private Data Members Outside the Class Without Making "Friend"S
Why Does Storing References (Not Pointers) in Containers in C++ Not Work
Does the Behavior of Guaranteed Copy Elision Depend on Existence of User-Defined Copy Constructor
Converting Epoch Time to "Real" Date/Time
Getting a Vector<Derived*> into a Function That Expects a Vector<Base*>
Move Semantics == Custom Swap Function Obsolete
How to Get the Process Name in C++
Need to Call a Function at Periodic Time Intervals in C++
Std::Vector Removing Elements Which Fulfill Some Conditions
Why Can't Templates Be Within Extern "C" Blocks
How to Set a Breakpoint in Gdb That Is Conditional on the Call Stack