// Arrays mode uses vertex arrays which involves gl*Pointer calls and // directly passing in the vertex data on every render pass. This is slower // than using VBO's, because the data has to be uploaded to the GPU on every // render pass, but it is useful for older systems where glBufferData is // not available. func (mb *MeshBuffer) renderArrays(mode gl.GLenum, m Mesh, pa, ca, na, ta, ia *Attr) { ps, pc := m[mbPositionKey][0], m[mbPositionKey][1] is, ic := m[mbIndexKey][0], m[mbIndexKey][1] cc := m[mbColorKey][1] nc := m[mbNormalKey][1] tc := m[mbTexCoordKey][1] gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT) defer gl.PopClientAttrib() if pc > 0 { gl.EnableClientState(gl.VERTEX_ARRAY) defer gl.DisableClientState(gl.VERTEX_ARRAY) gl.VertexPointer(pa.size, pa.typ, 0, pa.ptr(0)) } if cc > 0 { gl.EnableClientState(gl.COLOR_ARRAY) defer gl.DisableClientState(gl.COLOR_ARRAY) gl.ColorPointer(ca.size, ca.typ, 0, ca.ptr(0)) } if nc > 0 { gl.EnableClientState(gl.NORMAL_ARRAY) defer gl.DisableClientState(gl.NORMAL_ARRAY) gl.NormalPointer(na.typ, 0, na.ptr(0)) } if tc > 0 { gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) defer gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) gl.TexCoordPointer(ta.size, ta.typ, 0, ta.ptr(0)) } if ic > 0 { gl.EnableClientState(gl.INDEX_ARRAY) defer gl.DisableClientState(gl.INDEX_ARRAY) gl.IndexPointer(ia.typ, 0, ia.ptr(0)) gl.DrawElements(mode, ic, ia.typ, ia.ptr(is*ia.size)) } else { gl.DrawArrays(mode, ps, pc) } }
// renderBuffered uses VBO's. This is the preferred mode for systems // where shader support is not present or deemed necessary. func (mb *MeshBuffer) renderBuffered(mode gl.GLenum, m Mesh, pa, ca, na, ta, ia *Attr) { ps, pc := m[mbPositionKey][0], m[mbPositionKey][1] is, ic := m[mbIndexKey][0], m[mbIndexKey][1] cc := m[mbColorKey][1] nc := m[mbNormalKey][1] tc := m[mbTexCoordKey][1] if pc > 0 { gl.EnableClientState(gl.VERTEX_ARRAY) defer gl.DisableClientState(gl.VERTEX_ARRAY) pa.bind() if pa.Invalid() { pa.buffer() } gl.VertexPointer(pa.size, pa.typ, 0, uintptr(0)) pa.unbind() } if cc > 0 { gl.EnableClientState(gl.COLOR_ARRAY) defer gl.DisableClientState(gl.COLOR_ARRAY) ca.bind() if ca.Invalid() { ca.buffer() } gl.ColorPointer(ca.size, ca.typ, 0, uintptr(0)) ca.unbind() } if nc > 0 { gl.EnableClientState(gl.NORMAL_ARRAY) defer gl.DisableClientState(gl.NORMAL_ARRAY) na.bind() if na.Invalid() { na.buffer() } gl.NormalPointer(na.typ, 0, uintptr(0)) na.unbind() } if tc > 0 { gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) defer gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) ta.bind() if ta.Invalid() { ta.buffer() } gl.TexCoordPointer(ta.size, ta.typ, 0, uintptr(0)) ta.unbind() } if ic > 0 { ia.bind() if ia.Invalid() { ia.buffer() } gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT) gl.DrawElements(mode, ic, ia.typ, uintptr(is*ia.stride)) gl.PopClientAttrib() ia.unbind() } else { pa.bind() gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT) gl.DrawArrays(mode, ps, pc) gl.PopClientAttrib() pa.unbind() } }
func (r *RenderTarget) Render(verts []Vertex, primType PrimitiveType, states RenderStates) { // Nothing to draw? if len(verts) == 0 { return } // First set the persistent OpenGL states if it's the very first call if !r.glStatesSet { r.resetGlStates() } // Check if the vertex count is low enough so that we can pre-transform them useVertexCache := len(verts) <= vertexCacheSize if useVertexCache { // Pre-transform the vertices and store them into the vertex cache for i := 0; i < len(verts); i++ { r.vpCache[i] = states.Transform.TransformPoint(verts[i].Pos) r.vcCache[i] = verts[i].Color r.vtCache[i] = verts[i].TexCoords } // Since vertices are transformed, we must use an identity transform to render them if !r.useVertexCache { r.applyTransform(IdentityTransform()) } } else { r.applyTransform(states.Transform) } // Apply the view if r.viewChanged { r.applyCurrentView() } // Apply the blend mode if states.BlendMode != r.lastBlendMode { r.applyBlendMode(states.BlendMode) } // Apply the texture var textureId uint64 if states.Texture != nil { textureId = states.Texture.cacheId } if textureId != r.lastTextureId { r.applyTexture(states.Texture) } // Apply the shader // TODO /*if states.shader { applyShader(states.shader); }*/ // ######################################### if !useVertexCache { // Find the OpenGL primitive type modes := [...]gl.GLenum{gl.POINTS, gl.LINES, gl.LINE_STRIP, gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN, gl.QUADS} mode := modes[primType] gl.Begin(mode) for i, _ := range verts { gl.TexCoord2f(verts[i].TexCoords.X, verts[i].TexCoords.Y) gl.Color4f(float32(verts[i].Color.R)/255, float32(verts[i].Color.G)/255, float32(verts[i].Color.B)/255, float32(verts[i].Color.A)/255) gl.Vertex2f(verts[i].Pos.X, verts[i].Pos.Y) } gl.End() } // ######################################### // Setup the pointers to the vertices' components // ... and if we already used it previously, we don't need to set the pointers again if useVertexCache { if !r.useVertexCache { gl.VertexPointer(2, gl.FLOAT, 0, r.vpCache[:]) gl.ColorPointer(4, gl.UNSIGNED_BYTE, 0, r.vcCache[:]) gl.TexCoordPointer(2, gl.FLOAT, 0, r.vtCache[:]) } // Find the OpenGL primitive type modes := [...]gl.GLenum{gl.POINTS, gl.LINES, gl.LINE_STRIP, gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN, gl.QUADS} mode := modes[primType] // Draw the primitives gl.DrawArrays(mode, 0, len(verts)) } // Unbind the shader, if any // TODO /*if (states.shader) { r.applyShader(nil) }*/ // Update the cache r.useVertexCache = useVertexCache }