From 2b6205fe45b7665da0eb36c2f5b0c71abe89fbc3 Mon Sep 17 00:00:00 2001 From: faiface Date: Sat, 31 Dec 2016 01:33:53 +0100 Subject: [PATCH] remove Doer and replace with BeginEnder --- pixelgl/interface.go | 75 +----------- pixelgl/shader.go | 251 +++++++++++++++++++--------------------- pixelgl/texture.go | 82 +++++++------ pixelgl/vertex.go | 267 ++++++++++++++++++++----------------------- 4 files changed, 281 insertions(+), 394 deletions(-) diff --git a/pixelgl/interface.go b/pixelgl/interface.go index 72869f5..73189cd 100644 --- a/pixelgl/interface.go +++ b/pixelgl/interface.go @@ -1,76 +1,11 @@ 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 // example, you can bind a buffer and unbind a buffer, bind a texture and unbind it, use shader // and unuse it, and so on. -// -// This interface provides a clever and flexible way to do it. A typical workflow of an OpenGL -// object is that you enter (load, bind) that object's state, then do something with it, and -// 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{} +type BeginEnder interface { + Begin() + End() +} \ No newline at end of file diff --git a/pixelgl/shader.go b/pixelgl/shader.go index 92851da..35f2820 100644 --- a/pixelgl/shader.go +++ b/pixelgl/shader.go @@ -10,7 +10,6 @@ import ( // Shader is an OpenGL shader program. type Shader struct { - parent Doer program binder vertexFmt AttrFormat uniformFmt AttrFormat @@ -22,9 +21,8 @@ type Shader struct { // // Note that vertexShader and fragmentShader parameters must contain the source code, they're // 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{ - parent: parent, program: binder{ restoreLoc: gl.CURRENT_PROGRAM, bindFunc: func(obj uint32) { @@ -36,84 +34,74 @@ func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, frag 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 - { - vshader = gl.CreateShader(gl.VERTEX_SHADER) - src, free := gl.Strs(vertexShader) - defer free() - length := int32(len(vertexShader)) - gl.ShaderSource(vshader, 1, src, &length) - gl.CompileShader(vshader) + // vertex shader + { + vshader = gl.CreateShader(gl.VERTEX_SHADER) + src, free := gl.Strs(vertexShader) + defer free() + length := int32(len(vertexShader)) + gl.ShaderSource(vshader, 1, src, &length) + gl.CompileShader(vshader) - var ( - success int32 - infoLog = make([]byte, 512) - ) - gl.GetShaderiv(vshader, gl.COMPILE_STATUS, &success) - if success == 0 { - gl.GetShaderInfoLog(vshader, int32(len(infoLog)), nil, &infoLog[0]) - return fmt.Errorf("error compiling vertex shader: %s", string(infoLog)) - } + var ( + success int32 + infoLog = make([]byte, 512) + ) + gl.GetShaderiv(vshader, gl.COMPILE_STATUS, &success) + if success == 0 { + gl.GetShaderInfoLog(vshader, int32(len(infoLog)), nil, &infoLog[0]) + return nil, fmt.Errorf("error compiling vertex shader: %s", string(infoLog)) + } - defer gl.DeleteShader(vshader) - } + defer gl.DeleteShader(vshader) + } - // fragment shader - { - fshader = gl.CreateShader(gl.FRAGMENT_SHADER) - src, free := gl.Strs(fragmentShader) - defer free() - length := int32(len(fragmentShader)) - gl.ShaderSource(fshader, 1, src, &length) - gl.CompileShader(fshader) + // fragment shader + { + fshader = gl.CreateShader(gl.FRAGMENT_SHADER) + src, free := gl.Strs(fragmentShader) + defer free() + length := int32(len(fragmentShader)) + gl.ShaderSource(fshader, 1, src, &length) + gl.CompileShader(fshader) - var ( - success int32 - infoLog = make([]byte, 512) - ) - gl.GetShaderiv(fshader, gl.COMPILE_STATUS, &success) - if success == 0 { - gl.GetShaderInfoLog(fshader, int32(len(infoLog)), nil, &infoLog[0]) - return fmt.Errorf("error compiling fragment shader: %s", string(infoLog)) - } + var ( + success int32 + infoLog = make([]byte, 512) + ) + gl.GetShaderiv(fshader, gl.COMPILE_STATUS, &success) + if success == 0 { + gl.GetShaderInfoLog(fshader, int32(len(infoLog)), nil, &infoLog[0]) + return nil, fmt.Errorf("error compiling fragment shader: %s", string(infoLog)) + } - defer gl.DeleteShader(fshader) - } + defer gl.DeleteShader(fshader) + } - // shader program - { - shader.program.obj = gl.CreateProgram() - gl.AttachShader(shader.program.obj, vshader) - gl.AttachShader(shader.program.obj, fshader) - gl.LinkProgram(shader.program.obj) + // shader program + { + shader.program.obj = gl.CreateProgram() + gl.AttachShader(shader.program.obj, vshader) + gl.AttachShader(shader.program.obj, fshader) + gl.LinkProgram(shader.program.obj) - var ( - success int32 - infoLog = make([]byte, 512) - ) - gl.GetProgramiv(shader.program.obj, gl.LINK_STATUS, &success) - if success == 0 { - gl.GetProgramInfoLog(shader.program.obj, int32(len(infoLog)), nil, &infoLog[0]) - return fmt.Errorf("error linking shader program: %s", string(infoLog)) - } - } + var ( + success int32 + infoLog = make([]byte, 512) + ) + gl.GetProgramiv(shader.program.obj, gl.LINK_STATUS, &success) + if success == 0 { + gl.GetProgramInfoLog(shader.program.obj, int32(len(infoLog)), nil, &infoLog[0]) + return nil, fmt.Errorf("error linking shader program: %s", string(infoLog)) + } + } - // uniforms - for name := range uniformFmt { - loc := gl.GetUniformLocation(shader.program.obj, gl.Str(name+"\x00")) - shader.uniforms[name] = loc - } - - return nil - }) - }) - if err != nil { - return nil, err + // uniforms + for name := range uniformFmt { + loc := gl.GetUniformLocation(shader.program.obj, gl.Str(name+"\x00")) + shader.uniforms[name] = loc } runtime.SetFinalizer(shader, (*Shader).delete) @@ -163,76 +151,69 @@ func (s *Shader) UniformFormat() AttrFormat { // Attr{Type: Mat42}: mgl32.Mat4x2 // Attr{Type: Mat43}: mgl32.Mat4x3 // No other types are supported. +// +// The shader must be bound before calling this method. func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) { if !s.uniformFmt.Contains(attr) { return false } - DoNoBlock(func() { - s.program.bind() - - switch attr.Type { - case Int: - value := value.(int32) - gl.Uniform1iv(s.uniforms[attr.Name], 1, &value) - case Float: - value := value.(float32) - gl.Uniform1fv(s.uniforms[attr.Name], 1, &value) - case Vec2: - value := value.(mgl32.Vec2) - gl.Uniform2fv(s.uniforms[attr.Name], 1, &value[0]) - case Vec3: - value := value.(mgl32.Vec3) - gl.Uniform3fv(s.uniforms[attr.Name], 1, &value[0]) - case Vec4: - value := value.(mgl32.Vec4) - gl.Uniform4fv(s.uniforms[attr.Name], 1, &value[0]) - case Mat2: - value := value.(mgl32.Mat2) - gl.UniformMatrix2fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat23: - value := value.(mgl32.Mat2x3) - gl.UniformMatrix2x3fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat24: - value := value.(mgl32.Mat2x4) - gl.UniformMatrix2x4fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat3: - value := value.(mgl32.Mat3) - gl.UniformMatrix3fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat32: - value := value.(mgl32.Mat3x2) - gl.UniformMatrix3x2fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat34: - value := value.(mgl32.Mat3x4) - gl.UniformMatrix3x4fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat4: - value := value.(mgl32.Mat4) - gl.UniformMatrix4fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat42: - value := value.(mgl32.Mat4x2) - gl.UniformMatrix4x2fv(s.uniforms[attr.Name], 1, false, &value[0]) - case Mat43: - value := value.(mgl32.Mat4x3) - gl.UniformMatrix4x3fv(s.uniforms[attr.Name], 1, false, &value[0]) - default: - panic("set uniform attr: invalid attribute type") - } - - s.program.restore() - }) + switch attr.Type { + case Int: + value := value.(int32) + gl.Uniform1iv(s.uniforms[attr.Name], 1, &value) + case Float: + value := value.(float32) + gl.Uniform1fv(s.uniforms[attr.Name], 1, &value) + case Vec2: + value := value.(mgl32.Vec2) + gl.Uniform2fv(s.uniforms[attr.Name], 1, &value[0]) + case Vec3: + value := value.(mgl32.Vec3) + gl.Uniform3fv(s.uniforms[attr.Name], 1, &value[0]) + case Vec4: + value := value.(mgl32.Vec4) + gl.Uniform4fv(s.uniforms[attr.Name], 1, &value[0]) + case Mat2: + value := value.(mgl32.Mat2) + gl.UniformMatrix2fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat23: + value := value.(mgl32.Mat2x3) + gl.UniformMatrix2x3fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat24: + value := value.(mgl32.Mat2x4) + gl.UniformMatrix2x4fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat3: + value := value.(mgl32.Mat3) + gl.UniformMatrix3fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat32: + value := value.(mgl32.Mat3x2) + gl.UniformMatrix3x2fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat34: + value := value.(mgl32.Mat3x4) + gl.UniformMatrix3x4fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat4: + value := value.(mgl32.Mat4) + gl.UniformMatrix4fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat42: + value := value.(mgl32.Mat4x2) + gl.UniformMatrix4x2fv(s.uniforms[attr.Name], 1, false, &value[0]) + case Mat43: + value := value.(mgl32.Mat4x3) + gl.UniformMatrix4x3fv(s.uniforms[attr.Name], 1, false, &value[0]) + default: + panic("set uniform attr: invalid attribute type") + } return true } -// Do stars using a shader, executes sub, and stops using it. -func (s *Shader) Do(sub func(Context)) { - s.parent.Do(func(ctx Context) { - DoNoBlock(func() { - s.program.bind() - }) - sub(ctx.WithShader(s)) - DoNoBlock(func() { - s.program.restore() - }) - }) +// Begin binds a shader program. This is necessary before using the shader. +func (s *Shader) Begin() { + s.program.bind() +} + +// End unbinds a shader program and restores the previous one. +func (s *Shader) End() { + s.program.restore() } diff --git a/pixelgl/texture.go b/pixelgl/texture.go index dad02ac..24ac3e1 100644 --- a/pixelgl/texture.go +++ b/pixelgl/texture.go @@ -1,20 +1,21 @@ package pixelgl -import "github.com/go-gl/gl/v3.3-core/gl" -import "runtime" +import ( + "runtime" + + "github.com/go-gl/gl/v3.3-core/gl" +) // Texture is an OpenGL texture. type Texture struct { - parent Doer tex binder width, height int } // NewTexture creates a new texture with the specified width and height. // 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{ - parent: parent, tex: binder{ restoreLoc: gl.TEXTURE_BINDING_2D, bindFunc: func(obj uint32) { @@ -25,37 +26,35 @@ func NewTexture(parent Doer, width, height int, smooth bool, pixels []uint8) (*T height: height, } - parent.Do(func(ctx Context) { - Do(func() { - gl.GenTextures(1, &texture.tex.obj) - defer texture.tex.bind().restore() + gl.GenTextures(1, &texture.tex.obj) - gl.TexImage2D( - gl.TEXTURE_2D, - 0, - gl.RGBA, - int32(width), - int32(height), - 0, - gl.RGBA, - gl.UNSIGNED_BYTE, - gl.Ptr(pixels), - ) + texture.Begin() + defer texture.End() - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT) + gl.TexImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + int32(width), + int32(height), + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + gl.Ptr(pixels), + ) - if smooth { - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) - } else { - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - } + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT) - gl.GenerateMipmap(gl.TEXTURE_2D) - }) - }) + if smooth { + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + } else { + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) + } + + gl.GenerateMipmap(gl.TEXTURE_2D) runtime.SetFinalizer(texture, (*Texture).delete) @@ -83,15 +82,12 @@ func (t *Texture) Height() int { return t.height } -// Do bind a texture, executes sub, and unbinds the texture. -func (t *Texture) Do(sub func(Context)) { - t.parent.Do(func(ctx Context) { - DoNoBlock(func() { - t.tex.bind() - }) - sub(ctx) - DoNoBlock(func() { - t.tex.restore() - }) - }) +// Begin binds a texture. This is necessary before using the texture. +func (t *Texture) Begin() { + t.tex.bind() +} + +// End unbinds a texture and restores the previous one. +func (t *Texture) End() { + t.tex.restore() } diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go index 039175e..b928a09 100644 --- a/pixelgl/vertex.go +++ b/pixelgl/vertex.go @@ -1,9 +1,8 @@ package pixelgl import ( - "unsafe" - "runtime" + "unsafe" "github.com/go-gl/gl/v3.3-core/gl" "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. // From the user's points of view, VertexArray is an array of vertices that can be drawn. type VertexArray struct { - parent Doer vao, vbo, ebo binder numVertices, numIndices int format AttrFormat @@ -21,14 +19,13 @@ type VertexArray struct { 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 // SetVertexAttribute* methods to set the vertex attributes. Use indices to specify how you // 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{ - parent: parent, vao: binder{ restoreLoc: gl.VERTEX_ARRAY_BINDING, bindFunc: func(obj uint32) { @@ -48,65 +45,62 @@ func NewVertexArray(parent Doer, format AttrFormat, numVertices int, indices []i }, }, numVertices: numVertices, - format: format, - stride: format.Size(), + format: shader.VertexFormat(), + stride: shader.VertexFormat().Size(), offset: make(map[string]int), } offset := 0 - for name, typ := range format { + for name, typ := range va.format { switch typ { case Float, Vec2, Vec3, Vec4: 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 offset += typ.Size() } - parent.Do(func(ctx Context) { - Do(func() { - gl.GenVertexArrays(1, &va.vao.obj) - va.vao.bind() + gl.GenVertexArrays(1, &va.vao.obj) - gl.GenBuffers(1, &va.vbo.obj) - defer va.vbo.bind().restore() + va.vao.bind() - emptyData := make([]byte, numVertices*va.stride) - gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), gl.DYNAMIC_DRAW) + gl.GenBuffers(1, &va.vbo.obj) + defer va.vbo.bind().restore() - gl.GenBuffers(1, &va.ebo.obj) - defer va.ebo.bind().restore() + emptyData := make([]byte, numVertices*va.stride) + gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), gl.DYNAMIC_DRAW) - for name, typ := range format { - loc := gl.GetAttribLocation(ctx.Shader().ID(), gl.Str(name+"\x00")) + gl.GenBuffers(1, &va.ebo.obj) + defer va.ebo.bind().restore() - var size int32 - switch typ { - case Float: - size = 1 - case Vec2: - size = 2 - case Vec3: - size = 3 - case Vec4: - size = 4 - } + for name, typ := range va.format { + loc := gl.GetAttribLocation(shader.ID(), gl.Str(name+"\x00")) - gl.VertexAttribPointer( - uint32(loc), - size, - gl.FLOAT, - false, - int32(va.stride), - gl.PtrOffset(va.offset[name]), - ) - gl.EnableVertexAttribArray(uint32(loc)) - } + var size int32 + switch typ { + case Float: + size = 1 + case Vec2: + size = 2 + case Vec3: + size = 3 + case Vec4: + size = 4 + } - va.vao.restore() - }) - }) + gl.VertexAttribPointer( + uint32(loc), + size, + gl.FLOAT, + false, + int32(va.stride), + gl.PtrOffset(va.offset[name]), + ) + gl.EnableVertexAttribArray(uint32(loc)) + } + + va.vao.restore() va.SetIndices(indices) @@ -141,13 +135,17 @@ func (va *VertexArray) VertexFormat() AttrFormat { } // Draw draws a vertex array. +// +// The vertex array must be bound before calling this method. 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 // 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 vertex array must be bound before calling this method. func (va *VertexArray) SetIndices(indices []int) { if len(indices)%3 != 0 { 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]) } va.numIndices = len(indices32) - DoNoBlock(func() { - va.ebo.bind() - gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 4*len(indices32), gl.Ptr(indices32), gl.DYNAMIC_DRAW) - va.ebo.restore() - }) + + gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, 4*len(indices32), gl.Ptr(indices32), gl.DYNAMIC_DRAW) } // 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 { indices32 := make([]uint32, va.numIndices) - Do(func() { - va.ebo.bind() - gl.GetBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, 4*len(indices32), gl.Ptr(indices32)) - va.ebo.restore() - }) + + gl.GetBufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, 4*len(indices32), gl.Ptr(indices32)) + indices := make([]int, len(indices32)) for i := range indices { indices[i] = int(indices32[i]) } + return indices } @@ -191,6 +187,8 @@ func (va *VertexArray) Indices() []int { // Attr{Type: Vec3}: mgl32.Vec3 // Attr{Type: Vec4}: mgl32.Vec4 // 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) { if vertex < 0 || vertex >= va.numVertices { panic("set vertex attr: invalid vertex index") @@ -200,30 +198,24 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) ( 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 { - case Float: - value := value.(float32) - gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) - case Vec2: - value := value.(mgl32.Vec2) - gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) - case Vec3: - value := value.(mgl32.Vec3) - gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) - case Vec4: - value := value.(mgl32.Vec4) - gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) - default: - panic("set vertex attr: invalid attribute type") - } - - va.vbo.restore() - }) + switch attr.Type { + case Float: + value := value.(float32) + gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) + case Vec2: + value := value.(mgl32.Vec2) + gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) + case Vec3: + value := value.(mgl32.Vec3) + gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) + case Vec4: + value := value.(mgl32.Vec4) + gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&value)) + default: + panic("set vertex attr: invalid attribute type") + } return true } @@ -234,6 +226,8 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) ( // out of range, this method panics. // // 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) { if vertex < 0 || vertex >= va.numVertices { panic("vertex attr: invalid vertex index") @@ -243,34 +237,28 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok 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 { - case Float: - var data float32 - gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) - value = data - case Vec2: - var data mgl32.Vec2 - gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) - value = data - case Vec3: - var data mgl32.Vec3 - gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) - value = data - case Vec4: - var data mgl32.Vec4 - gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) - value = data - default: - panic("set vertex attr: invalid attribute type") - } - - va.vbo.restore() - }) + switch attr.Type { + case Float: + var data float32 + gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) + value = data + case Vec2: + var data mgl32.Vec2 + gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) + value = data + case Vec3: + var data mgl32.Vec3 + gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) + value = data + case Vec4: + var data mgl32.Vec4 + gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), unsafe.Pointer(&data)) + value = data + default: + panic("set vertex attr: invalid attribute type") + } return value, true } @@ -279,6 +267,8 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok // will be set to zero. // // 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{}) { if vertex < 0 || vertex >= va.numVertices { 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 - gl.BufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) - - va.vbo.restore() - }) + offset := va.stride * vertex + gl.BufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) } // 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{}) { if vertex < 0 || vertex >= va.numVertices { panic("set vertex: invalid vertex index") @@ -328,14 +314,8 @@ func (va *VertexArray) Vertex(vertex int) (values map[Attr]interface{}) { data := make([]float32, va.format.Size()/4) - Do(func() { - va.vbo.bind() - - offset := va.stride * vertex - gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) - - va.vbo.restore() - }) + offset := va.stride * vertex + gl.GetBufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) values = make(map[Attr]interface{}) @@ -369,6 +349,8 @@ func (va *VertexArray) Vertex(vertex int) (values map[Attr]interface{}) { // array, this method panics. // // Not existing attributes are silently skipped. +// +// The vertex array must be bound before calling this metod. func (va *VertexArray) SetVertices(vertices []map[Attr]interface{}) { if len(vertices) != va.numVertices { 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)) - va.vbo.restore() - }) + gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data)) } // Vertices returns values of vertex attributes of all vertices in a vertex array in a slice // of maps. +// +// The vertex array must be bound before calling this metod. func (va *VertexArray) Vertices() (vertices []map[Attr]interface{}) { 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)) - va.vbo.restore() - }) + gl.GetBufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data)) vertices = make([]map[Attr]interface{}, va.numVertices) @@ -453,17 +429,16 @@ func (va *VertexArray) Vertices() (vertices []map[Attr]interface{}) { return vertices } -// 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)) { - va.parent.Do(func(ctx Context) { - DoNoBlock(func() { - va.vao.bind() - }) - sub(ctx) - DoNoBlock(func() { - gl.DrawElements(gl.TRIANGLES, int32(va.numIndices), gl.UNSIGNED_INT, gl.PtrOffset(0)) - va.vao.restore() - }) - }) +// Begin binds a vertex array. This is neccessary before using the vertex array. +func (va *VertexArray) Begin() { + va.vao.bind() + va.vbo.bind() + va.ebo.bind() +} + +// End unbinds a vertex array and restores the previous one. +func (va *VertexArray) End() { + va.ebo.restore() + va.vbo.restore() + va.vao.restore() }