ebiten: add WritePixels replacing ReplacePixels

Closes #2236
This commit is contained in:
Hajime Hoshi 2022-08-08 03:50:25 +09:00
parent 24424d036c
commit 0217ed0544
14 changed files with 87 additions and 80 deletions

View File

@ -134,7 +134,7 @@ func (g *Game) Update() error {
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
g.renderFire() g.renderFire()
screen.ReplacePixels(g.pixels) screen.WritePixels(g.pixels)
} }
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {

View File

@ -186,7 +186,7 @@ func drawKey(t *ebiten.Image, name string, x, y, width int) {
} }
} }
} }
img.ReplacePixels(p) img.WritePixels(p)
const offset = 4 const offset = 4
text.Draw(img, name, arcadeFont, offset, arcadeFontSize+offset+1, color.White) text.Draw(img, name, arcadeFont, offset, arcadeFontSize+offset+1, color.White)

View File

@ -171,7 +171,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
g.pixels = make([]byte, screenWidth*screenHeight*4) g.pixels = make([]byte, screenWidth*screenHeight*4)
} }
g.world.Draw(g.pixels) g.world.Draw(g.pixels)
screen.ReplacePixels(g.pixels) screen.WritePixels(g.pixels)
} }
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {

View File

@ -85,7 +85,7 @@ func (gm *Game) updateOffscreen(centerX, centerY, size float64) {
gm.offscreenPix[p+3] = 0xff gm.offscreenPix[p+3] = 0xff
} }
} }
gm.offscreen.ReplacePixels(gm.offscreenPix) gm.offscreen.WritePixels(gm.offscreenPix)
} }
func (g *Game) Update() error { func (g *Game) Update() error {

View File

@ -93,7 +93,7 @@ func (g *game) Update() error {
} }
func (g *game) Draw(screen *ebiten.Image) { func (g *game) Draw(screen *ebiten.Image) {
screen.ReplacePixels(getDots(screen.Size())) screen.WritePixels(getDots(screen.Size()))
} }
func main() { func main() {

View File

@ -64,7 +64,7 @@ func (g *Game) Update() error {
} }
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
screen.ReplacePixels(g.noiseImage.Pix) screen.WritePixels(g.noiseImage.Pix)
ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.ActualTPS(), ebiten.ActualFPS())) ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.ActualTPS(), ebiten.ActualFPS()))
} }

View File

@ -86,7 +86,7 @@ func createRandomIconImage() image.Image {
} }
} }
} }
img.ReplacePixels(pix) img.WritePixels(pix)
return img return img
} }

View File

@ -922,17 +922,17 @@ func (i *Image) Dispose() {
i.setVerticesCache = nil i.setVerticesCache = nil
} }
// ReplacePixels replaces the pixels of the image. // WritePixels replaces the pixels of the image.
// //
// The given pixels are treated as RGBA pre-multiplied alpha values. // The given pixels are treated as RGBA pre-multiplied alpha values.
// //
// len(pix) must be 4 * (bounds width) * (bounds height). // len(pix) must be 4 * (bounds width) * (bounds height).
// If len(pix) is not correct, WritePixels panics. // If len(pix) is not correct, WritePixels panics.
// //
// ReplacePixels also works on a sub-image. // WritePixels also works on a sub-image.
// //
// When the image is disposed, ReplacePixels does nothing. // When the image is disposed, WritePixels does nothing.
func (i *Image) ReplacePixels(pixels []byte) { func (i *Image) WritePixels(pixels []byte) {
i.copyCheck() i.copyCheck()
if i.isDisposed() { if i.isDisposed() {
@ -949,6 +949,13 @@ func (i *Image) ReplacePixels(pixels []byte) {
i.image.WritePixels(pixels, x, y, r.Dx(), r.Dy()) i.image.WritePixels(pixels, x, y, r.Dx(), r.Dy())
} }
// ReplacePixels replaces the pixels of the image.
//
// Deprecated: as of v2.4. Use WritePixels instead.
func (i *Image) ReplacePixels(pixels []byte) {
i.WritePixels(pixels)
}
// NewImage returns an empty image. // NewImage returns an empty image.
// //
// If width or height is less than 1 or more than device-dependent maximum size, NewImage panics. // If width or height is less than 1 or more than device-dependent maximum size, NewImage panics.
@ -1023,7 +1030,7 @@ func newImage(bounds image.Rectangle, imageType atlas.ImageType) *Image {
// //
// NewImageFromImage should be called only when necessary. // NewImageFromImage should be called only when necessary.
// For example, you should avoid to call NewImageFromImage every Update or Draw call. // For example, you should avoid to call NewImageFromImage every Update or Draw call.
// Reusing the same image by Clear and ReplacePixels is much more efficient than creating a new image. // Reusing the same image by Clear and WritePixels is much more efficient than creating a new image.
// //
// NewImageFromImage panics if RunGame already finishes. // NewImageFromImage panics if RunGame already finishes.
// //
@ -1055,7 +1062,7 @@ type NewImageFromImageOptions struct {
// //
// NewImageFromImageWithOptions should be called only when necessary. // NewImageFromImageWithOptions should be called only when necessary.
// For example, you should avoid to call NewImageFromImageWithOptions every Update or Draw call. // For example, you should avoid to call NewImageFromImageWithOptions every Update or Draw call.
// Reusing the same image by Clear and ReplacePixels is much more efficient than creating a new image. // Reusing the same image by Clear and WritePixels is much more efficient than creating a new image.
// //
// NewImageFromImageWithOptions panics if RunGame already finishes. // NewImageFromImageWithOptions panics if RunGame already finishes.
func NewImageFromImageWithOptions(source image.Image, options *NewImageFromImageOptions) *Image { func NewImageFromImageWithOptions(source image.Image, options *NewImageFromImageOptions) *Image {
@ -1086,7 +1093,7 @@ func NewImageFromImageWithOptions(source image.Image, options *NewImageFromImage
return i return i
} }
i.ReplacePixels(imageToBytes(source)) i.WritePixels(imageToBytes(source))
return i return i
} }

View File

@ -261,7 +261,7 @@ func TestImageDotByDotInversion(t *testing.T) {
} }
} }
func TestImageReplacePixels(t *testing.T) { func TestImageWritePixels(t *testing.T) {
// Create a dummy image so that the shared texture is used and origImg's position is shfited. // Create a dummy image so that the shared texture is used and origImg's position is shfited.
dummyImg := ebiten.NewImageFromImage(image.NewRGBA(image.Rect(0, 0, 16, 16))) dummyImg := ebiten.NewImageFromImage(image.NewRGBA(image.Rect(0, 0, 16, 16)))
defer dummyImg.Dispose() defer dummyImg.Dispose()
@ -278,7 +278,7 @@ func TestImageReplacePixels(t *testing.T) {
size := img.Bounds().Size() size := img.Bounds().Size()
img0 := ebiten.NewImage(size.X, size.Y) img0 := ebiten.NewImage(size.X, size.Y)
img0.ReplacePixels(img.Pix) img0.WritePixels(img.Pix)
for j := 0; j < img0.Bounds().Size().Y; j++ { for j := 0; j < img0.Bounds().Size().Y; j++ {
for i := 0; i < img0.Bounds().Size().X; i++ { for i := 0; i < img0.Bounds().Size().X; i++ {
got := img0.At(i, j) got := img0.At(i, j)
@ -293,7 +293,7 @@ func TestImageReplacePixels(t *testing.T) {
for i := range p { for i := range p {
p[i] = 0x80 p[i] = 0x80
} }
img0.ReplacePixels(p) img0.WritePixels(p)
// Even if p is changed after calling ReplacePixel, img0 uses the original values. // Even if p is changed after calling ReplacePixel, img0 uses the original values.
for i := range p { for i := range p {
p[i] = 0 p[i] = 0
@ -309,16 +309,16 @@ func TestImageReplacePixels(t *testing.T) {
} }
} }
func TestImageReplacePixelsNil(t *testing.T) { func TestImageWritePixelsNil(t *testing.T) {
defer func() { defer func() {
if r := recover(); r == nil { if r := recover(); r == nil {
t.Errorf("ReplacePixels(nil) must panic") t.Errorf("WritePixels(nil) must panic")
} }
}() }()
img := ebiten.NewImage(16, 16) img := ebiten.NewImage(16, 16)
img.Fill(color.White) img.Fill(color.White)
img.ReplacePixels(nil) img.WritePixels(nil)
} }
func TestImageDispose(t *testing.T) { func TestImageDispose(t *testing.T) {
@ -486,7 +486,7 @@ func TestImageEdge(t *testing.T) {
pixels[idx+3] = 0xff pixels[idx+3] = 0xff
} }
} }
img0.ReplacePixels(pixels) img0.WritePixels(pixels)
img1 := ebiten.NewImage(img1Width, img1Height) img1 := ebiten.NewImage(img1Width, img1Height)
red := color.RGBA{0xff, 0, 0, 0xff} red := color.RGBA{0xff, 0, 0, 0xff}
transparent := color.RGBA{0, 0, 0, 0} transparent := color.RGBA{0, 0, 0, 0}
@ -638,7 +638,7 @@ func BenchmarkDrawImage(b *testing.B) {
func TestImageLinearGraduation(t *testing.T) { func TestImageLinearGraduation(t *testing.T) {
img0 := ebiten.NewImage(2, 2) img0 := ebiten.NewImage(2, 2)
img0.ReplacePixels([]byte{ img0.WritePixels([]byte{
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
@ -778,7 +778,7 @@ func Skip_TestImageSize4096(t *testing.T) {
pix[idx+2] = uint8((i + j) >> 16) pix[idx+2] = uint8((i + j) >> 16)
pix[idx+3] = 0xff pix[idx+3] = 0xff
} }
src.ReplacePixels(pix) src.WritePixels(pix)
dst.DrawImage(src, nil) dst.DrawImage(src, nil)
for i := 4095; i < 4096; i++ { for i := 4095; i < 4096; i++ {
j := 4095 j := 4095
@ -828,7 +828,7 @@ loop:
pix[4*i] = 0xff pix[4*i] = 0xff
pix[4*i+3] = 0xff pix[4*i+3] = 0xff
} }
src.ReplacePixels(pix) src.WritePixels(pix)
_, dh := dst.Size() _, dh := dst.Size()
for i := 0; i < dh; { for i := 0; i < dh; {
@ -1179,7 +1179,7 @@ func TestImageLinearFilterGlitch(t *testing.T) {
} }
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
for _, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} { for _, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} {
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
@ -1229,7 +1229,7 @@ func TestImageLinearFilterGlitch2(t *testing.T) {
idx++ idx++
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.Filter = ebiten.FilterLinear op.Filter = ebiten.FilterLinear
@ -1272,7 +1272,7 @@ func TestImageAddressRepeat(t *testing.T) {
} }
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
vs := []ebiten.Vertex{ vs := []ebiten.Vertex{
{ {
@ -1353,7 +1353,7 @@ func TestImageAddressRepeatNegativePosition(t *testing.T) {
} }
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
vs := []ebiten.Vertex{ vs := []ebiten.Vertex{
{ {
@ -1413,16 +1413,16 @@ func TestImageAddressRepeatNegativePosition(t *testing.T) {
} }
} }
func TestImageReplacePixelsAfterClear(t *testing.T) { func TestImageWritePixelsAfterClear(t *testing.T) {
const w, h = 256, 256 const w, h = 256, 256
img := ebiten.NewImage(w, h) img := ebiten.NewImage(w, h)
img.ReplacePixels(make([]byte, 4*w*h)) img.WritePixels(make([]byte, 4*w*h))
// Clear used to call DrawImage to clear the image, which was the cause of crash. It is because after // Clear used to call DrawImage to clear the image, which was the cause of crash. It is because after
// DrawImage is called, ReplacePixels for a region is forbidden. // DrawImage is called, WritePixels for a region is forbidden.
// //
// Now ReplacePixels was always called at Clear instead. // Now WritePixels was always called at Clear instead.
img.Clear() img.Clear()
img.ReplacePixels(make([]byte, 4*w*h)) img.WritePixels(make([]byte, 4*w*h))
// The test passes if this doesn't crash. // The test passes if this doesn't crash.
} }
@ -1540,7 +1540,7 @@ func TestImageAlphaOnBlack(t *testing.T) {
} }
} }
} }
src0.ReplacePixels(pix0) src0.WritePixels(pix0)
pix1 := make([]byte, 4*w*h) pix1 := make([]byte, 4*w*h)
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
@ -1558,7 +1558,7 @@ func TestImageAlphaOnBlack(t *testing.T) {
} }
} }
} }
src1.ReplacePixels(pix1) src1.WritePixels(pix1)
dst0.Fill(color.Black) dst0.Fill(color.Black)
dst1.Fill(color.Black) dst1.Fill(color.Black)
@ -1608,7 +1608,7 @@ func TestImageDrawTrianglesWithSubImage(t *testing.T) {
} }
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
vs := []ebiten.Vertex{ vs := []ebiten.Vertex{
{ {
@ -1864,7 +1864,7 @@ func TestImageDrawTrianglesAndMutateArgs(t *testing.T) {
} }
} }
func TestImageReplacePixelsOnSubImage(t *testing.T) { func TestImageWritePixelsOnSubImage(t *testing.T) {
dst := ebiten.NewImage(17, 31) dst := ebiten.NewImage(17, 31)
dst.Fill(color.RGBA{0xff, 0, 0, 0xff}) dst.Fill(color.RGBA{0xff, 0, 0, 0xff})
@ -1880,7 +1880,7 @@ func TestImageReplacePixelsOnSubImage(t *testing.T) {
} }
} }
r0 := image.Rect(4, 5, 9, 8) r0 := image.Rect(4, 5, 9, 8)
dst.SubImage(r0).(*ebiten.Image).ReplacePixels(pix0) dst.SubImage(r0).(*ebiten.Image).WritePixels(pix0)
pix1 := make([]byte, 4*5*3) pix1 := make([]byte, 4*5*3)
idx = 0 idx = 0
@ -1894,7 +1894,7 @@ func TestImageReplacePixelsOnSubImage(t *testing.T) {
} }
} }
r1 := image.Rect(11, 10, 16, 13) r1 := image.Rect(11, 10, 16, 13)
dst.SubImage(r1).(*ebiten.Image).ReplacePixels(pix1) dst.SubImage(r1).(*ebiten.Image).WritePixels(pix1)
// Clear the pixels. This should not affect the result. // Clear the pixels. This should not affect the result.
idx = 0 idx = 0
@ -2284,7 +2284,7 @@ func TestImageFloatTranslate(t *testing.T) {
pix[4*(j*w+i)+3] = 0xff pix[4*(j*w+i)+3] = 0xff
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
check(src) check(src)
}) })
@ -2297,7 +2297,7 @@ func TestImageFloatTranslate(t *testing.T) {
pix[4*(j*(w*s)+i)+3] = 0xff pix[4*(j*(w*s)+i)+3] = 0xff
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
check(src.SubImage(image.Rect(0, 0, w, h)).(*ebiten.Image)) check(src.SubImage(image.Rect(0, 0, w, h)).(*ebiten.Image))
}) })
}) })
@ -2329,7 +2329,7 @@ func TestImageColorMCopy(t *testing.T) {
} }
// TODO: Do we have to guarantee this behavior? See #1222 // TODO: Do we have to guarantee this behavior? See #1222
func TestImageReplacePixelsAndModifyPixels(t *testing.T) { func TestImageWritePixelsAndModifyPixels(t *testing.T) {
const w, h = 16, 16 const w, h = 16, 16
dst := ebiten.NewImage(w, h) dst := ebiten.NewImage(w, h)
src := ebiten.NewImage(w, h) src := ebiten.NewImage(w, h)
@ -2345,9 +2345,9 @@ func TestImageReplacePixelsAndModifyPixels(t *testing.T) {
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
// Modify pix after ReplacePixels // Modify pix after WritePixels
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
for i := 0; i < w; i++ { for i := 0; i < w; i++ {
idx := 4 * (i + j*w) idx := 4 * (i + j*w)
@ -2882,7 +2882,7 @@ func TestImageNewImageFromEbitenImage(t *testing.T) {
} }
img0 := ebiten.NewImage(w, h) img0 := ebiten.NewImage(w, h)
img0.ReplacePixels(pix) img0.WritePixels(pix)
img1 := ebiten.NewImageFromImage(img0) img1 := ebiten.NewImageFromImage(img0)
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
@ -2928,7 +2928,7 @@ func TestImageOptionsUnmanaged(t *testing.T) {
Unmanaged: true, Unmanaged: true,
} }
img := ebiten.NewImageWithOptions(image.Rect(0, 0, w, h), op) img := ebiten.NewImageWithOptions(image.Rect(0, 0, w, h), op)
img.ReplacePixels(pix) img.WritePixels(pix)
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
for i := 0; i < w; i++ { for i := 0; i < w; i++ {
@ -2941,7 +2941,7 @@ func TestImageOptionsUnmanaged(t *testing.T) {
} }
} }
func TestImageOptionsNegativeBoundsReplacePixels(t *testing.T) { func TestImageOptionsNegativeBoundsWritePixels(t *testing.T) {
const ( const (
w = 16 w = 16
h = 16 h = 16
@ -2960,7 +2960,7 @@ func TestImageOptionsNegativeBoundsReplacePixels(t *testing.T) {
const offset = -8 const offset = -8
img := ebiten.NewImageWithOptions(image.Rect(offset, offset, w+offset, h+offset), nil) img := ebiten.NewImageWithOptions(image.Rect(offset, offset, w+offset, h+offset), nil)
img.ReplacePixels(pix0) img.WritePixels(pix0)
for j := offset; j < h+offset; j++ { for j := offset; j < h+offset; j++ {
for i := offset; i < w+offset; i++ { for i := offset; i < w+offset; i++ {
@ -2985,7 +2985,7 @@ func TestImageOptionsNegativeBoundsReplacePixels(t *testing.T) {
const offset2 = -4 const offset2 = -4
sub := image.Rect(offset2, offset2, w/2+offset2, h/2+offset2) sub := image.Rect(offset2, offset2, w/2+offset2, h/2+offset2)
img.SubImage(sub).(*ebiten.Image).ReplacePixels(pix1) img.SubImage(sub).(*ebiten.Image).WritePixels(pix1)
for j := offset; j < h+offset; j++ { for j := offset; j < h+offset; j++ {
for i := offset; i < w+offset; i++ { for i := offset; i < w+offset; i++ {
got := img.At(i, j) got := img.At(i, j)
@ -3019,7 +3019,7 @@ func TestImageOptionsNegativeBoundsSet(t *testing.T) {
const offset = -8 const offset = -8
img := ebiten.NewImageWithOptions(image.Rect(offset, offset, w+offset, h+offset), nil) img := ebiten.NewImageWithOptions(image.Rect(offset, offset, w+offset, h+offset), nil)
img.ReplacePixels(pix0) img.WritePixels(pix0)
img.Set(-1, -2, color.RGBA{0, 0, 0, 0}) img.Set(-1, -2, color.RGBA{0, 0, 0, 0})
for j := offset; j < h+offset; j++ { for j := offset; j < h+offset; j++ {
@ -3048,7 +3048,7 @@ func TestImageOptionsNegativeBoundsDrawImage(t *testing.T) {
for i := range pix { for i := range pix {
pix[i] = 0xff pix[i] = 0xff
} }
src.ReplacePixels(pix) src.WritePixels(pix)
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(-1, -1) op.GeoM.Translate(-1, -1)
@ -3080,7 +3080,7 @@ func TestImageOptionsNegativeBoundsDrawTriangles(t *testing.T) {
for i := range pix { for i := range pix {
pix[i] = 0xff pix[i] = 0xff
} }
src.ReplacePixels(pix) src.WritePixels(pix)
vs := []ebiten.Vertex{ vs := []ebiten.Vertex{
{ {
DstX: -2, DstX: -2,
@ -3177,7 +3177,7 @@ func TestImageFromEbitenImageOptions(t *testing.T) {
for i := range pix { for i := range pix {
pix[i] = 0xff pix[i] = 0xff
} }
src.ReplacePixels(pix) src.WritePixels(pix)
op := &ebiten.NewImageFromImageOptions{ op := &ebiten.NewImageFromImageOptions{
PreserveBounds: true, PreserveBounds: true,

View File

@ -231,7 +231,7 @@ func TestSetAndFillBeforeMain(t *testing.T) {
} }
} }
var testSetAndReplacePixelsBeforeMainResult = func() testResult { var testSetAndWritePixelsBeforeMainResult = func() testResult {
clr := color.RGBA{1, 2, 3, 4} clr := color.RGBA{1, 2, 3, 4}
img := ebiten.NewImage(16, 16) img := ebiten.NewImage(16, 16)
img.Set(0, 0, clr) img.Set(0, 0, clr)
@ -242,7 +242,7 @@ var testSetAndReplacePixelsBeforeMainResult = func() testResult {
pix[4*i+2] = 7 pix[4*i+2] = 7
pix[4*i+3] = 8 pix[4*i+3] = 8
} }
img.ReplacePixels(pix) img.WritePixels(pix)
img.Set(1, 0, clr) img.Set(1, 0, clr)
ch := make(chan color.RGBA, 1) ch := make(chan color.RGBA, 1)
@ -258,16 +258,16 @@ var testSetAndReplacePixelsBeforeMainResult = func() testResult {
} }
}() }()
func TestSetAndReplacePixelsBeforeMain(t *testing.T) { func TestSetAndWritePixelsBeforeMain(t *testing.T) {
got := <-testSetAndReplacePixelsBeforeMainResult.got got := <-testSetAndWritePixelsBeforeMainResult.got
want := testSetAndReplacePixelsBeforeMainResult.want want := testSetAndWritePixelsBeforeMainResult.want
if got != want { if got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
} }
var testReplacePixelsAndModifyBeforeMainResult = func() testResult { var testWritePixelsAndModifyBeforeMainResult = func() testResult {
img := ebiten.NewImage(16, 16) img := ebiten.NewImage(16, 16)
pix := make([]byte, 4*16*16) pix := make([]byte, 4*16*16)
for i := 0; i < len(pix)/4; i++ { for i := 0; i < len(pix)/4; i++ {
@ -276,8 +276,8 @@ var testReplacePixelsAndModifyBeforeMainResult = func() testResult {
pix[4*i+2] = 3 pix[4*i+2] = 3
pix[4*i+3] = 4 pix[4*i+3] = 4
} }
img.ReplacePixels(pix) img.WritePixels(pix)
// After calling ReplacePixels, modifying pix must not affect the result. // After calling WritePixels, modifying pix must not affect the result.
for i := 0; i < len(pix)/4; i++ { for i := 0; i < len(pix)/4; i++ {
pix[4*i] = 5 pix[4*i] = 5
pix[4*i+1] = 6 pix[4*i+1] = 6
@ -298,13 +298,13 @@ var testReplacePixelsAndModifyBeforeMainResult = func() testResult {
} }
}() }()
func TestReplacePixelsAndModifyBeforeMain(t *testing.T) { func TestWritePixelsAndModifyBeforeMain(t *testing.T) {
got := <-testReplacePixelsAndModifyBeforeMainResult.got got := <-testWritePixelsAndModifyBeforeMainResult.got
want := testReplacePixelsAndModifyBeforeMainResult.want want := testWritePixelsAndModifyBeforeMainResult.want
if got != want { if got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
} }
// TODO: Add tests for shaders and ReplacePixels to check resolvePendingPiexles works correctly. // TODO: Add tests for shaders and WritePixels to check resolvePendingPiexles works correctly.

View File

@ -46,7 +46,7 @@ func init() {
baseImage.Fill(color.White) baseImage.Fill(color.White)
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
for i := 0; i < w; i++ { for i := 0; i < w; i++ {
baseImage.SubImage(image.Rect(i, j, i+1, j+1)).(*ebiten.Image).ReplacePixels([]byte{0, 0, 0, 0xff}) baseImage.SubImage(image.Rect(i, j, i+1, j+1)).(*ebiten.Image).WritePixels([]byte{0, 0, 0, 0xff})
} }
} }
derivedImage.DrawImage(baseImage, nil) derivedImage.DrawImage(baseImage, nil)

View File

@ -37,7 +37,7 @@
// In other words, If A.DrawImage(B, ...) is called, // In other words, If A.DrawImage(B, ...) is called,
// it can be said that the image A depends on the image B. // it can be said that the image A depends on the image B.
// //
// * Fill, ReplacePixels and Dispose // * Fill, WritePixels and Dispose
// //
// These functions are also drawing functions and the target image stores the pixel data // These functions are also drawing functions and the target image stores the pixel data
// instead of draw image history items. There is no dependency here. // instead of draw image history items. There is no dependency here.

View File

@ -287,7 +287,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
} }
} }
} }
src0.ReplacePixels(pix0) src0.WritePixels(pix0)
src0 = src0.SubImage(image.Rect(2, 3, 10, 11)).(*ebiten.Image) src0 = src0.SubImage(image.Rect(2, 3, 10, 11)).(*ebiten.Image)
src1 := ebiten.NewImage(w, h) src1 := ebiten.NewImage(w, h)
@ -302,7 +302,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
} }
} }
} }
src1.ReplacePixels(pix1) src1.WritePixels(pix1)
src1 = src1.SubImage(image.Rect(6, 8, 14, 16)).(*ebiten.Image) src1 = src1.SubImage(image.Rect(6, 8, 14, 16)).(*ebiten.Image)
testPixels := func(testname string, dst *ebiten.Image) { testPixels := func(testname string, dst *ebiten.Image) {
@ -412,7 +412,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
pix[4*(j*w+i)+3] = 0xff pix[4*(j*w+i)+3] = 0xff
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
op := &ebiten.DrawRectShaderOptions{} op := &ebiten.DrawRectShaderOptions{}
op.Images[0] = src op.Images[0] = src
@ -470,7 +470,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
pix[4*(j*w+i)+3] = 0xff pix[4*(j*w+i)+3] = 0xff
} }
} }
src.ReplacePixels(pix) src.WritePixels(pix)
op := &ebiten.DrawRectShaderOptions{} op := &ebiten.DrawRectShaderOptions{}
op.Images[0] = src op.Images[0] = src
@ -998,7 +998,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
} }
} }
} }
src0.ReplacePixels(pix0) src0.WritePixels(pix0)
src0 = src0.SubImage(image.Rect(2+offset0, 3+offset0, 10+offset0, 11+offset0)).(*ebiten.Image) src0 = src0.SubImage(image.Rect(2+offset0, 3+offset0, 10+offset0, 11+offset0)).(*ebiten.Image)
const offset1 = -6 const offset1 = -6
@ -1014,7 +1014,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
} }
} }
} }
src1.ReplacePixels(pix1) src1.WritePixels(pix1)
src1 = src1.SubImage(image.Rect(6+offset1, 8+offset1, 14+offset1, 16+offset1)).(*ebiten.Image) src1 = src1.SubImage(image.Rect(6+offset1, 8+offset1, 14+offset1, 16+offset1)).(*ebiten.Image)
const offset2 = -2 const offset2 = -2

View File

@ -170,9 +170,9 @@ var textM sync.Mutex
// //
// Draw/DrawWithOptions and CacheGlyphs are implemented like this: // Draw/DrawWithOptions and CacheGlyphs are implemented like this:
// //
// Draw = Create glyphs by `(*ebiten.Image).ReplacePixels` and put them into the cache if necessary // Draw = Create glyphs by `(*ebiten.Image).WritePixels` and put them into the cache if necessary
// + Draw them onto the destination by `(*ebiten.Image).DrawImage` // + Draw them onto the destination by `(*ebiten.Image).DrawImage`
// CacheGlyphs = Create glyphs by `(*ebiten.Image).ReplacePixels` and put them into the cache if necessary // CacheGlyphs = Create glyphs by `(*ebiten.Image).WritePixels` and put them into the cache if necessary
// //
// Be careful that the passed font face is held by this package and is never released. // Be careful that the passed font face is held by this package and is never released.
// This is a known issue (#498). // This is a known issue (#498).
@ -210,9 +210,9 @@ func Draw(dst *ebiten.Image, text string, face font.Face, x, y int, clr color.Co
// //
// Draw/DrawWithOptions and CacheGlyphs are implemented like this: // Draw/DrawWithOptions and CacheGlyphs are implemented like this:
// //
// Draw = Create glyphs by `(*ebiten.Image).ReplacePixels` and put them into the cache if necessary // Draw = Create glyphs by `(*ebiten.Image).WritePixels` and put them into the cache if necessary
// + Draw them onto the destination by `(*ebiten.Image).DrawImage` // + Draw them onto the destination by `(*ebiten.Image).DrawImage`
// CacheGlyphs = Create glyphs by `(*ebiten.Image).ReplacePixels` and put them into the cache if necessary // CacheGlyphs = Create glyphs by `(*ebiten.Image).WritePixels` and put them into the cache if necessary
// //
// Be careful that the passed font face is held by this package and is never released. // Be careful that the passed font face is held by this package and is never released.
// This is a known issue (#498). // This is a known issue (#498).
@ -327,14 +327,14 @@ func BoundString(face font.Face, text string) image.Rectangle {
// //
// Draw/DrawWithOptions and CacheGlyphs are implemented like this: // Draw/DrawWithOptions and CacheGlyphs are implemented like this:
// //
// Draw = Create glyphs by `(*ebiten.Image).ReplacePixels` and put them into the cache if necessary // Draw = Create glyphs by `(*ebiten.Image).WritePixels` and put them into the cache if necessary
// + Draw them onto the destination by `(*ebiten.Image).DrawImage` // + Draw them onto the destination by `(*ebiten.Image).DrawImage`
// CacheGlyphs = Create glyphs by `(*ebiten.Image).ReplacePixels` and put them into the cache if necessary // CacheGlyphs = Create glyphs by `(*ebiten.Image).WritePixels` and put them into the cache if necessary
// //
// Draw automatically creates and caches necessary glyphs, so usually you don't have to call CacheGlyphs // Draw automatically creates and caches necessary glyphs, so usually you don't have to call CacheGlyphs
// explicitly. However, for example, when you call Draw for each rune of one big text, Draw tries to create the glyph // explicitly. However, for example, when you call Draw for each rune of one big text, Draw tries to create the glyph
// cache and render it for each rune. This is very inefficient because creating a glyph image and rendering it are // cache and render it for each rune. This is very inefficient because creating a glyph image and rendering it are
// different operations (`(*ebiten.Image).ReplacePixels` and `(*ebiten.Image).DrawImage`) and can never be merged as // different operations (`(*ebiten.Image).WritePixels` and `(*ebiten.Image).DrawImage`) and can never be merged as
// one draw call. CacheGlyphs creates necessary glyphs without rendering them so that these operations are likely // one draw call. CacheGlyphs creates necessary glyphs without rendering them so that these operations are likely
// merged into one draw call regardless of the size of the text. // merged into one draw call regardless of the size of the text.
// //