From 97c396e54c965cbe4811a818d48aed32e226dfa4 Mon Sep 17 00:00:00 2001 From: bloeys Date: Sat, 9 Oct 2021 11:56:05 +0400 Subject: [PATCH] Vertex buffer objects+vertex arrays objects+element buffer objects --- main.go | 77 +++++++++++++++++++++++++++++++++--- res/shaders/simple.frag.glsl | 8 ++-- res/shaders/simple.vert.glsl | 6 +-- shaders/program.go | 17 ++++++-- shaders/shader.go | 9 +++-- 5 files changed, 98 insertions(+), 19 deletions(-) diff --git a/main.go b/main.go index 08ed1ed..a38339b 100755 --- a/main.go +++ b/main.go @@ -2,6 +2,8 @@ package main import ( "fmt" + "math" + "time" "github.com/bloeys/go-sdl-engine/input" "github.com/bloeys/go-sdl-engine/logging" @@ -105,23 +107,74 @@ var simpleProg shaders.Program func loadShaders() { - simpleVert, err := shaders.NewShaderFromFile("./res/shaders/simple.vert.glsl", shaders.Vertex) + simpleVert, err := shaders.NewShaderFromFile("simpleVert", "./res/shaders/simple.vert.glsl", shaders.Vertex) panicIfErr(err, "Parsing vert shader failed") - simpleFrag, err := shaders.NewShaderFromFile("./res/shaders/simple.frag.glsl", shaders.Fragment) + simpleFrag, err := shaders.NewShaderFromFile("simpleFrag", "./res/shaders/simple.frag.glsl", shaders.Fragment) panicIfErr(err, "Parsing frag shader failed") simpleProg = shaders.NewProgram("simple") simpleProg.AttachShader(simpleVert) simpleProg.AttachShader(simpleFrag) - - simpleProg.SetUniformF32("r", 255) - simpleProg.Link() } +var vao uint32 + func gameLoop() { + //vertex positions in opengl coords + verts := []float32{ + -0.5, 0.5, 0, + 0.5, 0.5, 0, + 0.5, -0.5, 0, + -0.5, -0.5, 0, + } + + //Trianlge indices used for drawing + indices := []uint32{ + 0, 1, 2, + 0, 2, 3, + } + + //Create a VAO to store the different VBOs of a given object/set of vertices + gl.GenVertexArrays(1, &vao) + + //Bind the VAO first so later buffer binds/VBOs are put within this VAO + gl.BindVertexArray(vao) + + //Gen buffer to hold EBOs and fill it with data. Note that an EBO must NOT be unbound before the VAO, otherwise + //its settings are lost as the VAO records its actions + var ebo uint32 + gl.GenBuffers(1, &ebo) + + gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo) + gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*4, gl.Ptr(indices), gl.STATIC_DRAW) + + //Gen vertPos VBO and fill it with data + var vertPosVBO uint32 + gl.GenBuffers(1, &vertPosVBO) + + gl.BindBuffer(gl.ARRAY_BUFFER, vertPosVBO) + gl.BufferData(gl.ARRAY_BUFFER, len(verts)*4, gl.Ptr(verts), gl.STATIC_DRAW) + + //Assign vertPos VBO to vertPos shader attribute by specifying that each vertPos variable + //takes 3 values from the VBO, where each value is a float. + + //We also specify the total size (in bytes) of the values used for a single vertPos. + //The offset defines the bytes to skip between each set of vertPos values + vertPosLoc := uint32(gl.GetAttribLocation(simpleProg.ID, gl.Str("vertPos\x00"))) + gl.VertexAttribPointer(vertPosLoc, 3, gl.FLOAT, false, 3*4, gl.PtrOffset(0)) + + //Vertex attributes are disabled by default, so we need to finally enable it + gl.EnableVertexAttribArray(vertPosLoc) + + //We are done working with VBOs so can unbind the VAO to avoid corrupting it later. + //Note: Actions (binding/setting buffers, enabling/disabling attribs) done between + //bind and unbind of a VAO are recorded by it, and when its rebinded before a draw the + //settings are retrieved, therefore keep in mind work after a VAO unbind will be lost. + gl.BindVertexArray(0) + for isRunning { timing.FrameStarted() @@ -164,6 +217,20 @@ func update() { func draw() { //Clear screen and depth buffers gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + + simpleProg.Use() + + deg2rad := math.Pi / 180.0 + t := float64(time.Now().UnixMilli()) / 10 + + x := float32(math.Sin(t*deg2rad*0.3)+1) * 0.5 + y := float32(math.Sin(t*deg2rad*0.5)+1) * 0.5 + z := float32(math.Sin(t*deg2rad*0.7)+1) * 0.5 + simpleProg.SetUniformF32("c", x, y, z) + + gl.BindVertexArray(vao) + gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, gl.PtrOffset(0)) + gl.BindVertexArray(0) } func panicIfErr(err error, msg string) { diff --git a/res/shaders/simple.frag.glsl b/res/shaders/simple.frag.glsl index 21056ca..77e6afc 100755 --- a/res/shaders/simple.frag.glsl +++ b/res/shaders/simple.frag.glsl @@ -1,9 +1,9 @@ -#version 400 +#version 460 core -uniform float r; +uniform vec3 c; -out vec4 color; +out vec4 fragColor; void main() { - color = vec4(r,r,r,0); + fragColor = vec4(c, 1); } diff --git a/res/shaders/simple.vert.glsl b/res/shaders/simple.vert.glsl index 072fbf6..571c947 100755 --- a/res/shaders/simple.vert.glsl +++ b/res/shaders/simple.vert.glsl @@ -1,7 +1,7 @@ -#version 400 +#version 460 core -uniform float r; +in vec3 vertPos; void main() { - + gl_Position = vec4(vertPos, 1.0); } \ No newline at end of file diff --git a/shaders/program.go b/shaders/program.go index b32e871..fa528b7 100755 --- a/shaders/program.go +++ b/shaders/program.go @@ -51,10 +51,21 @@ func (p *Program) DetachShader(s Shader) { } } +//Link deletes all shaders from opengl and clears the shaders array if linking is successful. +//Note: This is allowed because only the final program is needed after linking func (p *Program) Link() error { gl.LinkProgram(p.ID) - return getProgramLinkError(*p) + if err := getProgramLinkError(*p); err != nil { + return err + } + + for _, v := range p.Shaders { + gl.DeleteShader(v.ID) + } + + p.Shaders = nil + return nil } func getProgramLinkError(p Program) error { @@ -89,7 +100,7 @@ func (p *Program) GetUniformLocation(name string) int32 { func (p *Program) SetUniformF32(name string, floats ...float32) bool { loc := p.GetUniformLocation(name) - if loc == 0 { + if loc == -1 { logging.WarnLog.Printf( "Uniform with name '%s' was not found. "+ "This is either because it doesn't exist or isn't used in the shader", @@ -120,7 +131,7 @@ func (p *Program) SetUniformF32(name string, floats ...float32) bool { func (p *Program) SetUniformI32(name string, ints ...int32) bool { loc := p.GetUniformLocation(name) - if loc == 0 { + if loc == -1 { logging.WarnLog.Printf( "Uniform with name '%s' was not found. "+ "This is either because it doesn't exist or isn't used in the shader", diff --git a/shaders/shader.go b/shaders/shader.go index efc814f..f2c2b67 100755 --- a/shaders/shader.go +++ b/shaders/shader.go @@ -10,28 +10,29 @@ import ( ) type Shader struct { + Name string 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) { +func NewShaderFromFile(name, shaderFilePath string, st ShaderType) (Shader, error) { b, err := os.ReadFile(shaderFilePath) if err != nil { return Shader{}, err } - return NewShaderFromString(string(b), st) + return NewShaderFromString(name, string(b), st) } //NewShaderFromString creates a new opengl shader and compiles it -func NewShaderFromString(sourceString string, st ShaderType) (Shader, error) { +func NewShaderFromString(name, sourceString string, st ShaderType) (Shader, error) { glString, freeFunc := gl.Strs(sourceString + "\x00") defer freeFunc() - newShader := Shader{Type: st} + newShader := Shader{Name: name, Type: st} if newShader.ID = gl.CreateShader(st.GLType()); newShader.ID == 0 { logging.ErrLog.Panicln("Creating shader failed. ShaderType:", st) }