replace reentrancy by enabled by more general binder

This commit is contained in:
faiface 2016-12-14 16:24:31 +01:00
parent cbfc770d4f
commit 1b01cba814
4 changed files with 161 additions and 279 deletions

View File

@ -16,9 +16,8 @@ type UniformFormat map[string]Attr
// Shader is an OpenGL shader program. // Shader is an OpenGL shader program.
type Shader struct { type Shader struct {
enabled bool
parent Doer parent Doer
program uint32 program binder
vertexFormat VertexFormat vertexFormat VertexFormat
uniformFormat UniformFormat uniformFormat UniformFormat
uniforms map[Attr]int32 uniforms map[Attr]int32
@ -30,6 +29,12 @@ type Shader struct {
func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformFormat, vertexShader, fragmentShader string) (*Shader, error) { func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformFormat, vertexShader, fragmentShader string) (*Shader, error) {
shader := &Shader{ shader := &Shader{
parent: parent, parent: parent,
program: binder{
restoreLoc: gl.CURRENT_PROGRAM,
bindFunc: func(obj uint32) {
gl.UseProgram(obj)
},
},
vertexFormat: vertexFormat, vertexFormat: vertexFormat,
uniformFormat: uniformFormat, uniformFormat: uniformFormat,
uniforms: make(map[Attr]int32), uniforms: make(map[Attr]int32),
@ -86,31 +91,31 @@ func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformForm
// shader program // shader program
{ {
shader.program = gl.CreateProgram() shader.program.obj = gl.CreateProgram()
gl.AttachShader(shader.program, vshader) gl.AttachShader(shader.program.obj, vshader)
gl.AttachShader(shader.program, fshader) gl.AttachShader(shader.program.obj, fshader)
gl.LinkProgram(shader.program) gl.LinkProgram(shader.program.obj)
var ( var (
success int32 success int32
infoLog = make([]byte, 512) infoLog = make([]byte, 512)
) )
gl.GetProgramiv(shader.program, gl.LINK_STATUS, &success) gl.GetProgramiv(shader.program.obj, gl.LINK_STATUS, &success)
if success == 0 { if success == 0 {
gl.GetProgramInfoLog(shader.program, 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 fmt.Errorf("error linking shader program: %s", string(infoLog))
} }
} }
// uniforms // uniforms
for uname, utype := range uniformFormat { for uname, utype := range uniformFormat {
ulocation := gl.GetUniformLocation(shader.program, gl.Str(uname+"\x00")) ulocation := gl.GetUniformLocation(shader.program.obj, gl.Str(uname+"\x00"))
if ulocation == -1 { if ulocation == -1 {
gl.DeleteProgram(shader.program) gl.DeleteProgram(shader.program.obj)
return fmt.Errorf("shader does not contain uniform '%s'", uname) return fmt.Errorf("shader does not contain uniform '%s'", uname)
} }
if _, ok := shader.uniforms[utype]; ok { if _, ok := shader.uniforms[utype]; ok {
gl.DeleteProgram(shader.program) gl.DeleteProgram(shader.program.obj)
return fmt.Errorf("failed to create shader: invalid uniform format: duplicate uniform attribute") return fmt.Errorf("failed to create shader: invalid uniform format: duplicate uniform attribute")
} }
shader.uniforms[utype] = ulocation shader.uniforms[utype] = ulocation
@ -130,14 +135,14 @@ func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformForm
func (s *Shader) Delete() { func (s *Shader) Delete() {
s.parent.Do(func(ctx Context) { s.parent.Do(func(ctx Context) {
DoNoBlock(func() { DoNoBlock(func() {
gl.DeleteProgram(s.program) gl.DeleteProgram(s.program.obj)
}) })
}) })
} }
// ID returns an OpenGL identifier of a shader program. // ID returns an OpenGL identifier of a shader program.
func (s *Shader) ID() uint32 { func (s *Shader) ID() uint32 {
return s.program return s.program.obj
} }
// VertexFormat returns the vertex attribute format of this shader. Do not change it. // VertexFormat returns the vertex attribute format of this shader. Do not change it.
@ -150,245 +155,94 @@ func (s *Shader) UniformFormat() UniformFormat {
return s.uniformFormat return s.uniformFormat
} }
// SetUniformInt sets the value of an uniform attribute Attr{Purpose: purpose, Type: Int}. // SetUniformAttr sets the value of a uniform attribute of a shader.
// //
// Returns false if the attribute does not exist. // If the attribute does not exist, this method returns false.
func (s *Shader) SetUniformInt(purpose AttrPurpose, value int32) (ok bool) { //
attr := Attr{Purpose: purpose, Type: Int} // Supplied value must correspond to the type of the attribute. Correct types are these (right-hand is the type of the value):
// Attr{Type: Int}: int32
// Attr{Type: Float}: float32
// Attr{Type: Vec2}: mgl32.Vec2
// Attr{Type: Vec3}: mgl32.Vec3
// Attr{Type: Vec4}: mgl32.Vec4
// Attr{Type: Mat2}: mgl32.Mat2
// Attr{Type: Mat23}: mgl32.Mat2x3
// Attr{Type: Mat24}: mgl32.Mat2x4
// Attr{Type: Mat3}: mgl32.Mat3
// Attr{Type: Mat32}: mgl32.Mat3x2
// Attr{Type: Mat34}: mgl32.Mat3x4
// Attr{Type: Mat4}: mgl32.Mat4
// Attr{Type: Mat42}: mgl32.Mat4x2
// Attr{Type: Mat43}: mgl32.Mat4x3
// No other types are supported.
func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) {
if _, ok := s.uniforms[attr]; !ok { if _, ok := s.uniforms[attr]; !ok {
return false return false
} }
s.Do(func(Context) {
DoNoBlock(func() {
gl.Uniform1i(s.uniforms[attr], value)
})
})
return true
}
// SetUniformFloat sets the value of an uniform attribute Attr{Purpose: purpose, Type: Float}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformFloat(purpose AttrPurpose, value float32) (ok bool) {
attr := Attr{Purpose: purpose, Type: Float}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() { DoNoBlock(func() {
gl.Uniform1f(s.uniforms[attr], value) defer s.program.bind().restore()
})
})
return true
}
// SetUniformVec2 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Vec2}. switch attr.Type {
// case Int:
// Returns false if the attribute does not exist. value := value.(int32)
func (s *Shader) SetUniformVec2(purpose AttrPurpose, value mgl32.Vec2) (ok bool) { gl.Uniform1iv(s.uniforms[attr], 1, &value)
attr := Attr{Purpose: purpose, Type: Vec2} case Float:
if _, ok := s.uniforms[attr]; !ok { value := value.(float32)
return false gl.Uniform1fv(s.uniforms[attr], 1, &value)
} case Vec2:
s.Do(func(Context) { value := value.(mgl32.Vec2)
DoNoBlock(func() { gl.Uniform2fv(s.uniforms[attr], 1, &value[0])
gl.Uniform2f(s.uniforms[attr], value[0], value[1]) case Vec3:
}) value := value.(mgl32.Vec3)
}) gl.Uniform3fv(s.uniforms[attr], 1, &value[0])
return true case Vec4:
} value := value.(mgl32.Vec4)
gl.Uniform4fv(s.uniforms[attr], 1, &value[0])
// SetUniformVec3 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Vec3}. case Mat2:
// value := value.(mgl32.Mat2)
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformVec3(purpose AttrPurpose, value mgl32.Vec3) (ok bool) {
attr := Attr{Purpose: purpose, Type: Vec3}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.Uniform3f(s.uniforms[attr], value[0], value[1], value[2])
})
})
return true
}
// SetUniformVec4 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Vec4}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformVec4(purpose AttrPurpose, value mgl32.Vec4) (ok bool) {
attr := Attr{Purpose: purpose, Type: Vec4}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.Uniform4f(s.uniforms[attr], value[0], value[1], value[2], value[3])
})
})
return true
}
// SetUniformMat2 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat2}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat2(purpose AttrPurpose, value mgl32.Mat2) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat2}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix2fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix2fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat23:
}) value := value.(mgl32.Mat2x3)
return true
}
// SetUniformMat23 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat23}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat23(purpose AttrPurpose, value mgl32.Mat2x3) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat23}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix2x3fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix2x3fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat24:
}) value := value.(mgl32.Mat2x4)
return true
}
// SetUniformMat24 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat24}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat24(purpose AttrPurpose, value mgl32.Mat2x4) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat24}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix2x4fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix2x4fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat3:
}) value := value.(mgl32.Mat3)
return true
}
// SetUniformMat3 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat3}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat3(purpose AttrPurpose, value mgl32.Mat3) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat3}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix3fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix3fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat32:
}) value := value.(mgl32.Mat3x2)
return true
}
// SetUniformMat32 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat32}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat32(purpose AttrPurpose, value mgl32.Mat3x2) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat32}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix3x2fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix3x2fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat34:
}) value := value.(mgl32.Mat3x4)
return true
}
// SetUniformMat34 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat34}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat34(purpose AttrPurpose, value mgl32.Mat3x4) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat34}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix3x4fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix3x4fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat4:
}) value := value.(mgl32.Mat4)
return true
}
// SetUniformMat4 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat4}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat4(purpose AttrPurpose, value mgl32.Mat4) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat4}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix4fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix4fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat42:
}) value := value.(mgl32.Mat4x2)
return true
}
// SetUniformMat42 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat42}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat42(purpose AttrPurpose, value mgl32.Mat4x2) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat42}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix4x2fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix4x2fv(s.uniforms[attr], 1, false, &value[0])
}) case Mat43:
}) value := value.(mgl32.Mat4x3)
return true
}
// SetUniformMat43 sets the value of an uniform attribute Attr{Purpose: purpose, Type: Mat43}.
//
// Returns false if the attribute does not exist.
func (s *Shader) SetUniformMat43(purpose AttrPurpose, value mgl32.Mat4x3) (ok bool) {
attr := Attr{Purpose: purpose, Type: Mat43}
if _, ok := s.uniforms[attr]; !ok {
return false
}
s.Do(func(Context) {
DoNoBlock(func() {
gl.UniformMatrix4x3fv(s.uniforms[attr], 1, false, &value[0]) gl.UniformMatrix4x3fv(s.uniforms[attr], 1, false, &value[0])
default:
panic("set uniform attr: invalid attribute type")
}
}) })
})
return true return true
} }
// Do stars using a shader, executes sub, and stops using it. // Do stars using a shader, executes sub, and stops using it.
func (s *Shader) Do(sub func(Context)) { func (s *Shader) Do(sub func(Context)) {
s.parent.Do(func(ctx Context) { s.parent.Do(func(ctx Context) {
if s.enabled {
sub(ctx.WithShader(s))
return
}
DoNoBlock(func() { DoNoBlock(func() {
gl.UseProgram(s.program) s.program.bind()
}) })
s.enabled = true
sub(ctx.WithShader(s)) sub(ctx.WithShader(s))
s.enabled = false
DoNoBlock(func() { DoNoBlock(func() {
gl.UseProgram(0) s.program.restore()
}) })
}) })
} }

View File

@ -4,9 +4,8 @@ import "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 {
enabled bool
parent Doer parent Doer
tex uint32 tex binder
width, height int width, height int
} }
@ -15,14 +14,20 @@ type Texture struct {
func NewTexture(parent Doer, width, height int, pixels []uint8) (*Texture, error) { func NewTexture(parent Doer, width, height int, pixels []uint8) (*Texture, error) {
texture := &Texture{ texture := &Texture{
parent: parent, parent: parent,
tex: binder{
restoreLoc: gl.TEXTURE_BINDING_2D,
bindFunc: func(obj uint32) {
gl.BindTexture(gl.TEXTURE_2D, obj)
},
},
width: width, width: width,
height: height, height: height,
} }
parent.Do(func(ctx Context) { parent.Do(func(ctx Context) {
Do(func() { Do(func() {
gl.GenTextures(1, &texture.tex) gl.GenTextures(1, &texture.tex.obj)
gl.BindTexture(gl.TEXTURE_2D, texture.tex) defer texture.tex.bind().restore()
gl.TexImage2D( gl.TexImage2D(
gl.TEXTURE_2D, gl.TEXTURE_2D,
@ -37,8 +42,6 @@ func NewTexture(parent Doer, width, height int, pixels []uint8) (*Texture, error
) )
gl.GenerateMipmap(gl.TEXTURE_2D) gl.GenerateMipmap(gl.TEXTURE_2D)
gl.BindTexture(gl.TEXTURE_2D, 0)
}) })
}) })
@ -49,14 +52,14 @@ func NewTexture(parent Doer, width, height int, pixels []uint8) (*Texture, error
func (t *Texture) Delete() { func (t *Texture) Delete() {
t.parent.Do(func(ctx Context) { t.parent.Do(func(ctx Context) {
DoNoBlock(func() { DoNoBlock(func() {
gl.DeleteTextures(1, &t.tex) gl.DeleteTextures(1, &t.tex.obj)
}) })
}) })
} }
// ID returns an OpenGL identifier of a texture. // ID returns an OpenGL identifier of a texture.
func (t *Texture) ID() uint32 { func (t *Texture) ID() uint32 {
return t.tex return t.tex.obj
} }
// Width returns the width of a texture in pixels. // Width returns the width of a texture in pixels.
@ -72,18 +75,12 @@ func (t *Texture) Height() int {
// Do bind a texture, executes sub, and unbinds the texture. // Do bind a texture, executes sub, and unbinds the texture.
func (t *Texture) Do(sub func(Context)) { func (t *Texture) Do(sub func(Context)) {
t.parent.Do(func(ctx Context) { t.parent.Do(func(ctx Context) {
if t.enabled {
sub(ctx)
return
}
DoNoBlock(func() { DoNoBlock(func() {
gl.BindTexture(gl.TEXTURE_2D, t.tex) t.tex.bind()
}) })
t.enabled = true
sub(ctx) sub(ctx)
t.enabled = false
DoNoBlock(func() { DoNoBlock(func() {
gl.BindTexture(gl.TEXTURE_2D, 0) t.tex.restore()
}) })
}) })
} }

27
pixelgl/util.go Normal file
View File

@ -0,0 +1,27 @@
package pixelgl
import "github.com/go-gl/gl/v3.3-core/gl"
type binder struct {
restoreLoc uint32
bindFunc func(uint32)
obj uint32
prev []uint32
}
func (b *binder) bind() *binder {
var prev int32
gl.GetIntegerv(b.restoreLoc, &prev)
b.prev = append(b.prev, uint32(prev))
b.bindFunc(b.obj)
return b
}
func (b *binder) restore() *binder {
b.bindFunc(b.prev[len(b.prev)-1])
b.prev = b.prev[:len(b.prev)-1]
return b
}

View File

@ -43,9 +43,8 @@ const (
// 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 {
enabled bool
parent Doer parent Doer
vao, vbo, ebo uint32 vao, vbo, ebo binder
vertexNum, indexNum int vertexNum, indexNum int
format VertexFormat format VertexFormat
usage VertexUsage usage VertexUsage
@ -60,9 +59,27 @@ type VertexArray struct {
func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexNum int, indices []int) (*VertexArray, error) { func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexNum int, indices []int) (*VertexArray, error) {
va := &VertexArray{ va := &VertexArray{
parent: parent, parent: parent,
vao: binder{
restoreLoc: gl.VERTEX_ARRAY_BINDING,
bindFunc: func(obj uint32) {
gl.BindVertexArray(obj)
},
},
vbo: binder{
restoreLoc: gl.ARRAY_BUFFER_BINDING,
bindFunc: func(obj uint32) {
gl.BindBuffer(gl.ARRAY_BUFFER, obj)
},
},
ebo: binder{
restoreLoc: gl.ELEMENT_ARRAY_BUFFER_BINDING,
bindFunc: func(obj uint32) {
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj)
},
},
vertexNum: vertexNum,
format: format, format: format,
usage: usage, usage: usage,
vertexNum: vertexNum,
stride: format.Size(), stride: format.Size(),
attrs: make(map[Attr]int), attrs: make(map[Attr]int),
} }
@ -83,16 +100,17 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN
parent.Do(func(ctx Context) { parent.Do(func(ctx Context) {
Do(func() { Do(func() {
gl.GenVertexArrays(1, &va.vao) gl.GenVertexArrays(1, &va.vao.obj)
gl.BindVertexArray(va.vao) va.vao.bind()
gl.GenBuffers(1, &va.vbo) gl.GenBuffers(1, &va.vbo.obj)
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo) defer va.vbo.bind().restore()
emptyData := make([]byte, vertexNum*va.stride) emptyData := make([]byte, vertexNum*va.stride)
gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), uint32(usage)) gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), uint32(usage))
gl.GenBuffers(1, &va.ebo) gl.GenBuffers(1, &va.ebo.obj)
defer va.ebo.bind().restore()
offset := 0 offset := 0
for i, attr := range format { for i, attr := range format {
@ -120,12 +138,7 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN
offset += attr.Type.Size() offset += attr.Type.Size()
} }
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, va.ebo) // need to bind EBO, so that VAO registers it va.vao.restore()
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
gl.BindVertexArray(0)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
}) })
}) })
@ -138,15 +151,15 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN
func (va *VertexArray) Delete() { func (va *VertexArray) Delete() {
va.parent.Do(func(ctx Context) { va.parent.Do(func(ctx Context) {
DoNoBlock(func() { DoNoBlock(func() {
gl.DeleteVertexArrays(1, &va.vao) gl.DeleteVertexArrays(1, &va.vao.obj)
gl.DeleteBuffers(1, &va.vbo) gl.DeleteBuffers(1, &va.vbo.obj)
}) })
}) })
} }
// ID returns an OpenGL identifier of a vertex array. // ID returns an OpenGL identifier of a vertex array.
func (va *VertexArray) ID() uint32 { func (va *VertexArray) ID() uint32 {
return va.vao return va.vao.obj
} }
// VertexNum returns the number of vertices in a vertex array. // VertexNum returns the number of vertices in a vertex array.
@ -184,9 +197,8 @@ func (va *VertexArray) SetIndices(indices []int) {
} }
va.indexNum = len(indices32) va.indexNum = len(indices32)
DoNoBlock(func() { DoNoBlock(func() {
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, va.ebo) defer va.ebo.bind().restore()
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 4*len(indices32), gl.Ptr(indices32), uint32(va.usage)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 4*len(indices32), gl.Ptr(indices32), uint32(va.usage))
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
}) })
} }
@ -195,7 +207,7 @@ func (va *VertexArray) SetIndices(indices []int) {
// If the vertex attribute does not exist, this method returns false. If the vertex is out of range, // If the vertex attribute does not exist, this method returns false. If the vertex is out of range,
// this method panics. // this method panics.
// //
// Supplied value must correspond to the type of the attribute. Correct types are these (righ-hand is the type of value): // Supplied value must correspond to the type of the attribute. Correct types are these (righ-hand is the type of the value):
// Attr{Type: Float}: float32 // Attr{Type: Float}: float32
// Attr{Type: Vec2}: mgl32.Vec2 // Attr{Type: Vec2}: mgl32.Vec2
// Attr{Type: Vec3}: mgl32.Vec3 // Attr{Type: Vec3}: mgl32.Vec3
@ -211,7 +223,7 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (
} }
DoNoBlock(func() { DoNoBlock(func() {
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo) defer va.vbo.bind().restore()
offset := va.stride*vertex + va.attrs[attr] offset := va.stride*vertex + va.attrs[attr]
@ -228,9 +240,9 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (
case Vec4: case Vec4:
value := value.(mgl32.Vec4) value := value.(mgl32.Vec4)
gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value))
default:
panic("set vertex attr: invalid attribute type")
} }
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
}) })
return true return true
@ -251,8 +263,8 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
return nil, false return nil, false
} }
DoNoBlock(func() { Do(func() {
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo) defer va.vbo.bind().restore()
offset := va.stride*vertex + va.attrs[attr] offset := va.stride*vertex + va.attrs[attr]
@ -274,8 +286,6 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data))
value = data value = data
} }
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
}) })
return value, true return value, true
@ -284,19 +294,13 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
// Do binds a vertex arrray and it's associated vertex buffer, executes sub, and unbinds the vertex array and it's vertex buffer. // Do binds a vertex arrray and it's associated vertex buffer, executes sub, and unbinds the vertex array and it's vertex buffer.
func (va *VertexArray) Do(sub func(Context)) { func (va *VertexArray) Do(sub func(Context)) {
va.parent.Do(func(ctx Context) { va.parent.Do(func(ctx Context) {
if va.enabled {
sub(ctx)
return
}
DoNoBlock(func() { DoNoBlock(func() {
gl.BindVertexArray(va.vao) va.vao.bind()
}) })
va.enabled = true
sub(ctx) sub(ctx)
va.enabled = false
DoNoBlock(func() { DoNoBlock(func() {
gl.DrawElements(gl.TRIANGLES, int32(va.indexNum), gl.UNSIGNED_INT, gl.PtrOffset(0)) gl.DrawElements(gl.TRIANGLES, int32(va.indexNum), gl.UNSIGNED_INT, gl.PtrOffset(0))
gl.BindVertexArray(0) va.vao.restore()
}) })
}) })
} }