diff --git a/internal/atlas/image.go b/internal/atlas/image.go index a940949ae..eb0225983 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -572,29 +572,32 @@ func (i *Image) replacePixels(pix []byte, x, y, width, height int) { i.backend.restorable.ReplacePixels(pixb, x, y, pw, ph) } -func (img *Image) Pixels(graphicsDriver graphicsdriver.Graphics) ([]byte, error) { +func (img *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte) error { backendsM.Lock() defer backendsM.Unlock() x := img.paddingSize() y := img.paddingSize() - bs := make([]byte, 4*img.width*img.height) + if got, want := len(pixels), 4*img.width*img.height; got != want { + return fmt.Errorf("atlas: len(pixels) must be %d but %d", want, got) + } + idx := 0 for j := y; j < y+img.height; j++ { for i := x; i < x+img.width; i++ { r, g, b, a, err := img.at(graphicsDriver, i, j) if err != nil { - return nil, err + return err } - bs[4*idx] = r - bs[4*idx+1] = g - bs[4*idx+2] = b - bs[4*idx+3] = a + pixels[4*idx] = r + pixels[4*idx+1] = g + pixels[4*idx+2] = b + pixels[4*idx+3] = a idx++ } } - return bs, nil + return nil } func (i *Image) at(graphicsDriver graphicsdriver.Graphics, x, y int) (byte, byte, byte, byte, error) { diff --git a/internal/atlas/image_test.go b/internal/atlas/image_test.go index 5798d7515..d27220f99 100644 --- a/internal/atlas/image_test.go +++ b/internal/atlas/image_test.go @@ -125,8 +125,8 @@ func TestEnsureIsolated(t *testing.T) { t.Errorf("got: %v, want: %v", got, want) } - pix, err := img4.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*size*size) + if err := img4.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < size; j++ { @@ -217,8 +217,8 @@ func TestReputOnAtlas(t *testing.T) { t.Fatal(err) } - pix, err := img1.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*size*size) + if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < size; j++ { @@ -241,8 +241,8 @@ func TestReputOnAtlas(t *testing.T) { t.Errorf("got: %v, want: %v", got, want) } - pix, err = img1.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*size*size) + if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < size; j++ { @@ -329,8 +329,8 @@ func TestExtend(t *testing.T) { // Ensure to allocate img1.ReplacePixels(p1, 0, 0, w1, h1) - pix0, err := img0.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix0 := make([]byte, 4*w0*h0) + if err := img0.ReadPixels(ui.GraphicsDriverForTesting(), pix0); err != nil { t.Fatal(err) } for j := 0; j < h0; j++ { @@ -348,8 +348,8 @@ func TestExtend(t *testing.T) { } } - pix1, err := img1.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix1 := make([]byte, 4*w1*h1) + if err := img1.ReadPixels(ui.GraphicsDriverForTesting(), pix1); err != nil { t.Fatal(err) } for j := 0; j < h1; j++ { @@ -395,8 +395,8 @@ func TestReplacePixelsAfterDrawTriangles(t *testing.T) { dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) dst.ReplacePixels(pix, 0, 0, w, h) - pix, err := dst.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*w*h) + if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < h; j++ { @@ -442,8 +442,8 @@ func TestSmallImages(t *testing.T) { } dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) - pix, err := dst.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*w*h) + if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < h; j++ { @@ -490,8 +490,8 @@ func TestLongImages(t *testing.T) { } dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) - pix, err := dst.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*dstW*dstH) + if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < h; j++ { @@ -717,8 +717,8 @@ func TestImageReplacePixelsModify(t *testing.T) { } // Check the pixels are the original ones. - pix, err := img.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix = make([]byte, 4*size*size) + if err := img.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Fatal(err) } for j := 0; j < size; j++ { diff --git a/internal/atlas/shader_test.go b/internal/atlas/shader_test.go index 87d3676c9..ed7a954fd 100644 --- a/internal/atlas/shader_test.go +++ b/internal/atlas/shader_test.go @@ -48,8 +48,8 @@ func TestShaderFillTwice(t *testing.T) { s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff)) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s1, nil, false) - pix, err := dst.Pixels(g) - if err != nil { + pix := make([]byte, 4*w*h) + if err := dst.ReadPixels(g, pix); err != nil { t.Error(err) } if got, want := (color.RGBA{pix[0], pix[1], pix[2], pix[3]}), (color.RGBA{0x80, 0x80, 0x80, 0xff}); got != want { @@ -80,8 +80,8 @@ func TestImageDrawTwice(t *testing.T) { vs = quadVertices(w, h, 0, 0, 1) dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) - pix, err := dst.Pixels(ui.GraphicsDriverForTesting()) - if err != nil { + pix := make([]byte, 4*w*h) + if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { t.Error(err) } if got, want := (color.RGBA{pix[0], pix[1], pix[2], pix[3]}), (color.RGBA{0x80, 0x80, 0x80, 0xff}); got != want { diff --git a/internal/buffered/image.go b/internal/buffered/image.go index 75b4fefd7..740f485d5 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -80,20 +80,20 @@ func (i *Image) MarkDisposed() { i.img.MarkDisposed() } -func (img *Image) At(graphicsDriver graphicsdriver.Graphics, x, y int) (r, g, b, a byte, err error) { +func (i *Image) At(graphicsDriver graphicsdriver.Graphics, x, y int) (r, g, b, a byte, err error) { checkDelayedCommandsFlushed("At") - idx := (y*img.width + x) - if img.pixels != nil { - return img.pixels[4*idx], img.pixels[4*idx+1], img.pixels[4*idx+2], img.pixels[4*idx+3], nil + idx := (y*i.width + x) + if i.pixels != nil { + return i.pixels[4*idx], i.pixels[4*idx+1], i.pixels[4*idx+2], i.pixels[4*idx+3], nil } - pix, err := img.img.Pixels(graphicsDriver) - if err != nil { + pix := make([]byte, 4*i.width*i.height) + if err := i.img.ReadPixels(graphicsDriver, pix); err != nil { return 0, 0, 0, 0, err } - img.pixels = pix - return img.pixels[4*idx], img.pixels[4*idx+1], img.pixels[4*idx+2], img.pixels[4*idx+3], nil + i.pixels = pix + return i.pixels[4*idx], i.pixels[4*idx+1], i.pixels[4*idx+2], i.pixels[4*idx+3], nil } func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) error {