package shader import ( "errors" "fmt" "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, fragmantSource string) (shader Shader, _ error) { shader.uniforms = make(map[string]int32) vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER) if err != nil { return shader, err } fragmantShader, err := compileShader(fragmantSource, gl.FRAGMENT_SHADER) if err != nil { return shader, err } shader.program = gl.CreateProgram() gl.AttachShader(shader.program, vertexShader) gl.AttachShader(shader.program, fragmantShader) gl.LinkProgram(shader.program) defer gl.DeleteShader(vertexShader) defer gl.DeleteShader(fragmantShader) 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 }