carpy-breakout/pkg/game_window/game_window.go

334 lines
7.4 KiB
Go

package game_window
import (
"fmt"
"log"
gl "github.com/go-gl/gl/v3.1/gles2"
"github.com/go-gl/mathgl/mgl32"
"github.com/veandco/go-sdl2/sdl"
"gitea.wisellama.rocks/Wisellama/carpy-breakout/pkg/gl_helpers"
"gitea.wisellama.rocks/Wisellama/carpy-breakout/pkg/gl_objects"
)
const DefaultWindowWidth int32 = 800
const DefaultWindowHeight int32 = 600
const DefaultWindowFlags uint32 = sdl.WINDOW_SHOWN | sdl.WINDOW_RESIZABLE | sdl.WINDOW_OPENGL
const FullscreenWindowFlags uint32 = DefaultWindowFlags | sdl.WINDOW_FULLSCREEN_DESKTOP
type GameWindow struct {
SDLWindow *sdl.Window
GLContext *sdl.GLContext
GLProgram uint32
GLObjects []gl_objects.GLObject
Camera *gl_objects.Camera
Paddle *gl_objects.Box
PositiveBoundary mgl32.Vec3
NegativeBoundary mgl32.Vec3
running bool
fullscreen bool
wireframe bool
freelook bool
}
func NewGameWindow(title string) (*GameWindow, error) {
gameWindow := GameWindow{
running: true,
fullscreen: false,
wireframe: false,
freelook: false,
}
window, err := sdl.CreateWindow(
title,
sdl.WINDOWPOS_UNDEFINED,
sdl.WINDOWPOS_UNDEFINED,
DefaultWindowWidth,
DefaultWindowHeight,
DefaultWindowFlags)
if err != nil {
log.Println("Failed creating SDL window")
return nil, err
}
gameWindow.SDLWindow = window
context, err := window.GLCreateContext()
if err != nil {
log.Println("Failed Creating GL context.")
return nil, err
}
gameWindow.GLContext = &context
return &gameWindow, err
}
func (w *GameWindow) GLInit() error {
program, err := gl_helpers.NewDefaultProgram()
if err != nil {
return err
}
gl.UseProgram(program)
w.GLProgram = program
w.WindowProjection()
return nil
}
func (w *GameWindow) AddObject(object gl_objects.GLObject) {
w.GLObjects = append(w.GLObjects, object)
}
func (w *GameWindow) Destroy() {
w.SDLWindow.Destroy()
sdl.GLDeleteContext(*w.GLContext)
}
func (w *GameWindow) ToggleFullscreen() {
if w.fullscreen {
w.SDLWindow.SetFullscreen(DefaultWindowFlags)
} else {
w.SDLWindow.SetFullscreen(FullscreenWindowFlags)
}
w.fullscreen = !w.fullscreen
}
func (w *GameWindow) ToggleFreelook() {
w.freelook = !w.freelook
}
func (w *GameWindow) IsFreelookOn() bool {
return w.freelook
}
func (w *GameWindow) IsRunning() bool {
return w.running
}
func (w *GameWindow) StopRunning() {
w.running = false
}
func (w *GameWindow) WindowProjection() {
width, height := w.SDLWindow.GLGetDrawableSize()
projection := mgl32.Perspective(mgl32.DegToRad(45.0), float32(width)/float32(height), 0.01, 1000.0)
gl_helpers.SetUniformMatrix4f(w.GLProgram, "projection", &projection)
gl.Viewport(0, 0, width, height)
}
func (w *GameWindow) SetPaddle(paddle *gl_objects.Box) {
w.Paddle = paddle
}
func (w *GameWindow) SetCamera(camera *gl_objects.Camera) {
w.Camera = camera
}
func (w *GameWindow) ToggleWireframe() {
// TODO figure out concurrency
// var wg sync.WaitGroup
// for _, o := range w.GLObjects {
// wg.Add(1)
// go func() {
// o.ToggleWireframe()
// wg.Done()
// }()
// }
// wg.Wait()
for _, o := range w.GLObjects {
o.ToggleWireframe()
}
w.wireframe = !w.wireframe
}
func (w *GameWindow) GLDraw() {
model := mgl32.Ident4()
// Probably can't do concurrent drawing due to OpenGL
for _, o := range w.GLObjects {
gl_helpers.SetUniformMatrix4f(w.GLProgram, "model", &model)
o.GLDraw()
}
}
func (w *GameWindow) Update() {
// TODO figure out concurrency
// var wg sync.WaitGroup
// for _, o := range w.GLObjects {
// wg.Add(1)
// go func() {
// o.Update()
// wg.Done()
// }()
// }
// wg.Wait()
for _, o := range w.GLObjects {
o.Update()
}
w.ensurePaddleBoundary()
}
func (w *GameWindow) HandleEvents() {
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch e := event.(type) {
case *sdl.WindowEvent:
w.WindowProjection()
case *sdl.QuitEvent:
log.Println("Quiting")
w.StopRunning()
case *sdl.MouseMotionEvent:
w.HandleMouseMovementEvent(e)
case *sdl.MouseButtonEvent:
fmt.Printf("[%d ms] MouseButton\ttype:%d\tid:%d\tx:%d\ty:%d\tbutton:%d\tstate:%d\n",
e.Timestamp, e.Type, e.Which, e.X, e.Y, e.Button, e.State)
case *sdl.MouseWheelEvent:
fmt.Printf("[%d ms] MouseWheel\ttype:%d\tid:%d\tx:%d\ty:%d\n",
e.Timestamp, e.Type, e.Which, e.X, e.Y)
case *sdl.KeyboardEvent:
w.HandleKeyboardEvent(e)
}
}
}
func (w *GameWindow) HandleKeyboardEvent(e *sdl.KeyboardEvent) {
if e.Keysym.Sym == sdl.K_ESCAPE {
log.Println("Esc quitting")
w.StopRunning()
}
if e.Keysym.Sym == sdl.K_f {
if e.Type == sdl.KEYDOWN {
w.ToggleFullscreen()
}
}
if e.Keysym.Sym == sdl.K_l {
if e.Type == sdl.KEYDOWN {
w.ToggleWireframe()
}
}
if e.Keysym.Sym == sdl.K_k {
if e.Type == sdl.KEYDOWN {
w.ToggleFreelook()
}
}
// Movement
if w.IsFreelookOn() {
w.handleFreelookMovement(e)
} else {
w.handleGameKeyboardMovement(e)
}
}
func (w *GameWindow) handleFreelookMovement(e *sdl.KeyboardEvent) {
if e.Keysym.Sym == sdl.K_w {
if e.Type == sdl.KEYDOWN {
w.Camera.SetZVelocity(1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetZVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_a {
if e.Type == sdl.KEYDOWN {
w.Camera.SetXVelocity(-1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetXVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_s {
if e.Type == sdl.KEYDOWN {
w.Camera.SetZVelocity(-1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetZVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_d {
if e.Type == sdl.KEYDOWN {
w.Camera.SetXVelocity(1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetXVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_q {
if e.Type == sdl.KEYDOWN {
w.Camera.SetYVelocity(-1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetYVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_e {
if e.Type == sdl.KEYDOWN {
w.Camera.SetYVelocity(1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetYVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_z {
if e.Type == sdl.KEYDOWN {
w.Camera.SetRotationVelocity(-1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetRotationVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_x {
if e.Type == sdl.KEYDOWN {
w.Camera.SetRotationVelocity(1)
} else if e.Type == sdl.KEYUP {
w.Camera.SetRotationVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_LSHIFT {
if e.Type == sdl.KEYDOWN {
w.Camera.SetFastMoveVelocity(2)
} else if e.Type == sdl.KEYUP {
w.Camera.SetFastMoveVelocity(0)
}
}
}
func (w *GameWindow) HandleMouseMovementEvent(e *sdl.MouseMotionEvent) {
if w.IsFreelookOn() {
if e.XRel != 0 || e.YRel != 0 {
w.Camera.Rotate(e.XRel, e.YRel, 0)
}
} else {
w.handleGameMouseMovement(e)
}
}
func (w *GameWindow) handleGameKeyboardMovement(e *sdl.KeyboardEvent) {
if e.Keysym.Sym == sdl.K_a {
if e.Type == sdl.KEYDOWN {
w.Paddle.SetXVelocity(-0.5)
} else if e.Type == sdl.KEYUP {
w.Paddle.SetXVelocity(0)
}
}
if e.Keysym.Sym == sdl.K_d {
if e.Type == sdl.KEYDOWN {
w.Paddle.SetXVelocity(0.5)
} else if e.Type == sdl.KEYUP {
w.Paddle.SetXVelocity(0)
}
}
}
func (w *GameWindow) handleGameMouseMovement(e *sdl.MouseMotionEvent) {
if e.XRel != 0 || e.YRel != 0 {
v := float32(e.XRel) / 50.0
w.Paddle.SetXVelocity(v)
}
}
func (w *GameWindow) ensurePaddleBoundary() {
if w.Paddle.Translation.X() < w.NegativeBoundary.X() {
w.Paddle.Translation[0] = w.NegativeBoundary.X()
} else if w.Paddle.Translation.X() > w.PositiveBoundary.X() {
w.Paddle.Translation[0] = w.PositiveBoundary.X()
}
}