Shader handling

This commit is contained in:
bloeys
2021-10-09 08:19:53 +04:00
parent e4f79a2a53
commit 9f4c34bcbb
6 changed files with 225 additions and 16 deletions

32
main.go
View File

@ -4,8 +4,9 @@ import (
"fmt"
"github.com/bloeys/go-sdl-engine/input"
"github.com/bloeys/go-sdl-engine/shaders"
"github.com/bloeys/go-sdl-engine/timing"
"github.com/go-gl/gl/v4.6-compatibility/gl"
"github.com/go-gl/gl/v4.6-core/gl"
"github.com/veandco/go-sdl2/sdl"
)
@ -50,8 +51,7 @@ func main() {
panicIfErr(err, "")
//Run in compatiability (old and modern opengl) or modern (core) opengl only
// sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE)
err = sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_COMPATIBILITY)
err = sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE)
panicIfErr(err, "")
//Set wanted opengl version
@ -86,6 +86,7 @@ func main() {
}
initGL()
loadShaders()
gameLoop()
}
@ -99,6 +100,18 @@ func initGL() {
gl.Viewport(0, 0, winWidth, winHeight)
}
func loadShaders() {
simpleProg := shaders.NewProgram("simple")
simpleVert, err := shaders.NewShaderFromFile("./res/shaders/simple.vert.glsl", shaders.Vertex)
panicIfErr(err, "Parsing vert shader failed")
simpleFrag, err := shaders.NewShaderFromFile("./res/shaders/simple.frag.glsl", shaders.Fragment)
panicIfErr(err, "Parsing frag shader failed")
simpleProg.AttachShader(simpleVert)
simpleProg.AttachShader(simpleFrag)
}
func gameLoop() {
for isRunning {
@ -138,24 +151,11 @@ func handleEvents() {
}
func update() {
println(input.AnyKeyDown(), ";", input.AnyMouseBtnDown())
}
func draw() {
//Clear screen and depth buffers
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.Begin(gl.TRIANGLES)
gl.Color3f(1, 0, 0)
gl.Vertex3f(0, 0.5, 0)
gl.Color3f(1, 0, 0)
gl.Vertex3f(0.5, 0, 0)
gl.Color3f(1, 0, 0)
gl.Vertex3f(-0.5, 0, 0)
gl.End()
}
func panicIfErr(err error, msg string) {

5
res/shaders/simple.frag.glsl Executable file
View File

@ -0,0 +1,5 @@
#version 400
void main() {
}

5
res/shaders/simple.vert.glsl Executable file
View File

@ -0,0 +1,5 @@
#version 400
void main() {
}

89
shaders/program.go Executable file
View File

@ -0,0 +1,89 @@
package shaders
import (
"fmt"
"log"
"strings"
"github.com/go-gl/gl/v4.6-core/gl"
)
type Program struct {
Name string
ID uint32
Shaders []Shader
}
func NewProgram(name string) Program {
p := Program{Name: name}
p.Shaders = make([]Shader, 0)
if p.ID = gl.CreateProgram(); p.ID == 0 {
log.Fatalln("Creating OpenGL program failed")
}
return p
}
//AttachShader adds the shader to list of shaders and attaches it in opengl
func (p *Program) AttachShader(s Shader) {
p.Shaders = append(p.Shaders, s)
gl.AttachShader(p.ID, s.ID)
}
//DetachShader removes the shader from the list of shaders and detaches it in opengl
func (p *Program) DetachShader(s Shader) {
//To remove a shader we move the last shader to its place, then shrink the slice by one
for i := 0; i < len(p.Shaders); i++ {
if p.Shaders[i].ID != s.ID {
continue
}
gl.DetachShader(p.ID, s.ID)
p.Shaders[i] = p.Shaders[len(p.Shaders)-1]
p.Shaders = p.Shaders[:len(p.Shaders)-1]
return
}
}
func (p *Program) Link() error {
gl.LinkProgram(p.ID)
return getProgramLinkError(*p)
}
func getProgramLinkError(p Program) error {
var linkSuccessful int32
gl.GetProgramiv(p.ID, gl.LINK_STATUS, &linkSuccessful)
if linkSuccessful == gl.TRUE {
return nil
}
//Get the log length and create a string big enough for it and fill it with NULL
var logLength int32
gl.GetProgramiv(p.ID, gl.INFO_LOG_LENGTH, &logLength)
infoLog := gl.Str(strings.Repeat("\x00", int(logLength)))
//Read the error log and return a go error
gl.GetProgramInfoLog(p.ID, logLength, nil, infoLog)
return fmt.Errorf("Program linking failed. Linking log: %s", gl.GoStr(infoLog))
}
func (p *Program) Use() {
gl.UseProgram(p.ID)
}
//Delete deletes all shaders and then deletes the program
func (p *Program) Delete() {
for _, v := range p.Shaders {
v.Delete()
}
gl.DeleteProgram(p.ID)
}

65
shaders/shader.go Executable file
View File

@ -0,0 +1,65 @@
package shaders
import (
"fmt"
"log"
"os"
"strings"
"github.com/go-gl/gl/v4.6-core/gl"
)
type Shader struct {
ID uint32
Type ShaderType
}
//NewShaderFromFile reads a shader from file, creates a new opengl shader and compiles it
func NewShaderFromFile(shaderFilePath string, st ShaderType) (Shader, error) {
b, err := os.ReadFile(shaderFilePath)
if err != nil {
return Shader{}, err
}
return NewShaderFromString(string(b), st)
}
//NewShaderFromString creates a new opengl shader and compiles it
func NewShaderFromString(sourceString string, st ShaderType) (Shader, error) {
glString, freeFunc := gl.Strs(sourceString + "\x00")
defer freeFunc()
newShader := Shader{Type: st}
if newShader.ID = gl.CreateShader(st.GLType()); newShader.ID == 0 {
log.Fatalln("Creating shader failed. ShaderType:", st)
}
gl.ShaderSource(newShader.ID, 1, glString, nil)
gl.CompileShader(newShader.ID)
return newShader, getShaderCompileError(newShader)
}
func getShaderCompileError(s Shader) error {
var compileSuccessful int32
gl.GetShaderiv(s.ID, gl.COMPILE_STATUS, &compileSuccessful)
if compileSuccessful == gl.TRUE {
return nil
}
//Get the log length and create a string big enough for it and fill it with NULL
var logLength int32
gl.GetShaderiv(s.ID, gl.INFO_LOG_LENGTH, &logLength)
infoLog := gl.Str(strings.Repeat("\x00", int(logLength)))
//Read the error log and return a go error
gl.GetShaderInfoLog(s.ID, logLength, nil, infoLog)
return fmt.Errorf("Shader compilation failed. Compilation log: %s", gl.GoStr(infoLog))
}
func (s *Shader) Delete() {
gl.DeleteShader(s.ID)
}

45
shaders/shader_type.go Executable file
View File

@ -0,0 +1,45 @@
package shaders
import (
"log"
"github.com/go-gl/gl/v4.6-core/gl"
)
type ShaderType int
const (
Unknown ShaderType = iota
Vertex
Fragment
)
//GLType returns the GL shader type of this ShaderType
//Panics if not known
func (t ShaderType) GLType() uint32 {
switch t {
case Vertex:
return gl.VERTEX_SHADER
case Fragment:
return gl.FRAGMENT_SHADER
}
log.Panicf("Converting ShaderType->GL Shader Type failed. Unknown ShaderType of value: %v\n", t)
return 0
}
//FromGLShaderType returns the ShaderType of the passed GL shader type.
//Panics if not known
func (t ShaderType) FromGLShaderType(glShaderType int) ShaderType {
switch glShaderType {
case gl.VERTEX_SHADER:
return Vertex
case gl.FRAGMENT_SHADER:
return Fragment
default:
log.Printf("Converting GL shader type->ShaderType failed. Unknown GL shader type of value: %v\n", glShaderType)
return Unknown
}
}