diff --git a/platform/imgui_backend/imgui_backend.go b/platform/imgui_backend/imgui_backend.go index e5da052..3b75234 100644 --- a/platform/imgui_backend/imgui_backend.go +++ b/platform/imgui_backend/imgui_backend.go @@ -15,7 +15,7 @@ var ( ErrWasNotInit = errors.New("imgui backend was not initialized") ) -var state struct { +var singleton struct { isInit bool buttonsDown [3]bool lastTime uint64 @@ -24,11 +24,11 @@ var state struct { } func Init() error { - if state.isInit { + if singleton.isInit { return ErrAlreadyInit } - state.context = imgui.CreateContext(nil) + singleton.context = imgui.CreateContext(nil) keys := map[int]int{ imgui.KeyTab: sdl.SCANCODE_TAB, @@ -60,30 +60,30 @@ func Init() error { io.KeyMap(imguiKey, nativeKey) } - state.fontTexture = createFontTexture() - state.isInit = true + singleton.fontTexture = createFontTexture() + singleton.isInit = true return nil } func Shutdown() error { - if !state.isInit { + if !singleton.isInit { return ErrWasNotInit } - state.isInit = false + singleton.isInit = false - destroyFontTexture(state.fontTexture) - state.fontTexture = 0 + destroyFontTexture(singleton.fontTexture) + singleton.fontTexture = 0 - state.context.Destroy() - state.context = nil + singleton.context.Destroy() + singleton.context = nil return nil } func NewFrame(windowSize math.Vec2i) error { - if !state.isInit { + if !singleton.isInit { return ErrWasNotInit } @@ -94,18 +94,18 @@ func NewFrame(windowSize math.Vec2i) error { // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) frequency := sdl.GetPerformanceFrequency() currentTime := sdl.GetPerformanceCounter() - if state.lastTime > 0 { - io.SetDeltaTime(float32(currentTime-state.lastTime) / float32(frequency)) + if singleton.lastTime > 0 { + io.SetDeltaTime(float32(currentTime-singleton.lastTime) / float32(frequency)) } else { io.SetDeltaTime(1.0 / 60.0) } - state.lastTime = currentTime + singleton.lastTime = currentTime // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. x, y, state := sdl.GetMouseState() for i, button := range []uint32{sdl.BUTTON_LEFT, sdl.BUTTON_RIGHT, sdl.BUTTON_MIDDLE} { - io.SetMouseButtonDown(i, state.buttonsDown[i] || (state&sdl.Button(button)) != 0) - state.buttonsDown[i] = false + io.SetMouseButtonDown(i, singleton.buttonsDown[i] || (state&sdl.Button(button)) != 0) + singleton.buttonsDown[i] = false } io.SetMousePosition(imgui.Vec2{X: float32(x), Y: float32(y)}) @@ -120,7 +120,7 @@ func NewFrame(windowSize math.Vec2i) error { // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. // If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field. func ProcessEvent(event sdl.Event) (bool, error) { - if !state.isInit { + if !singleton.isInit { return false, ErrWasNotInit } @@ -143,13 +143,13 @@ func ProcessEvent(event sdl.Event) (bool, error) { buttonEvent := event.(*sdl.MouseButtonEvent) switch buttonEvent.Button { case sdl.BUTTON_LEFT: - state.buttonsDown[0] = true + singleton.buttonsDown[0] = true break case sdl.BUTTON_RIGHT: - state.buttonsDown[1] = true + singleton.buttonsDown[1] = true break case sdl.BUTTON_MIDDLE: - state.buttonsDown[2] = true + singleton.buttonsDown[2] = true break } return true, nil @@ -178,9 +178,9 @@ func ProcessEvent(event sdl.Event) (bool, error) { } // OpenGL2 Render function. -// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL singleton explicitly, in order to be able to run within any OpenGL engine that doesn't do so. func Render(windowSize, fbSize math.Vec2i, drawData imgui.DrawData) error { - if !state.isInit { + if !singleton.isInit { return ErrWasNotInit } @@ -190,7 +190,7 @@ func Render(windowSize, fbSize math.Vec2i, drawData imgui.DrawData) error { }) // We are using the OpenGL fixed pipeline to make the example code simpler to read! - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. + // Setup render singleton: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. var lastTexture int32 gl.GetIntegerv(gl.TEXTURE_BINDING_2D, &lastTexture) var lastPolygonMode [2]int32 @@ -296,7 +296,7 @@ func createFontTexture() uint32 { // Store our identifier io.Fonts().SetTextureID(imgui.TextureID(fontTexture)) - // Restore state + // Restore singleton gl.BindTexture(gl.TEXTURE_2D, uint32(lastTexture)) return fontTexture } diff --git a/platform/platform.go b/platform/platform.go index 0da3c33..ec9f559 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -17,7 +17,11 @@ var ( var state struct { isInit bool - windows []Window + windows []*window +} + +type Scene interface { + Advance() } func Init() error { @@ -69,12 +73,13 @@ func ProcessEvents() error { return ErrWasNotInit } - var terminate bool - for !terminate { + for running := true; running; { + advanceWindows() + renderWindows() + for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { - switch event.(type) { - case *sdl.QuitEvent: - terminate = true + if !handleEvent(event) { + running = false break } } @@ -85,12 +90,12 @@ func ProcessEvents() error { return nil } -func CreateWindow(title string, width, height int) (Window, error) { +func CreateWindow(title string, width, height int, scene Scene) (Window, error) { if !state.isInit { return nil, ErrWasNotInit } - window, err := newWindow(title, width, height) + window, err := newWindow(title, width, height, scene) if err != nil { return nil, err } @@ -99,3 +104,24 @@ func CreateWindow(title string, width, height int) (Window, error) { return window, err } + +func advanceWindows() { + for _, window := range state.windows { + window.advance() + } +} + +func renderWindows() { + for _, window := range state.windows { + window.render() + } +} + +func handleEvent(event sdl.Event) bool { + switch event.(type) { + case *sdl.QuitEvent: + return false + } + + return true +} diff --git a/platform/window.go b/platform/window.go index ffcde00..1a8e7fe 100644 --- a/platform/window.go +++ b/platform/window.go @@ -1,6 +1,9 @@ package platform -import "github.com/veandco/go-sdl2/sdl" +import ( + "github.com/FooSoft/lazarus/math" + "github.com/veandco/go-sdl2/sdl" +) type Window interface { Destroy() error @@ -10,9 +13,10 @@ type window struct { sdlWindow *sdl.Window sdlGlContext sdl.GLContext sdlRenderer *sdl.Renderer + scene Scene } -func newWindow(title string, width, height int) (Window, error) { +func newWindow(title string, width, height int, scene Scene) (*window, error) { sdlWindow, err := sdl.CreateWindow( title, sdl.WINDOWPOS_CENTERED, @@ -37,7 +41,7 @@ func newWindow(title string, width, height int) (Window, error) { return nil, err } - return &window{sdlWindow, sdlGlContext, sdlRenderer}, nil + return &window{sdlWindow, sdlGlContext, sdlRenderer, scene}, nil } func (w *window) Destroy() error { @@ -52,3 +56,21 @@ func (w *window) Destroy() error { return nil } + +func (w *window) advance() { + w.scene.Advance() +} + +func (w *window) render() { + w.sdlWindow.GLMakeCurrent(w.sdlGlContext) +} + +func (w *window) displaySize() math.Vec2i { + width, height := w.sdlWindow.GetSize() + return math.Vec2i{X: int(width), Y: int(height)} +} + +func (w *window) bufferSize() math.Vec2i { + width, height := w.sdlWindow.GLGetDrawableSize() + return math.Vec2i{X: int(width), Y: int(height)} +}