From fe2aef6b6d33cdd561f22da23c192b061699542e Mon Sep 17 00:00:00 2001 From: bloeys Date: Sat, 2 Jul 2022 22:49:28 +0400 Subject: [PATCH] Support combined shaders+allow loading shaders from string --- main.go | 10 +++--- materials/material.go | 28 +++++++--------- res/shaders/imgui.frag.glsl | 13 -------- res/shaders/imgui.vert.glsl | 17 ---------- res/shaders/simple.frag.glsl | 26 --------------- res/shaders/simple.glsl | 55 ++++++++++++++++++++++++++++++++ res/shaders/simple.vert.glsl | 26 --------------- shaders/shaders.go | 62 ++++++++++++++++++++++++++++++++++-- ui/imgui/imgui.go | 38 +++++++++++++++++++++- 9 files changed, 167 insertions(+), 108 deletions(-) delete mode 100755 res/shaders/imgui.frag.glsl delete mode 100755 res/shaders/imgui.vert.glsl delete mode 100755 res/shaders/simple.frag.glsl create mode 100755 res/shaders/simple.glsl delete mode 100755 res/shaders/simple.vert.glsl diff --git a/main.go b/main.go index 837adf2..02736e3 100755 --- a/main.go +++ b/main.go @@ -19,10 +19,9 @@ import ( ) //TODO: Tasks: -// Build simple game -// Integrate physx -// Entities and components // Camera class +// Entities and components +// Integrate physx //Low Priority: // Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) @@ -31,7 +30,6 @@ import ( // Separate engine loop from rendering loop? or leave it to the user? // Abstract keys enum away from sdl // Proper Asset loading -// Audio // Frustum culling // Material system editor with fields automatically extracted from the shader @@ -58,7 +56,7 @@ type OurGame struct { func (g *OurGame) Init() { //Create materials - simpleMat = materials.NewMaterial("Simple Mat", "./res/shaders/simple") + simpleMat = materials.NewMaterial("Simple Mat", "./res/shaders/simple.glsl") //Load meshes var err error @@ -98,7 +96,7 @@ func (g *OurGame) Init() { func (g *OurGame) Update() { - if input.IsQuitClicked() { + if input.IsQuitClicked() || input.KeyClicked(sdl.K_ESCAPE) { engine.Quit() } diff --git a/materials/material.go b/materials/material.go index 55f8cee..c7afa96 100755 --- a/materials/material.go +++ b/materials/material.go @@ -106,24 +106,20 @@ func (m *Material) Delete() { func NewMaterial(matName, shaderPath string) *Material { - shdrProg, err := shaders.NewShaderProgram() + shdrProg, err := shaders.LoadAndCompileCombinedShader(shaderPath) if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader program. Err: ", err) + logging.ErrLog.Fatalln("Failed to create new material. Err: ", err) + } + + return &Material{Name: matName, ShaderProg: shdrProg, UnifLocs: make(map[string]int32), AttribLocs: make(map[string]int32)} +} + +func NewMaterialSrc(matName string, shaderSrc []byte) *Material { + + shdrProg, err := shaders.LoadAndCompileCombinedShaderSrc(shaderSrc) + if err != nil { + logging.ErrLog.Fatalln("Failed to create new material. Err: ", err) } - vertShader, err := shaders.LoadAndCompilerShader(shaderPath+".vert.glsl", shaders.VertexShaderType) - if err != nil { - logging.ErrLog.Fatalln("Failed to load and create vertex shader. Err: ", err) - } - - fragShader, err := shaders.LoadAndCompilerShader(shaderPath+".frag.glsl", shaders.FragmentShaderType) - if err != nil { - logging.ErrLog.Fatalln("Failed to load and create fragment shader. Err: ", err) - } - - shdrProg.AttachShader(vertShader) - shdrProg.AttachShader(fragShader) - shdrProg.Link() - return &Material{Name: matName, ShaderProg: shdrProg, UnifLocs: make(map[string]int32), AttribLocs: make(map[string]int32)} } diff --git a/res/shaders/imgui.frag.glsl b/res/shaders/imgui.frag.glsl deleted file mode 100755 index edde592..0000000 --- a/res/shaders/imgui.frag.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#version 410 - -uniform sampler2D Texture; - -in vec2 Frag_UV; -in vec4 Frag_Color; - -out vec4 Out_Color; - -void main() -{ - Out_Color = vec4(Frag_Color.rgb, Frag_Color.a * texture(Texture, Frag_UV.st).r); -} \ No newline at end of file diff --git a/res/shaders/imgui.vert.glsl b/res/shaders/imgui.vert.glsl deleted file mode 100755 index a39109a..0000000 --- a/res/shaders/imgui.vert.glsl +++ /dev/null @@ -1,17 +0,0 @@ -#version 410 - -uniform mat4 ProjMtx; - -in vec2 Position; -in vec2 UV; -in vec4 Color; - -out vec2 Frag_UV; -out vec4 Frag_Color; - -void main() -{ - Frag_UV = UV; - Frag_Color = Color; - gl_Position = ProjMtx * vec4(Position.xy, 0, 1); -} \ No newline at end of file diff --git a/res/shaders/simple.frag.glsl b/res/shaders/simple.frag.glsl deleted file mode 100755 index 57f9c9c..0000000 --- a/res/shaders/simple.frag.glsl +++ /dev/null @@ -1,26 +0,0 @@ -#version 410 - -uniform float ambientStrength = 0.1; -uniform vec3 ambientLightColor = vec3(1, 1, 1); - -uniform vec3 lightPos1; -uniform vec3 lightColor1; - -uniform sampler2D diffTex; - -in vec3 vertColor; -in vec3 vertNormal; -in vec2 vertUV0; -in vec3 fragPos; - -out vec4 fragColor; - -void main() -{ - vec3 lightDir = normalize(lightPos1 - fragPos); - float diffStrength = max(0.0, dot(normalize(vertNormal), lightDir)); - - vec3 finalAmbientColor = ambientLightColor * ambientStrength; - vec4 texColor = texture(diffTex, vertUV0); - fragColor = vec4(texColor.rgb * vertColor * (finalAmbientColor + diffStrength*lightColor1) , texColor.a); -} diff --git a/res/shaders/simple.glsl b/res/shaders/simple.glsl new file mode 100755 index 0000000..8bbf37b --- /dev/null +++ b/res/shaders/simple.glsl @@ -0,0 +1,55 @@ +//shader:vertex +#version 410 + +layout(location=0) in vec3 vertPosIn; +layout(location=1) in vec3 vertNormalIn; +layout(location=2) in vec2 vertUV0In; +layout(location=3) in vec3 vertColorIn; + +out vec3 vertNormal; +out vec2 vertUV0; +out vec3 vertColor; +out vec3 fragPos; + +//MVP = Model View Projection +uniform mat4 modelMat; +uniform mat4 viewMat; +uniform mat4 projMat; + +void main() +{ + vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn; + vertUV0 = vertUV0In; + vertColor = vertColorIn; + fragPos = vec3(modelMat * vec4(vertPosIn, 1.0)); + + gl_Position = projMat * viewMat * modelMat * vec4(vertPosIn, 1.0); +} + +//shader:fragment +#version 410 + +uniform float ambientStrength = 0.1; +uniform vec3 ambientLightColor = vec3(1, 1, 1); + +uniform vec3 lightPos1; +uniform vec3 lightColor1; + +uniform sampler2D diffTex; + +in vec3 vertColor; +in vec3 vertNormal; +in vec2 vertUV0; +in vec3 fragPos; + +out vec4 fragColor; + +void main() +{ + vec3 lightDir = normalize(lightPos1 - fragPos); + float diffStrength = max(0.0, dot(normalize(vertNormal), lightDir)); + + vec3 finalAmbientColor = ambientLightColor * ambientStrength; + vec4 texColor = texture(diffTex, vertUV0); + fragColor = vec4(texColor.rgb * vertColor * (finalAmbientColor + diffStrength*lightColor1) , texColor.a); +} diff --git a/res/shaders/simple.vert.glsl b/res/shaders/simple.vert.glsl deleted file mode 100755 index fa88385..0000000 --- a/res/shaders/simple.vert.glsl +++ /dev/null @@ -1,26 +0,0 @@ -#version 410 - -layout(location=0) in vec3 vertPosIn; -layout(location=1) in vec3 vertNormalIn; -layout(location=2) in vec2 vertUV0In; -layout(location=3) in vec3 vertColorIn; - -out vec3 vertNormal; -out vec2 vertUV0; -out vec3 vertColor; -out vec3 fragPos; - -//MVP = Model View Projection -uniform mat4 modelMat; -uniform mat4 viewMat; -uniform mat4 projMat; - -void main() -{ - vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn; - vertUV0 = vertUV0In; - vertColor = vertColorIn; - fragPos = vec3(modelMat * vec4(vertPosIn, 1.0)); - - gl_Position = projMat * viewMat * modelMat * vec4(vertPosIn, 1.0); -} \ No newline at end of file diff --git a/shaders/shaders.go b/shaders/shaders.go index cd9766e..8d40f05 100755 --- a/shaders/shaders.go +++ b/shaders/shaders.go @@ -1,6 +1,7 @@ package shaders import ( + "bytes" "errors" "os" "strings" @@ -28,14 +29,69 @@ func NewShaderProgram() (ShaderProgram, error) { return ShaderProgram{ID: id}, nil } -func LoadAndCompilerShader(shaderPath string, shaderType ShaderType) (Shader, error) { +func LoadAndCompileCombinedShader(shaderPath string) (ShaderProgram, error) { - shaderSource, err := os.ReadFile(shaderPath) + combinedSource, err := os.ReadFile(shaderPath) if err != nil { logging.ErrLog.Println("Failed to read shader. Err: ", err) - return Shader{}, err + return ShaderProgram{}, err } + return LoadAndCompileCombinedShaderSrc(combinedSource) + +} +func LoadAndCompileCombinedShaderSrc(shaderSrc []byte) (ShaderProgram, error) { + + shaderSources := bytes.Split(shaderSrc, []byte("//shader:")) + if len(shaderSources) == 1 { + return ShaderProgram{}, errors.New("failed to read combined shader. Did not find '//shader:vertex' or '//shader:fragment'") + } + + shdrProg, err := NewShaderProgram() + if err != nil { + return ShaderProgram{}, errors.New("failed to create new shader program. Err: " + err.Error()) + } + + loadedShdrCount := 0 + for i := 0; i < len(shaderSources); i++ { + + src := shaderSources[i] + + //This can happen when the shader type is at the start of the file + if len(bytes.TrimSpace(src)) == 0 { + continue + } + + var shdrType ShaderType + if bytes.HasPrefix(src, []byte("vertex")) { + src = src[6:] + shdrType = VertexShaderType + } else if bytes.HasPrefix(src, []byte("fragment")) { + src = src[8:] + shdrType = FragmentShaderType + } else { + return ShaderProgram{}, errors.New("unknown shader type. Must be '//shader:vertex' or '//shader:fragment'") + } + + shdr, err := CompileShaderOfType(src, shdrType) + if err != nil { + return ShaderProgram{}, err + } + + loadedShdrCount++ + shdrProg.AttachShader(shdr) + } + + if loadedShdrCount == 0 { + return ShaderProgram{}, errors.New("no valid shaders found. Please put '//shader:vertex' or '//shader:fragment' before your shaders") + } + + shdrProg.Link() + return shdrProg, nil +} + +func CompileShaderOfType(shaderSource []byte, shaderType ShaderType) (Shader, error) { + shaderID := gl.CreateShader(uint32(shaderType)) if shaderID == 0 { logging.ErrLog.Println("Failed to create shader.") diff --git a/ui/imgui/imgui.go b/ui/imgui/imgui.go index 6235cb5..371ee93 100755 --- a/ui/imgui/imgui.go +++ b/ui/imgui/imgui.go @@ -149,11 +149,47 @@ func (i *ImguiInfo) AddFontTTF(fontPath string, fontSize float32, fontConfig *im return f } +const imguiShdrSrc = ` +//shader:vertex +#version 410 + +uniform mat4 ProjMtx; + +in vec2 Position; +in vec2 UV; +in vec4 Color; + +out vec2 Frag_UV; +out vec4 Frag_Color; + +void main() +{ + Frag_UV = UV; + Frag_Color = Color; + gl_Position = ProjMtx * vec4(Position.xy, 0, 1); +} + +//shader:fragment +#version 410 + +uniform sampler2D Texture; + +in vec2 Frag_UV; +in vec4 Frag_Color; + +out vec4 Out_Color; + +void main() +{ + Out_Color = vec4(Frag_Color.rgb, Frag_Color.a * texture(Texture, Frag_UV.st).r); +} +` + func NewImGUI() ImguiInfo { imguiInfo := ImguiInfo{ ImCtx: imgui.CreateContext(nil), - Mat: materials.NewMaterial("ImGUI Mat", "./res/shaders/imgui"), + Mat: materials.NewMaterialSrc("ImGUI Mat", []byte(imguiShdrSrc)), } imIO := imgui.CurrentIO()