diff --git a/platform/platform.go b/platform/platform.go index 4098a65..0c854a3 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -1,57 +1,25 @@ package platform import ( - "errors" "runtime" + "github.com/FooSoft/lazarus/math" "github.com/go-gl/gl/v2.1/gl" "github.com/veandco/go-sdl2/sdl" ) -var ( - ErrAlreadyInit = errors.New("platform is already initialized") - ErrWasNotInit = errors.New("platform was not initialized") -) - var singleton struct { - isInit bool - windows []*Window + sdlIsInit bool + windows []*Window } 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) { - if !singleton.isInit { - return false, ErrWasNotInit + if err := advanceWindows(); err != nil { + return false, err } - advanceWindows() - for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch event.(type) { case *sdl.QuitEvent: @@ -63,32 +31,25 @@ func Advance() (bool, error) { } } - return true, nil + return len(singleton.windows) > 0, nil } -func Shutdown() error { - if !singleton.isInit { - return ErrWasNotInit - } +func NewWindow(title string, size math.Vec2i, scene Scene) (*Window, error) { + if !singleton.sdlIsInit { + runtime.LockOSThread() - for _, w := range singleton.windows { - if err := w.Destroy(); err != nil { - return err + if err := sdl.Init(sdl.INIT_VIDEO); err != nil { + return nil, err } + + if err := gl.Init(); err != nil { + return nil, err + } + + singleton.sdlIsInit = true } - singleton.windows = nil - 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) + w, err := newWindow(title, size, scene) if err != nil { return nil, err } @@ -112,10 +73,23 @@ func removeWindow(window *Window) bool { return false } -func advanceWindows() { +func advanceWindows() error { + var windowsToRemove []*Window 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 { diff --git a/platform/scene.go b/platform/scene.go new file mode 100644 index 0000000..ec71cdf --- /dev/null +++ b/platform/scene.go @@ -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 +} diff --git a/platform/window.go b/platform/window.go index c284264..59565e2 100644 --- a/platform/window.go +++ b/platform/window.go @@ -14,7 +14,7 @@ type Window struct { 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_MINOR_VERSION, 1) sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1) @@ -23,8 +23,8 @@ func newWindow(title string, width, height int, scene Scene) (*Window, error) { title, sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, - int32(width), - int32(height), + int32(size.X), + int32(size.Y), sdl.WINDOW_OPENGL, ) if err != nil { @@ -40,16 +40,17 @@ func newWindow(title string, width, height int, scene Scene) (*Window, error) { w := &Window{ sdlWindow: sdlWindow, sdlGlContext: sdlGlContext, - scene: scene, } + w.makeCurrent() + w.imguiContext, err = imgui_backend.New(w.DisplaySize(), w.BufferSize()) if err != nil { w.Destroy() return nil, err } - if err := scene.Init(w); err != nil { + if err := w.SetScene(scene); err != nil { w.Destroy() return nil, err } @@ -57,15 +58,43 @@ func newWindow(title string, width, height int, scene Scene) (*Window, error) { 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 { if w == nil || w.sdlWindow == nil { return nil } - if err := w.scene.Shutdown(w); err != nil { + w.makeCurrent() + + if err := w.SetScene(nil); err != nil { return err } - w.scene = nil + + if err := w.imguiContext.Destroy(); err != nil { + return err + } + w.imguiContext = nil sdl.GLDeleteContext(w.sdlGlContext) w.sdlGlContext = nil @@ -115,8 +144,8 @@ func (w *Window) BufferSize() math.Vec2i { return math.Vec2i{X: int(width), Y: int(height)} } -func (w *Window) advance() { - w.sdlWindow.GLMakeCurrent(w.sdlGlContext) +func (w *Window) advance() (bool, error) { + w.makeCurrent() displaySize := w.DisplaySize() w.imguiContext.SetDisplaySize(displaySize) @@ -133,12 +162,23 @@ func (w *Window) advance() { gl.MatrixMode(gl.MODELVIEW) 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.sdlWindow.GLSwap() + + return w.scene != nil, nil } func (w *Window) processEvent(event sdl.Event) (bool, error) { return w.imguiContext.ProcessEvent(event) } + +func (w *Window) makeCurrent() { + w.sdlWindow.GLMakeCurrent(w.sdlGlContext) + +} diff --git a/tools/viewer/main.go b/tools/viewer/main.go index bb90ade..8b9ba78 100644 --- a/tools/viewer/main.go +++ b/tools/viewer/main.go @@ -41,15 +41,7 @@ type scene struct { frameIndex int32 } -func (s *scene) Init(window *platform.Window) error { - return nil -} - -func (s *scene) Shutdown(window *platform.Window) error { - if s.texture == nil { - return nil - } - +func (s *scene) Destroy(window *platform.Window) error { 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("Offset: %+v", frame.Offset)) + if imgui.Button("Exit") { + window.SetScene(nil) + } + if directionIndex != s.directionIndex || frameIndex != s.frameIndex { s.directionIndex = directionIndex s.frameIndex = frameIndex @@ -146,11 +142,8 @@ func main() { palette = dat.NewFromGrayscale() } - platform.Init() - defer platform.Shutdown() - 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 { fmt.Fprintln(os.Stderr, err) os.Exit(1)