replace BeginEnder with Doer and migrate everything
This commit is contained in:
parent
f7c4a6e1ad
commit
52a3a96d20
|
@ -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
|
||||||
|
}
|
|
@ -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()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
191
window.go
|
@ -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()
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue