func init() { ui.Init() ui.ExecOnUIThread(func() { glContext = opengl.NewContext() }) audio.Init() }
// Run runs the game. // f is a function which is called at every frame. // The argument (*Image) is the render target that represents the screen. // // This function must be called from the main thread. // // The given function f is guaranteed to be called 60 times a second // even if a rendering frame is skipped. // f is not called when the screen is not shown. func Run(f func(*Image) error, width, height, scale int, title string) error { runContext.running = true defer func() { runContext.running = false }() actualScale, err := ui.Start(width, height, scale, title) if err != nil { return err } defer ui.Terminate() ui.ExecOnUIThread(func() { glContext.Check() }) graphicsContext, err := newGraphicsContext(width, height, actualScale) if err != nil { return err } frames := 0 gameTime := ui.Now() before := ui.Now() for { if 0 < runContext.newScreenWidth || 0 < runContext.newScreenHeight || 0 < runContext.newScreenScale { changed := false actualScale := 0 if 0 < runContext.newScreenWidth || 0 < runContext.newScreenHeight { c, a := ui.SetScreenSize(runContext.newScreenWidth, runContext.newScreenHeight) changed = changed || c actualScale = a } if 0 < runContext.newScreenScale { c, a := ui.SetScreenScale(runContext.newScreenScale) changed = changed || c // actualScale of SetScreenState is more reliable than one of SetScreenSize actualScale = a } if changed { w, h := runContext.newScreenWidth, runContext.newScreenHeight if err := graphicsContext.setSize(w, h, actualScale); err != nil { return err } } } runContext.newScreenWidth = 0 runContext.newScreenHeight = 0 runContext.newScreenScale = 0 if err := ui.DoEvents(); err != nil { return err } if ui.IsClosed() { return nil } now := ui.Now() // If gameTime is too old, we assume that screen is not shown. if int64(5*time.Second/60) < now-gameTime { gameTime = now } for gameTime < now { gameTime += int64(time.Second / 60) if err := graphicsContext.preUpdate(); err != nil { return err } if err := f(graphicsContext.screen); err != nil { return err } audio.Tick() } if err := graphicsContext.postUpdate(); err != nil { return err } ui.SwapBuffers() // Calc the current FPS. now = ui.Now() frames++ if time.Second <= time.Duration(now-before) { runContext.fps = float64(frames) * float64(time.Second) / float64(now-before) before = now frames = 0 } } }
func useGLContext(f func(*opengl.Context)) { ui.ExecOnUIThread(func() { f(glContext) }) }