mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
internal/ui: refactoring: add ui.SetError
This is a preparation to move uiContext to the package internal/ui.
This commit is contained in:
parent
2c68124f0e
commit
b282b1805b
7
image.go
7
image.go
@ -23,6 +23,7 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
|
||||
// panicOnErrorAtImageAt indicates whether (*Image).At panics on an error or not.
|
||||
@ -718,7 +719,7 @@ func (i *Image) at(x, y int) (r, g, b, a uint8) {
|
||||
if panicOnErrorAtImageAt {
|
||||
panic(err)
|
||||
}
|
||||
theUIContext.setError(err)
|
||||
ui.SetError(err)
|
||||
return 0, 0, 0, 0
|
||||
}
|
||||
return pix[0], pix[1], pix[2], pix[3]
|
||||
@ -746,7 +747,7 @@ func (i *Image) Set(x, y int, clr color.Color) {
|
||||
r, g, b, a := clr.RGBA()
|
||||
pix := []byte{byte(r >> 8), byte(g >> 8), byte(b >> 8), byte(a >> 8)}
|
||||
if err := i.mipmap.ReplacePixels(pix, x, y, 1, 1); err != nil {
|
||||
theUIContext.setError(err)
|
||||
ui.SetError(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -794,7 +795,7 @@ func (i *Image) ReplacePixels(pixels []byte) {
|
||||
// * In internal/mipmap, pixels are copied when necessary.
|
||||
// * In internal/shareable, pixels are copied to make its paddings.
|
||||
if err := i.mipmap.ReplacePixels(pixels, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
|
||||
theUIContext.setError(err)
|
||||
ui.SetError(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
70
internal/ui/context.go
Normal file
70
internal/ui/context.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2022 The Ebiten Authors
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Context interface {
|
||||
UpdateFrame() error
|
||||
ForceUpdateFrame() error
|
||||
Layout(outsideWidth, outsideHeight float64)
|
||||
|
||||
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
|
||||
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
|
||||
}
|
||||
|
||||
type contextImpl struct {
|
||||
context Context
|
||||
|
||||
err atomic.Value
|
||||
}
|
||||
|
||||
func (c *contextImpl) updateFrame() error {
|
||||
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||
return err
|
||||
}
|
||||
return c.context.UpdateFrame()
|
||||
}
|
||||
|
||||
func (c *contextImpl) forceUpdateFrame() error {
|
||||
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||
return err
|
||||
}
|
||||
return c.context.ForceUpdateFrame()
|
||||
}
|
||||
|
||||
func (c *contextImpl) layout(outsideWidth, outsideHeight float64) {
|
||||
// The given outside size can be 0 e.g. just after restoring from the fullscreen mode on Windows (#1589)
|
||||
// Just ignore such cases. Otherwise, creating a zero-sized framebuffer causes a panic.
|
||||
if outsideWidth == 0 || outsideHeight == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.context.Layout(outsideWidth, outsideHeight)
|
||||
}
|
||||
|
||||
func (c *contextImpl) adjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) {
|
||||
return c.context.AdjustPosition(x, y, deviceScaleFactor)
|
||||
}
|
||||
|
||||
func (c *contextImpl) setError(err error) {
|
||||
c.err.Store(err)
|
||||
}
|
||||
|
||||
func SetError(err error) {
|
||||
Get().context.setError(err)
|
||||
}
|
@ -31,7 +31,7 @@ type Input struct {
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (i *Input) update(context Context) {
|
||||
func (i *Input) update(context *contextImpl) {
|
||||
i.m.Lock()
|
||||
defer i.m.Unlock()
|
||||
|
||||
@ -41,7 +41,7 @@ func (i *Input) update(context Context) {
|
||||
i.touches = cbackend.AppendTouches(i.touches)
|
||||
|
||||
for idx, t := range i.touches {
|
||||
x, y := context.AdjustPosition(float64(t.X), float64(t.Y), deviceScaleFactor)
|
||||
x, y := context.adjustPosition(float64(t.X), float64(t.Y), deviceScaleFactor)
|
||||
i.touches[idx].X = int(x)
|
||||
i.touches[idx].Y = int(y)
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ var glfwMouseButtonToMouseButton = map[glfw.MouseButton]MouseButton{
|
||||
}
|
||||
|
||||
// update must be called from the main thread.
|
||||
func (i *Input) update(window *glfw.Window, context Context) error {
|
||||
func (i *Input) update(window *glfw.Window, context *contextImpl) error {
|
||||
i.ui.m.Lock()
|
||||
defer i.ui.m.Unlock()
|
||||
|
||||
@ -196,7 +196,7 @@ func (i *Input) update(window *glfw.Window, context Context) error {
|
||||
s := i.ui.deviceScaleFactor(m)
|
||||
cx = i.ui.dipFromGLFWPixel(cx, m)
|
||||
cy = i.ui.dipFromGLFWPixel(cy, m)
|
||||
cx, cy = context.AdjustPosition(cx, cy, s)
|
||||
cx, cy = context.adjustPosition(cx, cy, s)
|
||||
|
||||
// AdjustPosition can return NaN at the initialization.
|
||||
if !math.IsNaN(cx) && !math.IsNaN(cy) {
|
||||
|
@ -75,7 +75,7 @@ func (i *Input) CursorPosition() (x, y int) {
|
||||
if i.ui.context == nil {
|
||||
return 0, 0
|
||||
}
|
||||
xf, yf := i.ui.context.AdjustPosition(float64(i.cursorX), float64(i.cursorY), i.ui.DeviceScaleFactor())
|
||||
xf, yf := i.ui.context.adjustPosition(float64(i.cursorX), float64(i.cursorY), i.ui.DeviceScaleFactor())
|
||||
return int(xf), int(yf)
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ func (i *Input) TouchPosition(id TouchID) (x, y int) {
|
||||
d := i.ui.DeviceScaleFactor()
|
||||
for tid, pos := range i.touches {
|
||||
if id == tid {
|
||||
x, y := i.ui.context.AdjustPosition(float64(pos.X), float64(pos.Y), d)
|
||||
x, y := i.ui.context.adjustPosition(float64(pos.X), float64(pos.Y), d)
|
||||
return int(x), int(y)
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,9 @@ import (
|
||||
)
|
||||
|
||||
func (u *UserInterface) Run(uicontext Context) error {
|
||||
u.context = uicontext
|
||||
u.context = &contextImpl{
|
||||
context: uicontext,
|
||||
}
|
||||
|
||||
// Initialize the main thread first so the thread is available at u.run (#809).
|
||||
u.t = thread.NewOSThread()
|
||||
|
@ -23,7 +23,9 @@ import (
|
||||
)
|
||||
|
||||
func (u *UserInterface) Run(uicontext Context) error {
|
||||
u.context = uicontext
|
||||
u.context = &contextImpl{
|
||||
context: uicontext,
|
||||
}
|
||||
|
||||
// Initialize the main thread first so the thread is available at u.run (#809).
|
||||
u.t = thread.NewNoopThread()
|
||||
|
@ -20,15 +20,6 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
)
|
||||
|
||||
type Context interface {
|
||||
UpdateFrame() error
|
||||
ForceUpdateFrame() error
|
||||
Layout(outsideWidth, outsideHeight float64)
|
||||
|
||||
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
|
||||
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
|
||||
}
|
||||
|
||||
type MouseButton int
|
||||
|
||||
const (
|
||||
|
@ -30,7 +30,8 @@ func init() {
|
||||
}
|
||||
|
||||
type UserInterface struct {
|
||||
input Input
|
||||
context *contextImpl
|
||||
input Input
|
||||
}
|
||||
|
||||
var theUserInterface UserInterface
|
||||
@ -40,15 +41,18 @@ func Get() *UserInterface {
|
||||
}
|
||||
|
||||
func (u *UserInterface) Run(context Context) error {
|
||||
u.context = &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
cbackend.InitializeGame()
|
||||
for {
|
||||
w, h := cbackend.ScreenSize()
|
||||
context.Layout(float64(w), float64(h))
|
||||
u.context.layout(float64(w), float64(h))
|
||||
|
||||
cbackend.BeginFrame()
|
||||
u.input.update(context)
|
||||
u.input.update(u.context)
|
||||
|
||||
if err := context.UpdateFrame(); err != nil {
|
||||
if err := u.context.updateFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ func driverCursorModeToGLFWCursorMode(mode CursorMode) int {
|
||||
}
|
||||
|
||||
type UserInterface struct {
|
||||
context Context
|
||||
context *contextImpl
|
||||
title string
|
||||
window *glfw.Window
|
||||
|
||||
@ -731,8 +731,8 @@ func (u *UserInterface) registerWindowSetSizeCallback() {
|
||||
|
||||
outsideWidth, outsideHeight = u.updateSize()
|
||||
})
|
||||
u.context.Layout(outsideWidth, outsideHeight)
|
||||
if err := u.context.ForceUpdateFrame(); err != nil {
|
||||
u.context.layout(outsideWidth, outsideHeight)
|
||||
if err := u.context.forceUpdateFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
if graphics().IsGL() {
|
||||
@ -1042,9 +1042,9 @@ func (u *UserInterface) loop() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
u.context.Layout(outsideWidth, outsideHeight)
|
||||
u.context.layout(outsideWidth, outsideHeight)
|
||||
|
||||
if err := u.context.UpdateFrame(); err != nil {
|
||||
if err := u.context.updateFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -1365,7 +1365,7 @@ func (u *UserInterface) ResetForFrame() {
|
||||
u.t.Call(func() {
|
||||
w, h = u.updateSize()
|
||||
})
|
||||
u.context.Layout(w, h)
|
||||
u.context.layout(w, h)
|
||||
u.input.resetForFrame()
|
||||
|
||||
u.m.Lock()
|
||||
|
@ -61,7 +61,7 @@ type UserInterface struct {
|
||||
|
||||
lastDeviceScaleFactor float64
|
||||
|
||||
context Context
|
||||
context *contextImpl
|
||||
input Input
|
||||
}
|
||||
|
||||
@ -240,14 +240,14 @@ func (u *UserInterface) updateSize() {
|
||||
body := document.Get("body")
|
||||
bw := body.Get("clientWidth").Float()
|
||||
bh := body.Get("clientHeight").Float()
|
||||
u.context.Layout(bw, bh)
|
||||
u.context.layout(bw, bh)
|
||||
case go2cpp.Truthy():
|
||||
w := go2cpp.Get("screenWidth").Float()
|
||||
h := go2cpp.Get("screenHeight").Float()
|
||||
u.context.Layout(w, h)
|
||||
u.context.layout(w, h)
|
||||
default:
|
||||
// Node.js
|
||||
u.context.Layout(640, 480)
|
||||
u.context.layout(640, 480)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,11 +293,11 @@ func (u *UserInterface) updateImpl(force bool) error {
|
||||
u.input.updateForGo2Cpp()
|
||||
u.updateSize()
|
||||
if force {
|
||||
if err := u.context.ForceUpdateFrame(); err != nil {
|
||||
if err := u.context.forceUpdateFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := u.context.UpdateFrame(); err != nil {
|
||||
if err := u.context.updateFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -319,7 +319,9 @@ func (u *UserInterface) needsUpdate() bool {
|
||||
}
|
||||
|
||||
func (u *UserInterface) loop(context Context) <-chan error {
|
||||
u.context = context
|
||||
u.context = &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
reqStopAudioCh := make(chan struct{})
|
||||
|
@ -109,7 +109,7 @@ type UserInterface struct {
|
||||
setGBuildSizeCh chan struct{}
|
||||
once sync.Once
|
||||
|
||||
context Context
|
||||
context *contextImpl
|
||||
|
||||
input Input
|
||||
|
||||
@ -273,7 +273,9 @@ func (u *UserInterface) run(context Context, mainloop bool) (err error) {
|
||||
u.sizeChanged = true
|
||||
u.m.Unlock()
|
||||
|
||||
u.context = context
|
||||
u.context = &contextImpl{
|
||||
context: context,
|
||||
}
|
||||
|
||||
if mainloop {
|
||||
// When mainloop is true, gomobile-build is used. In this case, GL functions must be called via
|
||||
@ -320,7 +322,7 @@ func (u *UserInterface) layoutIfNeeded() {
|
||||
u.m.RUnlock()
|
||||
|
||||
if sizeChanged {
|
||||
u.context.Layout(outsideWidth, outsideHeight)
|
||||
u.context.layout(outsideWidth, outsideHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,7 +332,7 @@ func (u *UserInterface) update() error {
|
||||
renderEndCh <- struct{}{}
|
||||
}()
|
||||
|
||||
if err := u.context.UpdateFrame(); err != nil {
|
||||
if err := u.context.updateFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -368,7 +370,7 @@ func (u *UserInterface) setGBuildSize(widthPx, heightPx int) {
|
||||
}
|
||||
|
||||
func (u *UserInterface) adjustPosition(x, y int) (int, int) {
|
||||
xf, yf := u.context.AdjustPosition(float64(x), float64(y), deviceScale())
|
||||
xf, yf := u.context.adjustPosition(float64(x), float64(y), deviceScale())
|
||||
return int(xf), int(yf)
|
||||
}
|
||||
|
||||
|
16
uicontext.go
16
uicontext.go
@ -18,7 +18,6 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||
@ -39,8 +38,6 @@ type uiContext struct {
|
||||
outsideWidth float64
|
||||
outsideHeight float64
|
||||
|
||||
err atomic.Value
|
||||
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
@ -52,16 +49,7 @@ func (c *uiContext) set(game Game) {
|
||||
c.game = game
|
||||
}
|
||||
|
||||
func (c *uiContext) setError(err error) {
|
||||
c.err.Store(err)
|
||||
}
|
||||
|
||||
func (c *uiContext) Layout(outsideWidth, outsideHeight float64) {
|
||||
// The given outside size can be 0 e.g. just after restoring from the fullscreen mode on Windows (#1589)
|
||||
// Just ignore such cases. Otherwise, creating a zero-sized framebuffer causes a panic.
|
||||
if outsideWidth == 0 || outsideHeight == 0 {
|
||||
return
|
||||
}
|
||||
c.outsideWidth = outsideWidth
|
||||
c.outsideHeight = outsideHeight
|
||||
}
|
||||
@ -149,10 +137,6 @@ func (c *uiContext) ForceUpdateFrame() error {
|
||||
}
|
||||
|
||||
func (c *uiContext) updateFrame(updateCount int) error {
|
||||
if err, ok := c.err.Load().(error); ok && err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
debug.Logf("----\n")
|
||||
|
||||
if err := buffered.BeginFrame(); err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user