internal/ui: refactoring: keep screen/offscreen sizes as float64

Updates #2285
This commit is contained in:
Hajime Hoshi 2022-11-09 01:07:03 +09:00
parent 9ce394df43
commit 0d6b42fedd
2 changed files with 46 additions and 44 deletions

View File

@ -125,8 +125,20 @@ func (g *gameForUI) NewScreenImage(width, height int) *ui.Image {
return g.screen.image return g.screen.image
} }
func (g *gameForUI) Layout(outsideWidth, outsideHeight int) (int, int) { func (g *gameForUI) Layout(outsideWidth, outsideHeight float64) (float64, float64) {
return g.game.Layout(outsideWidth, outsideHeight) // Even if the original value is less than 1, the value must be a positive integer (#2340).
// This is for a simple implementation of Layout, which returns the argument values without modifications.
// TODO: Remove this hack when Game.Layout takes floats instead of integers.
if outsideWidth < 1 {
outsideWidth = 1
}
if outsideHeight < 1 {
outsideHeight = 1
}
// TODO: Add a new Layout function taking float values (#2285).
sw, sh := g.game.Layout(int(outsideWidth), int(outsideHeight))
return float64(sw), float64(sh)
} }
func (g *gameForUI) Update() error { func (g *gameForUI) Update() error {
@ -147,8 +159,7 @@ func (g *gameForUI) DrawOffscreen() error {
return nil return nil
} }
func (g *gameForUI) DrawFinalScreen() { func (g *gameForUI) DrawFinalScreen(scale, offsetX, offsetY float64) {
scale, offsetX, offsetY := g.ScreenScaleAndOffsets()
var geoM GeoM var geoM GeoM
geoM.Scale(scale, scale) geoM.Scale(scale, scale)
geoM.Translate(offsetX, offsetY) geoM.Translate(offsetX, offsetY)
@ -176,20 +187,3 @@ func (g *gameForUI) DrawFinalScreen() {
g.screen.DrawRectShader(w, h, g.screenShader, op) g.screen.DrawRectShader(w, h, g.screenShader, op)
} }
} }
func (g *gameForUI) ScreenScaleAndOffsets() (scale, offsetX, offsetY float64) {
if g.screen == nil {
return
}
sw, sh := g.screen.Size()
ow, oh := g.offscreen.Size()
scaleX := float64(sw) / float64(ow)
scaleY := float64(sh) / float64(oh)
scale = math.Min(scaleX, scaleY)
width := float64(ow) * scale
height := float64(oh) * scale
offsetX = (float64(sw) - width) / 2
offsetY = (float64(sh) - height) / 2
return
}

View File

@ -35,11 +35,10 @@ var (
type Game interface { type Game interface {
NewOffscreenImage(width, height int) *Image NewOffscreenImage(width, height int) *Image
NewScreenImage(width, height int) *Image NewScreenImage(width, height int) *Image
Layout(outsideWidth, outsideHeight int) (int, int) Layout(outsideWidth, outsideHeight float64) (screenWidth, screenHeight float64)
Update() error Update() error
DrawOffscreen() error DrawOffscreen() error
DrawFinalScreen() DrawFinalScreen(scale, offsetX, offsetY float64)
ScreenScaleAndOffsets() (scale, offsetX, offsetY float64)
} }
type context struct { type context struct {
@ -50,9 +49,10 @@ type context struct {
offscreen *Image offscreen *Image
screen *Image screen *Image
// The following members must be protected by the mutex m. screenWidth float64
outsideWidth float64 screenHeight float64
outsideHeight float64 offscreenWidth float64
offscreenHeight float64
isOffscreenDirty bool isOffscreenDirty bool
@ -190,7 +190,7 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, forceDraw boo
c.screen.clear() c.screen.clear()
} }
c.game.DrawFinalScreen() c.game.DrawFinalScreen(c.screenScaleAndOffsets())
// The final screen is never used as the rendering source. // The final screen is never used as the rendering source.
// Flush its buffer here just in case. // Flush its buffer here just in case.
@ -201,24 +201,21 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics, forceDraw boo
} }
func (c *context) layoutGame(outsideWidth, outsideHeight float64, deviceScaleFactor float64) (int, int) { func (c *context) layoutGame(outsideWidth, outsideHeight float64, deviceScaleFactor float64) (int, int) {
c.outsideWidth = outsideWidth owf, ohf := c.game.Layout(outsideWidth, outsideHeight)
c.outsideHeight = outsideHeight if owf <= 0 || ohf <= 0 {
// Adjust the outside size to integer values.
// Even if the original value is less than 1, the value must be a positive integer (#2340).
iow, ioh := int(outsideWidth), int(outsideHeight)
if iow == 0 {
iow = 1
}
if ioh == 0 {
ioh = 1
}
ow, oh := c.game.Layout(iow, ioh)
if ow <= 0 || oh <= 0 {
panic("ui: Layout must return positive numbers") panic("ui: Layout must return positive numbers")
} }
sw, sh := int(outsideWidth*deviceScaleFactor), int(outsideHeight*deviceScaleFactor) c.screenWidth = outsideWidth * deviceScaleFactor
c.screenHeight = outsideHeight * deviceScaleFactor
c.offscreenWidth = owf
c.offscreenHeight = ohf
sw := int(math.Ceil(c.screenWidth))
sh := int(math.Ceil(c.screenHeight))
ow := int(math.Ceil(c.offscreenWidth))
oh := int(math.Ceil(c.offscreenHeight))
if c.screen != nil { if c.screen != nil {
if c.screen.width != sw || c.screen.height != sh { if c.screen.width != sw || c.screen.height != sh {
c.screen.MarkDisposed() c.screen.MarkDisposed()
@ -246,7 +243,7 @@ func (c *context) layoutGame(outsideWidth, outsideHeight float64, deviceScaleFac
} }
func (c *context) adjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) { func (c *context) adjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64) {
s, ox, oy := c.game.ScreenScaleAndOffsets() s, ox, oy := c.screenScaleAndOffsets()
// The scale 0 indicates that the screen is not initialized yet. // The scale 0 indicates that the screen is not initialized yet.
// As any cursor values don't make sense, just return NaN. // As any cursor values don't make sense, just return NaN.
if s == 0 { if s == 0 {
@ -254,3 +251,14 @@ func (c *context) adjustPosition(x, y float64, deviceScaleFactor float64) (float
} }
return (x*deviceScaleFactor - ox) / s, (y*deviceScaleFactor - oy) / s return (x*deviceScaleFactor - ox) / s, (y*deviceScaleFactor - oy) / s
} }
func (c *context) screenScaleAndOffsets() (scale, offsetX, offsetY float64) {
scaleX := c.screenWidth / c.offscreenWidth
scaleY := c.screenHeight / c.offscreenHeight
scale = math.Min(scaleX, scaleY)
width := c.offscreenWidth * scale
height := c.offscreenHeight * scale
offsetX = (c.screenWidth - width) / 2
offsetY = (c.screenHeight - height) / 2
return
}