From 5c68ee40343c98190bbdc77126260449c656a340 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 18 May 2016 01:30:27 +0900 Subject: [PATCH] ui: Use events in the game loop --- internal/ui/event.go | 21 ++++++++++++++ internal/ui/ui_glfw.go | 22 +++++++------- internal/ui/ui_js.go | 8 ++--- run.go | 66 ++++++++++++++++++++++-------------------- 4 files changed, 70 insertions(+), 47 deletions(-) create mode 100644 internal/ui/event.go diff --git a/internal/ui/event.go b/internal/ui/event.go new file mode 100644 index 000000000..aa7f8251b --- /dev/null +++ b/internal/ui/event.go @@ -0,0 +1,21 @@ +// Copyright 2016 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ui + +type CloseEvent struct { +} + +type RenderEvent struct { +} diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 88b59bc83..630b050a9 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -196,7 +196,14 @@ func (u *UserInterface) pollEvents() error { return currentInput.update(u.window, u.windowScale()) } -func (u *UserInterface) Update() error { +func (u *UserInterface) Update() (interface{}, error) { + shouldClose := false + u.runOnMainThread(func() { + shouldClose = u.window.ShouldClose() + }) + if shouldClose { + return CloseEvent{}, nil + } var ferr error u.runOnMainThread(func() { if err := u.pollEvents(); err != nil { @@ -215,7 +222,10 @@ func (u *UserInterface) Update() error { } } }) - return ferr + if ferr != nil { + return nil, ferr + } + return RenderEvent{}, nil } func (u *UserInterface) Terminate() { @@ -226,14 +236,6 @@ func (u *UserInterface) Terminate() { u.funcs = nil } -func (u *UserInterface) IsClosed() bool { - r := false - u.runOnMainThread(func() { - r = u.window.ShouldClose() - }) - return r -} - func (u *UserInterface) SwapBuffers() { u.runOnMainThread(func() { u.swapBuffers() diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 74aa871c6..8df96c630 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -83,19 +83,15 @@ func vsync() { <-ch } -func (u *UserInterface) Update() error { +func (u *UserInterface) Update() (interface{}, error) { currentInput.UpdateGamepads() - return nil + return RenderEvent{}, nil } func (u *UserInterface) Terminate() { // Do nothing. } -func (u *UserInterface) IsClosed() bool { - return false -} - func (u *UserInterface) SwapBuffers() { vsync() for !shown() { diff --git a/run.go b/run.go index 8ecefb5c9..15405ae1b 100644 --- a/run.go +++ b/run.go @@ -204,46 +204,50 @@ func run(f func(*Image) error, width, height, scale int, title string) error { beforeForUpdate := n beforeForFPS := n for { - // TODO: setSize should be called after swapping buffers? if err := currentRunContext.updateScreenSize(graphicsContext); err != nil { return err } - if err := ui.CurrentUI().Update(); err != nil { + e, err := ui.CurrentUI().Update() + if err != nil { return err } - if ui.CurrentUI().IsClosed() { + switch e.(type) { + case ui.CloseEvent: return nil - } - now := ui.Now() - // If beforeForUpdate is too old, we assume that screen is not shown. - if int64(5*time.Second/FPS) < now-beforeForUpdate { - currentRunContext.setRunningSlowly(false) - beforeForUpdate = now - } else { - // Note that generally t is a little different from 1/60[sec]. - t := now - beforeForUpdate - currentRunContext.setRunningSlowly(t*FPS >= int64(time.Second*5/2)) - tt := int(t * FPS / int64(time.Second)) - // As t is not accurate 1/60[sec], errors are accumulated. - // To make the FPS stable, set tt 1 if t is a little less than 1/60[sec]. - if tt == 0 && (int64(time.Second)/FPS-int64(5*time.Millisecond)) < t { - tt = 1 - } - for i := 0; i < tt; i++ { - if err := graphicsContext.update(f); err != nil { - return err + case ui.RenderEvent: + now := ui.Now() + // If beforeForUpdate is too old, we assume that screen is not shown. + if int64(5*time.Second/FPS) < now-beforeForUpdate { + currentRunContext.setRunningSlowly(false) + beforeForUpdate = now + } else { + // Note that generally t is a little different from 1/60[sec]. + t := now - beforeForUpdate + currentRunContext.setRunningSlowly(t*FPS >= int64(time.Second*5/2)) + tt := int(t * FPS / int64(time.Second)) + // As t is not accurate 1/60[sec], errors are accumulated. + // To make the FPS stable, set tt 1 if t is a little less than 1/60[sec]. + if tt == 0 && (int64(time.Second)/FPS-int64(5*time.Millisecond)) < t { + tt = 1 } + for i := 0; i < tt; i++ { + if err := graphicsContext.update(f); err != nil { + return err + } + } + ui.CurrentUI().SwapBuffers() + beforeForUpdate += int64(tt) * int64(time.Second) / FPS + frames++ } - ui.CurrentUI().SwapBuffers() - beforeForUpdate += int64(tt) * int64(time.Second) / FPS - frames++ - } - // Calc the current FPS. - if time.Second <= time.Duration(now-beforeForFPS) { - currentRunContext.updateFPS(float64(frames) * float64(time.Second) / float64(now-beforeForFPS)) - beforeForFPS = now - frames = 0 + // Calc the current FPS. + if time.Second <= time.Duration(now-beforeForFPS) { + currentRunContext.updateFPS(float64(frames) * float64(time.Second) / float64(now-beforeForFPS)) + beforeForFPS = now + frames = 0 + } + default: + panic("not reach") } } }