ui: Refactoring: Remove events

This commit is contained in:
Hajime Hoshi 2016-09-02 00:53:05 +09:00
parent b95d714eed
commit 6da16aa1a0
6 changed files with 70 additions and 120 deletions

View File

@ -86,10 +86,17 @@ type GraphicsContext interface {
UpdateAndDraw(context *opengl.Context, updateCount int) error
}
type regularTermination struct{}
type loopGraphicsContext struct {
runContext *runContext
graphicsContext GraphicsContext
}
func (e regularTermination) Error() string {
return "regular termination"
func (g *loopGraphicsContext) SetSize(width, height int, scale float64) error {
return g.graphicsContext.SetSize(width, height, scale)
}
func (g *loopGraphicsContext) Update() error {
return g.runContext.render(g.graphicsContext)
}
func Run(g GraphicsContext, width, height int, scale float64, title string, fps int) (err error) {
@ -114,10 +121,8 @@ func Run(g GraphicsContext, width, height int, scale float64, title string, fps
currentRunContext.lastUpdated = n
currentRunContext.lastFPSUpdated = n
if err := ui.CurrentUI().AnimationFrameLoop(func() error {
return currentRunContext.update(g)
}); err != nil {
if err == (regularTermination{}) {
if err := ui.CurrentUI().AnimationFrameLoop(&loopGraphicsContext{currentRunContext, g}); err != nil {
if _, ok := err.(*ui.RegularTermination); ok {
return nil
}
return err
@ -125,31 +130,6 @@ func Run(g GraphicsContext, width, height int, scale float64, title string, fps
return nil
}
func (c *runContext) update(g GraphicsContext) error {
e, err := ui.CurrentUI().Update()
if err != nil {
return err
}
switch e := e.(type) {
case ui.NopEvent:
case ui.ScreenSizeEvent:
if err := g.SetSize(e.Width, e.Height, e.ActualScale); err != nil {
return err
}
e.Done <- struct{}{}
case ui.CloseEvent:
return regularTermination{}
case ui.RenderEvent:
if err := currentRunContext.render(g); err != nil {
return err
}
e.Done <- struct{}{}
default:
panic("not reach")
}
return nil
}
func (c *runContext) render(g GraphicsContext) error {
fps := c.fps
n := now()

View File

@ -1,32 +0,0 @@
// 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 NopEvent struct {
}
type CloseEvent struct {
}
type ScreenSizeEvent struct {
Width int
Height int
ActualScale float64
Done chan struct{}
}
type RenderEvent struct {
Done chan struct{}
}

View File

@ -14,12 +14,23 @@
package ui
type GraphicsContext interface {
SetSize(width, height int, scale float64) error
Update() error
}
type UserInterface interface {
Start(width, height int, scale float64, title string) error
Update() (interface{}, error)
Terminate() error
AnimationFrameLoop(f func() error) error
AnimationFrameLoop(g GraphicsContext) error
ScreenScale() float64
SetScreenSize(width, height int) (bool, error)
SetScreenScale(scale float64) (bool, error)
}
type RegularTermination struct {
}
func (*RegularTermination) Error() string {
return "regular termination"
}

View File

@ -192,32 +192,29 @@ func (u *userInterface) pollEvents() error {
return currentInput.update(u.window, u.scale*glfwScale())
}
func (u *userInterface) Update() (interface{}, error) {
func (u *userInterface) update(g GraphicsContext) error {
shouldClose := false
_ = u.runOnMainThread(func() error {
shouldClose = u.window.ShouldClose()
return nil
})
if shouldClose {
return CloseEvent{}, nil
return &RegularTermination{}
}
var screenSizeEvent *ScreenSizeEvent
actualScale := 0.0
_ = u.runOnMainThread(func() error {
if !u.sizeChanged {
return nil
}
u.sizeChanged = false
screenSizeEvent = &ScreenSizeEvent{
Width: u.width,
Height: u.height,
ActualScale: u.actualScreenScale(),
Done: make(chan struct{}, 1),
}
actualScale = u.actualScreenScale()
return nil
})
if screenSizeEvent != nil {
return *screenSizeEvent, nil
if 0 < actualScale {
if err := g.SetSize(u.width, u.height, actualScale); err != nil {
return err
}
}
if err := u.runOnMainThread(func() error {
@ -236,11 +233,12 @@ func (u *userInterface) Update() (interface{}, error) {
}
return nil
}); err != nil {
return nil, err
return err
}
// Dummy channel
ch := make(chan struct{}, 1)
return RenderEvent{ch}, nil
if err := g.Update(); err != nil {
return err
}
return nil
}
func (u *userInterface) Terminate() error {
@ -251,9 +249,9 @@ func (u *userInterface) Terminate() error {
return nil
}
func (u *userInterface) AnimationFrameLoop(f func() error) error {
func (u *userInterface) AnimationFrameLoop(g GraphicsContext) error {
for {
if err := f(); err != nil {
if err := u.update(g); err != nil {
return err
}
// The bound framebuffer must be the default one (0) before swapping buffers.

View File

@ -65,28 +65,26 @@ func (u *userInterface) ActualScreenScale() float64 {
return u.scale * u.deviceScale
}
func (u *userInterface) Update() (interface{}, error) {
func (u *userInterface) update(g GraphicsContext) error {
if !u.windowFocus {
return NopEvent{}, nil
return nil
}
if !u.contextRestored {
return NopEvent{}, nil
return nil
}
currentInput.updateGamepads()
if u.sizeChanged {
u.sizeChanged = false
w, h := u.size()
e := ScreenSizeEvent{
Width: w,
Height: h,
ActualScale: u.ActualScreenScale(),
Done: make(chan struct{}, 1),
if err := g.SetSize(w, h, u.ActualScreenScale()); err != nil {
return err
}
return e, nil
return nil
}
// Dummy channel
ch := make(chan struct{}, 1)
return RenderEvent{ch}, nil
if err := g.Update(); err != nil {
return err
}
return nil
}
func (u *userInterface) Terminate() error {
@ -94,18 +92,18 @@ func (u *userInterface) Terminate() error {
return nil
}
func (u *userInterface) AnimationFrameLoop(f func() error) error {
func (u *userInterface) AnimationFrameLoop(g GraphicsContext) error {
ch := make(chan error)
var ff func()
ff = func() {
if err := f(); err != nil {
var f func()
f = func() {
if err := u.update(g); err != nil {
ch <- err
close(ch)
return
}
js.Global.Get("window").Call("requestAnimationFrame", ff)
js.Global.Get("window").Call("requestAnimationFrame", f)
}
ff()
f()
return <-ch
}

View File

@ -81,28 +81,23 @@ func (u *userInterface) Terminate() error {
return nil
}
func (u *userInterface) Update() (interface{}, error) {
func (u *userInterface) AnimationFrameLoop(g GraphicsContext) error {
for {
if u.sizeChanged {
// Sizing also calls GL functions
<-chRender
u.sizeChanged = false
e := ScreenSizeEvent{
Width: u.width,
Height: u.height,
ActualScale: u.actualScreenScale(),
Done: chRenderEnd,
}
return e, nil
}
<-chRender
return RenderEvent{chRenderEnd}, nil
}
func (u *userInterface) AnimationFrameLoop(f func() error) error {
for {
if err := f(); err != nil {
if err := g.SetSize(u.width, u.height, u.actualScreenScale()); err != nil {
return err
}
chRenderEnd <- struct{}{}
continue
}
<-chRender
if err := g.Update(); err != nil {
return err
}
chRenderEnd <- struct{}{}
}
}