147 lines
3.4 KiB
Go
147 lines
3.4 KiB
Go
package shader
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.tek.govt.hu/dowerx/opengl-deferred/types/light"
|
|
"github.com/go-gl/gl/v4.6-core/gl"
|
|
"github.com/go-gl/mathgl/mgl32"
|
|
)
|
|
|
|
type Shader struct {
|
|
program uint32
|
|
uniforms map[string]int32
|
|
lightCount int32
|
|
}
|
|
|
|
func (s *Shader) Use() {
|
|
gl.UseProgram(s.program)
|
|
s.lightCount = 0
|
|
}
|
|
|
|
func (s *Shader) Delete() {
|
|
gl.DeleteProgram(s.program)
|
|
}
|
|
|
|
func (s *Shader) getUniformLocation(name string) int32 {
|
|
if val, ok := s.uniforms[name]; ok {
|
|
return val
|
|
}
|
|
|
|
uniform := gl.GetUniformLocation(s.program, gl.Str(name+"\x00"))
|
|
s.uniforms[name] = uniform
|
|
|
|
return uniform
|
|
}
|
|
|
|
func (s *Shader) Mat4(name string, mat mgl32.Mat4) {
|
|
gl.UniformMatrix4fv(s.getUniformLocation(name), 1, false, &mat[0])
|
|
}
|
|
|
|
func (s *Shader) Int(name string, val int32) {
|
|
gl.Uniform1i(s.getUniformLocation(name), val)
|
|
}
|
|
|
|
func (s *Shader) Float(name string, val float32) {
|
|
gl.Uniform1f(s.getUniformLocation(name), val)
|
|
}
|
|
|
|
func (s *Shader) Vec3(name string, val *float32) {
|
|
gl.Uniform3fv(s.getUniformLocation(name), 1, val)
|
|
}
|
|
|
|
func (s *Shader) Light(l *light.Light) error {
|
|
if s.lightCount >= light.MAX_LIGHT_COUNT {
|
|
return errors.New("too many lights")
|
|
}
|
|
|
|
s.Vec3(fmt.Sprintf("lights[%d].color", s.lightCount), &l.Color[0])
|
|
s.Vec3(fmt.Sprintf("lights[%d].position", s.lightCount), &l.Position[0])
|
|
s.Vec3(fmt.Sprintf("lights[%d].direction", s.lightCount), &l.Direction[0])
|
|
s.Float(fmt.Sprintf("lights[%d].intensity", s.lightCount), l.Intensity)
|
|
s.Int(fmt.Sprintf("lights[%d].type", s.lightCount), l.Type)
|
|
s.lightCount++
|
|
s.Int("light_count", s.lightCount)
|
|
|
|
return nil
|
|
}
|
|
|
|
func compileShader(source string, shaderType uint32) (uint32, error) {
|
|
shader := gl.CreateShader(shaderType)
|
|
|
|
csource, free := gl.Strs(source + "\x00")
|
|
gl.ShaderSource(shader, 1, csource, nil)
|
|
free()
|
|
gl.CompileShader(shader)
|
|
|
|
var status int32
|
|
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
|
|
if status == gl.FALSE {
|
|
var logLength int32
|
|
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
|
|
|
|
log := strings.Repeat("\x00", int(logLength+1))
|
|
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
|
|
|
|
return 0, errors.New(log)
|
|
}
|
|
|
|
return shader, nil
|
|
}
|
|
|
|
func New(vertexSource string, fragmentSource string) (shader Shader, _ error) {
|
|
shader.uniforms = make(map[string]int32)
|
|
|
|
vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER)
|
|
if err != nil {
|
|
return shader, err
|
|
}
|
|
|
|
fragmentShader, err := compileShader(fragmentSource, gl.FRAGMENT_SHADER)
|
|
if err != nil {
|
|
return shader, err
|
|
}
|
|
|
|
shader.program = gl.CreateProgram()
|
|
gl.AttachShader(shader.program, vertexShader)
|
|
gl.AttachShader(shader.program, fragmentShader)
|
|
gl.LinkProgram(shader.program)
|
|
defer gl.DeleteShader(vertexShader)
|
|
defer gl.DeleteShader(fragmentShader)
|
|
|
|
var status int32
|
|
gl.GetProgramiv(shader.program, gl.LINK_STATUS, &status)
|
|
if status == gl.FALSE {
|
|
var logLength int32
|
|
gl.GetProgramiv(shader.program, gl.INFO_LOG_LENGTH, &logLength)
|
|
|
|
log := strings.Repeat("\x00", int(logLength+1))
|
|
gl.GetProgramInfoLog(shader.program, logLength, nil, gl.Str(log))
|
|
|
|
return shader, errors.New(log)
|
|
}
|
|
|
|
return shader, nil
|
|
}
|
|
|
|
func FromFiles(vertexPath, fragmentPath string) (shader Shader, _ error) {
|
|
vertexSource, err := os.ReadFile(vertexPath)
|
|
if err != nil {
|
|
return shader, err
|
|
}
|
|
fragmentSource, err := os.ReadFile(fragmentPath)
|
|
if err != nil {
|
|
return shader, err
|
|
}
|
|
|
|
shader, err = New(string(vertexSource), string(fragmentSource))
|
|
if err != nil {
|
|
return shader, err
|
|
}
|
|
|
|
return shader, nil
|
|
}
|