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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"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"
|
"gitea.wisellama.rocks/Wisellama/gosimpleconf"
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
@ -28,43 +29,50 @@ func main() {
|
||||||
}
|
}
|
||||||
defer logWriter.Cleanup()
|
defer logWriter.Cleanup()
|
||||||
|
|
||||||
// Start everything
|
// Start everything with the SDL goroutine context
|
||||||
log.Printf("=== Starting %v", configMap["game.title"])
|
log.Printf("=== Starting %v ===", configMap["game.title"])
|
||||||
err = run(configMap)
|
sdl.Main(func() {
|
||||||
|
err = run(configMap)
|
||||||
|
})
|
||||||
|
|
||||||
|
exitcode := 0
|
||||||
if err != nil {
|
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 {
|
func run(configMap gosimpleconf.ConfigMap) error {
|
||||||
runtime.LockOSThread()
|
var err error
|
||||||
|
|
||||||
err := sdl.Init(config.SDL_INIT_FLAGS)
|
err = game.SdlInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed initializing SDL: %w", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer sdl.Quit()
|
defer game.SdlQuit()
|
||||||
|
|
||||||
err = config.SdlSettings()
|
gameWindow, err := game.NewWindow(configMap["game.title"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed in SDL settings: %w", err)
|
err = fmt.Errorf("failed creating GameWindow: %w", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gameWindow, err := createWindow(configMap["game.title"])
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("failed creating SDL window: %w", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer gameWindow.Destroy()
|
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 {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed creating SDL renderer: %w", err)
|
err = fmt.Errorf("failed creating SDL renderer: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer renderer.Destroy()
|
defer func() {
|
||||||
|
sdl.Do(func() {
|
||||||
|
renderer.Destroy()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
var rect *sdl.Rect
|
var rect *sdl.Rect
|
||||||
var x int32 = 0
|
var x int32 = 0
|
||||||
|
@ -74,7 +82,11 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
||||||
|
|
||||||
running := true
|
running := true
|
||||||
for running {
|
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) {
|
switch e := event.(type) {
|
||||||
case *sdl.QuitEvent:
|
case *sdl.QuitEvent:
|
||||||
running = false
|
running = false
|
||||||
|
@ -91,6 +103,10 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
||||||
keystates[e.Keysym.Sym] = false
|
keystates[e.Keysym.Sym] = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdl.Do(func() {
|
||||||
|
event = sdl.PollEvent()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if keystates[sdl.K_a] {
|
if keystates[sdl.K_a] {
|
||||||
|
@ -101,7 +117,7 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
||||||
}
|
}
|
||||||
if keystates[sdl.K_d] {
|
if keystates[sdl.K_d] {
|
||||||
x += 1
|
x += 1
|
||||||
w, _ := gameWindow.GetSize()
|
w, _ := gameWindow.SdlWindow.GetSize()
|
||||||
if x+rect.W > w {
|
if x+rect.W > w {
|
||||||
x = w - rect.W
|
x = w - rect.W
|
||||||
}
|
}
|
||||||
|
@ -115,41 +131,32 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
||||||
}
|
}
|
||||||
if keystates[sdl.K_s] {
|
if keystates[sdl.K_s] {
|
||||||
y += 1
|
y += 1
|
||||||
_, h := gameWindow.GetSize()
|
_, h := gameWindow.SdlWindow.GetSize()
|
||||||
if y+rect.H > h {
|
if y+rect.H > h {
|
||||||
y = h - rect.H
|
y = h - rect.H
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Black background
|
// Black background
|
||||||
renderer.SetDrawColor(0, 0, 0, 255)
|
sdl.Do(func() {
|
||||||
renderer.Clear()
|
renderer.SetDrawColor(0, 0, 0, 255)
|
||||||
|
renderer.Clear()
|
||||||
|
})
|
||||||
|
|
||||||
// Blue square
|
// Blue square
|
||||||
renderer.SetDrawColor(0, 0, 255, 255)
|
sdl.Do(func() {
|
||||||
rect = &sdl.Rect{X: x, Y: y, W: 200, H: 200}
|
renderer.SetDrawColor(0, 0, 255, 255)
|
||||||
renderer.DrawRect(rect)
|
rect = &sdl.Rect{X: x, Y: y, W: 200, H: 200}
|
||||||
renderer.FillRect(rect)
|
renderer.DrawRect(rect)
|
||||||
|
renderer.FillRect(rect)
|
||||||
|
})
|
||||||
|
|
||||||
renderer.Present()
|
// Draw
|
||||||
sdl.Delay(16)
|
sdl.Do(func() {
|
||||||
|
renderer.Present()
|
||||||
|
sdl.Delay(16)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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