From 335781759cca3d46d4a66e144d33888f62cf5b37 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 18 May 2016 11:56:43 +0900 Subject: [PATCH] ui: Introduce ScreenSizeEvent to simplify the run loop --- internal/loop/run.go | 95 ++++-------------------------------------- internal/ui/event.go | 7 ++++ internal/ui/ui_glfw.go | 33 ++++++++++----- internal/ui/ui_js.go | 17 +++++++- run.go | 15 ++++--- 5 files changed, 64 insertions(+), 103 deletions(-) diff --git a/internal/loop/run.go b/internal/loop/run.go index ac49717f4..dd3cdd6cc 100644 --- a/internal/loop/run.go +++ b/internal/loop/run.go @@ -15,7 +15,6 @@ package loop import ( - "errors" "sync" "time" @@ -24,10 +23,6 @@ import ( const FPS = 60 -func Main() { - ui.Main() -} - func CurrentFPS() float64 { return currentRunContext.currentFPS() } @@ -40,26 +35,11 @@ func IsRunningSlowly() bool { return currentRunContext.isRunningSlowly() } -func SetScreenSize(width, height int) error { - return currentRunContext.setScreenSize(width, height) -} - -func SetScreenScale(scale int) error { - return currentRunContext.setScreenScale(scale) -} - -func ScreenScale() int { - return ui.CurrentUI().ScreenScale() -} - type runContext struct { - running bool - fps float64 - newScreenWidth int - newScreenHeight int - newScreenScale int - runningSlowly bool - m sync.RWMutex + running bool + fps float64 + runningSlowly bool + m sync.RWMutex } var currentRunContext runContext @@ -114,60 +94,6 @@ func (c *runContext) setRunningSlowly(isRunningSlowly bool) { c.runningSlowly = isRunningSlowly } -func (c *runContext) updateScreenSize(g GraphicsContext) error { - c.m.Lock() - defer c.m.Unlock() - if c.newScreenWidth == 0 && c.newScreenHeight == 0 && c.newScreenScale == 0 { - return nil - } - changed := false - if 0 < c.newScreenWidth || 0 < c.newScreenHeight { - c := ui.CurrentUI().SetScreenSize(c.newScreenWidth, c.newScreenHeight) - changed = changed || c - } - if 0 < c.newScreenScale { - c := ui.CurrentUI().SetScreenScale(c.newScreenScale) - changed = changed || c - } - if changed { - w, h := c.newScreenWidth, c.newScreenHeight - if err := g.SetSize(w, h, ui.CurrentUI().ActualScreenScale()); err != nil { - return err - } - } - c.newScreenWidth = 0 - c.newScreenHeight = 0 - c.newScreenScale = 0 - return nil -} - -func (c *runContext) setScreenSize(width, height int) error { - c.m.Lock() - defer c.m.Unlock() - if !c.running { - return errors.New("ebiten: SetScreenSize must be called during Run") - } - if width <= 0 || height <= 0 { - return errors.New("ebiten: width and height must be positive") - } - c.newScreenWidth = width - c.newScreenHeight = height - return nil -} - -func (c *runContext) setScreenScale(scale int) error { - c.m.Lock() - defer c.m.Unlock() - if !c.running { - return errors.New("ebiten: SetScreenScale must be called during Run") - } - if scale <= 0 { - return errors.New("ebiten: scale must be positive") - } - c.newScreenScale = scale - return nil -} - type GraphicsContext interface { SetSize(width, height, scale int) error Update() error @@ -182,23 +108,20 @@ func Run(g GraphicsContext, width, height, scale int, title string) error { } defer ui.CurrentUI().Terminate() - if err := g.SetSize(width, height, ui.CurrentUI().ActualScreenScale()); err != nil { - return err - } - frames := 0 n := now() beforeForUpdate := n beforeForFPS := n for { - if err := currentRunContext.updateScreenSize(g); err != nil { - return err - } e, err := ui.CurrentUI().Update() if err != nil { return err } - switch e.(type) { + switch e := e.(type) { + case ui.ScreenSizeEvent: + if err := g.SetSize(e.Width, e.Height, e.ActualScale); err != nil { + return err + } case ui.CloseEvent: return nil case ui.RenderEvent: diff --git a/internal/ui/event.go b/internal/ui/event.go index aa7f8251b..ffd6a0473 100644 --- a/internal/ui/event.go +++ b/internal/ui/event.go @@ -19,3 +19,10 @@ type CloseEvent struct { type RenderEvent struct { } + +type ScreenSizeEvent struct { + Width int + Height int + Scale int + ActualScale int +} diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 5aa2b7d64..17258c939 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -35,6 +35,7 @@ type UserInterface struct { framebufferScale int context *opengl.Context funcs chan func() + sizeChanged bool } var currentUI *UserInterface @@ -61,8 +62,9 @@ func initialize() (*opengl.Context, error) { } u := &UserInterface{ - window: window, - funcs: make(chan func()), + window: window, + funcs: make(chan func()), + sizeChanged: true, } ch := make(chan error) go func() { @@ -140,14 +142,6 @@ func (u *UserInterface) ScreenScale() int { return s } -func (u *UserInterface) ActualScreenScale() int { - s := 0 - u.runOnMainThread(func() { - s = u.actualScreenScale() - }) - return s -} - func (u *UserInterface) Start(width, height, scale int, title string) error { var err error u.runOnMainThread(func() { @@ -200,6 +194,24 @@ func (u *UserInterface) Update() (interface{}, error) { if shouldClose { return CloseEvent{}, nil } + + var screenSizeEvent *ScreenSizeEvent + u.runOnMainThread(func() { + if !u.sizeChanged { + return + } + u.sizeChanged = false + screenSizeEvent = &ScreenSizeEvent{ + Width: u.width, + Height: u.height, + Scale: u.scale, + ActualScale: u.actualScreenScale(), + } + }) + if screenSizeEvent != nil { + return *screenSizeEvent, nil + } + var ferr error u.runOnMainThread(func() { if err := u.pollEvents(); err != nil { @@ -291,5 +303,6 @@ event: // This is usually 1, but sometimes more than 1 (e.g. Retina Mac) fw, _ := window.GetFramebufferSize() u.framebufferScale = fw / width / u.windowScale() + u.sizeChanged = true return true } diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 96892ce2a..801215911 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -46,9 +46,12 @@ var canvas *js.Object type UserInterface struct { scale int deviceScale float64 + sizeChanged bool } -var currentUI = &UserInterface{} +var currentUI = &UserInterface{ + sizeChanged: true, +} func CurrentUI() *UserInterface { return currentUI @@ -79,6 +82,17 @@ func vsync() { func (u *UserInterface) Update() (interface{}, error) { currentInput.UpdateGamepads() + if u.sizeChanged { + u.sizeChanged = false + w, h := u.size() + e := ScreenSizeEvent{ + Width: w, + Height: h, + Scale: u.ScreenScale(), + ActualScale: u.ActualScreenScale(), + } + return e, nil + } return RenderEvent{}, nil } @@ -276,5 +290,6 @@ func (u *UserInterface) setScreenSize(width, height, scale int) bool { // CSS calc requires space chars. canvasStyle.Set("left", "calc((100% - "+strconv.Itoa(cssWidth)+"px) / 2)") canvasStyle.Set("top", "calc((100% - "+strconv.Itoa(cssHeight)+"px) / 2)") + u.sizeChanged = true return true } diff --git a/run.go b/run.go index 6cded7a5f..0997e660a 100644 --- a/run.go +++ b/run.go @@ -16,6 +16,7 @@ package ebiten import ( "github.com/hajimehoshi/ebiten/internal/loop" + "github.com/hajimehoshi/ebiten/internal/ui" ) // FPS represents how many times game updating happens in a second. @@ -58,7 +59,7 @@ func Run(f func(*Image) error, width, height, scale int, title string) error { g := newGraphicsContext(f) ch <- loop.Run(g, width, height, scale, title) }() - loop.Main() + ui.Main() return <-ch } @@ -67,23 +68,25 @@ func Run(f func(*Image) error, width, height, scale int, title string) error { // // This function is concurrent-safe. func SetScreenSize(width, height int) { - if err := loop.SetScreenSize(width, height); err != nil { - panic(err) + if width <= 0 || height <= 0 { + panic("ebiten: width and height must be positive") } + ui.CurrentUI().SetScreenSize(width, height) } // SetScreenScale changes the scale of the screen. // // This function is concurrent-safe. func SetScreenScale(scale int) { - if err := loop.SetScreenScale(scale); err != nil { - panic(err) + if scale <= 0 { + panic("ebiten: scale must be positive") } + ui.CurrentUI().SetScreenScale(scale) } // ScreenScale returns the current screen scale. // // This function is concurrent-safe. func ScreenScale() int { - return loop.ScreenScale() + return ui.CurrentUI().ScreenScale() }