VBO状态调用的结构

I'm converting my OpenGL 2 program to OpenGL 3, one small step at a time. The current step is to get rid of immediate mode in favor of VBOs. I'm stumbling on the proper placement of all the VBO state management calls.

Let's assume I'm going to have a bunch of objects, each with its own VBOs for vertex and element data. Each object has a load function that sets up its VBOs and loads data into them; and it has a draw function that binds its VBOs and issues the appropriate draw command. To keep the objects from interfering with each other, my main loop should call PushClientAttrib(CLIENT_VERTEX_ARRAY_BIT) before either draw or load is called, correct? (And of course PopClientAttrib() after.)

When I push/pop that state to protect my load function, the object doesn't get drawn. It seems like there's some state I need to (re)set in my draw function, but I can't figure out what it could be.

Here's code to add a new object e to the scene, letting it call its load function:


    gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT)
    e.SceneAdded()
    gl.PopClientAttrib()

And here's how I call each object's draw function:


    gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT)
    gl.PushMatrix()
    p.Paint()
    gl.PopMatrix()
    gl.PopClientAttrib()

Here's the object's load function:


    // Make the vertex & texture data known to GL.
    gl.GenBuffers(1, &vboId)
    gl.BindBuffer(gl.ARRAY_BUFFER, vboId)
    gl.BufferData(gl.ARRAY_BUFFER,
        gl.Sizeiptr(unsafe.Sizeof(gldata[0])*uintptr(len(gldata))),
        gl.Pointer(&gldata[0].x), gl.STATIC_DRAW)
    gl.VertexPointer(3, gl.DOUBLE, gl.Sizei(unsafe.Sizeof(gldata[0])),
        gl.Pointer(unsafe.Offsetof(gldata[0].x)))
    gl.TexCoordPointer(2, gl.DOUBLE, gl.Sizei(unsafe.Sizeof(gldata[0])),
        gl.Pointer(unsafe.Offsetof(gldata[0].s)))

    // Make the index data known to GL.
    gl.GenBuffers(1, &iboId)
    gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, iboId)
    gl.BufferData(gl.ELEMENT_ARRAY_BUFFER,
        gl.Sizeiptr(unsafe.Sizeof(sd.indices[0])*uintptr(len(sd.indices))),
        gl.Pointer(&sd.indices[0]), gl.STATIC_DRAW)

Finally, here's the object's draw function:


func draw() {
    gl.BindBuffer(gl.ARRAY_BUFFER, vboId)
    gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, iboId)
    gl.EnableClientState(gl.VERTEX_ARRAY)
    gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)

    gl.DrawElements(gl.TRIANGLES, indexcount, gl.UNSIGNED_SHORT, nil)
}

Just to be clear, if I move the two EnableClientState calls from draw to load, and if I don't protect load with PushClientState, everything works fine.

The answer to the question I actually asked is that gl.VertexPointer() and friends need to be called from the object's draw function. My main loop is pushing and popping all state related to client vertices, so of course that gets lost.

The question I implied is, "How can I convert my old, GL2 program to new, GL3 code?" That's answered very elegantly here.

I'm converting my OpenGL 2 program to OpenGL 3

Well then the following

To keep the objects from interfering with each other, my main loop should call PushClientAttrib(CLIENT_VERTEX_ARRAY_BIT) before either draw or load is called, correct? (And of course PopClientAttrib() after.)

is not a sane approach. glPushAttrib and glPopAttrib are deprecated, i.e. should not be used in OpenGL-3 program.

Also OpenGL vertex arrays don't use glVertexPointer the use glVertexAttribPointer. Attribute pointer state can be managed (and I recommend that) in a Vertex Array Object, which you can bind/unbind.


BTW: When you wrote for OpenGL-2, why did you use immediate mode in the first place? Use of immediate mode is discouraged ever since OpenGL-1.1, when vertex arrays had been introduced. And already with OpenGL-2 it was considered to remove immediate mode.