graphics: Implement Image.Fill with DrawImage

This commit is contained in:
Hajime Hoshi 2018-02-23 23:58:17 +09:00
parent 3736fd3cfc
commit 556b2ec31b
2 changed files with 57 additions and 17 deletions

View File

@ -75,18 +75,6 @@ func (c *graphicsContext) initializeIfNeeded() error {
return nil return nil
} }
func drawWithFittingScale(dst *Image, src *Image, filter Filter) {
wd, hd := dst.Size()
ws, hs := src.Size()
sw := float64(wd) / float64(ws)
sh := float64(hd) / float64(hs)
op := &DrawImageOptions{}
op.GeoM.Scale(sw, sh)
op.CompositeMode = CompositeModeCopy
op.Filter = filter
_ = dst.DrawImage(src, op)
}
func (c *graphicsContext) Update(afterFrameUpdate func()) error { func (c *graphicsContext) Update(afterFrameUpdate func()) error {
updateCount := clock.Update() updateCount := clock.Update()
@ -105,7 +93,7 @@ func (c *graphicsContext) Update(afterFrameUpdate func()) error {
afterFrameUpdate() afterFrameUpdate()
} }
if 0 < updateCount { if 0 < updateCount {
drawWithFittingScale(c.screen, c.offscreen, filterScreen) drawWithFittingScale(c.screen, c.offscreen, nil, filterScreen)
} }
if err := restorable.ResolveStaleImages(); err != nil { if err := restorable.ResolveStaleImages(); err != nil {

View File

@ -26,6 +26,36 @@ import (
"github.com/hajimehoshi/ebiten/internal/restorable" "github.com/hajimehoshi/ebiten/internal/restorable"
) )
// 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() {
const (
w = 16
h = 16
)
emptyImage = newImageWithoutInit(w, h)
pix := make([]uint8, w*h*4)
_ = emptyImage.ReplacePixels(pix)
}
func drawWithFittingScale(dst *Image, src *Image, colorM *ColorM, filter Filter) {
wd, hd := dst.Size()
ws, hs := src.Size()
sw := float64(wd) / float64(ws)
sh := float64(hd) / float64(hs)
op := &DrawImageOptions{}
op.GeoM.Scale(sw, sh)
if colorM != nil {
op.ColorM = *colorM
}
op.CompositeMode = CompositeModeCopy
op.Filter = filter
_ = dst.DrawImage(src, op)
}
// Image represents a rectangle set of pixels. // Image represents a rectangle set of pixels.
// The pixel format is alpha-premultiplied RGBA. // The pixel format is alpha-premultiplied RGBA.
// Image implements image.Image. // Image implements image.Image.
@ -47,7 +77,7 @@ func (i *Image) Size() (width, height int) {
// //
// Clear always returns nil as of 1.5.0-alpha. // Clear always returns nil as of 1.5.0-alpha.
func (i *Image) Clear() error { func (i *Image) Clear() error {
i.restorable.Fill(0, 0, 0, 0) i.fill(0, 0, 0, 0)
return nil return nil
} }
@ -58,10 +88,23 @@ func (i *Image) Clear() error {
// Fill always returns nil as of 1.5.0-alpha. // Fill always returns nil as of 1.5.0-alpha.
func (i *Image) Fill(clr color.Color) error { func (i *Image) Fill(clr color.Color) error {
r, g, b, a := clr.RGBA() r, g, b, a := clr.RGBA()
i.restorable.Fill(uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8)) i.fill(uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8))
return nil return nil
} }
func (i *Image) fill(r, g, b, a uint8) {
var c *ColorM
if a > 0 {
c = &ColorM{}
rf := float64(r) / float64(a)
gf := float64(g) / float64(a)
bf := float64(b) / float64(a)
af := float64(a) / 0xff
c.Translate(rf, gf, bf, af)
}
drawWithFittingScale(i, emptyImage, c, FilterNearest)
}
// DrawImage draws the given image on the image i. // DrawImage draws the given image on the image i.
// //
// DrawImage accepts the options. For details, see the document of DrawImageOptions. // DrawImage accepts the options. For details, see the document of DrawImageOptions.
@ -283,12 +326,21 @@ type DrawImageOptions struct {
func NewImage(width, height int, filter Filter) (*Image, error) { func NewImage(width, height int, filter Filter) (*Image, error) {
checkSize(width, height) checkSize(width, height)
r := restorable.NewImage(width, height, false) r := restorable.NewImage(width, height, false)
r.Fill(0, 0, 0, 0)
i := &Image{r, filter} i := &Image{r, filter}
i.fill(0, 0, 0, 0)
runtime.SetFinalizer(i, (*Image).Dispose) runtime.SetFinalizer(i, (*Image).Dispose)
return i, nil return i, nil
} }
// newImageWithoutInit creates an empty image without initialization.
func newImageWithoutInit(width, height int) *Image {
checkSize(width, height)
r := restorable.NewImage(width, height, false)
i := &Image{r, FilterDefault}
runtime.SetFinalizer(i, (*Image).Dispose)
return i
}
// newVolatileImage returns an empty 'volatile' image. // newVolatileImage returns an empty 'volatile' image.
// A volatile image is always cleared at the start of a frame. // A volatile image is always cleared at the start of a frame.
// //
@ -307,8 +359,8 @@ func NewImage(width, height int, filter Filter) (*Image, error) {
func newVolatileImage(width, height int, filter Filter) *Image { func newVolatileImage(width, height int, filter Filter) *Image {
checkSize(width, height) checkSize(width, height)
r := restorable.NewImage(width, height, true) r := restorable.NewImage(width, height, true)
r.Fill(0, 0, 0, 0)
i := &Image{r, filter} i := &Image{r, filter}
i.fill(0, 0, 0, 0)
runtime.SetFinalizer(i, (*Image).Dispose) runtime.SetFinalizer(i, (*Image).Dispose)
return i return i
} }