internal/ui: refactoring: move AdjustPosition to the package internal/ui

This commit is contained in:
Hajime Hoshi 2022-02-13 18:31:28 +09:00
parent 08ae7006ef
commit 7b164882fc
6 changed files with 54 additions and 55 deletions

View File

@ -15,6 +15,7 @@
package ui package ui
import ( import (
"math"
"sync/atomic" "sync/atomic"
"github.com/hajimehoshi/ebiten/v2/internal/buffered" "github.com/hajimehoshi/ebiten/v2/internal/buffered"
@ -27,10 +28,7 @@ const DefaultTPS = 60
type Context interface { type Context interface {
UpdateOffscreen(outsideWidth, outsideHeight float64) (int, int) UpdateOffscreen(outsideWidth, outsideHeight float64) (int, int)
UpdateFrame(updateCount int, outsideWidth, outsideHeight float64) error UpdateFrame(updateCount int, screenScale float64, offsetX, offsetY float64) error
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
AdjustPosition(x, y float64, outsideWidth, outsideHeight float64, deviceScaleFactor float64) (float64, float64)
} }
type contextImpl struct { type contextImpl struct {
@ -48,16 +46,16 @@ func newContextImpl(context Context) *contextImpl {
} }
} }
func (c *contextImpl) updateFrame() error { func (c *contextImpl) updateFrame(deviceScaleFactor float64) error {
// TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped. // TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped.
return c.updateFrameImpl(clock.Update(theGlobalState.maxTPS())) return c.updateFrameImpl(clock.Update(theGlobalState.maxTPS()), deviceScaleFactor)
} }
func (c *contextImpl) forceUpdateFrame() error { func (c *contextImpl) forceUpdateFrame(deviceScaleFactor float64) error {
return c.updateFrameImpl(1) return c.updateFrameImpl(1, deviceScaleFactor)
} }
func (c *contextImpl) updateFrameImpl(updateCount int) error { func (c *contextImpl) updateFrameImpl(updateCount int, deviceScaleFactor float64) error {
ow, oh := c.context.UpdateOffscreen(c.outsideWidth, c.outsideHeight) ow, oh := c.context.UpdateOffscreen(c.outsideWidth, c.outsideHeight)
c.offscreenWidth = ow c.offscreenWidth = ow
c.offscreenHeight = oh c.offscreenHeight = oh
@ -76,7 +74,10 @@ func (c *contextImpl) updateFrameImpl(updateCount int) error {
if err := buffered.BeginFrame(); err != nil { if err := buffered.BeginFrame(); err != nil {
return err return err
} }
if err := c.context.UpdateFrame(updateCount, c.outsideWidth, c.outsideHeight); err != nil {
screenScale := c.screenScale(deviceScaleFactor)
offsetX, offsetY := c.offsets(deviceScaleFactor)
if err := c.context.UpdateFrame(updateCount, screenScale, offsetX, offsetY); err != nil {
return err return err
} }
@ -101,8 +102,37 @@ func (c *contextImpl) layout(outsideWidth, outsideHeight float64) {
c.outsideHeight = outsideHeight c.outsideHeight = outsideHeight
} }
// TODO: Make adjustPosition concurrent-safe.
func (c *contextImpl) adjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) { func (c *contextImpl) adjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) {
return c.context.AdjustPosition(x, y, c.outsideWidth, c.outsideHeight, deviceScaleFactor) ox, oy := c.offsets(deviceScaleFactor)
s := c.screenScale(deviceScaleFactor)
// The scale 0 indicates that the offscreen is not initialized yet.
// As any cursor values don't make sense, just return NaN.
if s == 0 {
return math.NaN(), math.NaN()
}
return (x*deviceScaleFactor - ox) / s, (y*deviceScaleFactor - oy) / s
}
func (c *contextImpl) offsets(deviceScaleFactor float64) (float64, float64) {
if c.offscreenWidth == 0 || c.offscreenHeight == 0 {
return 0, 0
}
s := c.screenScale(deviceScaleFactor)
width := float64(c.offscreenWidth) * s
height := float64(c.offscreenHeight) * s
x := (c.outsideWidth*deviceScaleFactor - width) / 2
y := (c.outsideHeight*deviceScaleFactor - height) / 2
return x, y
}
func (c *contextImpl) screenScale(deviceScaleFactor float64) float64 {
if c.offscreenWidth == 0 || c.offscreenHeight == 0 {
return 0
}
scaleX := c.outsideWidth / float64(c.offscreenWidth) * deviceScaleFactor
scaleY := c.outsideHeight / float64(c.offscreenHeight) * deviceScaleFactor
return math.Min(scaleX, scaleY)
} }
var theGlobalState = globalState{ var theGlobalState = globalState{

View File

@ -50,7 +50,7 @@ func (u *UserInterface) Run(context Context) error {
cbackend.BeginFrame() cbackend.BeginFrame()
u.input.update(u.context) u.input.update(u.context)
if err := u.context.updateFrame(); err != nil { if err := u.context.updateFrame(deviceScaleFactor); err != nil {
return err return err
} }

View File

@ -707,6 +707,7 @@ func (u *UserInterface) registerWindowSetSizeCallback() {
if err := u.runOnAnotherThreadFromMainThread(func() error { if err := u.runOnAnotherThreadFromMainThread(func() error {
var outsideWidth, outsideHeight float64 var outsideWidth, outsideHeight float64
var deviceScaleFactor float64
u.t.Call(func() { u.t.Call(func() {
if width != 0 || height != 0 { if width != 0 || height != 0 {
@ -716,9 +717,10 @@ func (u *UserInterface) registerWindowSetSizeCallback() {
} }
outsideWidth, outsideHeight = u.updateSize() outsideWidth, outsideHeight = u.updateSize()
deviceScaleFactor = u.deviceScaleFactor(u.currentMonitor())
}) })
u.context.layout(outsideWidth, outsideHeight) u.context.layout(outsideWidth, outsideHeight)
if err := u.context.forceUpdateFrame(); err != nil { if err := u.context.forceUpdateFrame(deviceScaleFactor); err != nil {
return err return err
} }
if graphics().IsGL() { if graphics().IsGL() {
@ -1022,15 +1024,17 @@ func (u *UserInterface) loop() error {
} }
var outsideWidth, outsideHeight float64 var outsideWidth, outsideHeight float64
var deviceScaleFactor float64
var err error var err error
if u.t.Call(func() { if u.t.Call(func() {
outsideWidth, outsideHeight, err = u.update() outsideWidth, outsideHeight, err = u.update()
deviceScaleFactor = u.deviceScaleFactor(u.currentMonitor())
}); err != nil { }); err != nil {
return err return err
} }
u.context.layout(outsideWidth, outsideHeight) u.context.layout(outsideWidth, outsideHeight)
if err := u.context.updateFrame(); err != nil { if err := u.context.updateFrame(deviceScaleFactor); err != nil {
return err return err
} }

View File

@ -289,11 +289,11 @@ func (u *UserInterface) updateImpl(force bool) error {
u.input.updateForGo2Cpp() u.input.updateForGo2Cpp()
u.updateSize() u.updateSize()
if force { if force {
if err := u.context.forceUpdateFrame(); err != nil { if err := u.context.forceUpdateFrame(u.DeviceScaleFactor()); err != nil {
return err return err
} }
} else { } else {
if err := u.context.updateFrame(); err != nil { if err := u.context.updateFrame(u.DeviceScaleFactor()); err != nil {
return err return err
} }
} }

View File

@ -330,7 +330,7 @@ func (u *UserInterface) update() error {
renderEndCh <- struct{}{} renderEndCh <- struct{}{}
}() }()
if err := u.context.updateFrame(); err != nil { if err := u.context.updateFrame(deviceScale()); err != nil {
return err return err
} }
return nil return nil

View File

@ -16,7 +16,6 @@ package ebiten
import ( import (
"fmt" "fmt"
"math"
"sync" "sync"
"github.com/hajimehoshi/ebiten/v2/internal/debug" "github.com/hajimehoshi/ebiten/v2/internal/debug"
@ -91,30 +90,7 @@ func (c *uiContext) setScreenClearedEveryFrame(cleared bool) {
} }
} }
func (c *uiContext) screenScale(outsideWidth, outsideHeight float64, deviceScaleFactor float64) float64 { func (c *uiContext) UpdateFrame(updateCount int, screenScale float64, offsetX, offsetY float64) error {
if c.offscreen == nil {
return 0
}
sw, sh := c.offscreen.Size()
scaleX := outsideWidth / float64(sw) * deviceScaleFactor
scaleY := outsideHeight / float64(sh) * deviceScaleFactor
return math.Min(scaleX, scaleY)
}
func (c *uiContext) offsets(outsideWidth, outsideHeight float64, deviceScaleFactor float64) (float64, float64) {
if c.offscreen == nil {
return 0, 0
}
sw, sh := c.offscreen.Size()
s := c.screenScale(outsideWidth, outsideHeight, deviceScaleFactor)
width := float64(sw) * s
height := float64(sh) * s
x := (outsideWidth*deviceScaleFactor - width) / 2
y := (outsideHeight*deviceScaleFactor - height) / 2
return x, y
}
func (c *uiContext) UpdateFrame(updateCount int, outsideWidth, outsideHeight float64) error {
// Ensure that Update is called once before Draw so that Update can be used for initialization. // Ensure that Update is called once before Draw so that Update can be used for initialization.
if !c.updateCalled && updateCount == 0 { if !c.updateCalled && updateCount == 0 {
updateCount = 1 updateCount = 1
@ -147,7 +123,7 @@ func (c *uiContext) UpdateFrame(updateCount int, outsideWidth, outsideHeight flo
op := &DrawImageOptions{} op := &DrawImageOptions{}
s := c.screenScale(outsideWidth, outsideHeight, ui.Get().DeviceScaleFactor()) s := screenScale
switch vd := ui.FramebufferYDirection(); vd { switch vd := ui.FramebufferYDirection(); vd {
case graphicsdriver.Upward: case graphicsdriver.Upward:
op.GeoM.Scale(s, -s) op.GeoM.Scale(s, -s)
@ -159,7 +135,7 @@ func (c *uiContext) UpdateFrame(updateCount int, outsideWidth, outsideHeight flo
panic(fmt.Sprintf("ebiten: invalid v-direction: %d", vd)) panic(fmt.Sprintf("ebiten: invalid v-direction: %d", vd))
} }
op.GeoM.Translate(c.offsets(outsideWidth, outsideHeight, ui.Get().DeviceScaleFactor())) op.GeoM.Translate(offsetX, offsetY)
op.CompositeMode = CompositeModeCopy op.CompositeMode = CompositeModeCopy
// filterScreen works with >=1 scale, but does not well with <1 scale. // filterScreen works with >=1 scale, but does not well with <1 scale.
@ -172,14 +148,3 @@ func (c *uiContext) UpdateFrame(updateCount int, outsideWidth, outsideHeight flo
c.screen.DrawImage(c.offscreen, op) c.screen.DrawImage(c.offscreen, op)
return nil return nil
} }
func (c *uiContext) AdjustPosition(x, y float64, outsideWidth, outsideHeight float64, deviceScaleFactor float64) (float64, float64) {
ox, oy := c.offsets(outsideWidth, outsideHeight, deviceScaleFactor)
s := c.screenScale(outsideWidth, outsideHeight, deviceScaleFactor)
// The scale 0 indicates that the offscreen is not initialized yet.
// As any cursor values don't make sense, just return NaN.
if s == 0 {
return math.NaN(), math.NaN()
}
return (x*deviceScaleFactor - ox) / s, (y*deviceScaleFactor - oy) / s
}