4

I'm building a graphics API for OpenGL, which is based off the basic call-to-draw graphics style. Basically, instead of storing the data into the GPU, and call it using it's handle, give the info to draw what it should be drawing each update. I know it's slow, but it's simple and it's for non-performance critical applications. Anyway, is there any modern equivalent to glBegin/glEnd? It doesn't have to a call for every vertex, but a way where I can send the data each update, without storing the vertices in the gpu?

user2896590
  • 45
  • 1
  • 1
  • 4
  • Retained mode example: http://stackoverflow.com/questions/6733934/what-does-immediate-mode-mean-in-opengl/36166310#36166310 – Ciro Santilli OurBigBook.com Apr 14 '16 at 11:32
  • 1
    @CiroSantilli新疆改造中心996ICU六四事件 'Retained Mode' has never existed within OpenGL. It's always been immediate, and always will be. Retained mode pertains to a specific portion of early versions of D3D that did everything for you. – robthebloke Sep 20 '19 at 06:59

2 Answers2

8

You pretty much answered your own question.

is there any modern equivalent to glBegin/glEnd? It doesn't have to a call for every vertex, but a way where I can send the data each update, without storing the vertices in the gpu?

Basically no, the modern way is to use VAOs with VBOs (and IBOs).

If you're going to change the data within the VBO, then remember that you can change the mode parameter in glBufferData.

  • GL_STREAM_DRAW - The data store contents will be modified once and used at most a few times.

  • GL_STATIC_DRAW - The data store contents will be modified once and used many times.

  • GL_DYNAMIC_DRAW - The data store contents will be modified repeatedly and used many times.

Then instead of using GL_STATIC_DRAW, then use GL_DYNAMIC_DRAW this will increase the FPS a lot compared to when using GL_STATIC_DRAW, though this depends on the amount of data, and how frequent you change it. But try to limit it as much as you can, like don't update the data within the buffers if you don't actually need to.

You can read more about the different buffers on the OpenGL Wiki.

vallentin
  • 23,478
  • 6
  • 59
  • 81
  • 1
    I think in reality, the performance increase provided by using the correct mode was not "a lot", but it does exist, and depends on your GPU and driver, so you should still get it right. Basically it helps the driver guess whether to keep the data in the main memory or the GPU memory. – user253751 Apr 04 '23 at 18:42
2

Look for VAO / VBO usage that is what you want to implement.
In C/C++ code bellow is a simple example.
Input variable mode is GL_POINTS/TRIANGLES/QUADS/... (as in glBegin())
This is also the only option with GLSL and core profile to pass attributes (glVertex/glNormal/... is unknown in core for some time now)

//------------------------------------------------------------------------------
//--- Open GL VAO example (GLSL) -----------------------------------------------
//------------------------------------------------------------------------------
#ifndef _OpenGL_VAO_example_h
#define _OpenGL_VAO_example_h
//------------------------------------------------------------------------------
GLuint vbo[4]={-1,-1,-1,-1};
GLuint vao[4]={-1,-1,-1,-1};
const float vao_pos[]=
    {
//       x      y     z
     0.75f, 0.75f, 0.0f,
     0.75f,-0.75f, 0.0f,
    -0.75f,-0.75f, 0.0f,
    };
const float vao_col[]=
    {
//      r   g    b
     1.0f,0.0f,0.0f,
     0.0f,1.0f,0.0f,
     0.0f,0.0f,1.0f,
     };
//---------------------------------------------------------------------------
void vao_init()
    {
    glGenVertexArrays(4,vao);
    glGenBuffers(4,vbo);

    glBindVertexArray(vao[0]);
        glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);

        glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    }
//---------------------------------------------------------------------------
void vao_exit()
    {
    glDeleteVertexArrays(4,vao);
    glDeleteBuffers(4,vbo);
    }
//---------------------------------------------------------------------------
void vao_draw(GLuint mode)
    {
    void *p=NULL;
    glBindVertexArray(vao[0]);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glDrawArrays(mode,0,3);
    glBindVertexArray(0);
    }
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------
//--- end. ---------------------------------------------------------------------
//------------------------------------------------------------------------------

If you do not want to use GLSL than you must change the code a little to something like this instead:

//tetraeder
#define V_SIZ 12
#define I_SIZ 6
GLfloat tet_verts[V_SIZ] = { \
-0.5f, -1.0f, -0.86f, \
-0.5f, -1.0f, 0.86f, \
1.0f, -1.0f, 0.0f, \
0.0f, 1.0f, 0.0f};

GLushort tet_index = {3, 0, 1, 2, 3, 0};


void init_buffers() {
    glGenBuffersARB(1, &vertex_buf);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buf);
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, V_SIZ*sizeof(GLfloat), tet_verts, GL_STATIC_DRAW_ARB); //upload data

    glGenBuffersARB(1, &index_buf);
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);
    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, I_SIZ*sizeof(GLushort), tet_index, GL_STATIC_DRAW_ARB); //upload data

    return;
}

void draw_buffers() {
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buf);
    glVertexPointer(3, GL_FLOAT, 0, 0); //3 is xyz, last 0 ("pointer") is offset in vertex-array

    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);

    glEnableClientState(GL_VERTEX_ARRAY);

    //use indexing
    glDrawElements(GL_TRIANGLE_STRIP, I_SIZ, GL_UNSIGNED_SHORT, 0); //last 0 is offset in element-array

    return;
}

void deinit_buffers() {
    glDeleteBuffersARB(1, &vertex_buf);
    glDeleteBuffersARB(1, &index_buf);

    return;
}

PS. i recommend not to use indexing its usually much slower on all cards i use but of course that takes more memory. Also indexing is not very good implemented on drivers sometimes gets buggy (even on nVidia and of course on ATI too if the correct circumstances are met)

If you want also shaders see my:

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • In modern OpenGL `gl*Pointer` calls are deprecated and will generate an error at runtime. – vallentin Oct 28 '13 at 07:32
  • In modern OpenGL you basically need to create a shader, before you can render your VAOs. (You don't need to, there is a default shader, though you're suppose to create a shader) – vallentin Oct 28 '13 at 07:38
  • but then what attribute number is per what? (vertex,color,normal,(multi)texture coords ???) and are they constantly enumerated or is there a way to obtain their actual layout position in default shader? I use shaders, but on some gfx its not possible (like Intel) and also not everyone is comfortale with shaders therefore i add also the second example – Spektre Oct 28 '13 at 07:44
  • Damn, I completely overlooked your VAO code. I only know that in the default shader (location = 0) is always the position. I never really use the default shader, and not at all if I also have normals, colors, etc. in the VAO. – vallentin Oct 28 '13 at 07:51
  • yeap... but i make corporate apps and they have to run safely on everything from Intel, Toshiba (crappy) notebokes to multicore nVidia/ATI based desktops so i have to use the old stuff sometimes ... – Spektre Oct 28 '13 at 08:30
  • Makes sense, I do that as well, though using deprecated functions doesn't answer the question. – vallentin Oct 28 '13 at 08:49