shareable: Add Fill

Before introducing Fill, filling an image with a solid color was
implemented by ReplacePixels. When an offscreen image is used, the
offscreen image is not fully cleared or filled with a color and
out of (0,0)-(width,height) region. This causes a glitch thin line
on mobile platforms.

This change adds (*shareable.Image).Fill to fill the whole
framebuffer region of the image.
This commit is contained in:
Hajime Hoshi 2019-01-13 02:09:51 +09:00
parent d5e6e6893e
commit 1e1f309a1c
3 changed files with 36 additions and 47 deletions

View File

@ -112,16 +112,9 @@ func (c *graphicsContext) Update(afterFrameUpdate func()) error {
afterFrameUpdate()
}
// Clear the screen framebuffer by DrawImage instad of Fill
// to clear the whole region including fullscreen's padding.
// TODO: This clear is needed only when the screen size is changed.
if c.offsetX > 0 || c.offsetY > 0 {
op := &DrawImageOptions{}
w, h := emptyImage.Size()
sw, sh := c.screen.Size()
op.GeoM.Scale(float64(sw)/float64(w), float64(sh)/float64(h))
op.CompositeMode = CompositeModeCopy
c.screen.DrawImage(emptyImage, op)
c.screen.Clear()
}
op := &DrawImageOptions{}

View File

@ -25,15 +25,6 @@ import (
"github.com/hajimehoshi/ebiten/internal/shareable"
)
// emptyImage is an empty image used for filling other images with a uniform color.
//
// Do not call Fill or Clear on emptyImage or the program causes infinite recursion.
var emptyImage *Image
func init() {
emptyImage, _ = NewImage(16, 16, FilterDefault)
}
type mipmap struct {
orig *shareable.Image
imgs map[image.Rectangle][]*shareable.Image
@ -191,36 +182,8 @@ func (i *Image) Fill(clr color.Color) error {
r16, g16, b16, a16 := clr.RGBA()
r, g, b, a := uint8(r16>>8), uint8(g16>>8), uint8(b16>>8), uint8(a16>>8)
wd, hd := i.Size()
if wd*hd <= 256 {
// Prefer ReplacePixels since ReplacePixels can keep the images shared.
pix := make([]uint8, 4*wd*hd)
for i := 0; i < wd*hd; i++ {
pix[4*i] = r
pix[4*i+1] = g
pix[4*i+2] = b
pix[4*i+3] = a
}
i.ReplacePixels(pix)
return nil
}
ws, hs := emptyImage.Size()
sw := float64(wd) / float64(ws)
sh := float64(hd) / float64(hs)
op := &DrawImageOptions{}
op.GeoM.Scale(sw, sh)
if a > 0 {
rf := float64(r) / float64(a)
gf := float64(g) / float64(a)
bf := float64(b) / float64(a)
af := float64(a) / 0xff
op.ColorM.Translate(rf, gf, bf, af)
}
op.CompositeMode = CompositeModeCopy
op.Filter = FilterNearest
i.drawImage(emptyImage, op)
i.mipmap.original().Fill(r, g, b, a)
i.disposeMipmaps()
return nil
}

View File

@ -256,6 +256,39 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colo
// }
}
// emptyImage is an empty image used for filling other images with a uniform color.
//
// Do not call Fill on emptyImage or the program causes infinite recursion.
var emptyImage = NewImage(16, 16)
// Fill fills the image with a color. This affects not only the (0, 0)-(width, height) region but also the whole
// framebuffer region.
func (i *Image) Fill(r, g, b, a uint8) {
backendsM.Lock()
if i.disposed {
panic("shareable: the drawing target image must not be disposed")
}
i.ensureNotShared()
backendsM.Unlock()
dw, dh := i.backend.restorable.SizePowerOf2()
sw, sh := emptyImage.Size()
vs := emptyImage.QuadVertices(0, 0, sw, sh,
float32(dw)/float32(sw), 0, 0, float32(dh)/float32(sh), 0, 0,
1, 1, 1, 1)
is := graphics.QuadIndices()
var colorm *affine.ColorM
if a > 0 {
rf := float32(r) / float32(a)
gf := float32(g) / float32(a)
bf := float32(b) / float32(a)
af := float32(a) / 0xff
colorm = colorm.Translate(rf, gf, bf, af)
}
i.DrawImage(emptyImage, vs, is, colorm, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
}
func (i *Image) ReplacePixels(p []byte) {
backendsM.Lock()
defer backendsM.Unlock()