Wrap SDL function with sdl.Do() for goroutine thread-safety.
parent
c13ba6359e
commit
fcd11a4e53
|
@ -1,27 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
const (
|
||||
SDL_INIT_FLAGS uint32 = sdl.INIT_TIMER | sdl.INIT_AUDIO | sdl.INIT_VIDEO | sdl.INIT_EVENTS | sdl.INIT_JOYSTICK | sdl.INIT_HAPTIC | sdl.INIT_GAMECONTROLLER // ignore sensor subsystem
|
||||
|
||||
SDL_WINDOW_FLAGS uint32 = sdl.WINDOW_SHOWN | sdl.WINDOW_RESIZABLE
|
||||
SDL_FULLSCREEN_WINDOW_FLAGS uint32 = SDL_WINDOW_FLAGS | sdl.WINDOW_FULLSCREEN_DESKTOP
|
||||
SDL_WINDOW_WIDTH int32 = 800
|
||||
SDL_WINDOW_HEIGHT int32 = 600
|
||||
)
|
||||
|
||||
func SdlSettings() error {
|
||||
// Disable the Linux compositor flicker.
|
||||
// https://github.com/mosra/magnum/issues/184#issuecomment-425952900
|
||||
sdl.SetHint(sdl.HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0")
|
||||
|
||||
sdl.DisableScreenSaver()
|
||||
|
||||
// Capture the mouse for movement
|
||||
sdl.SetRelativeMouseMode(true)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
/*
|
||||
NOTE: We're using the SDL with goroutines example.
|
||||
Every call to an SDL function must be passed through the sdl.Do() function so that it joins the queue of thread-sensitive calls.
|
||||
You'll see this a lot below, but basically every SDL function must do something like this:
|
||||
sdl.Do(func() {
|
||||
err = sdl.SomeFunction()
|
||||
})
|
||||
This is for thread safety because SDL is not intended to be thread-safe.
|
||||
However, the rest of the code can do whatever it wants with threads so long as the SDL calls all use this method.
|
||||
*/
|
||||
|
||||
const (
|
||||
SDL_INIT_FLAGS uint32 = sdl.INIT_TIMER | sdl.INIT_AUDIO | sdl.INIT_VIDEO | sdl.INIT_EVENTS | sdl.INIT_JOYSTICK | sdl.INIT_HAPTIC | sdl.INIT_GAMECONTROLLER // ignore sensor subsystem
|
||||
|
||||
SDL_WINDOW_FLAGS uint32 = sdl.WINDOW_SHOWN | sdl.WINDOW_RESIZABLE
|
||||
SDL_FULLSCREEN_WINDOW_FLAGS uint32 = SDL_WINDOW_FLAGS | sdl.WINDOW_FULLSCREEN_DESKTOP
|
||||
SDL_WINDOW_WIDTH int32 = 800
|
||||
SDL_WINDOW_HEIGHT int32 = 600
|
||||
)
|
||||
|
||||
func SdlInit() error {
|
||||
var err error
|
||||
|
||||
// Initialize SDL
|
||||
sdl.Do(func() {
|
||||
err = sdl.Init(SDL_INIT_FLAGS)
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed initializing SDL: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Set some base SDL settings
|
||||
sdl.Do(func() {
|
||||
// Disable the Linux compositor flicker.
|
||||
// https://github.com/mosra/magnum/issues/184#issuecomment-425952900
|
||||
sdl.SetHint(sdl.HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0")
|
||||
|
||||
sdl.DisableScreenSaver()
|
||||
|
||||
// Capture the mouse for movement
|
||||
//sdl.SetRelativeMouseMode(true)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SdlQuit() {
|
||||
sdl.Do(func() {
|
||||
sdl.Quit()
|
||||
})
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
type window struct {
|
||||
SdlWindow *sdl.Window
|
||||
KeyStates map[sdl.Keycode]bool
|
||||
}
|
||||
|
||||
func NewWindow(title string) (*window, error) {
|
||||
var (
|
||||
err error
|
||||
sdlWindow *sdl.Window
|
||||
)
|
||||
|
||||
sdl.Do(func() {
|
||||
sdlWindow, err = sdl.CreateWindow(
|
||||
title,
|
||||
sdl.WINDOWPOS_UNDEFINED,
|
||||
sdl.WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOW_WIDTH,
|
||||
SDL_WINDOW_HEIGHT,
|
||||
SDL_WINDOW_FLAGS)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyStates := make(map[sdl.Keycode]bool)
|
||||
gw := &window{
|
||||
SdlWindow: sdlWindow,
|
||||
KeyStates: keyStates,
|
||||
}
|
||||
|
||||
return gw, nil
|
||||
}
|
||||
|
||||
func (g *window) Destroy() {
|
||||
if g.SdlWindow != nil {
|
||||
sdl.Do(func() {
|
||||
g.SdlWindow.Destroy()
|
||||
})
|
||||
}
|
||||
}
|
101
main.go
101
main.go
|
@ -3,9 +3,10 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"os"
|
||||
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/config"
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/config"
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/game"
|
||||
"gitea.wisellama.rocks/Wisellama/gosimpleconf"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
@ -28,43 +29,50 @@ func main() {
|
|||
}
|
||||
defer logWriter.Cleanup()
|
||||
|
||||
// Start everything
|
||||
log.Printf("=== Starting %v", configMap["game.title"])
|
||||
err = run(configMap)
|
||||
// Start everything with the SDL goroutine context
|
||||
log.Printf("=== Starting %v ===", configMap["game.title"])
|
||||
sdl.Main(func() {
|
||||
err = run(configMap)
|
||||
})
|
||||
|
||||
exitcode := 0
|
||||
if err != nil {
|
||||
log.Fatalf("error running: %v\n", err)
|
||||
log.Printf("ERROR: %v\n", err)
|
||||
exitcode = 1
|
||||
}
|
||||
|
||||
os.Exit(exitcode)
|
||||
}
|
||||
|
||||
func run(configMap gosimpleconf.ConfigMap) error {
|
||||
runtime.LockOSThread()
|
||||
var err error
|
||||
|
||||
err := sdl.Init(config.SDL_INIT_FLAGS)
|
||||
err = game.SdlInit()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed initializing SDL: %w", err)
|
||||
return err
|
||||
}
|
||||
defer sdl.Quit()
|
||||
defer game.SdlQuit()
|
||||
|
||||
err = config.SdlSettings()
|
||||
gameWindow, err := game.NewWindow(configMap["game.title"])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed in SDL settings: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
gameWindow, err := createWindow(configMap["game.title"])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed creating SDL window: %w", err)
|
||||
err = fmt.Errorf("failed creating GameWindow: %w", err)
|
||||
return err
|
||||
}
|
||||
defer gameWindow.Destroy()
|
||||
|
||||
renderer, err := sdl.CreateRenderer(gameWindow, -1, sdl.RENDERER_ACCELERATED)
|
||||
var renderer *sdl.Renderer
|
||||
sdl.Do(func() {
|
||||
renderer, err = sdl.CreateRenderer(gameWindow.SdlWindow, -1, sdl.RENDERER_ACCELERATED)
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed creating SDL renderer: %w", err)
|
||||
return err
|
||||
}
|
||||
defer renderer.Destroy()
|
||||
defer func() {
|
||||
sdl.Do(func() {
|
||||
renderer.Destroy()
|
||||
})
|
||||
}()
|
||||
|
||||
var rect *sdl.Rect
|
||||
var x int32 = 0
|
||||
|
@ -74,7 +82,11 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
|
||||
running := true
|
||||
for running {
|
||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||
var event sdl.Event
|
||||
sdl.Do(func() {
|
||||
event = sdl.PollEvent()
|
||||
})
|
||||
for event != nil {
|
||||
switch e := event.(type) {
|
||||
case *sdl.QuitEvent:
|
||||
running = false
|
||||
|
@ -91,6 +103,10 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
keystates[e.Keysym.Sym] = false
|
||||
}
|
||||
}
|
||||
|
||||
sdl.Do(func() {
|
||||
event = sdl.PollEvent()
|
||||
})
|
||||
}
|
||||
|
||||
if keystates[sdl.K_a] {
|
||||
|
@ -101,7 +117,7 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
}
|
||||
if keystates[sdl.K_d] {
|
||||
x += 1
|
||||
w, _ := gameWindow.GetSize()
|
||||
w, _ := gameWindow.SdlWindow.GetSize()
|
||||
if x+rect.W > w {
|
||||
x = w - rect.W
|
||||
}
|
||||
|
@ -115,41 +131,32 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
}
|
||||
if keystates[sdl.K_s] {
|
||||
y += 1
|
||||
_, h := gameWindow.GetSize()
|
||||
_, h := gameWindow.SdlWindow.GetSize()
|
||||
if y+rect.H > h {
|
||||
y = h - rect.H
|
||||
}
|
||||
}
|
||||
|
||||
// Black background
|
||||
renderer.SetDrawColor(0, 0, 0, 255)
|
||||
renderer.Clear()
|
||||
sdl.Do(func() {
|
||||
renderer.SetDrawColor(0, 0, 0, 255)
|
||||
renderer.Clear()
|
||||
})
|
||||
|
||||
// Blue square
|
||||
renderer.SetDrawColor(0, 0, 255, 255)
|
||||
rect = &sdl.Rect{X: x, Y: y, W: 200, H: 200}
|
||||
renderer.DrawRect(rect)
|
||||
renderer.FillRect(rect)
|
||||
sdl.Do(func() {
|
||||
renderer.SetDrawColor(0, 0, 255, 255)
|
||||
rect = &sdl.Rect{X: x, Y: y, W: 200, H: 200}
|
||||
renderer.DrawRect(rect)
|
||||
renderer.FillRect(rect)
|
||||
})
|
||||
|
||||
renderer.Present()
|
||||
sdl.Delay(16)
|
||||
// Draw
|
||||
sdl.Do(func() {
|
||||
renderer.Present()
|
||||
sdl.Delay(16)
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createWindow(title string) (*sdl.Window, error) {
|
||||
window, err := sdl.CreateWindow(
|
||||
title,
|
||||
sdl.WINDOWPOS_UNDEFINED,
|
||||
sdl.WINDOWPOS_UNDEFINED,
|
||||
config.SDL_WINDOW_WIDTH,
|
||||
config.SDL_WINDOW_HEIGHT,
|
||||
config.SDL_WINDOW_FLAGS)
|
||||
if err != nil {
|
||||
log.Println("Failed creating SDL window")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return window, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue