replace reentrancy by enabled by more general binder
This commit is contained in:
parent
cbfc770d4f
commit
1b01cba814
|
@ -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()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue