ui: Introduce ScreenSizeEvent to simplify the run loop

This commit is contained in:
Hajime Hoshi 2016-05-18 11:56:43 +09:00
parent faff188574
commit 335781759c
5 changed files with 64 additions and 103 deletions

View File

@ -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:

View File

@ -19,3 +19,10 @@ type CloseEvent struct {
type RenderEvent struct {
}
type ScreenSizeEvent struct {
Width int
Height int
Scale int
ActualScale int
}

View File

@ -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
}

View File

@ -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
}

15
run.go
View File

@ -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()
}