mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-11 19:48:54 +01:00
loop: Bug fix: vsync should not use channels on browsers (#259)
This commit is contained in:
parent
57a32464dc
commit
1e0bdf844d
@ -86,6 +86,12 @@ type GraphicsContext interface {
|
|||||||
UpdateAndDraw(context *opengl.Context, updateCount int) error
|
UpdateAndDraw(context *opengl.Context, updateCount int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type regularTermination struct{}
|
||||||
|
|
||||||
|
func (e regularTermination) Error() string {
|
||||||
|
return "regular termination"
|
||||||
|
}
|
||||||
|
|
||||||
func Run(g GraphicsContext, width, height int, scale float64, title string, fps int) (err error) {
|
func Run(g GraphicsContext, width, height int, scale float64, title string, fps int) (err error) {
|
||||||
if currentRunContext != nil {
|
if currentRunContext != nil {
|
||||||
return errors.New("loop: The game is already running")
|
return errors.New("loop: The game is already running")
|
||||||
@ -107,24 +113,41 @@ func Run(g GraphicsContext, width, height int, scale float64, title string, fps
|
|||||||
n := now()
|
n := now()
|
||||||
currentRunContext.lastUpdated = n
|
currentRunContext.lastUpdated = n
|
||||||
currentRunContext.lastFPSUpdated = n
|
currentRunContext.lastFPSUpdated = n
|
||||||
|
|
||||||
|
if err := ui.CurrentUI().AnimationFrameLoop(func() error {
|
||||||
|
return currentRunContext.update(g)
|
||||||
|
}); err != nil {
|
||||||
|
if err == (regularTermination{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *runContext) update(g GraphicsContext) error {
|
||||||
for {
|
for {
|
||||||
e, err := ui.CurrentUI().Update()
|
e, err := ui.CurrentUI().Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
|
case ui.NopEvent:
|
||||||
|
return nil
|
||||||
case ui.ScreenSizeEvent:
|
case ui.ScreenSizeEvent:
|
||||||
if err := g.SetSize(e.Width, e.Height, e.ActualScale); err != nil {
|
if err := g.SetSize(e.Width, e.Height, e.ActualScale); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e.Done <- struct{}{}
|
e.Done <- struct{}{}
|
||||||
|
continue
|
||||||
case ui.CloseEvent:
|
case ui.CloseEvent:
|
||||||
return nil
|
return regularTermination{}
|
||||||
case ui.RenderEvent:
|
case ui.RenderEvent:
|
||||||
if err := currentRunContext.render(g); err != nil {
|
if err := currentRunContext.render(g); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e.Done <- struct{}{}
|
e.Done <- struct{}{}
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
panic("not reach")
|
panic("not reach")
|
||||||
}
|
}
|
||||||
@ -163,9 +186,9 @@ func (c *runContext) render(g GraphicsContext) error {
|
|||||||
if err := g.UpdateAndDraw(ui.GLContext(), tt); err != nil {
|
if err := g.UpdateAndDraw(ui.GLContext(), tt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ui.CurrentUI().SwapBuffers(); err != nil {
|
/*if err := ui.CurrentUI().SwapBuffers(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}*/
|
||||||
c.lastUpdated += int64(tt) * int64(time.Second) / int64(fps)
|
c.lastUpdated += int64(tt) * int64(time.Second) / int64(fps)
|
||||||
c.frames++
|
c.frames++
|
||||||
return nil
|
return nil
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
|
type NopEvent struct {
|
||||||
|
}
|
||||||
|
|
||||||
type CloseEvent struct {
|
type CloseEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ package ui
|
|||||||
type UserInterface interface {
|
type UserInterface interface {
|
||||||
Start(width, height int, scale float64, title string) error
|
Start(width, height int, scale float64, title string) error
|
||||||
Update() (interface{}, error)
|
Update() (interface{}, error)
|
||||||
SwapBuffers() error
|
|
||||||
Terminate() error
|
Terminate() error
|
||||||
|
AnimationFrameLoop(f func() error) error
|
||||||
ScreenScale() float64
|
ScreenScale() float64
|
||||||
SetScreenSize(width, height int) (bool, error)
|
SetScreenSize(width, height int) (bool, error)
|
||||||
SetScreenScale(scale float64) (bool, error)
|
SetScreenScale(scale float64) (bool, error)
|
||||||
|
@ -251,17 +251,21 @@ func (u *userInterface) Terminate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) SwapBuffers() error {
|
func (u *userInterface) AnimationFrameLoop(f func() error) error {
|
||||||
// The bound framebuffer must be the default one (0) before swapping buffers.
|
for {
|
||||||
if err := glContext.BindScreenFramebuffer(); err != nil {
|
if err := f(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
// The bound framebuffer must be the default one (0) before swapping buffers.
|
||||||
|
if err := glContext.BindScreenFramebuffer(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.runOnMainThread(func() error {
|
||||||
|
return u.swapBuffers()
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := u.runOnMainThread(func() error {
|
|
||||||
return u.swapBuffers()
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) swapBuffers() error {
|
func (u *userInterface) swapBuffers() error {
|
||||||
|
@ -29,12 +29,14 @@ type userInterface struct {
|
|||||||
scale float64
|
scale float64
|
||||||
deviceScale float64
|
deviceScale float64
|
||||||
sizeChanged bool
|
sizeChanged bool
|
||||||
contextRestored chan struct{}
|
contextRestored bool
|
||||||
windowFocus chan struct{}
|
windowFocus bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentUI = &userInterface{
|
var currentUI = &userInterface{
|
||||||
sizeChanged: true,
|
sizeChanged: true,
|
||||||
|
contextRestored: true,
|
||||||
|
windowFocus: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func CurrentUI() UserInterface {
|
func CurrentUI() UserInterface {
|
||||||
@ -46,16 +48,6 @@ func shown() bool {
|
|||||||
return !js.Global.Get("document").Get("hidden").Bool()
|
return !js.Global.Get("document").Get("hidden").Bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
func vsync() {
|
|
||||||
ch := make(chan struct{})
|
|
||||||
js.Global.Get("window").Call("requestAnimationFrame", func() {
|
|
||||||
// TODO: In iOS8, this is called at every 1/30[sec] frame.
|
|
||||||
// Can we use DOMHighResTimeStamp?
|
|
||||||
close(ch)
|
|
||||||
})
|
|
||||||
<-ch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *userInterface) SetScreenSize(width, height int) (bool, error) {
|
func (u *userInterface) SetScreenSize(width, height int) (bool, error) {
|
||||||
return u.setScreenSize(width, height, u.scale), nil
|
return u.setScreenSize(width, height, u.scale), nil
|
||||||
}
|
}
|
||||||
@ -74,11 +66,11 @@ func (u *userInterface) ActualScreenScale() float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) Update() (interface{}, error) {
|
func (u *userInterface) Update() (interface{}, error) {
|
||||||
if u.windowFocus != nil {
|
if !u.windowFocus {
|
||||||
<-u.windowFocus
|
return NopEvent{}, nil
|
||||||
}
|
}
|
||||||
if u.contextRestored != nil {
|
if !u.contextRestored {
|
||||||
<-u.contextRestored
|
return NopEvent{}, nil
|
||||||
}
|
}
|
||||||
currentInput.updateGamepads()
|
currentInput.updateGamepads()
|
||||||
if u.sizeChanged {
|
if u.sizeChanged {
|
||||||
@ -102,12 +94,19 @@ func (u *userInterface) Terminate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) SwapBuffers() error {
|
func (u *userInterface) AnimationFrameLoop(f func() error) error {
|
||||||
vsync()
|
ch := make(chan error)
|
||||||
for !shown() {
|
var ff func()
|
||||||
vsync()
|
ff = func() {
|
||||||
|
if err := f(); err != nil {
|
||||||
|
ch <- err
|
||||||
|
close(ch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
js.Global.Get("window").Call("requestAnimationFrame", ff)
|
||||||
}
|
}
|
||||||
return nil
|
ff()
|
||||||
|
return <-ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) FinishRendering() error {
|
func (u *userInterface) FinishRendering() error {
|
||||||
@ -151,14 +150,10 @@ func initialize() error {
|
|||||||
<-ch
|
<-ch
|
||||||
}
|
}
|
||||||
window.Call("addEventListener", "focus", func() {
|
window.Call("addEventListener", "focus", func() {
|
||||||
if currentUI.windowFocus == nil {
|
currentUI.windowFocus = true
|
||||||
return
|
|
||||||
}
|
|
||||||
close(currentUI.windowFocus)
|
|
||||||
currentUI.windowFocus = nil
|
|
||||||
})
|
})
|
||||||
window.Call("addEventListener", "blur", func() {
|
window.Call("addEventListener", "blur", func() {
|
||||||
currentUI.windowFocus = make(chan struct{})
|
currentUI.windowFocus = false
|
||||||
})
|
})
|
||||||
|
|
||||||
canvas = doc.Call("createElement", "canvas")
|
canvas = doc.Call("createElement", "canvas")
|
||||||
@ -244,11 +239,11 @@ func initialize() error {
|
|||||||
|
|
||||||
canvas.Call("addEventListener", "webglcontextlost", func(e *js.Object) {
|
canvas.Call("addEventListener", "webglcontextlost", func(e *js.Object) {
|
||||||
e.Call("preventDefault")
|
e.Call("preventDefault")
|
||||||
currentUI.contextRestored = make(chan struct{})
|
currentUI.contextRestored = false
|
||||||
})
|
})
|
||||||
canvas.Call("addEventListener", "webglcontextrestored", func(e *js.Object) {
|
canvas.Call("addEventListener", "webglcontextrestored", func(e *js.Object) {
|
||||||
close(currentUI.contextRestored)
|
// TODO: Call preventDefault?
|
||||||
currentUI.contextRestored = nil
|
currentUI.contextRestored = true
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -98,8 +98,12 @@ func (u *userInterface) Update() (interface{}, error) {
|
|||||||
return RenderEvent{chRenderEnd}, nil
|
return RenderEvent{chRenderEnd}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) SwapBuffers() error {
|
func (u *userInterface) AnimationFrameLoop(f func() error) error {
|
||||||
return nil
|
for {
|
||||||
|
if err := f(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterface) SetScreenSize(width, height int) (bool, error) {
|
func (u *userInterface) SetScreenSize(width, height int) (bool, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user