Skip to content

Commit

Permalink
internal/ui: refactoring: move the logic in gameForUI to context
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Apr 1, 2022
1 parent 9c448d2 commit 5c79178
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 151 deletions.
91 changes: 10 additions & 81 deletions gameforui.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,12 @@
package ebiten

import (
"fmt"
"math"

"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/ui"
)

type gameForUI struct {
game Game
offscreen *Image
screen *Image
}

func newGameForUI(game Game) *gameForUI {
Expand All @@ -33,90 +29,23 @@ func newGameForUI(game Game) *gameForUI {
}
}

func (c *gameForUI) Layout(outsideWidth, outsideHeight float64, deviceScaleFactor float64) (int, int) {
ow, oh := c.game.Layout(int(outsideWidth), int(outsideHeight))
if ow <= 0 || oh <= 0 {
panic("ebiten: Layout must return positive numbers")
}

sw, sh := int(outsideWidth*deviceScaleFactor), int(outsideHeight*deviceScaleFactor)
if c.screen != nil {
if w, h := c.screen.Size(); w != sw || h != sh {
c.screen.Dispose()
c.screen = nil
}
}
if c.screen == nil {
c.screen = newScreenFramebufferImage(sw, sh)
}

func (c *gameForUI) NewOffscreenImage(width, height int) *ui.Image {
if c.offscreen != nil {
if w, h := c.offscreen.Size(); w != ow || h != oh {
c.offscreen.Dispose()
c.offscreen = nil
}
}
if c.offscreen == nil {
c.offscreen = NewImage(ow, oh)

// Keep the offscreen an independent image from an atlas (#1938).
// The shader program for the screen is special and doesn't work well with an image on an atlas.
// An image on an atlas is surrounded by a transparent edge,
// and the shader program unexpectedly picks the pixel on the edges.
c.offscreen.image.SetIndependent(true)
c.offscreen.Dispose()
c.offscreen = nil
}
c.offscreen = NewImage(width, height)
return c.offscreen.image
}

return ow, oh
func (c *gameForUI) Layout(outsideWidth, outsideHeight int) (int, int) {
return c.game.Layout(outsideWidth, outsideHeight)
}

func (c *gameForUI) Update() error {
return c.game.Update()
}

func (c *gameForUI) Draw(screenScale float64, offsetX, offsetY float64, needsClearingScreen bool, framebufferYDirection graphicsdriver.YDirection, clearScreenEveryFrame, filterEnabled bool) {
c.offscreen.image.SetVolatile(clearScreenEveryFrame)

// Even though updateCount == 0, the offscreen is cleared and Draw is called.
// Draw should not update the game state and then the screen should not be updated without Update, but
// users might want to process something at Draw with the time intervals of FPS.
if clearScreenEveryFrame {
c.offscreen.Clear()
}
func (c *gameForUI) Draw() {
c.game.Draw(c.offscreen)

if needsClearingScreen {
// This clear is needed for fullscreen mode or some mobile platforms (#622).
c.screen.Clear()
}

op := &DrawImageOptions{}

s := screenScale
switch framebufferYDirection {
case graphicsdriver.Upward:
op.GeoM.Scale(s, -s)
_, h := c.offscreen.Size()
op.GeoM.Translate(0, float64(h)*s)
case graphicsdriver.Downward:
op.GeoM.Scale(s, s)
default:
panic(fmt.Sprintf("ebiten: invalid v-direction: %d", framebufferYDirection))
}

op.GeoM.Translate(offsetX, offsetY)
op.CompositeMode = CompositeModeCopy

switch {
case !filterEnabled:
op.Filter = FilterNearest
case math.Floor(s) == s:
op.Filter = FilterNearest
case s > 1:
op.Filter = filterScreen
default:
// filterScreen works with >=1 scale, but does not well with <1 scale.
// Use regular FilterLinear instead so far (#669).
op.Filter = FilterLinear
}
c.screen.DrawImage(c.offscreen, op)
}
5 changes: 0 additions & 5 deletions graphics.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ const (

// FilterLinear represents linear filter
FilterLinear Filter = Filter(graphicsdriver.FilterLinear)

// filterScreen represents a special filter for screen. Inner usage only.
//
// Some parameters like a color matrix or color vertex values can be ignored when filterScreen is used.
filterScreen Filter = Filter(graphicsdriver.FilterScreen)
)

// CompositeMode represents Porter-Duff composition mode.
Expand Down
48 changes: 11 additions & 37 deletions image.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,39 +66,22 @@ func (i *Image) Clear() {
i.Fill(color.Transparent)
}

var (
emptyImage = NewImage(3, 3)
emptySubImage = emptyImage.SubImage(image.Rect(1, 1, 2, 2)).(*Image)
)

func init() {
w, h := emptyImage.Size()
pix := make([]byte, 4*w*h)
for i := range pix {
pix[i] = 0xff
}
// As emptyImage is used at Fill, use ReplacePixels instead.
emptyImage.ReplacePixels(pix)
}

// Fill fills the image with a solid color.
//
// When the image is disposed, Fill does nothing.
func (i *Image) Fill(clr color.Color) {
// Use the original size to cover the entire region (#1691).
// DrawImage automatically clips the rendering region.
orig := i
if i.isSubImage() {
orig = i.original
}
w, h := orig.Size()

op := &DrawImageOptions{}
op.GeoM.Scale(float64(w), float64(h))
op.ColorM.ScaleWithColor(clr)
op.CompositeMode = CompositeModeCopy
i.copyCheck()

i.DrawImage(emptySubImage, op)
var crf, cgf, cbf, caf float32
cr, cg, cb, ca := clr.RGBA()
if ca != 0 {
crf = float32(cr) / float32(ca)
cgf = float32(cg) / float32(ca)
cbf = float32(cb) / float32(ca)
caf = float32(ca) / 0xffff
}
b := i.Bounds()
i.image.Fill(crf, cgf, cbf, caf, b.Min.X, b.Min.Y, b.Dx(), b.Dy())
}

func canSkipMipmap(geom GeoM, filter graphicsdriver.Filter) bool {
Expand Down Expand Up @@ -845,12 +828,3 @@ func NewImageFromImage(source image.Image) *Image {
i.ReplacePixels(imageToBytes(source))
return i
}

func newScreenFramebufferImage(width, height int) *Image {
i := &Image{
image: ui.NewScreenFramebufferImage(width, height),
bounds: image.Rect(0, 0, width, height),
}
i.addr = i
return i
}
Loading

0 comments on commit 5c79178

Please sign in to comment.