mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
internal/ui: refactoring: move some logics to internal/ui
This commit is contained in:
parent
b282b1805b
commit
2609d73a1a
@ -16,11 +16,14 @@ package ui
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||
)
|
||||
|
||||
const DefaultTPS = 60
|
||||
|
||||
type Context interface {
|
||||
UpdateFrame() error
|
||||
ForceUpdateFrame() error
|
||||
UpdateFrame(updateCount int) error
|
||||
Layout(outsideWidth, outsideHeight float64)
|
||||
|
||||
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
|
||||
@ -30,21 +33,36 @@ type Context interface {
|
||||
type contextImpl struct {
|
||||
context Context
|
||||
|
||||
err atomic.Value
|
||||
outsideWidth float64
|
||||
outsideHeight float64
|
||||
}
|
||||
|
||||
func newContextImpl(context Context) *contextImpl {
|
||||
return &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *contextImpl) updateFrame() error {
|
||||
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||
if err := theGlobalState.err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.context.UpdateFrame()
|
||||
|
||||
// TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped.
|
||||
return c.context.UpdateFrame(clock.Update(theGlobalState.maxTPS()))
|
||||
}
|
||||
|
||||
func (c *contextImpl) forceUpdateFrame() error {
|
||||
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||
if err := theGlobalState.err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.context.ForceUpdateFrame()
|
||||
|
||||
// ForceUpdate can be invoked even if the context is not initialized yet (#1591).
|
||||
if c.outsideWidth == 0 || c.outsideHeight == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.context.UpdateFrame(1)
|
||||
}
|
||||
|
||||
func (c *contextImpl) layout(outsideWidth, outsideHeight float64) {
|
||||
@ -54,6 +72,8 @@ func (c *contextImpl) layout(outsideWidth, outsideHeight float64) {
|
||||
return
|
||||
}
|
||||
|
||||
c.outsideWidth = outsideWidth
|
||||
c.outsideHeight = outsideHeight
|
||||
c.context.Layout(outsideWidth, outsideHeight)
|
||||
}
|
||||
|
||||
@ -61,10 +81,69 @@ func (c *contextImpl) adjustPosition(x, y float64, deviceScaleFactor float64) (f
|
||||
return c.context.AdjustPosition(x, y, deviceScaleFactor)
|
||||
}
|
||||
|
||||
func (c *contextImpl) setError(err error) {
|
||||
c.err.Store(err)
|
||||
var theGlobalState = globalState{
|
||||
currentMaxTPS: DefaultTPS,
|
||||
}
|
||||
|
||||
// globalState represents a global state in this package.
|
||||
// This is available even before the game loop starts.
|
||||
type globalState struct {
|
||||
currentErr atomic.Value
|
||||
currentFPSMode int32
|
||||
currentMaxTPS int32
|
||||
}
|
||||
|
||||
func (g *globalState) err() error {
|
||||
err, ok := g.currentErr.Load().(error)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *globalState) setError(err error) {
|
||||
g.currentErr.Store(err)
|
||||
}
|
||||
|
||||
func (g *globalState) fpsMode() FPSModeType {
|
||||
return FPSModeType(atomic.LoadInt32(&g.currentFPSMode))
|
||||
}
|
||||
|
||||
func (g *globalState) setFPSMode(fpsMode FPSModeType) {
|
||||
atomic.StoreInt32(&g.currentFPSMode, int32(fpsMode))
|
||||
}
|
||||
|
||||
func (g *globalState) maxTPS() int {
|
||||
if g.fpsMode() == FPSModeVsyncOffMinimum {
|
||||
return clock.SyncWithFPS
|
||||
}
|
||||
return int(atomic.LoadInt32(&g.currentMaxTPS))
|
||||
}
|
||||
|
||||
func (g *globalState) setMaxTPS(tps int) {
|
||||
if tps < 0 && tps != clock.SyncWithFPS {
|
||||
panic("ebiten: tps must be >= 0 or SyncWithFPS")
|
||||
}
|
||||
atomic.StoreInt32(&g.currentMaxTPS, int32(tps))
|
||||
}
|
||||
|
||||
func SetError(err error) {
|
||||
Get().context.setError(err)
|
||||
theGlobalState.setError(err)
|
||||
}
|
||||
|
||||
func FPSMode() FPSModeType {
|
||||
return theGlobalState.fpsMode()
|
||||
}
|
||||
|
||||
func SetFPSMode(fpsMode FPSModeType) {
|
||||
theGlobalState.setFPSMode(fpsMode)
|
||||
Get().SetFPSMode(fpsMode)
|
||||
}
|
||||
|
||||
func MaxTPS() int {
|
||||
return theGlobalState.maxTPS()
|
||||
}
|
||||
|
||||
func SetMaxTPS(tps int) {
|
||||
theGlobalState.setMaxTPS(tps)
|
||||
}
|
||||
|
@ -22,10 +22,8 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/thread"
|
||||
)
|
||||
|
||||
func (u *UserInterface) Run(uicontext Context) error {
|
||||
u.context = &contextImpl{
|
||||
context: uicontext,
|
||||
}
|
||||
func (u *UserInterface) Run(context Context) error {
|
||||
u.context = newContextImpl(context)
|
||||
|
||||
// Initialize the main thread first so the thread is available at u.run (#809).
|
||||
u.t = thread.NewOSThread()
|
||||
|
@ -22,10 +22,8 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/thread"
|
||||
)
|
||||
|
||||
func (u *UserInterface) Run(uicontext Context) error {
|
||||
u.context = &contextImpl{
|
||||
context: uicontext,
|
||||
}
|
||||
func (u *UserInterface) Run(context Context) error {
|
||||
u.context = newContextImpl(context)
|
||||
|
||||
// Initialize the main thread first so the thread is available at u.run (#809).
|
||||
u.t = thread.NewNoopThread()
|
||||
|
@ -35,10 +35,10 @@ type TouchID int
|
||||
// the game loop should be terminated as soon as possible.
|
||||
var RegularTermination = errors.New("regular termination")
|
||||
|
||||
type FPSMode int
|
||||
type FPSModeType int
|
||||
|
||||
const (
|
||||
FPSModeVsyncOn FPSMode = iota
|
||||
FPSModeVsyncOn FPSModeType = iota
|
||||
FPSModeVsyncOffMaximum
|
||||
FPSModeVsyncOffMinimum
|
||||
)
|
||||
|
@ -41,9 +41,7 @@ func Get() *UserInterface {
|
||||
}
|
||||
|
||||
func (u *UserInterface) Run(context Context) error {
|
||||
u.context = &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
u.context = newContextImpl(context)
|
||||
cbackend.InitializeGame()
|
||||
for {
|
||||
w, h := cbackend.ScreenSize()
|
||||
@ -107,11 +105,7 @@ func (*UserInterface) IsRunnableOnUnfocused() bool {
|
||||
func (*UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
|
||||
}
|
||||
|
||||
func (*UserInterface) FPSMode() FPSMode {
|
||||
return FPSModeVsyncOn
|
||||
}
|
||||
|
||||
func (*UserInterface) SetFPSMode(mode FPSMode) {
|
||||
func (*UserInterface) SetFPSMode(mode FPSModeType) {
|
||||
}
|
||||
|
||||
func (*UserInterface) ScheduleFrame() {
|
||||
|
@ -65,7 +65,7 @@ type UserInterface struct {
|
||||
origPosX int
|
||||
origPosY int
|
||||
runnableOnUnfocused bool
|
||||
fpsMode FPSMode
|
||||
fpsMode FPSModeType
|
||||
iconImages []image.Image
|
||||
cursorShape CursorShape
|
||||
windowClosingHandled bool
|
||||
@ -536,7 +536,7 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
|
||||
return u.isRunnableOnUnfocused()
|
||||
}
|
||||
|
||||
func (u *UserInterface) SetFPSMode(mode FPSMode) {
|
||||
func (u *UserInterface) SetFPSMode(mode FPSModeType) {
|
||||
if !u.isRunning() {
|
||||
u.m.Lock()
|
||||
u.fpsMode = mode
|
||||
@ -553,20 +553,6 @@ func (u *UserInterface) SetFPSMode(mode FPSMode) {
|
||||
})
|
||||
}
|
||||
|
||||
func (u *UserInterface) FPSMode() FPSMode {
|
||||
if !u.isRunning() {
|
||||
u.m.Lock()
|
||||
m := u.fpsMode
|
||||
u.m.Unlock()
|
||||
return m
|
||||
}
|
||||
var v FPSMode
|
||||
u.t.Call(func() {
|
||||
v = u.fpsMode
|
||||
})
|
||||
return v
|
||||
}
|
||||
|
||||
func (u *UserInterface) ScheduleFrame() {
|
||||
if !u.isRunning() {
|
||||
return
|
||||
@ -943,7 +929,7 @@ func (u *UserInterface) updateSize() (float64, float64) {
|
||||
}
|
||||
|
||||
// setFPSMode must be called from the main thread.
|
||||
func (u *UserInterface) setFPSMode(fpsMode FPSMode) {
|
||||
func (u *UserInterface) setFPSMode(fpsMode FPSModeType) {
|
||||
needUpdate := u.fpsMode != fpsMode || !u.fpsModeInited
|
||||
u.fpsMode = fpsMode
|
||||
u.fpsModeInited = true
|
||||
|
@ -48,7 +48,7 @@ func driverCursorShapeToCSSCursor(cursor CursorShape) string {
|
||||
|
||||
type UserInterface struct {
|
||||
runnableOnUnfocused bool
|
||||
fpsMode FPSMode
|
||||
fpsMode FPSModeType
|
||||
renderingScheduled bool
|
||||
running bool
|
||||
initFocused bool
|
||||
@ -152,14 +152,10 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
|
||||
return u.runnableOnUnfocused
|
||||
}
|
||||
|
||||
func (u *UserInterface) SetFPSMode(mode FPSMode) {
|
||||
func (u *UserInterface) SetFPSMode(mode FPSModeType) {
|
||||
u.fpsMode = mode
|
||||
}
|
||||
|
||||
func (u *UserInterface) FPSMode() FPSMode {
|
||||
return u.fpsMode
|
||||
}
|
||||
|
||||
func (u *UserInterface) ScheduleFrame() {
|
||||
u.renderingScheduled = true
|
||||
}
|
||||
@ -319,9 +315,7 @@ func (u *UserInterface) needsUpdate() bool {
|
||||
}
|
||||
|
||||
func (u *UserInterface) loop(context Context) <-chan error {
|
||||
u.context = &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
u.context = newContextImpl(context)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
reqStopAudioCh := make(chan struct{})
|
||||
|
@ -113,7 +113,7 @@ type UserInterface struct {
|
||||
|
||||
input Input
|
||||
|
||||
fpsMode FPSMode
|
||||
fpsMode FPSModeType
|
||||
renderRequester RenderRequester
|
||||
|
||||
t *thread.OSThread
|
||||
@ -273,9 +273,7 @@ func (u *UserInterface) run(context Context, mainloop bool) (err error) {
|
||||
u.sizeChanged = true
|
||||
u.m.Unlock()
|
||||
|
||||
u.context = &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
u.context = newContextImpl(context)
|
||||
|
||||
if mainloop {
|
||||
// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
|
||||
@ -410,11 +408,7 @@ func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
func (u *UserInterface) FPSMode() FPSMode {
|
||||
return u.fpsMode
|
||||
}
|
||||
|
||||
func (u *UserInterface) SetFPSMode(mode FPSMode) {
|
||||
func (u *UserInterface) SetFPSMode(mode FPSModeType) {
|
||||
u.fpsMode = mode
|
||||
u.updateExplicitRenderingModeIfNeeded()
|
||||
}
|
||||
|
25
run.go
25
run.go
@ -61,7 +61,7 @@ type Game interface {
|
||||
}
|
||||
|
||||
// DefaultTPS represents a default ticks per second, that represents how many times game updating happens in a second.
|
||||
const DefaultTPS = 60
|
||||
const DefaultTPS = ui.DefaultTPS
|
||||
|
||||
// CurrentFPS returns the current number of FPS (frames per second), that represents
|
||||
// how many swapping buffer happens per second.
|
||||
@ -79,7 +79,6 @@ func CurrentFPS() float64 {
|
||||
var (
|
||||
isScreenClearedEveryFrame = int32(1)
|
||||
isRunGameEnded_ = int32(0)
|
||||
currentMaxTPS = int32(DefaultTPS)
|
||||
)
|
||||
|
||||
// SetScreenClearedEveryFrame enables or disables the clearing of the screen at the beginning of each frame.
|
||||
@ -324,7 +323,7 @@ func DeviceScaleFactor() float64 {
|
||||
//
|
||||
// Deprecated: as of v2.2. Use FPSMode instead.
|
||||
func IsVsyncEnabled() bool {
|
||||
return ui.Get().FPSMode() == ui.FPSModeVsyncOn
|
||||
return ui.FPSMode() == ui.FPSModeVsyncOn
|
||||
}
|
||||
|
||||
// SetVsyncEnabled sets a boolean value indicating whether
|
||||
@ -333,14 +332,14 @@ func IsVsyncEnabled() bool {
|
||||
// Deprecated: as of v2.2. Use SetFPSMode instead.
|
||||
func SetVsyncEnabled(enabled bool) {
|
||||
if enabled {
|
||||
ui.Get().SetFPSMode(ui.FPSModeVsyncOn)
|
||||
ui.SetFPSMode(ui.FPSModeVsyncOn)
|
||||
} else {
|
||||
ui.Get().SetFPSMode(ui.FPSModeVsyncOffMaximum)
|
||||
ui.SetFPSMode(ui.FPSModeVsyncOffMaximum)
|
||||
}
|
||||
}
|
||||
|
||||
// FPSModeType is a type of FPS modes.
|
||||
type FPSModeType = ui.FPSMode
|
||||
type FPSModeType = ui.FPSModeType
|
||||
|
||||
const (
|
||||
// FPSModeVsyncOn indicates that the game tries to sync the display's refresh rate.
|
||||
@ -371,7 +370,7 @@ const (
|
||||
//
|
||||
// FPSMode is concurrent-safe.
|
||||
func FPSMode() FPSModeType {
|
||||
return ui.Get().FPSMode()
|
||||
return ui.FPSMode()
|
||||
}
|
||||
|
||||
// SetFPSMode sets the FPS mode.
|
||||
@ -379,7 +378,7 @@ func FPSMode() FPSModeType {
|
||||
//
|
||||
// SetFPSMode is concurrent-safe.
|
||||
func SetFPSMode(mode FPSModeType) {
|
||||
ui.Get().SetFPSMode(mode)
|
||||
ui.SetFPSMode(mode)
|
||||
}
|
||||
|
||||
// ScheduleFrame schedules a next frame when the current FPS mode is FPSModeVsyncOffMinimum.
|
||||
@ -393,10 +392,7 @@ func ScheduleFrame() {
|
||||
//
|
||||
// MaxTPS is concurrent-safe.
|
||||
func MaxTPS() int {
|
||||
if FPSMode() == FPSModeVsyncOffMinimum {
|
||||
return SyncWithFPS
|
||||
}
|
||||
return int(atomic.LoadInt32(¤tMaxTPS))
|
||||
return ui.MaxTPS()
|
||||
}
|
||||
|
||||
// CurrentTPS returns the current TPS (ticks per second),
|
||||
@ -426,10 +422,7 @@ const UncappedTPS = SyncWithFPS
|
||||
//
|
||||
// SetMaxTPS is concurrent-safe.
|
||||
func SetMaxTPS(tps int) {
|
||||
if tps < 0 && tps != SyncWithFPS {
|
||||
panic("ebiten: tps must be >= 0 or SyncWithFPS")
|
||||
}
|
||||
atomic.StoreInt32(¤tMaxTPS, int32(tps))
|
||||
ui.SetMaxTPS(tps)
|
||||
}
|
||||
|
||||
// IsScreenTransparent reports whether the window is transparent.
|
||||
|
16
uicontext.go
16
uicontext.go
@ -20,7 +20,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
@ -123,20 +122,7 @@ func (c *uiContext) offsets(deviceScaleFactor float64) (float64, float64) {
|
||||
return x, y
|
||||
}
|
||||
|
||||
func (c *uiContext) UpdateFrame() error {
|
||||
// TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped.
|
||||
return c.updateFrame(clock.Update(MaxTPS()))
|
||||
}
|
||||
|
||||
func (c *uiContext) ForceUpdateFrame() error {
|
||||
// ForceUpdate can be invoked even if uiContext it not initialized yet (#1591).
|
||||
if c.outsideWidth == 0 || c.outsideHeight == 0 {
|
||||
return nil
|
||||
}
|
||||
return c.updateFrame(1)
|
||||
}
|
||||
|
||||
func (c *uiContext) updateFrame(updateCount int) error {
|
||||
func (c *uiContext) UpdateFrame(updateCount int) error {
|
||||
debug.Logf("----\n")
|
||||
|
||||
if err := buffered.BeginFrame(); err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user