ui: Use events in the game loop

This commit is contained in:
Hajime Hoshi 2016-05-18 01:30:27 +09:00
parent 49c156d2b5
commit 5c68ee4034
4 changed files with 70 additions and 47 deletions

21
internal/ui/event.go Normal file
View File

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

View File

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

View File

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

66
run.go
View File

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