remove Doer and replace with BeginEnder

This commit is contained in:
faiface 2016-12-31 01:33:53 +01:00
parent 727c9bd772
commit 2b6205fe45
4 changed files with 281 additions and 394 deletions

View File

@ -1,76 +1,11 @@
package pixelgl package pixelgl
// Doer is an interface for manipulating OpenGL state. // BeginEnder is an interface for manipulating OpenGL state.
// //
// OpenGL is a state machine. Every object can 'enter' it's state and 'leave' it's state. For // OpenGL is a state machine. Every object can 'enter' it's state and 'leave' it's state. For
// example, you can bind a buffer and unbind a buffer, bind a texture and unbind it, use shader // example, you can bind a buffer and unbind a buffer, bind a texture and unbind it, use shader
// and unuse it, and so on. // and unuse it, and so on.
// type BeginEnder interface {
// This interface provides a clever and flexible way to do it. A typical workflow of an OpenGL Begin()
// object is that you enter (load, bind) that object's state, then do something with it, and End()
// then leave the state. That 'something' in between, let's call it sub (as in subroutine).
//
// The recommended way to implement a Doer is to wrap another Doer (vertex array wraps texture
// and so on), let's call it parent. Then the Do method will look like this:
//
// func (o *MyObject) Do(sub func(Context)) {
// o.parent.Do(func(ctx Context) {
// // enter the object's state
// sub(ctx)
// // leave the object's state
// })
// }
//
// It might seem difficult to grasp this kind of recursion at first, but it's really simple. What
// it's basically saying is: "Hey parent, enter your state, then let me enter mine, then I'll
// do whatever I'm supposed to do in the middle. After that I'll leave my state and please
// leave your state too parent."
//
// Also notice, that the functions are passing a Context around. This context contains the
// most important state variables. Usually, you just pass it as you received it. If you want
// to pass a changed context to your child (e.g. your a shader), use ctx.With* methods.
//
// If possible and makes sense, Do method should be reentrant.
type Doer interface {
Do(sub func(Context))
} }
// Context takes state from one object to another. OpenGL is a state machine, so we have
// to approach it like that. However, global variables are evil, so we have Context, that
// transfers important OpenGL state from one object to another.
//
// This type does *not* represent an OpenGL context in the OpenGL terminology.
type Context struct {
shader *Shader
}
// Shader returns the current shader.
func (c Context) Shader() *Shader {
return c.shader
}
// WithShader returns a copy of this context with the specified shader.
func (c Context) WithShader(s *Shader) Context {
return Context{
shader: s,
}
}
// ContextHolder is a root Doer with no parent. It simply forwards a context to a child.
type ContextHolder struct {
Context Context
}
// Do calls sub and passes it the held context.
func (ch ContextHolder) Do(sub func(ctx Context)) {
sub(ch.Context)
}
type noOpDoer struct{}
func (noOpDoer) Do(sub func(ctx Context)) {
sub(Context{})
}
// NoOpDoer is a Doer that just passes an empty context to the caller of Do.
var NoOpDoer Doer = noOpDoer{}

View File

@ -10,7 +10,6 @@ import (
// Shader is an OpenGL shader program. // Shader is an OpenGL shader program.
type Shader struct { type Shader struct {
parent Doer
program binder program binder
vertexFmt AttrFormat vertexFmt AttrFormat
uniformFmt AttrFormat uniformFmt AttrFormat
@ -22,9 +21,8 @@ type Shader struct {
// //
// Note that vertexShader and fragmentShader parameters must contain the source code, they're // Note that vertexShader and fragmentShader parameters must contain the source code, they're
// not filenames. // not filenames.
func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader string) (*Shader, error) { func NewShader(vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader string) (*Shader, error) {
shader := &Shader{ shader := &Shader{
parent: parent,
program: binder{ program: binder{
restoreLoc: gl.CURRENT_PROGRAM, restoreLoc: gl.CURRENT_PROGRAM,
bindFunc: func(obj uint32) { bindFunc: func(obj uint32) {
@ -36,9 +34,6 @@ func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, frag
uniforms: make(map[string]int32), uniforms: make(map[string]int32),
} }
var err error
parent.Do(func(ctx Context) {
err = DoErr(func() error {
var vshader, fshader uint32 var vshader, fshader uint32
// vertex shader // vertex shader
@ -57,7 +52,7 @@ func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, frag
gl.GetShaderiv(vshader, gl.COMPILE_STATUS, &success) gl.GetShaderiv(vshader, gl.COMPILE_STATUS, &success)
if success == 0 { if success == 0 {
gl.GetShaderInfoLog(vshader, int32(len(infoLog)), nil, &infoLog[0]) gl.GetShaderInfoLog(vshader, int32(len(infoLog)), nil, &infoLog[0])
return fmt.Errorf("error compiling vertex shader: %s", string(infoLog)) return nil, fmt.Errorf("error compiling vertex shader: %s", string(infoLog))
} }
defer gl.DeleteShader(vshader) defer gl.DeleteShader(vshader)
@ -79,7 +74,7 @@ func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, frag
gl.GetShaderiv(fshader, gl.COMPILE_STATUS, &success) gl.GetShaderiv(fshader, gl.COMPILE_STATUS, &success)
if success == 0 { if success == 0 {
gl.GetShaderInfoLog(fshader, int32(len(infoLog)), nil, &infoLog[0]) gl.GetShaderInfoLog(fshader, int32(len(infoLog)), nil, &infoLog[0])
return fmt.Errorf("error compiling fragment shader: %s", string(infoLog)) return nil, fmt.Errorf("error compiling fragment shader: %s", string(infoLog))
} }
defer gl.DeleteShader(fshader) defer gl.DeleteShader(fshader)
@ -99,7 +94,7 @@ func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, frag
gl.GetProgramiv(shader.program.obj, gl.LINK_STATUS, &success) gl.GetProgramiv(shader.program.obj, gl.LINK_STATUS, &success)
if success == 0 { if success == 0 {
gl.GetProgramInfoLog(shader.program.obj, int32(len(infoLog)), nil, &infoLog[0]) gl.GetProgramInfoLog(shader.program.obj, int32(len(infoLog)), nil, &infoLog[0])
return fmt.Errorf("error linking shader program: %s", string(infoLog)) return nil, fmt.Errorf("error linking shader program: %s", string(infoLog))
} }
} }
@ -109,13 +104,6 @@ func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, frag
shader.uniforms[name] = loc shader.uniforms[name] = loc
} }
return nil
})
})
if err != nil {
return nil, err
}
runtime.SetFinalizer(shader, (*Shader).delete) runtime.SetFinalizer(shader, (*Shader).delete)
return shader, nil return shader, nil
@ -163,14 +151,13 @@ func (s *Shader) UniformFormat() AttrFormat {
// Attr{Type: Mat42}: mgl32.Mat4x2 // Attr{Type: Mat42}: mgl32.Mat4x2
// Attr{Type: Mat43}: mgl32.Mat4x3 // Attr{Type: Mat43}: mgl32.Mat4x3
// No other types are supported. // No other types are supported.
//
// The shader must be bound before calling this method.
func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) { func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) {
if !s.uniformFmt.Contains(attr) { if !s.uniformFmt.Contains(attr) {
return false return false
} }
DoNoBlock(func() {
s.program.bind()
switch attr.Type { switch attr.Type {
case Int: case Int:
value := value.(int32) value := value.(int32)
@ -218,21 +205,15 @@ func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) {
panic("set uniform attr: invalid attribute type") panic("set uniform attr: invalid attribute type")
} }
s.program.restore()
})
return true return true
} }
// Do stars using a shader, executes sub, and stops using it. // Begin binds a shader program. This is necessary before using the shader.
func (s *Shader) Do(sub func(Context)) { func (s *Shader) Begin() {
s.parent.Do(func(ctx Context) {
DoNoBlock(func() {
s.program.bind() s.program.bind()
}) }
sub(ctx.WithShader(s))
DoNoBlock(func() { // End unbinds a shader program and restores the previous one.
s.program.restore() func (s *Shader) End() {
}) s.program.restore()
})
} }

View File

@ -1,20 +1,21 @@
package pixelgl package pixelgl
import "github.com/go-gl/gl/v3.3-core/gl" import (
import "runtime" "runtime"
"github.com/go-gl/gl/v3.3-core/gl"
)
// Texture is an OpenGL texture. // Texture is an OpenGL texture.
type Texture struct { type Texture struct {
parent Doer
tex binder tex binder
width, height int width, height int
} }
// NewTexture creates a new texture with the specified width and height. // NewTexture creates a new texture with the specified width and height.
// The pixels must be a sequence of RGBA values. // The pixels must be a sequence of RGBA values.
func NewTexture(parent Doer, width, height int, smooth bool, pixels []uint8) (*Texture, error) { func NewTexture(width, height int, smooth bool, pixels []uint8) (*Texture, error) {
texture := &Texture{ texture := &Texture{
parent: parent,
tex: binder{ tex: binder{
restoreLoc: gl.TEXTURE_BINDING_2D, restoreLoc: gl.TEXTURE_BINDING_2D,
bindFunc: func(obj uint32) { bindFunc: func(obj uint32) {
@ -25,10 +26,10 @@ func NewTexture(parent Doer, width, height int, smooth bool, pixels []uint8) (*T
height: height, height: height,
} }
parent.Do(func(ctx Context) {
Do(func() {
gl.GenTextures(1, &texture.tex.obj) gl.GenTextures(1, &texture.tex.obj)
defer texture.tex.bind().restore()
texture.Begin()
defer texture.End()
gl.TexImage2D( gl.TexImage2D(
gl.TEXTURE_2D, gl.TEXTURE_2D,
@ -54,8 +55,6 @@ func NewTexture(parent Doer, width, height int, smooth bool, pixels []uint8) (*T
} }
gl.GenerateMipmap(gl.TEXTURE_2D) gl.GenerateMipmap(gl.TEXTURE_2D)
})
})
runtime.SetFinalizer(texture, (*Texture).delete) runtime.SetFinalizer(texture, (*Texture).delete)
@ -83,15 +82,12 @@ func (t *Texture) Height() int {
return t.height return t.height
} }
// Do bind a texture, executes sub, and unbinds the texture. // Begin binds a texture. This is necessary before using the texture.
func (t *Texture) Do(sub func(Context)) { func (t *Texture) Begin() {
t.parent.Do(func(ctx Context) {
DoNoBlock(func() {
t.tex.bind() t.tex.bind()
}) }
sub(ctx)
DoNoBlock(func() { // End unbinds a texture and restores the previous one.
t.tex.restore() func (t *Texture) End() {
}) t.tex.restore()
})
} }

View File

@ -1,9 +1,8 @@
package pixelgl package pixelgl
import ( import (
"unsafe"
"runtime" "runtime"
"unsafe"
"github.com/go-gl/gl/v3.3-core/gl" "github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/mathgl/mgl32" "github.com/go-gl/mathgl/mgl32"
@ -13,7 +12,6 @@ import (
// VertexArray is an OpenGL vertex array object that also holds it's own vertex buffer object. // VertexArray is an OpenGL vertex array object that also holds it's own vertex buffer object.
// From the user's points of view, VertexArray is an array of vertices that can be drawn. // From the user's points of view, VertexArray is an array of vertices that can be drawn.
type VertexArray struct { type VertexArray struct {
parent Doer
vao, vbo, ebo binder vao, vbo, ebo binder
numVertices, numIndices int numVertices, numIndices int
format AttrFormat format AttrFormat
@ -21,14 +19,13 @@ type VertexArray struct {
offset map[string]int offset map[string]int
} }
// NewVertexArray creates a new empty vertex array and wraps another Doer around it. // NewVertexArray creates a new empty vertex array.
// //
// You cannot specify vertex attributes in this constructor, only their count. Use // You cannot specify vertex attributes in this constructor, only their count. Use
// SetVertexAttribute* methods to set the vertex attributes. Use indices to specify how you // SetVertexAttribute* methods to set the vertex attributes. Use indices to specify how you
// want to combine vertices into triangles. // want to combine vertices into triangles.
func NewVertexArray(parent Doer, format AttrFormat, numVertices int, indices []int) (*VertexArray, error) { func NewVertexArray(shader *Shader, numVertices int, indices []int) (*VertexArray, error) {
va := &VertexArray{ va := &VertexArray{
parent: parent,
vao: binder{ vao: binder{
restoreLoc: gl.VERTEX_ARRAY_BINDING, restoreLoc: gl.VERTEX_ARRAY_BINDING,
bindFunc: func(obj uint32) { bindFunc: func(obj uint32) {
@ -48,25 +45,24 @@ func NewVertexArray(parent Doer, format AttrFormat, numVertices int, indices []i
}, },
}, },
numVertices: numVertices, numVertices: numVertices,
format: format, format: shader.VertexFormat(),
stride: format.Size(), stride: shader.VertexFormat().Size(),
offset: make(map[string]int), offset: make(map[string]int),
} }
offset := 0 offset := 0
for name, typ := range format { for name, typ := range va.format {
switch typ { switch typ {
case Float, Vec2, Vec3, Vec4: case Float, Vec2, Vec3, Vec4:
default: default:
return nil, errors.New("failed to create vertex array: invalid vertex format: invalid attribute type") return nil, errors.New("failed to create vertex array: invalid attribute type")
} }
va.offset[name] = offset va.offset[name] = offset
offset += typ.Size() offset += typ.Size()
} }
parent.Do(func(ctx Context) {
Do(func() {
gl.GenVertexArrays(1, &va.vao.obj) gl.GenVertexArrays(1, &va.vao.obj)
va.vao.bind() va.vao.bind()
gl.GenBuffers(1, &va.vbo.obj) gl.GenBuffers(1, &va.vbo.obj)
@ -78,8 +74,8 @@ func NewVertexArray(parent Doer, format AttrFormat, numVertices int, indices []i
gl.GenBuffers(1, &va.ebo.obj) gl.GenBuffers(1, &va.ebo.obj)
defer va.ebo.bind().restore() defer va.ebo.bind().restore()
for name, typ := range format { for name, typ := range va.format {
loc := gl.GetAttribLocation(ctx.Shader().ID(), gl.Str(name+"\x00")) loc := gl.GetAttribLocation(shader.ID(), gl.Str(name+"\x00"))
var size int32 var size int32
switch typ { switch typ {
@ -105,8 +101,6 @@ func NewVertexArray(parent Doer, format AttrFormat, numVertices int, indices []i
} }
va.vao.restore() va.vao.restore()
})
})
va.SetIndices(indices) va.SetIndices(indices)
@ -141,13 +135,17 @@ func (va *VertexArray) VertexFormat() AttrFormat {
} }
// Draw draws a vertex array. // Draw draws a vertex array.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) Draw() { func (va *VertexArray) Draw() {
va.Do(func(Context) {}) gl.DrawElements(gl.TRIANGLES, int32(va.numIndices), gl.UNSIGNED_INT, gl.PtrOffset(0))
} }
// SetIndices sets the indices of triangles to be drawn. Triangles will be formed from the // SetIndices sets the indices of triangles to be drawn. Triangles will be formed from the
// vertices of the array as defined by these indices. The first drawn triangle is specified by // vertices of the array as defined by these indices. The first drawn triangle is specified by
// the first three indices, the second by the fourth through sixth and so on. // the first three indices, the second by the fourth through sixth and so on.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) SetIndices(indices []int) { func (va *VertexArray) SetIndices(indices []int) {
if len(indices)%3 != 0 { if len(indices)%3 != 0 {
panic("vertex array set indices: number of indices not divisible by 3") panic("vertex array set indices: number of indices not divisible by 3")
@ -157,25 +155,23 @@ func (va *VertexArray) SetIndices(indices []int) {
indices32[i] = uint32(indices[i]) indices32[i] = uint32(indices[i])
} }
va.numIndices = len(indices32) va.numIndices = len(indices32)
DoNoBlock(func() {
va.ebo.bind()
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 4*len(indices32), gl.Ptr(indices32), gl.DYNAMIC_DRAW) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 4*len(indices32), gl.Ptr(indices32), gl.DYNAMIC_DRAW)
va.ebo.restore()
})
} }
// Indices returns the current indices of triangles to be drawn. // Indices returns the current indices of triangles to be drawn.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) Indices() []int { func (va *VertexArray) Indices() []int {
indices32 := make([]uint32, va.numIndices) indices32 := make([]uint32, va.numIndices)
Do(func() {
va.ebo.bind()
gl.GetBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, 4*len(indices32), gl.Ptr(indices32)) gl.GetBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, 4*len(indices32), gl.Ptr(indices32))
va.ebo.restore()
})
indices := make([]int, len(indices32)) indices := make([]int, len(indices32))
for i := range indices { for i := range indices {
indices[i] = int(indices32[i]) indices[i] = int(indices32[i])
} }
return indices return indices
} }
@ -191,6 +187,8 @@ func (va *VertexArray) Indices() []int {
// Attr{Type: Vec3}: mgl32.Vec3 // Attr{Type: Vec3}: mgl32.Vec3
// Attr{Type: Vec4}: mgl32.Vec4 // Attr{Type: Vec4}: mgl32.Vec4
// No other types are supported. // No other types are supported.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (ok bool) { func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (ok bool) {
if vertex < 0 || vertex >= va.numVertices { if vertex < 0 || vertex >= va.numVertices {
panic("set vertex attr: invalid vertex index") panic("set vertex attr: invalid vertex index")
@ -200,9 +198,6 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (
return false return false
} }
DoNoBlock(func() {
va.vbo.bind()
offset := va.stride*vertex + va.offset[attr.Name] offset := va.stride*vertex + va.offset[attr.Name]
switch attr.Type { switch attr.Type {
@ -222,9 +217,6 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (
panic("set vertex attr: invalid attribute type") panic("set vertex attr: invalid attribute type")
} }
va.vbo.restore()
})
return true return true
} }
@ -234,6 +226,8 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (
// out of range, this method panics. // out of range, this method panics.
// //
// The type of the returned value follows the same rules as with SetVertexAttr. // The type of the returned value follows the same rules as with SetVertexAttr.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok bool) { func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok bool) {
if vertex < 0 || vertex >= va.numVertices { if vertex < 0 || vertex >= va.numVertices {
panic("vertex attr: invalid vertex index") panic("vertex attr: invalid vertex index")
@ -243,9 +237,6 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
return nil, false return nil, false
} }
Do(func() {
va.vbo.bind()
offset := va.stride*vertex + va.offset[attr.Name] offset := va.stride*vertex + va.offset[attr.Name]
switch attr.Type { switch attr.Type {
@ -269,9 +260,6 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
panic("set vertex attr: invalid attribute type") panic("set vertex attr: invalid attribute type")
} }
va.vbo.restore()
})
return value, true return value, true
} }
@ -279,6 +267,8 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
// will be set to zero. // will be set to zero.
// //
// Not existing attributes are silently skipped. // Not existing attributes are silently skipped.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) SetVertex(vertex int, values map[Attr]interface{}) { func (va *VertexArray) SetVertex(vertex int, values map[Attr]interface{}) {
if vertex < 0 || vertex >= va.numVertices { if vertex < 0 || vertex >= va.numVertices {
panic("set vertex: invalid vertex index") panic("set vertex: invalid vertex index")
@ -310,17 +300,13 @@ func (va *VertexArray) SetVertex(vertex int, values map[Attr]interface{}) {
} }
} }
DoNoBlock(func() {
va.vbo.bind()
offset := va.stride * vertex offset := va.stride * vertex
gl.BufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) gl.BufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data))
va.vbo.restore()
})
} }
// Vertex returns values of all vertex attributes of the specified vertex in a map. // Vertex returns values of all vertex attributes of the specified vertex in a map.
//
// The vertex array must be bound before calling this method.
func (va *VertexArray) Vertex(vertex int) (values map[Attr]interface{}) { func (va *VertexArray) Vertex(vertex int) (values map[Attr]interface{}) {
if vertex < 0 || vertex >= va.numVertices { if vertex < 0 || vertex >= va.numVertices {
panic("set vertex: invalid vertex index") panic("set vertex: invalid vertex index")
@ -328,15 +314,9 @@ func (va *VertexArray) Vertex(vertex int) (values map[Attr]interface{}) {
data := make([]float32, va.format.Size()/4) data := make([]float32, va.format.Size()/4)
Do(func() {
va.vbo.bind()
offset := va.stride * vertex offset := va.stride * vertex
gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data))
va.vbo.restore()
})
values = make(map[Attr]interface{}) values = make(map[Attr]interface{})
for name, typ := range va.format { for name, typ := range va.format {
@ -369,6 +349,8 @@ func (va *VertexArray) Vertex(vertex int) (values map[Attr]interface{}) {
// array, this method panics. // array, this method panics.
// //
// Not existing attributes are silently skipped. // Not existing attributes are silently skipped.
//
// The vertex array must be bound before calling this metod.
func (va *VertexArray) SetVertices(vertices []map[Attr]interface{}) { func (va *VertexArray) SetVertices(vertices []map[Attr]interface{}) {
if len(vertices) != va.numVertices { if len(vertices) != va.numVertices {
panic("set vertex array: wrong number of supplied vertices") panic("set vertex array: wrong number of supplied vertices")
@ -402,23 +384,17 @@ func (va *VertexArray) SetVertices(vertices []map[Attr]interface{}) {
} }
} }
DoNoBlock(func() {
va.vbo.bind()
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data)) gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data))
va.vbo.restore()
})
} }
// Vertices returns values of vertex attributes of all vertices in a vertex array in a slice // Vertices returns values of vertex attributes of all vertices in a vertex array in a slice
// of maps. // of maps.
//
// The vertex array must be bound before calling this metod.
func (va *VertexArray) Vertices() (vertices []map[Attr]interface{}) { func (va *VertexArray) Vertices() (vertices []map[Attr]interface{}) {
data := make([]float32, va.numVertices*va.format.Size()/4) data := make([]float32, va.numVertices*va.format.Size()/4)
Do(func() {
va.vbo.bind()
gl.GetBufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data)) gl.GetBufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data))
va.vbo.restore()
})
vertices = make([]map[Attr]interface{}, va.numVertices) vertices = make([]map[Attr]interface{}, va.numVertices)
@ -453,17 +429,16 @@ func (va *VertexArray) Vertices() (vertices []map[Attr]interface{}) {
return vertices return vertices
} }
// Do binds a vertex arrray and it's associated vertex buffer, executes sub, and unbinds the // Begin binds a vertex array. This is neccessary before using the vertex array.
// vertex array and it's vertex buffer. func (va *VertexArray) Begin() {
func (va *VertexArray) Do(sub func(Context)) {
va.parent.Do(func(ctx Context) {
DoNoBlock(func() {
va.vao.bind() va.vao.bind()
}) va.vbo.bind()
sub(ctx) va.ebo.bind()
DoNoBlock(func() { }
gl.DrawElements(gl.TRIANGLES, int32(va.numIndices), gl.UNSIGNED_INT, gl.PtrOffset(0))
va.vao.restore() // End unbinds a vertex array and restores the previous one.
}) func (va *VertexArray) End() {
}) va.ebo.restore()
va.vbo.restore()
va.vao.restore()
} }