From b296f1af4c671516c94d5de486707c5e2444f97f Mon Sep 17 00:00:00 2001 From: bloeys Date: Sun, 17 Oct 2021 09:42:43 +0400 Subject: [PATCH] ep2: Finish input system+opengl window+glsl compilation --- input/input.go | 155 +++++++++++++++++++++++++++++++++++ main.go | 93 +++++++++++++++++++++ res/shaders/simple.frag.glsl | 8 ++ res/shaders/simple.vert.glsl | 8 ++ shaders/shaders.go | 73 +++++++++++++++++ 5 files changed, 337 insertions(+) create mode 100755 input/input.go create mode 100755 res/shaders/simple.frag.glsl create mode 100755 res/shaders/simple.vert.glsl create mode 100755 shaders/shaders.go diff --git a/input/input.go b/input/input.go new file mode 100755 index 0000000..2708d72 --- /dev/null +++ b/input/input.go @@ -0,0 +1,155 @@ +package input + +import "github.com/veandco/go-sdl2/sdl" + +type keyState struct { + Key sdl.Keycode + State int + IsPressedThisFrame bool + IsReleasedThisFrame bool +} + +type mouseBtnState struct { + Btn int + State int + + IsPressedThisFrame bool + IsReleasedThisFrame bool + IsDoubleClicked bool +} + +var ( + keyMap = make(map[sdl.Keycode]*keyState) + mouseBtnMap = make(map[int]*mouseBtnState) +) + +func EventLoopStart() { + + for _, v := range keyMap { + v.IsPressedThisFrame = false + v.IsReleasedThisFrame = false + } + + for _, v := range mouseBtnMap { + v.IsPressedThisFrame = false + v.IsReleasedThisFrame = false + v.IsDoubleClicked = false + } +} + +func HandleKeyboardEvent(e *sdl.KeyboardEvent) { + + ks := keyMap[e.Keysym.Sym] + if ks == nil { + ks = &keyState{Key: e.Keysym.Sym} + keyMap[ks.Key] = ks + } + + ks.State = int(e.State) + ks.IsPressedThisFrame = e.State == sdl.PRESSED && e.Repeat == 0 + ks.IsReleasedThisFrame = e.State == sdl.RELEASED && e.Repeat == 0 +} + +func HandleMouseEvent(e *sdl.MouseButtonEvent) { + + mb := mouseBtnMap[int(e.Button)] + if mb == nil { + mb = &mouseBtnState{Btn: int(e.Button)} + mouseBtnMap[int(e.Button)] = mb + } + + mb.State = int(e.State) + + mb.IsDoubleClicked = e.Clicks == 2 && e.State == sdl.PRESSED + mb.IsPressedThisFrame = e.State == sdl.PRESSED + mb.IsReleasedThisFrame = e.State == sdl.RELEASED +} + +func KeyClicked(kc sdl.Keycode) bool { + + ks := keyMap[kc] + if ks == nil { + return false + } + + return ks.IsPressedThisFrame +} + +func KeyReleased(kc sdl.Keycode) bool { + + ks := keyMap[kc] + if ks == nil { + return false + } + + return ks.IsReleasedThisFrame +} + +func KeyDown(kc sdl.Keycode) bool { + + ks := keyMap[kc] + if ks == nil { + return false + } + + return ks.State == sdl.PRESSED +} + +func KeyUp(kc sdl.Keycode) bool { + + ks := keyMap[kc] + if ks == nil { + return true + } + + return ks.State == sdl.RELEASED +} + +func MouseClicked(mb int) bool { + + btn := mouseBtnMap[mb] + if btn == nil { + return false + } + + return btn.IsPressedThisFrame +} + +func MouseDoubleClicked(mb int) bool { + + btn := mouseBtnMap[mb] + if btn == nil { + return false + } + + return btn.IsDoubleClicked +} + +func MouseReleased(mb int) bool { + btn := mouseBtnMap[mb] + if btn == nil { + return false + } + + return btn.IsReleasedThisFrame +} + +func MouseDown(mb int) bool { + + btn := mouseBtnMap[mb] + if btn == nil { + return false + } + + return btn.State == sdl.PRESSED +} + +func MouseUp(mb int) bool { + + btn := mouseBtnMap[mb] + if btn == nil { + return true + } + + return btn.State == sdl.RELEASED +} diff --git a/main.go b/main.go index 7905807..1db7270 100755 --- a/main.go +++ b/main.go @@ -1,5 +1,98 @@ package main +import ( + "github.com/bloeys/go-sdl-engine/input" + "github.com/bloeys/go-sdl-engine/logging" + "github.com/bloeys/go-sdl-engine/shaders" + "github.com/go-gl/gl/v4.6-compatibility/gl" + "github.com/veandco/go-sdl2/sdl" +) + +const ( + winWidth = 1280 + winHeight = 720 +) + +var ( + isRunning bool = true + + window *sdl.Window +) + func main() { + err := sdl.Init(sdl.INIT_EVERYTHING) + if err != nil { + logging.ErrLog.Fatalln("Failed to init SDL. Err:", err) + } + + window, err = sdl.CreateWindow("Go SDL Engine", sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, winWidth, winHeight, sdl.WINDOW_OPENGL) + if err != nil { + logging.ErrLog.Fatalln("Failed to create window. Err: ", err) + } + defer window.Destroy() + + glCtx, err := window.GLCreateContext() + if err != nil { + logging.ErrLog.Fatalln("Failed to create OpenGL context. Err: ", err) + } + defer sdl.GLDeleteContext(glCtx) + + initOpenGL() + shaders.LoadShaders() + + //Game loop + for isRunning { + + handleInputs() + runGameLogic() + draw() + + sdl.Delay(17) + } +} + +func initOpenGL() { + + if err := gl.Init(); err != nil { + logging.ErrLog.Fatalln(err) + } + + sdl.GLSetAttribute(sdl.MAJOR_VERSION, 4) + sdl.GLSetAttribute(sdl.MINOR_VERSION, 6) + + // R(0-255) G(0-255) B(0-255) + sdl.GLSetAttribute(sdl.GL_RED_SIZE, 8) + sdl.GLSetAttribute(sdl.GL_GREEN_SIZE, 8) + sdl.GLSetAttribute(sdl.GL_BLUE_SIZE, 8) + + sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1) + + sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_COMPATIBILITY) + // sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE) +} + +func handleInputs() { + + input.EventLoopStart() + + for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { + + switch e := event.(type) { + + case *sdl.KeyboardEvent: + input.HandleKeyboardEvent(e) + case *sdl.MouseButtonEvent: + input.HandleMouseEvent(e) + case *sdl.QuitEvent: + isRunning = false + } + } +} + +func runGameLogic() { + +} + +func draw() { } diff --git a/res/shaders/simple.frag.glsl b/res/shaders/simple.frag.glsl new file mode 100755 index 0000000..dd78aac --- /dev/null +++ b/res/shaders/simple.frag.glsl @@ -0,0 +1,8 @@ +#version 460 + +out vec4 FragColor; + +void main() +{ + FragColor = vec4(1, 0, 0, 1.0); +} \ No newline at end of file diff --git a/res/shaders/simple.vert.glsl b/res/shaders/simple.vert.glsl new file mode 100755 index 0000000..fc8198d --- /dev/null +++ b/res/shaders/simple.vert.glsl @@ -0,0 +1,8 @@ +#version 460 + +in vec3 vertPos; + +void main() +{ + gl_Position = vec4(vertPos, 1.0); +} \ No newline at end of file diff --git a/shaders/shaders.go b/shaders/shaders.go new file mode 100755 index 0000000..925e7f7 --- /dev/null +++ b/shaders/shaders.go @@ -0,0 +1,73 @@ +package shaders + +import ( + "os" + "strings" + + "github.com/bloeys/go-sdl-engine/logging" + "github.com/go-gl/gl/v4.6-compatibility/gl" +) + +type ShaderProgram struct { + ID uint32 + VertShaderID uint32 + FragShaderID uint32 +} + +func LoadShaders() { + + vertShaderText, err := os.ReadFile("./res/shaders/simple.vert.glsl") + if err != nil { + logging.ErrLog.Fatalln("Failed to read vertex shader. Err: ", err) + } + + fragShaderText, err := os.ReadFile("./res/shaders/simple.frag.glsl") + if err != nil { + logging.ErrLog.Fatalln("Failed to read fragment shader. Err: ", err) + } + + shader := &ShaderProgram{} + shader.ID = gl.CreateProgram() + if shader.ID == 0 { + logging.ErrLog.Fatalln("Failed to create shader program") + } + + shader.VertShaderID = gl.CreateShader(gl.VERTEX_SHADER) + shader.FragShaderID = gl.CreateShader(gl.FRAGMENT_SHADER) + + vertexCStr, vertFree := gl.Strs(string(vertShaderText) + "\x00") + defer vertFree() + gl.ShaderSource(shader.VertShaderID, 1, vertexCStr, nil) + + fragCStr, fragFree := gl.Strs(string(fragShaderText) + "\x00") + defer fragFree() + gl.ShaderSource(shader.FragShaderID, 1, fragCStr, nil) + + gl.CompileShader(shader.VertShaderID) + getShaderCompileErrors(shader.VertShaderID) + + gl.CompileShader(shader.FragShaderID) + getShaderCompileErrors(shader.FragShaderID) + + gl.AttachShader(shader.ID, shader.VertShaderID) + gl.AttachShader(shader.ID, shader.FragShaderID) + gl.LinkProgram(shader.ID) +} + +func getShaderCompileErrors(shaderID uint32) { + + var compiledSuccessfully int32 + gl.GetShaderiv(shaderID, gl.COMPILE_STATUS, &compiledSuccessfully) + if compiledSuccessfully == gl.TRUE { + return + } + + var logLength int32 + gl.GetShaderiv(shaderID, gl.INFO_LOG_LENGTH, &logLength) + + log := gl.Str(strings.Repeat("\x00", int(logLength))) + gl.GetShaderInfoLog(shaderID, logLength, nil, log) + + errMsg := gl.GoStr(log) + println("Compilation of shader with id ", shaderID, " failed. Err: ", errMsg) +}