334 lines
7.4 KiB
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()
|
|
}
|
|
}
|