go-opengl-pixel/pixelgl/shader.go

127 lines
2.9 KiB
Go
Raw Normal View History

2016-11-23 13:06:34 -06:00
package pixelgl
import (
"fmt"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/pkg/errors"
)
// Shader is an OpenGL shader program.
type Shader struct {
parent Doer
2016-11-23 13:06:34 -06:00
program uint32
}
// 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.
func NewShader(parent Doer, vertexShader, fragmentShader string) (*Shader, error) {
2016-11-23 13:06:34 -06:00
shader := &Shader{
parent: parent,
}
2016-11-25 15:56:17 -06:00
var err, glerr error
2016-11-28 16:26:56 -06:00
parent.Do(func(ctx Context) {
2016-11-25 15:56:17 -06:00
err, glerr = DoErrGLErr(func() error {
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)
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))
}
2016-11-23 13:06:34 -06:00
}
// 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))
}
2016-11-23 13:06:34 -06:00
}
// shader program
{
shader.program = gl.CreateProgram()
gl.AttachShader(shader.program, vshader)
gl.AttachShader(shader.program, fshader)
gl.LinkProgram(shader.program)
var (
success int32
infoLog = make([]byte, 512)
)
gl.GetProgramiv(shader.program, gl.LINK_STATUS, &success)
if success == 0 {
gl.GetProgramInfoLog(shader.program, int32(len(infoLog)), nil, &infoLog[0])
return fmt.Errorf("error linking shader program: %s", string(infoLog))
}
2016-11-23 13:06:34 -06:00
}
gl.DeleteShader(vshader)
gl.DeleteShader(fshader)
2016-11-23 13:06:34 -06:00
return nil
})
})
2016-11-25 15:56:17 -06:00
if err != nil && glerr != nil {
return nil, errors.Wrap(glerr, err.Error())
}
if err != nil {
2016-11-23 13:06:34 -06:00
return nil, err
}
2016-11-25 15:56:17 -06:00
if glerr != nil {
return nil, glerr
}
2016-11-23 13:06:34 -06:00
return shader, nil
}
// Delete deletes a shader program. Don't use a shader after deletion.
func (s *Shader) Delete() {
2016-11-28 16:26:56 -06:00
s.parent.Do(func(ctx Context) {
2016-11-25 15:56:17 -06:00
DoNoBlock(func() {
gl.DeleteProgram(s.program)
})
2016-11-23 13:06:34 -06:00
})
}
// Do stars using a shader, executes sub, and stops using it.
2016-11-28 16:26:56 -06:00
func (s *Shader) Do(sub func(Context)) {
s.parent.Do(func(ctx Context) {
DoNoBlock(func() {
gl.UseProgram(s.program)
})
2016-11-28 16:26:56 -06:00
sub(ctx.WithShader(s))
DoNoBlock(func() {
gl.UseProgram(0)
})
2016-11-23 13:06:34 -06:00
})
}