Handmade Hero » Forums » Code » Correct way to send data to OpenGL
OliverMarsh
Oliver
68 posts / 2 projects

A budding game developer and programmer

#15741 Correct way to send data to OpenGL
2 weeks ago Edited by Oliver on July 9, 2018, 6:37 a.m. 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);
    
}




ratchetfreak
377 posts
#15742 Correct way to send data to OpenGL
2 weeks ago

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.
OliverMarsh
Oliver
68 posts / 2 projects

A budding game developer and programmer

#15743 Correct way to send data to OpenGL
1 week, 6 days ago

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.
ratchetfreak
377 posts
#15744 Correct way to send data to OpenGL
1 week, 6 days ago

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.