mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Shader handling
This commit is contained in:
32
main.go
32
main.go
@ -4,8 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/bloeys/go-sdl-engine/input"
|
"github.com/bloeys/go-sdl-engine/input"
|
||||||
|
"github.com/bloeys/go-sdl-engine/shaders"
|
||||||
"github.com/bloeys/go-sdl-engine/timing"
|
"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"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,8 +51,7 @@ func main() {
|
|||||||
panicIfErr(err, "")
|
panicIfErr(err, "")
|
||||||
|
|
||||||
//Run in compatiability (old and modern opengl) or modern (core) opengl only
|
//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_CORE)
|
||||||
err = sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_COMPATIBILITY)
|
|
||||||
panicIfErr(err, "")
|
panicIfErr(err, "")
|
||||||
|
|
||||||
//Set wanted opengl version
|
//Set wanted opengl version
|
||||||
@ -86,6 +86,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initGL()
|
initGL()
|
||||||
|
loadShaders()
|
||||||
gameLoop()
|
gameLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +100,18 @@ func initGL() {
|
|||||||
gl.Viewport(0, 0, winWidth, winHeight)
|
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() {
|
func gameLoop() {
|
||||||
|
|
||||||
for isRunning {
|
for isRunning {
|
||||||
@ -138,24 +151,11 @@ func handleEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func update() {
|
func update() {
|
||||||
println(input.AnyKeyDown(), ";", input.AnyMouseBtnDown())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func draw() {
|
func draw() {
|
||||||
//Clear screen and depth buffers
|
//Clear screen and depth buffers
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
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) {
|
func panicIfErr(err error, msg string) {
|
||||||
|
|||||||
5
res/shaders/simple.frag.glsl
Executable file
5
res/shaders/simple.frag.glsl
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#version 400
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
}
|
||||||
5
res/shaders/simple.vert.glsl
Executable file
5
res/shaders/simple.vert.glsl
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#version 400
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
}
|
||||||
89
shaders/program.go
Executable file
89
shaders/program.go
Executable 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
65
shaders/shader.go
Executable 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
45
shaders/shader_type.go
Executable 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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user