mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 19:28:57 +01:00
restorable: Bug fix: Do not include emptyImage into the dependency graph
Instead, add baseColor to Pixels and use it when restoring. Fixes #928.
This commit is contained in:
parent
76330c492c
commit
22c31da6c1
@ -25,11 +25,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Pixels struct {
|
type Pixels struct {
|
||||||
|
baseColor color.RGBA
|
||||||
rectToPixels *rectToPixels
|
rectToPixels *rectToPixels
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply applies the Pixels state to the given image especially for restoring.
|
// Apply applies the Pixels state to the given image especially for restoring.
|
||||||
func (p *Pixels) Apply(img *graphicscommand.Image) {
|
func (p *Pixels) Apply(img *graphicscommand.Image) {
|
||||||
|
// Pixels doesn't clear the image. This is a caller's responsibility.
|
||||||
|
if p.baseColor != (color.RGBA{}) {
|
||||||
|
fillImage(img, p.baseColor)
|
||||||
|
}
|
||||||
|
|
||||||
if p.rectToPixels == nil {
|
if p.rectToPixels == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -58,7 +64,7 @@ func (p *Pixels) At(i, j int) (byte, byte, byte, byte) {
|
|||||||
return r, g, b, a
|
return r, g, b, a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0, 0, 0, 0
|
return p.baseColor.R, p.baseColor.G, p.baseColor.B, p.baseColor.A
|
||||||
}
|
}
|
||||||
|
|
||||||
// drawTrianglesHistoryItem is an item for history of draw-image commands.
|
// drawTrianglesHistoryItem is an item for history of draw-image commands.
|
||||||
@ -163,6 +169,9 @@ func (i *Image) Extend(width, height int) *Image {
|
|||||||
newImg := NewImage(width, height)
|
newImg := NewImage(width, height)
|
||||||
i.basePixels.Apply(newImg.image)
|
i.basePixels.Apply(newImg.image)
|
||||||
|
|
||||||
|
if i.basePixels.baseColor != (color.RGBA{}) {
|
||||||
|
panic("restorable: baseColor must be empty at Extend")
|
||||||
|
}
|
||||||
newImg.basePixels = i.basePixels
|
newImg.basePixels = i.basePixels
|
||||||
|
|
||||||
i.Dispose()
|
i.Dispose()
|
||||||
@ -233,20 +242,29 @@ func (i *Image) clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill fills the specified part of the image with a solid color.
|
// Fill fills the specified part of the image with a solid color.
|
||||||
func (i *Image) Fill(clr color.Color, x, y, width, height int) {
|
func (i *Image) Fill(clr color.Color) {
|
||||||
// If all the pixels will be changed, reset the information for restoring.
|
i.basePixels = Pixels{
|
||||||
if w, h := i.Size(); x == 0 && y == 0 && width == w && height == h {
|
baseColor: color.RGBAModel.Convert(clr).(color.RGBA),
|
||||||
i.basePixels = Pixels{}
|
}
|
||||||
i.drawTrianglesHistory = nil
|
i.drawTrianglesHistory = nil
|
||||||
i.stale = false
|
i.stale = false
|
||||||
|
|
||||||
|
// Do not call i.DrawTriangles as emptyImage is special (#928).
|
||||||
|
// baseColor is updated instead.
|
||||||
|
fillImage(i.image, i.basePixels.baseColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillImage(i *graphicscommand.Image, clr color.RGBA) {
|
||||||
|
if i == emptyImage.image {
|
||||||
|
panic("restorable: fillImage cannot be called on emptyImage")
|
||||||
}
|
}
|
||||||
|
|
||||||
var rf, gf, bf, af float32
|
var rf, gf, bf, af float32
|
||||||
if r, g, b, a := clr.RGBA(); a > 0 {
|
if clr.A > 0 {
|
||||||
rf = float32(r) / float32(a)
|
rf = float32(clr.R) / float32(clr.A)
|
||||||
gf = float32(g) / float32(a)
|
gf = float32(clr.G) / float32(clr.A)
|
||||||
bf = float32(b) / float32(a)
|
bf = float32(clr.B) / float32(clr.A)
|
||||||
af = float32(a) / 0xffff
|
af = float32(clr.A) / 0xff
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use the previous composite mode if possible.
|
// TODO: Use the previous composite mode if possible.
|
||||||
@ -255,15 +273,16 @@ func (i *Image) Fill(clr color.Color, x, y, width, height int) {
|
|||||||
compositemode = driver.CompositeModeCopy
|
compositemode = driver.CompositeModeCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
dw, dh := width, height
|
// TODO: Integrate with clearColor
|
||||||
|
dw, dh := i.InternalSize()
|
||||||
sw, sh := emptyImage.Size()
|
sw, sh := emptyImage.Size()
|
||||||
vs := make([]float32, 4*graphics.VertexFloatNum)
|
vs := make([]float32, 4*graphics.VertexFloatNum)
|
||||||
graphics.PutQuadVertices(vs, emptyImage, 0, 0, sw, sh,
|
graphics.PutQuadVertices(vs, emptyImage, 0, 0, sw, sh,
|
||||||
float32(dw)/float32(sw), 0, 0, float32(dh)/float32(sh), float32(x), float32(y),
|
float32(dw)/float32(sw), 0, 0, float32(dh)/float32(sh), 0, 0,
|
||||||
rf, gf, bf, af)
|
rf, gf, bf, af)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
|
|
||||||
i.DrawTriangles(emptyImage, vs, is, nil, compositemode, driver.FilterNearest, driver.AddressClampToZero)
|
i.DrawTriangles(emptyImage.image, vs, is, nil, compositemode, driver.FilterNearest, driver.AddressClampToZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) IsVolatile() bool {
|
func (i *Image) IsVolatile() bool {
|
||||||
|
@ -760,3 +760,23 @@ func TestClearPixels(t *testing.T) {
|
|||||||
// After clearing, the regions will be available again.
|
// After clearing, the regions will be available again.
|
||||||
img.ReplacePixels(make([]byte, 4*8*4), 0, 0, 8, 4)
|
img.ReplacePixels(make([]byte, 4*8*4), 0, 0, 8, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFill(t *testing.T) {
|
||||||
|
const w, h = 16, 16
|
||||||
|
img := NewImage(w, h)
|
||||||
|
img.Fill(color.RGBA{0xff, 0, 0, 0xff})
|
||||||
|
ResolveStaleImages()
|
||||||
|
if err := RestoreIfNeeded(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for j := 0; j < h; j++ {
|
||||||
|
for i := 0; i < w; i++ {
|
||||||
|
r, g, b, a := img.At(i, j)
|
||||||
|
got := color.RGBA{r, g, b, a}
|
||||||
|
want := color.RGBA{0xff, 0, 0, 0xff}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("img.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -332,8 +332,8 @@ func (i *Image) Fill(clr color.Color) {
|
|||||||
|
|
||||||
i.ensureNotShared()
|
i.ensureNotShared()
|
||||||
|
|
||||||
x, y, width, height := i.region()
|
// As *restorable.Image is an independent image, it is fine to fill the entire image.
|
||||||
i.backend.restorable.Fill(clr, x, y, width, height)
|
i.backend.restorable.Fill(clr)
|
||||||
|
|
||||||
i.nonUpdatedCount = 0
|
i.nonUpdatedCount = 0
|
||||||
delete(imagesToMakeShared, i)
|
delete(imagesToMakeShared, i)
|
||||||
|
Loading…
Reference in New Issue
Block a user