state control through scenes

This commit is contained in:
Alex Yatskov 2018-12-31 16:52:53 -08:00
parent 60e8f19535
commit 557608155d
4 changed files with 104 additions and 82 deletions

View File

@ -1,57 +1,25 @@
package platform package platform
import ( import (
"errors"
"runtime" "runtime"
"github.com/FooSoft/lazarus/math"
"github.com/go-gl/gl/v2.1/gl" "github.com/go-gl/gl/v2.1/gl"
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
) )
var (
ErrAlreadyInit = errors.New("platform is already initialized")
ErrWasNotInit = errors.New("platform was not initialized")
)
var singleton struct { var singleton struct {
isInit bool sdlIsInit bool
windows []*Window windows []*Window
} }
type Handle uintptr type Handle uintptr
type Scene interface {
Init(window *Window) error
Advance(window *Window) error
Shutdown(window *Window) error
}
func Init() error {
if singleton.isInit {
return ErrAlreadyInit
}
runtime.LockOSThread()
if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
return err
}
if err := gl.Init(); err != nil {
return err
}
singleton.isInit = true
return nil
}
func Advance() (bool, error) { func Advance() (bool, error) {
if !singleton.isInit { if err := advanceWindows(); err != nil {
return false, ErrWasNotInit return false, err
} }
advanceWindows()
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch event.(type) { switch event.(type) {
case *sdl.QuitEvent: case *sdl.QuitEvent:
@ -63,32 +31,25 @@ func Advance() (bool, error) {
} }
} }
return true, nil return len(singleton.windows) > 0, nil
} }
func Shutdown() error { func NewWindow(title string, size math.Vec2i, scene Scene) (*Window, error) {
if !singleton.isInit { if !singleton.sdlIsInit {
return ErrWasNotInit runtime.LockOSThread()
}
for _, w := range singleton.windows { if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
if err := w.Destroy(); err != nil { return nil, err
return err
} }
if err := gl.Init(); err != nil {
return nil, err
}
singleton.sdlIsInit = true
} }
singleton.windows = nil w, err := newWindow(title, size, scene)
singleton.isInit = false
return nil
}
func CreateWindow(title string, width, height int, scene Scene) (*Window, error) {
if !singleton.isInit {
return nil, ErrWasNotInit
}
w, err := newWindow(title, width, height, scene)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -112,10 +73,23 @@ func removeWindow(window *Window) bool {
return false return false
} }
func advanceWindows() { func advanceWindows() error {
var windowsToRemove []*Window
for _, window := range singleton.windows { for _, window := range singleton.windows {
window.advance() run, err := window.advance()
if err != nil {
return err
}
if !run {
windowsToRemove = append(windowsToRemove, window)
}
} }
for _, window := range windowsToRemove {
removeWindow(window)
}
return nil
} }
func processWindowEvents(event sdl.Event) error { func processWindowEvents(event sdl.Event) error {

15
platform/scene.go Normal file
View File

@ -0,0 +1,15 @@
package platform
type Scene interface{}
type SceneCreator interface {
Create(window *Window) error
}
type SceneAdvancer interface {
Advance(window *Window) error
}
type SceneDestroyer interface {
Destroy(window *Window) error
}

View File

@ -14,7 +14,7 @@ type Window struct {
scene Scene scene Scene
} }
func newWindow(title string, width, height int, scene Scene) (*Window, error) { func newWindow(title string, size math.Vec2i, scene Scene) (*Window, error) {
sdl.GLSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 2) sdl.GLSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 2)
sdl.GLSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 1) sdl.GLSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 1)
sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1) sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1)
@ -23,8 +23,8 @@ func newWindow(title string, width, height int, scene Scene) (*Window, error) {
title, title,
sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED,
sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED,
int32(width), int32(size.X),
int32(height), int32(size.Y),
sdl.WINDOW_OPENGL, sdl.WINDOW_OPENGL,
) )
if err != nil { if err != nil {
@ -40,16 +40,17 @@ func newWindow(title string, width, height int, scene Scene) (*Window, error) {
w := &Window{ w := &Window{
sdlWindow: sdlWindow, sdlWindow: sdlWindow,
sdlGlContext: sdlGlContext, sdlGlContext: sdlGlContext,
scene: scene,
} }
w.makeCurrent()
w.imguiContext, err = imgui_backend.New(w.DisplaySize(), w.BufferSize()) w.imguiContext, err = imgui_backend.New(w.DisplaySize(), w.BufferSize())
if err != nil { if err != nil {
w.Destroy() w.Destroy()
return nil, err return nil, err
} }
if err := scene.Init(w); err != nil { if err := w.SetScene(scene); err != nil {
w.Destroy() w.Destroy()
return nil, err return nil, err
} }
@ -57,15 +58,43 @@ func newWindow(title string, width, height int, scene Scene) (*Window, error) {
return w, nil return w, nil
} }
func (w *Window) SetScene(scene Scene) error {
if w.scene == scene {
return nil
}
if sceneDestroyer, ok := w.scene.(SceneDestroyer); ok {
if err := sceneDestroyer.Destroy(w); err != nil {
return err
}
}
w.scene = scene
if sceneCreator, ok := scene.(SceneCreator); ok {
if err := sceneCreator.Create(w); err != nil {
return err
}
}
return nil
}
func (w *Window) Destroy() error { func (w *Window) Destroy() error {
if w == nil || w.sdlWindow == nil { if w == nil || w.sdlWindow == nil {
return nil return nil
} }
if err := w.scene.Shutdown(w); err != nil { w.makeCurrent()
if err := w.SetScene(nil); err != nil {
return err return err
} }
w.scene = nil
if err := w.imguiContext.Destroy(); err != nil {
return err
}
w.imguiContext = nil
sdl.GLDeleteContext(w.sdlGlContext) sdl.GLDeleteContext(w.sdlGlContext)
w.sdlGlContext = nil w.sdlGlContext = nil
@ -115,8 +144,8 @@ func (w *Window) BufferSize() math.Vec2i {
return math.Vec2i{X: int(width), Y: int(height)} return math.Vec2i{X: int(width), Y: int(height)}
} }
func (w *Window) advance() { func (w *Window) advance() (bool, error) {
w.sdlWindow.GLMakeCurrent(w.sdlGlContext) w.makeCurrent()
displaySize := w.DisplaySize() displaySize := w.DisplaySize()
w.imguiContext.SetDisplaySize(displaySize) w.imguiContext.SetDisplaySize(displaySize)
@ -133,12 +162,23 @@ func (w *Window) advance() {
gl.MatrixMode(gl.MODELVIEW) gl.MatrixMode(gl.MODELVIEW)
gl.LoadIdentity() gl.LoadIdentity()
w.scene.Advance(w) if sceneAdvancer, ok := w.scene.(SceneAdvancer); ok {
if err := sceneAdvancer.Advance(w); err != nil {
return false, err
}
}
w.imguiContext.EndFrame() w.imguiContext.EndFrame()
w.sdlWindow.GLSwap() w.sdlWindow.GLSwap()
return w.scene != nil, nil
} }
func (w *Window) processEvent(event sdl.Event) (bool, error) { func (w *Window) processEvent(event sdl.Event) (bool, error) {
return w.imguiContext.ProcessEvent(event) return w.imguiContext.ProcessEvent(event)
} }
func (w *Window) makeCurrent() {
w.sdlWindow.GLMakeCurrent(w.sdlGlContext)
}

View File

@ -41,15 +41,7 @@ type scene struct {
frameIndex int32 frameIndex int32
} }
func (s *scene) Init(window *platform.Window) error { func (s *scene) Destroy(window *platform.Window) error {
return nil
}
func (s *scene) Shutdown(window *platform.Window) error {
if s.texture == nil {
return nil
}
return s.texture.Destroy() return s.texture.Destroy()
} }
@ -77,6 +69,10 @@ func (s *scene) Advance(window *platform.Window) error {
imgui.Text(fmt.Sprintf("Size: %+v", frame.Size)) imgui.Text(fmt.Sprintf("Size: %+v", frame.Size))
imgui.Text(fmt.Sprintf("Offset: %+v", frame.Offset)) imgui.Text(fmt.Sprintf("Offset: %+v", frame.Offset))
if imgui.Button("Exit") {
window.SetScene(nil)
}
if directionIndex != s.directionIndex || frameIndex != s.frameIndex { if directionIndex != s.directionIndex || frameIndex != s.frameIndex {
s.directionIndex = directionIndex s.directionIndex = directionIndex
s.frameIndex = frameIndex s.frameIndex = frameIndex
@ -146,11 +142,8 @@ func main() {
palette = dat.NewFromGrayscale() palette = dat.NewFromGrayscale()
} }
platform.Init()
defer platform.Shutdown()
scene := &scene{sprite: sprite, palette: palette} scene := &scene{sprite: sprite, palette: palette}
window, err := platform.CreateWindow("Viewer", 1280, 720, scene) window, err := platform.NewWindow("Viewer", math.Vec2i{X: 1024, Y: 768}, scene)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)