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()) 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 var ferr error
u.runOnMainThread(func() { u.runOnMainThread(func() {
if err := u.pollEvents(); err != nil { 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() { func (u *UserInterface) Terminate() {
@ -226,14 +236,6 @@ func (u *UserInterface) Terminate() {
u.funcs = nil u.funcs = nil
} }
func (u *UserInterface) IsClosed() bool {
r := false
u.runOnMainThread(func() {
r = u.window.ShouldClose()
})
return r
}
func (u *UserInterface) SwapBuffers() { func (u *UserInterface) SwapBuffers() {
u.runOnMainThread(func() { u.runOnMainThread(func() {
u.swapBuffers() u.swapBuffers()

View File

@ -83,19 +83,15 @@ func vsync() {
<-ch <-ch
} }
func (u *UserInterface) Update() error { func (u *UserInterface) Update() (interface{}, error) {
currentInput.UpdateGamepads() currentInput.UpdateGamepads()
return nil return RenderEvent{}, nil
} }
func (u *UserInterface) Terminate() { func (u *UserInterface) Terminate() {
// Do nothing. // Do nothing.
} }
func (u *UserInterface) IsClosed() bool {
return false
}
func (u *UserInterface) SwapBuffers() { func (u *UserInterface) SwapBuffers() {
vsync() vsync()
for !shown() { 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 beforeForUpdate := n
beforeForFPS := n beforeForFPS := n
for { for {
// TODO: setSize should be called after swapping buffers?
if err := currentRunContext.updateScreenSize(graphicsContext); err != nil { if err := currentRunContext.updateScreenSize(graphicsContext); err != nil {
return err return err
} }
if err := ui.CurrentUI().Update(); err != nil { e, err := ui.CurrentUI().Update()
if err != nil {
return err return err
} }
if ui.CurrentUI().IsClosed() { switch e.(type) {
case ui.CloseEvent:
return nil return nil
} case ui.RenderEvent:
now := ui.Now() now := ui.Now()
// If beforeForUpdate is too old, we assume that screen is not shown. // If beforeForUpdate is too old, we assume that screen is not shown.
if int64(5*time.Second/FPS) < now-beforeForUpdate { if int64(5*time.Second/FPS) < now-beforeForUpdate {
currentRunContext.setRunningSlowly(false) currentRunContext.setRunningSlowly(false)
beforeForUpdate = now beforeForUpdate = now
} else { } else {
// Note that generally t is a little different from 1/60[sec]. // Note that generally t is a little different from 1/60[sec].
t := now - beforeForUpdate t := now - beforeForUpdate
currentRunContext.setRunningSlowly(t*FPS >= int64(time.Second*5/2)) currentRunContext.setRunningSlowly(t*FPS >= int64(time.Second*5/2))
tt := int(t * FPS / int64(time.Second)) tt := int(t * FPS / int64(time.Second))
// As t is not accurate 1/60[sec], errors are accumulated. // 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]. // 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 { if tt == 0 && (int64(time.Second)/FPS-int64(5*time.Millisecond)) < t {
tt = 1 tt = 1
}
for i := 0; i < tt; i++ {
if err := graphicsContext.update(f); err != nil {
return err
} }
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. // Calc the current FPS.
if time.Second <= time.Duration(now-beforeForFPS) { if time.Second <= time.Duration(now-beforeForFPS) {
currentRunContext.updateFPS(float64(frames) * float64(time.Second) / float64(now-beforeForFPS)) currentRunContext.updateFPS(float64(frames) * float64(time.Second) / float64(now-beforeForFPS))
beforeForFPS = now beforeForFPS = now
frames = 0 frames = 0
}
default:
panic("not reach")
} }
} }
} }