replace BeginEnder with Doer and migrate everything

This commit is contained in:
faiface 2016-11-25 22:49:56 +01:00
parent f7c4a6e1ad
commit 52a3a96d20
6 changed files with 337 additions and 283 deletions

58
graphics.go Normal file
View File

@ -0,0 +1,58 @@
package pixel
import "github.com/faiface/pixel/pixelgl"
// Warning: technical stuff below.
// VertexFormat is an internal format of the OpenGL vertex data.
//
// You can actually change this and all of the Pixel's functions will use the new format.
// Only change when you're implementing an OpenGL effect or something similar.
var VertexFormat = DefaultVertexFormat()
// DefaultVertexFormat returns the default vertex format used by Pixel.
func DefaultVertexFormat() pixelgl.VertexFormat {
return pixelgl.VertexFormat{
{Purpose: pixelgl.Position, Size: 2},
{Purpose: pixelgl.Color, Size: 4},
{Purpose: pixelgl.TexCoord, Size: 2},
}
}
// ConvertVertexData converts data in the oldFormat to the newFormat. Vertex attributes in the new format
// will be copied from the corresponding vertex attributes in the old format. If a vertex attribute in the new format
// has no corresponding attribute in the old format, it will be filled with zeros.
func ConvertVertexData(oldFormat, newFormat pixelgl.VertexFormat, data []float64) []float64 {
// calculate the mapping between old and new format
// if i is a start of a vertex attribute in the new format, then mapping[i] returns
// the index where the same attribute starts in the old format
mapping := make(map[int]int)
i := 0
for _, newAttr := range newFormat {
j := 0
for _, oldAttr := range oldFormat {
if newAttr == oldAttr {
mapping[i] = j
break
}
j += oldAttr.Size
}
i += newAttr.Size
}
oldData, newData := data, []float64{}
for i := 0; i < len(oldData); i += oldFormat.Size() {
j := 0
for _, attr := range newFormat {
if oldIndex, ok := mapping[j]; ok { // the attribute was found in the old format
newData = append(newData, oldData[i+oldIndex:i+oldIndex+attr.Size]...)
} else { // the attribute wasn't found in the old format, so fill with zeros
newData = append(newData, make([]float64, attr.Size)...)
}
j += attr.Size
}
}
return newData
}

View File

@ -1,34 +1,28 @@
package pixelgl package pixelgl
// BeginEnder is an interface for manipulating OpenGL state. // Doer is an interface for manipulating OpenGL state.
// //
// OpenGL is a state machine and as such, it is natural to manipulate it in a begin-end manner. // OpenGL is a state machine. Every object can 'enter' it's state and 'leave' it's state. For example,
// This interface is intended for all OpenGL objects, that can begin being active and end being active // you can bind a buffer and unbind a buffer, bind a texture and unbind it, use shader and unuse it, and so on.
// such as windows, vertex arrays, vertex buffers, textures, shaders, pretty much everything.
// //
// It might seem natural to use BeginEnders this way: // 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).
// //
// window.Begin() // The recommended way to implement a Doer is to wrap another Doer (vertex array wrap texture and so on), let's call
// shader.Begin() // it parent. Then the Do method will look like this:
// texture.Begin()
// vertexarray.Begin()
// vertexarray.Draw()
// vertexarray.End()
// texture.End()
// shader.End()
// window.End()
// //
// Don't do this! A better practice is to make a BeginEnder so that it wraps another BeginEnder like this: // func (o *MyObject) Do(sub func()) {
// o.parent.Do(func() {
// // enter the object's state
// sub()
// // leave the object's state
// })
// }
// //
// shader := NewShader(window) // It might seem difficult to grasp this kind of recursion at first, but it's really simple. What it's basically saying
// texture := NewTexture(shader) // is: "Hey parent, enter your state, then let me enter mine, then I'll do whatever I'm supposed to do in the middle.
// vertexarray := NewVertexArray(texture) // After that I'll leave my state and please leave your state too parent."
// // now, somewhere else in your code, instead of calling numerous Begin/Ends, you just call type Doer interface {
// vertexarray.Draw() Do(sub func())
//
// The final single call to draw a vertex array executes all of the Begins and Ends, because the objects are
// wrapped around each other.
type BeginEnder interface {
Begin()
End()
} }

View File

@ -9,95 +9,104 @@ import (
// Shader is an OpenGL shader program. // Shader is an OpenGL shader program.
type Shader struct { type Shader struct {
parent BeginEnder parent Doer
program uint32 program uint32
} }
// NewShader creates a new shader program from the specified vertex shader and fragment shader sources. // NewShader creates a new shader program from the specified vertex shader and fragment shader sources.
// //
// Note that vertexShader and fragmentShader parameters must contain the source code, they're not filenames. // Note that vertexShader and fragmentShader parameters must contain the source code, they're not filenames.
func NewShader(parent BeginEnder, vertexShader, fragmentShader string) (*Shader, error) { func NewShader(parent Doer, vertexShader, fragmentShader string) (*Shader, error) {
parent.Begin()
defer parent.End()
shader := &Shader{ shader := &Shader{
parent: parent, parent: parent,
} }
err, glerr := DoErrGLErr(func() error {
var vshader, fshader uint32
// vertex shader errChan := make(chan error, 1)
{ parent.Do(func() {
vshader = gl.CreateShader(gl.VERTEX_SHADER) err, glerr := DoErrGLErr(func() error {
src, free := gl.Strs(vertexShader) var vshader, fshader uint32
defer free()
length := int32(len(vertexShader))
gl.ShaderSource(vshader, 1, src, &length)
gl.CompileShader(vshader)
var ( // vertex shader
success int32 {
infoLog = make([]byte, 512) vshader = gl.CreateShader(gl.VERTEX_SHADER)
) src, free := gl.Strs(vertexShader)
gl.GetShaderiv(vshader, gl.COMPILE_STATUS, &success) defer free()
if success == 0 { length := int32(len(vertexShader))
gl.GetShaderInfoLog(vshader, int32(len(infoLog)), nil, &infoLog[0]) gl.ShaderSource(vshader, 1, src, &length)
return fmt.Errorf("error compiling vertex shader: %s", string(infoLog)) 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))
}
} }
}
// fragment shader // fragment shader
{ {
fshader = gl.CreateShader(gl.FRAGMENT_SHADER) fshader = gl.CreateShader(gl.FRAGMENT_SHADER)
src, free := gl.Strs(fragmentShader) src, free := gl.Strs(fragmentShader)
defer free() defer free()
length := int32(len(fragmentShader)) length := int32(len(fragmentShader))
gl.ShaderSource(fshader, 1, src, &length) gl.ShaderSource(fshader, 1, src, &length)
gl.CompileShader(fshader) gl.CompileShader(fshader)
var ( var (
success int32 success int32
infoLog = make([]byte, 512) infoLog = make([]byte, 512)
) )
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 fmt.Errorf("error compiling fragment shader: %s", string(infoLog))
}
} }
}
// shader program // shader program
{ {
shader.program = gl.CreateProgram() shader.program = gl.CreateProgram()
gl.AttachShader(shader.program, vshader) gl.AttachShader(shader.program, vshader)
gl.AttachShader(shader.program, fshader) gl.AttachShader(shader.program, fshader)
gl.LinkProgram(shader.program) gl.LinkProgram(shader.program)
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, gl.LINK_STATUS, &success)
if success == 0 { if success == 0 {
gl.GetProgramInfoLog(shader.program, int32(len(infoLog)), nil, &infoLog[0]) gl.GetProgramInfoLog(shader.program, 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))
}
} }
gl.DeleteShader(vshader)
gl.DeleteShader(fshader)
return nil
})
if err != nil {
if glerr != nil {
err = errors.Wrap(glerr, err.Error())
}
errChan <- err
return
} }
gl.DeleteShader(vshader)
gl.DeleteShader(fshader)
return nil
})
if err != nil {
if glerr != nil { if glerr != nil {
err = errors.Wrap(glerr, err.Error()) errChan <- err
return
} }
errChan <- nil
})
err := <-errChan
if err != nil {
return nil, err return nil, err
} }
if glerr != nil {
return nil, glerr
}
return shader, nil return shader, nil
} }
@ -108,18 +117,15 @@ func (s *Shader) Delete() {
}) })
} }
// Begin starts using a shader program. // Do stars using a shader, executes sub, and stops using it.
func (s *Shader) Begin() { func (s *Shader) Do(sub func()) {
s.parent.Begin() s.parent.Do(func() {
DoNoBlock(func() { DoNoBlock(func() {
gl.UseProgram(s.program) gl.UseProgram(s.program)
})
sub()
DoNoBlock(func() {
gl.UseProgram(0)
})
}) })
} }
// End stops using a shader program.
func (s *Shader) End() {
DoNoBlock(func() {
gl.UseProgram(0)
})
s.parent.End()
}

View File

@ -7,37 +7,39 @@ import (
// Texture is an OpenGL texture. // Texture is an OpenGL texture.
type Texture struct { type Texture struct {
parent BeginEnder parent Doer
tex uint32 tex uint32
} }
// 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 BeginEnder, width, height int, pixels []uint8) (*Texture, error) { func NewTexture(parent Doer, width, height int, pixels []uint8) (*Texture, error) {
parent.Begin()
defer parent.End()
texture := &Texture{parent: parent} texture := &Texture{parent: parent}
err := DoGLErr(func() { errChan := make(chan error, 1)
gl.GenTextures(1, &texture.tex) parent.Do(func() {
gl.BindTexture(gl.TEXTURE_2D, texture.tex) errChan <- DoGLErr(func() {
gl.GenTextures(1, &texture.tex)
gl.BindTexture(gl.TEXTURE_2D, texture.tex)
gl.TexImage2D( gl.TexImage2D(
gl.TEXTURE_2D, gl.TEXTURE_2D,
0, 0,
gl.RGBA, gl.RGBA,
int32(width), int32(width),
int32(height), int32(height),
0, 0,
gl.RGBA, gl.RGBA,
gl.UNSIGNED_BYTE, gl.UNSIGNED_BYTE,
gl.Ptr(pixels), gl.Ptr(pixels),
) )
gl.GenerateMipmap(gl.TEXTURE_2D)
gl.BindTexture(gl.TEXTURE_2D, 0) gl.GenerateMipmap(gl.TEXTURE_2D)
gl.BindTexture(gl.TEXTURE_2D, 0)
})
}) })
err := <-errChan
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to create a texture") return nil, errors.Wrap(err, "failed to create a texture")
} }
@ -52,18 +54,15 @@ func (t *Texture) Delete() {
}) })
} }
// Begin binds a texture. // Do bind a texture, executes sub, and unbinds the texture.
func (t *Texture) Begin() { func (t *Texture) Do(sub func()) {
t.parent.Begin() t.parent.Do(func() {
DoNoBlock(func() { DoNoBlock(func() {
gl.BindTexture(gl.TEXTURE_2D, t.tex) gl.BindTexture(gl.TEXTURE_2D, t.tex)
})
sub()
DoNoBlock(func() {
gl.BindTexture(gl.TEXTURE_2D, 0)
})
}) })
} }
// End unbinds a texture.
func (t *Texture) End() {
DoNoBlock(func() {
gl.BindTexture(gl.TEXTURE_2D, 0)
})
t.parent.End()
}

View File

@ -90,7 +90,7 @@ 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 {
parent BeginEnder parent Doer
format VertexFormat format VertexFormat
vao uint32 vao uint32
vbo uint32 vbo uint32
@ -99,44 +99,50 @@ type VertexArray struct {
} }
// NewVertexArray creates a new vertex array and wraps another BeginEnder around it. // NewVertexArray creates a new vertex array and wraps another BeginEnder around it.
func NewVertexArray(parent BeginEnder, format VertexFormat, mode VertexDrawMode, usage VertexUsage, data []float64) (*VertexArray, error) { func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage VertexUsage, data []float64) (*VertexArray, error) {
parent.Begin()
defer parent.End()
va := &VertexArray{ va := &VertexArray{
parent: parent, parent: parent,
format: format, format: format,
mode: mode, mode: mode,
} }
err := DoGLErr(func() { errChan := make(chan error, 1)
gl.GenVertexArrays(1, &va.vao) parent.Do(func() {
gl.BindVertexArray(va.vao) err := DoGLErr(func() {
gl.GenVertexArrays(1, &va.vao)
gl.BindVertexArray(va.vao)
gl.GenBuffers(1, &va.vbo) gl.GenBuffers(1, &va.vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo) gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
gl.BufferData(gl.ARRAY_BUFFER, 8*len(data), gl.Ptr(data), uint32(usage)) gl.BufferData(gl.ARRAY_BUFFER, 8*len(data), gl.Ptr(data), uint32(usage))
stride := format.Size() stride := format.Size()
va.count = len(data) / stride va.count = len(data) / stride
offset := 0 offset := 0
for i, attr := range format { for i, attr := range format {
gl.VertexAttribPointer( gl.VertexAttribPointer(
uint32(i), uint32(i),
int32(attr.Size), int32(attr.Size),
gl.DOUBLE, gl.DOUBLE,
false, false,
int32(8*stride), int32(8*stride),
gl.PtrOffset(8*offset), gl.PtrOffset(8*offset),
) )
gl.EnableVertexAttribArray(uint32(i)) gl.EnableVertexAttribArray(uint32(i))
offset += attr.Size offset += attr.Size
}
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
gl.BindVertexArray(0)
})
if err != nil {
errChan <- err
return
} }
errChan <- nil
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
gl.BindVertexArray(0)
}) })
err := <-errChan
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to create a vertex array") return nil, errors.Wrap(err, "failed to create a vertex array")
} }
@ -176,8 +182,7 @@ func (va *VertexArray) DrawMode() VertexDrawMode {
// Draw draws a vertex array. // Draw draws a vertex array.
func (va *VertexArray) Draw() { func (va *VertexArray) Draw() {
va.Begin() va.Do(func() {})
va.End()
} }
// Data returns a copy of data inside a vertex array (actually it's vertex buffer). // Data returns a copy of data inside a vertex array (actually it's vertex buffer).
@ -207,21 +212,18 @@ func (va *VertexArray) UpdateData(offset int, data []float64) {
}) })
} }
// Begin binds a vertex array and it's associated 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) Begin() { func (va *VertexArray) Do(sub func()) {
va.parent.Begin() va.parent.Do(func() {
DoNoBlock(func() { DoNoBlock(func() {
gl.BindVertexArray(va.vao) gl.BindVertexArray(va.vao)
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo) gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
})
sub()
DoNoBlock(func() {
gl.DrawArrays(uint32(va.mode), 0, int32(va.count))
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
gl.BindVertexArray(0)
})
}) })
} }
// End draws a vertex array and unbinds it alongside with it's associated vertex buffer.
func (va *VertexArray) End() {
DoNoBlock(func() {
gl.DrawArrays(uint32(va.mode), 0, int32(va.count))
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
gl.BindVertexArray(0)
})
va.parent.End()
}

191
window.go
View File

@ -104,79 +104,79 @@ func NewWindow(config WindowConfig) (*Window, error) {
// Delete destroys a window. The window can't be used any further. // Delete destroys a window. The window can't be used any further.
func (w *Window) Delete() { func (w *Window) Delete() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.Destroy()
w.window.Destroy() })
}) })
} }
// Clear clears the window with a color. // Clear clears the window with a color.
func (w *Window) Clear(c color.Color) { func (w *Window) Clear(c color.Color) {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Clear(colorToRGBA(c))
pixelgl.Clear(colorToRGBA(c)) })
} }
// Update swaps buffers and polls events. // Update swaps buffers and polls events.
func (w *Window) Update() { func (w *Window) Update() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { if w.config.VSync {
if w.config.VSync { glfw.SwapInterval(1)
glfw.SwapInterval(1) }
} w.window.SwapBuffers()
w.window.SwapBuffers() glfw.PollEvents()
glfw.PollEvents() })
}) })
} }
// SetTitle changes the title of a window. // SetTitle changes the title of a window.
func (w *Window) SetTitle(title string) { func (w *Window) SetTitle(title string) {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.SetTitle(title)
w.window.SetTitle(title) })
}) })
} }
// SetSize resizes a window to the specified size in pixels. // SetSize resizes a window to the specified size in pixels.
// In case of a fullscreen window, it changes the resolution of that window. // In case of a fullscreen window, it changes the resolution of that window.
func (w *Window) SetSize(width, height float64) { func (w *Window) SetSize(width, height float64) {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.SetSize(int(width), int(height))
w.window.SetSize(int(width), int(height)) })
}) })
} }
// Size returns the size of the client area of a window (the part you can draw on). // Size returns the size of the client area of a window (the part you can draw on).
func (w *Window) Size() (width, height float64) { func (w *Window) Size() (width, height float64) {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { wi, hi := w.window.GetSize()
wi, hi := w.window.GetSize() width = float64(wi)
width = float64(wi) height = float64(hi)
height = float64(hi) })
}) })
return width, height return width, height
} }
// Show makes a window visible if it was hidden. // Show makes a window visible if it was hidden.
func (w *Window) Show() { func (w *Window) Show() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.Show()
w.window.Show() })
}) })
} }
// Hide hides a window if it was visible. // Hide hides a window if it was visible.
func (w *Window) Hide() { func (w *Window) Hide() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.Hide()
w.window.Hide() })
}) })
} }
@ -187,37 +187,35 @@ func (w *Window) Hide() {
func (w *Window) SetFullscreen(monitor *Monitor) { func (w *Window) SetFullscreen(monitor *Monitor) {
if w.Monitor() != monitor { if w.Monitor() != monitor {
if monitor == nil { if monitor == nil {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
w.window.SetMonitor(
pixelgl.Do(func() { nil,
w.window.SetMonitor( w.restore.xpos,
nil, w.restore.ypos,
w.restore.xpos, w.restore.width,
w.restore.ypos, w.restore.height,
w.restore.width, 0,
w.restore.height, )
0, })
)
}) })
} else { } else {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
w.restore.xpos, w.restore.ypos = w.window.GetPos()
w.restore.width, w.restore.height = w.window.GetSize()
pixelgl.Do(func() { width, height := monitor.Size()
w.restore.xpos, w.restore.ypos = w.window.GetPos() refreshRate := monitor.RefreshRate()
w.restore.width, w.restore.height = w.window.GetSize() w.window.SetMonitor(
monitor.monitor,
width, height := monitor.Size() 0,
refreshRate := monitor.RefreshRate() 0,
w.window.SetMonitor( int(width),
monitor.monitor, int(height),
0, int(refreshRate),
0, )
int(width), })
int(height),
int(refreshRate),
)
}) })
} }
} }
@ -230,12 +228,12 @@ func (w *Window) IsFullscreen() bool {
// Monitor returns a monitor a fullscreen window is on. If the window is not fullscreen, this function returns nil. // Monitor returns a monitor a fullscreen window is on. If the window is not fullscreen, this function returns nil.
func (w *Window) Monitor() *Monitor { func (w *Window) Monitor() *Monitor {
w.Begin() var monitor *glfw.Monitor
defer w.End() w.Do(func() {
monitor = pixelgl.DoVal(func() interface{} {
monitor := pixelgl.DoVal(func() interface{} { return w.window.GetMonitor()
return w.window.GetMonitor() }).(*glfw.Monitor)
}).(*glfw.Monitor) })
if monitor == nil { if monitor == nil {
return nil return nil
} }
@ -246,37 +244,39 @@ func (w *Window) Monitor() *Monitor {
// Focus brings a window to the front and sets input focus. // Focus brings a window to the front and sets input focus.
func (w *Window) Focus() { func (w *Window) Focus() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.Focus()
w.window.Focus() })
}) })
} }
// Focused returns true if a window has input focus. // Focused returns true if a window has input focus.
func (w *Window) Focused() bool { func (w *Window) Focused() bool {
w.Begin() var focused bool
defer w.End() w.Do(func() {
return pixelgl.DoVal(func() interface{} { focused = pixelgl.DoVal(func() interface{} {
return w.window.GetAttrib(glfw.Focused) == glfw.True return w.window.GetAttrib(glfw.Focused) == glfw.True
}).(bool) }).(bool)
})
return focused
} }
// Maximize puts a windowed window to a maximized state. // Maximize puts a windowed window to a maximized state.
func (w *Window) Maximize() { func (w *Window) Maximize() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.Maximize()
w.window.Maximize() })
}) })
} }
// Restore restores a windowed window from a maximized state. // Restore restores a windowed window from a maximized state.
func (w *Window) Restore() { func (w *Window) Restore() {
w.Begin() w.Do(func() {
defer w.End() pixelgl.Do(func() {
pixelgl.Do(func() { w.window.Restore()
w.window.Restore() })
}) })
} }
@ -285,11 +285,11 @@ var currentWindow struct {
handler *Window handler *Window
} }
// Begin makes the context of this window current. // Do makes the context of this window current, if it's not already, and executes sub.
// func (w *Window) Do(sub func()) {
// Note that you only need to use this function if you're designing a low-level technical plugin (such as an effect).
func (w *Window) Begin() {
currentWindow.Lock() currentWindow.Lock()
defer currentWindow.Unlock()
if currentWindow.handler != w { if currentWindow.handler != w {
pixelgl.Do(func() { pixelgl.Do(func() {
w.window.MakeContextCurrent() w.window.MakeContextCurrent()
@ -297,11 +297,6 @@ func (w *Window) Begin() {
}) })
currentWindow.handler = w currentWindow.handler = w
} }
}
// End makes it possible for other windows to make their context current. sub()
//
// Note that you only need to use this function if you're designing a low-level technical plugin (such as an effect).
func (w *Window) End() {
currentWindow.Unlock()
} }