// This Draw method is a wrapper to gl.DrawElements. func (drawer DrawElement) Draw() { gl.DrawElements(drawer.mode, drawer.count, drawer.typ, drawer.indices) if err := CheckGlError(); err != nil { err.Description = "gl.DrawElements" panic(err) } }
func (m *Map) Draw() { // gl.Enable(gl.PRIMITIVE_RESTART) // gl.PrimitiveRestartIndex(PRIMITIVE_RESTART) gl.EnableClientState(gl.VERTEX_ARRAY) gl.Translatef(float32(m.gridSize/2), float32(m.gridSize/2), 0) if m.renderSmooth { gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.POLYGON_SMOOTH) gl.Hint(gl.POLYGON_SMOOTH_HINT, gl.NICEST) } if m.renderMode == 1 { gl.LineWidth(1) gl.VertexPointer(2, gl.FLOAT, 0, m.gridLines) gl.Color3f(0.2, 0.2, 0.2) gl.DrawArrays(gl.LINES, 0, len(m.gridLines)/2) gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE) } for _, vl := range m.vl { if len(vl.vertices) > 0 { gl.VertexPointer(2, gl.FLOAT, 0, vl.vertices) gl.Color3f(vl.colors[0], vl.colors[1], vl.colors[2]) gl.DrawElements(gl.TRIANGLES, len(vl.indices), gl.UNSIGNED_INT, vl.indices) } } }
func fill(canv *Canvas, alphaTex *glh.Texture, paint *Paint) { gGl.GlColorConfig.SetColor(paint.fillColor) defer gGl.GlColorConfig.Reset() gGl.Activate(gGl.FillDrawer) gl.ColorMask(true, true, true, true) gl.StencilMask(0x3) gl.StencilFunc(gl.LESS, 0, 0xff) w, h := canv.W, canv.H p := canv.toGLPoints([]Point{ iPt(0, 0), iPt(w, 0), iPt(w, h), iPt(0, h), }) vertices := []float32{ p[0].X, p[0].Y, 0, 1, p[1].X, p[1].Y, 1, 1, p[2].X, p[2].Y, 1, 0, p[3].X, p[3].Y, 0, 0, } gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, vertices, gl.STATIC_DRAW) elements := []uint32{ 0, 1, 2, 2, 3, 0, } gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(elements)*4, elements, gl.STATIC_DRAW) glh.With(alphaTex, func() { gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) }) }
func (w World) Draw() { w.program.Use() w.vao.Bind() w.vbo.Bind(gl.ARRAY_BUFFER) w.ibo.Bind(gl.ELEMENT_ARRAY_BUFFER) posLoc.EnableArray() colorLoc.EnableArray() gl.DrawElements(gl.LINES, int(len(w.indices)), gl.UNSIGNED_INT, uintptr(0)) colorLoc.DisableArray() posLoc.DisableArray() w.ibo.Unbind(gl.ELEMENT_ARRAY_BUFFER) w.vbo.Unbind(gl.ARRAY_BUFFER) }
// Bind all the OpenGL buffers and such and draw the elements. func (m Model) Draw() { m.program.Use() m.vao.Bind() m.vbo.Bind(gl.ARRAY_BUFFER) m.ibo.Bind(gl.ELEMENT_ARRAY_BUFFER) posLoc.EnableArray() colorLoc.EnableArray() gl.DrawElements(gl.TRIANGLES, int(len(m.indices)), gl.UNSIGNED_INT, uintptr(0)) colorLoc.DisableArray() posLoc.DisableArray() m.ibo.Unbind(gl.ELEMENT_ARRAY_BUFFER) m.vbo.Unbind(gl.ARRAY_BUFFER) }
func (self *OpenGLRenderer) renderOne(operation render.RenderOperation, renderState RenderState) { mesh := operation.Mesh material := operation.Material transform := operation.Transform // No attributes? no loaded or empty? Better way to handle this than spamming // the console? if mesh.VertexArrayObj == nil { log.Println("WARNING: Trying to render an invalid mesh", mesh) return } vertexArrayObj := mesh.VertexArrayObj.(gl.VertexArray) vertexArrayObj.Bind() material.Shader.Program.Use() material.Shader.Program.SetUniformMatrix( "modelViewProjection", renderState.ViewProjection.Times(transform), ) if material.Texture != nil { glTexture := material.Texture.Id.(gl.Texture) gl.ActiveTexture(gl.TEXTURE0) if !material.IsCubeMap { glTexture.Bind(gl.TEXTURE_2D) defer glTexture.Unbind(gl.TEXTURE_2D) material.Shader.Program.SetUniformUnit("textureSampler", 0) } else { gl.Disable(gl.DEPTH_TEST) defer gl.Enable(gl.DEPTH_TEST) glTexture.Bind(gl.TEXTURE_CUBE_MAP) defer glTexture.Unbind(gl.TEXTURE_CUBE_MAP) material.Shader.Program.SetUniformUnit("cubeMap", 0) } } if len(mesh.IndexList) == 0 { gl.DrawArrays(gl.TRIANGLES, 0, len(mesh.VertexList)*3) } else { gl.DrawElements(gl.TRIANGLES, len(mesh.IndexList), gl.UNSIGNED_INT, nil) } }
// 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, program gl.Program) { is, ic := m[mbIndexKey][0], m[mbIndexKey][1] program.Use() var attribLocation gl.AttribLocation for _, value := range mb.attr { if value.name == "index" { continue } value.bind() if value.Invalid() { value.buffer() } attribLocation = program.GetAttribLocation(value.name) attribLocation.EnableArray() attribLocation.AttribPointer(value.size, value.typ, false, 0, uintptr(0)) value.unbind() } ia := mb.find(mbIndexKey) ia.bind() if ia.Invalid() { ia.buffer() } gl.DrawElements(mode, ic, ia.typ, uintptr(is*ia.stride)) ia.unbind() for _, value := range mb.attr { if value.name == "index" { continue } attribLocation := program.GetAttribLocation(value.name) attribLocation.DisableArray() } }
// 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 handleElement(camera *PerspectiveCamera, element SceneObject) { // Material material := element.Material() program := material.Program() if program == nil { program = createProgram(element) material.SetProgram(program) } program.Use() defer program.Unuse() view := camera.Transform.modelMatrix().Inv() model := element.Transform().modelMatrix() projection := camera.projectionMatrix MVP := projection.Mul4(view).Mul4(model) // Set model view projection matrix program.uniforms["MVP"].apply(MVP) program.uniforms["M"].apply(model) program.uniforms["V"].apply(view) // Light position lightPos := mgl32.Vec3{4., 4., 4.} program.uniforms["LightPosition_worldspace"].apply(lightPos) if c, ok := material.(Colored); ok { if c.Color() != nil { program.uniforms["diffuse"].apply(c.Color()) } } if t, ok := material.(Textured); ok { texture := t.Texture() if texture != nil { gl.ActiveTexture(gl.TEXTURE0) texture.Bind() defer texture.Unbind() program.uniforms["texture"].apply(texture) program.uniforms["repeat"].apply(texture.Repeat) } } for _, attribute := range program.attributes { attribute.enable() defer attribute.disable() attribute.bindBuffer() defer attribute.unbindBuffer() attribute.pointer() attribute.bindBuffer() } vertexAttrib := gl.AttribLocation(0) vertexAttrib.EnableArray() defer vertexAttrib.DisableArray() element.VertexBuffer().Bind(gl.ARRAY_BUFFER) defer element.VertexBuffer().Unbind(gl.ARRAY_BUFFER) vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil) if t, ok := material.(Wireframed); ok { if t.Wireframe() { gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE) } else { gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL) } } // If index available index := element.Index() if index != nil && index.count > 0 { index.enable() defer index.disable() gl.DrawElements(gl.TRIANGLES, index.count, gl.UNSIGNED_SHORT, nil) } else { gl.DrawArrays(element.Mode(), 0, element.Geometry().ArrayCount()) } }
// Draw makes a glDrawElements call using the previously set uniforms and // geometry. func (s *Shader) Draw() { gl.DrawElements(gl.TRIANGLES, s.indexCount, s.indexType, uintptr(s.indexOffset)) }
func main() { if err := glfw.Init(); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err.Error()) return } defer glfw.Terminate() glfw.OpenWindowHint(glfw.FsaaSamples, 4) glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3) glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3) glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err.Error()) return } glfw.SetSwapInterval(0) //gl.GlewExperimental(true) gl.Init() // Can't find gl.GLEW_OK or any variation, not sure how to check if this worked gl.GetError() // ignore error, since we're telling it to use CoreProfile above, we get "invalid enumerant" (GLError 1280) which freaks the OpenGLSentinel out glfw.SetWindowTitle("Tutorial 09") glfw.Enable(glfw.StickyKeys) glfw.Disable(glfw.MouseCursor) // Not in the original tutorial, but IMO it SHOULD be there glfw.SetMousePos(1024.0/2.0, 768.0/2.0) gl.ClearColor(0., 0., 0.4, 0.) gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.Enable(gl.CULL_FACE) camera := input.NewCamera() vertexArray := gl.GenVertexArray() defer vertexArray.Delete() vertexArray.Bind() prog := helper.MakeProgram("StandardShading.vertexshader", "StandardShading.fragmentshader") defer prog.Delete() matrixID := prog.GetUniformLocation("MVP") viewMatrixID := prog.GetUniformLocation("V") modelMatrixID := prog.GetUniformLocation("M") texture := helper.MakeTextureFromTGA("uvmap.tga") // Had to convert to tga, go-gl is missing the texture method for DDS right now defer texture.Delete() texSampler := prog.GetUniformLocation("myTextureSampler") meshObj := objloader.LoadObject("suzanne.obj") indices, indexedVertices, indexedUVs, indexedNormals := indexer.IndexVBO(meshObj.Vertices, meshObj.UVs, meshObj.Normals) vertexBuffer := gl.GenBuffer() defer vertexBuffer.Delete() vertexBuffer.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, len(indexedVertices)*3*4, indexedVertices, gl.STATIC_DRAW) uvBuffer := gl.GenBuffer() defer uvBuffer.Delete() uvBuffer.Bind(gl.ARRAY_BUFFER) // And yet, the weird length stuff doesn't seem to matter for UV or normal gl.BufferData(gl.ARRAY_BUFFER, len(indexedUVs)*2*4, indexedUVs, gl.STATIC_DRAW) normBuffer := gl.GenBuffer() defer normBuffer.Delete() normBuffer.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, len(indexedNormals)*3*4, indexedNormals, gl.STATIC_DRAW) elementBuffer := gl.GenBuffer() defer elementBuffer.Delete() elementBuffer.Bind(gl.ELEMENT_ARRAY_BUFFER) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*2, indices, gl.STATIC_DRAW) // NOTE: a GL_UNSIGNED_SHORT is 16-bits lightID := prog.GetUniformLocation("LightPosition_worldspace") lastTime := glfw.Time() nbFrames := 0 // Equivalent to a do... while for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE && glfw.Key('Q') != glfw.KeyPress) { currTime := glfw.Time() nbFrames++ if currTime-lastTime >= 1.0 { fmt.Printf("%f ms/frame\n", 1000.0/float64(nbFrames)) nbFrames = 0 lastTime += 1.0 } func() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) prog.Use() defer gl.ProgramUnuse() view, proj := camera.ComputeViewPerspective() model := mathgl.Ident4f() MVP := proj.Mul4(view).Mul4(model) //mvpArray := mvp.AsCMOArray(mathgl.FLOAT32).([16]float32) //vArray := view.AsCMOArray(mathgl.FLOAT32).([16]float32) //mArray := model.AsCMOArray(mathgl.FLOAT32).([16]float32) matrixID.UniformMatrix4fv(false, MVP) viewMatrixID.UniformMatrix4fv(false, view) modelMatrixID.UniformMatrix4fv(false, model) lightID.Uniform3f(4., 4., 4.) gl.ActiveTexture(gl.TEXTURE0) texture.Bind(gl.TEXTURE_2D) defer texture.Unbind(gl.TEXTURE_2D) texSampler.Uniform1i(0) vertexAttrib := gl.AttribLocation(0) vertexAttrib.EnableArray() defer vertexAttrib.DisableArray() vertexBuffer.Bind(gl.ARRAY_BUFFER) defer vertexBuffer.Unbind(gl.ARRAY_BUFFER) vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil) uvAttrib := gl.AttribLocation(1) uvAttrib.EnableArray() defer uvAttrib.DisableArray() uvBuffer.Bind(gl.ARRAY_BUFFER) defer uvBuffer.Unbind(gl.ARRAY_BUFFER) uvAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil) normAttrib := gl.AttribLocation(2) normAttrib.EnableArray() defer normAttrib.DisableArray() normBuffer.Bind(gl.ARRAY_BUFFER) defer normBuffer.Unbind(gl.ARRAY_BUFFER) normAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil) elementBuffer.Bind(gl.ELEMENT_ARRAY_BUFFER) defer elementBuffer.Unbind(gl.ELEMENT_ARRAY_BUFFER) gl.DrawElements(gl.TRIANGLES, len(indices), gl.UNSIGNED_SHORT, nil) glfw.SwapBuffers() }() // Defers unbinds and disables to here, end of the loop } }
func main() { runtime.LockOSThread() if !glfw.Init() { fmt.Fprintf(os.Stderr, "Can't open GLFW") return } defer glfw.Terminate() glfw.WindowHint(glfw.Samples, 4) glfw.WindowHint(glfw.ContextVersionMajor, 3) glfw.WindowHint(glfw.ContextVersionMinor, 3) glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile) glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True) // needed for macs window, err := glfw.CreateWindow(1024, 768, "Tutorial 8", nil, nil) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return } window.MakeContextCurrent() gl.Init() gl.GetError() // Ignore error window.SetInputMode(glfw.StickyKeys, 1) window.SetCursorPosition(1024/2, 768/2) window.SetInputMode(glfw.Cursor, glfw.CursorHidden) gl.ClearColor(0., 0., 0.4, 0.) gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.Enable(gl.CULL_FACE) camera := input.NewCamera(window) vertexArray := gl.GenVertexArray() defer vertexArray.Delete() vertexArray.Bind() prog := helper.MakeProgram("StandardShading.vertexshader", "StandardShading.fragmentshader") defer prog.Delete() matrixID := prog.GetUniformLocation("MVP") viewMatrixID := prog.GetUniformLocation("V") modelMatrixID := prog.GetUniformLocation("M") texture, err := helper.TextureFromDDS("uvmap.DDS") if err != nil { fmt.Printf("Could not load texture: %v\n", err) } defer texture.Delete() texSampler := prog.GetUniformLocation("myTextureSampler") meshObj := objloader.LoadObject("suzanne.obj", true) indices, indexedVertices, indexedUVs, indexedNormals := indexer.IndexVBOSlow(meshObj.Vertices, meshObj.UVs, meshObj.Normals) vertexBuffer := gl.GenBuffer() defer vertexBuffer.Delete() vertexBuffer.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, len(indexedVertices)*3*4, indexedVertices, gl.STATIC_DRAW) uvBuffer := gl.GenBuffer() defer uvBuffer.Delete() uvBuffer.Bind(gl.ARRAY_BUFFER) // And yet, the weird length stuff doesn't seem to matter for UV or normal gl.BufferData(gl.ARRAY_BUFFER, len(indexedUVs)*2*4, indexedUVs, gl.STATIC_DRAW) normBuffer := gl.GenBuffer() defer normBuffer.Delete() normBuffer.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, len(indexedNormals)*3*4, indexedNormals, gl.STATIC_DRAW) elementBuffer := gl.GenBuffer() defer elementBuffer.Delete() elementBuffer.Bind(gl.ELEMENT_ARRAY_BUFFER) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*2, indices, gl.STATIC_DRAW) // NOTE: a GL_UNSIGNED_SHORT is 16-bits lightID := prog.GetUniformLocation("LightPosition_worldspace") lastTime := glfw.GetTime() nbFrames := 0 // Equivalent to a do... while for ok := true; ok; ok = (window.GetKey(glfw.KeyEscape) != glfw.Press && !window.ShouldClose()) { currTime := glfw.GetTime() nbFrames++ if currTime-lastTime >= 1.0 { fmt.Printf("%f ms/frame\n", 1000.0/float64(nbFrames)) nbFrames = 0 lastTime += 1.0 } func() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) prog.Use() defer gl.ProgramUnuse() view, proj := camera.ComputeViewPerspective() model := mgl32.Ident4() MVP := proj.Mul4(view).Mul4(model) //mvpArray := mvp.AsCMOArray(mathgl.FLOAT32).([16]float32) //vArray := view.AsCMOArray(mathgl.FLOAT32).([16]float32) //mArray := model.AsCMOArray(mathgl.FLOAT32).([16]float32) matrixID.UniformMatrix4fv(false, MVP) viewMatrixID.UniformMatrix4fv(false, view) modelMatrixID.UniformMatrix4fv(false, model) lightID.Uniform3f(4., 4., 4.) gl.ActiveTexture(gl.TEXTURE0) texture.Bind(gl.TEXTURE_2D) defer texture.Unbind(gl.TEXTURE_2D) texSampler.Uniform1i(0) vertexAttrib := gl.AttribLocation(0) vertexAttrib.EnableArray() defer vertexAttrib.DisableArray() vertexBuffer.Bind(gl.ARRAY_BUFFER) defer vertexBuffer.Unbind(gl.ARRAY_BUFFER) vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil) uvAttrib := gl.AttribLocation(1) uvAttrib.EnableArray() defer uvAttrib.DisableArray() uvBuffer.Bind(gl.ARRAY_BUFFER) defer uvBuffer.Unbind(gl.ARRAY_BUFFER) uvAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil) normAttrib := gl.AttribLocation(2) normAttrib.EnableArray() defer normAttrib.DisableArray() normBuffer.Bind(gl.ARRAY_BUFFER) defer normBuffer.Unbind(gl.ARRAY_BUFFER) normAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil) elementBuffer.Bind(gl.ELEMENT_ARRAY_BUFFER) defer elementBuffer.Unbind(gl.ELEMENT_ARRAY_BUFFER) gl.DrawElements(gl.TRIANGLES, len(indices), gl.UNSIGNED_SHORT, nil) window.SwapBuffers() glfw.PollEvents() }() // Defers unbinds and disables to here, end of the loop } }