Handmade Hero»Forums»Code
Oliver Marsh
193 posts / 1 project
Olster1.github.io
Correct way to send data to OpenGL
Edited by Oliver Marsh on Reason: Initial post
Hi Everyone,

I'm still getting used to using the later OpengGL (3.3 and above) where you create Vertex buffers. I'm making a game and it runs at 30fps, but I don't think there shouldn't be any reason it shouldn't run at 60 fps. The current set up is:

A push buffer for render items like Handmade hero , then render them at the end of the frame. Each Render item (so a sprite or rectangle) goes through this loadVertices function. I'm caching the buffer handles to avoid calling glBufferData each frame, but is there any thing I could be doing better. I'm sure Casey would have gone over this in one of the videos. Thanks for the help!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    
 void loadVertices(GLBufferHandles *bufferHandles, Vertex *triangleData, int triCount, 
unsigned int *indicesData, int indexCount, GLuint programId, 
ShapeType type, GLuint textureId, Matrix4 PVM, float zoom) {
    glUseProgram(programId);
    glCheckError();
    
    GLuint vaoHandle; 
    glGenVertexArrays(1, &vaoHandle);
    glBindVertexArray(vaoHandle);
    
    GLuint vertices;
    GLuint indices;

    if(bufferHandles && bufferHandles->valid) {
//get cached vertex data and index data
        vertices = bufferHandles->verticesIndex;
        indices = bufferHandles->indicesIndex;
    } else {
        glGenBuffers(1, &vertices);
        glBindBuffer(GL_ARRAY_BUFFER, vertices);

        glBufferData(GL_ARRAY_BUFFER, triCount*sizeof(Vertex), triangleData, GL_STREAM_DRAW);
        
        glGenBuffers(1, &indices);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);

        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount*sizeof(unsigned int), indicesData, GL_STREAM_DRAW);

        if(bufferHandles) {
            assert(!bufferHandles->valid);
            bufferHandles->verticesIndex = vertices;
            bufferHandles->indicesIndex = indices;
            bufferHandles->valid = true;
        }
    }

    GLint PVMUniform = glGetUniformLocation(programId, "PVM");
    glCheckError();
    
    glUniformMatrix4fv(PVMUniform, 1, GL_FALSE, PVM.val);
    glCheckError();
    
    glBindBuffer(GL_ARRAY_BUFFER, vertices);
    glCheckError();
    
    if(type == SHAPE_TEXTURE) {
        GLint texUniform = glGetUniformLocation(programId, "tex");
        glCheckError();
        
        glUniform1i(texUniform, 1);
        glCheckError();
        glActiveTexture(GL_TEXTURE1);
        glCheckError();
        
        glBindTexture(GL_TEXTURE_2D, textureId); 
        glCheckError();

          
    } 
    
    GLint vertexAttrib = glGetAttribLocation(programId, "vertex");
    glCheckError();
    GLint texUVAttrib = glGetAttribLocation(programId, "texUV");
    glCheckError();
    
    GLint colorAttrib = glGetAttribLocation(programId, "color");
    glCheckError();
    
    glEnableVertexAttribArray(texUVAttrib);  
    glCheckError();
    unsigned int texUV_offset = 6;
    glVertexAttribPointer(texUVAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((char *)0) + (texUV_offset*sizeof(float)));
    glCheckError();
    
    glEnableVertexAttribArray(colorAttrib);  
    glCheckError();
    unsigned int color_offset = 8;
    glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((char *)0) + (color_offset*sizeof(float)));
    glCheckError();
    
    glEnableVertexAttribArray(vertexAttrib);  
    glCheckError();
    glVertexAttribPointer(vertexAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glCheckError();
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0); 
    glCheckError();
    
    glDeleteVertexArrays(1, &vaoHandle);
    if(!bufferHandles) {
        glDeleteBuffers(1, &vertices);
        glDeleteBuffers(1, &indices);
    }
    glUseProgram(0);
    
}




511 posts
Correct way to send data to OpenGL
You can fix the attribute locations using glBindAttributeLocation before linking the program, then you don't need to query them each time, you could also cache the locations.

You should also add the VAO to the GLBufferHandles struct so you don't need to call glVertexAttribPointer each time.
Oliver Marsh
193 posts / 1 project
Olster1.github.io
Correct way to send data to OpenGL
So if I keep the vao handle around I don't have to call glVertexAttribPointer each time, I just have to use glBindVertexArray(vaoHandle) each frame?

Thanks for the help ratchetfreak.
511 posts
Correct way to send data to OpenGL
OliverMarsh
So if I keep the vao handle around I don't have to call glVertexAttribPointer each time, I just have to use glBindVertexArray(vaoHandle) each frame?

Thanks for the help ratchetfreak.


It's the entire point of VAOs, it also caches the GL_ELEMENT_ARRAY_BUFFER binding.