restorable: Refactoring: Use width/height instead of length at Pixels

This commit is contained in:
Hajime Hoshi 2019-07-17 23:03:14 +09:00
parent efb6f9c453
commit b4dddd330a
2 changed files with 96 additions and 80 deletions

View File

@ -28,7 +28,8 @@ import (
type Pixels struct {
pixels []byte
length int
width int
height int
// color is used only when pixels == nil
color color.RGBA
@ -36,30 +37,23 @@ type Pixels struct {
func (p *Pixels) CopyFrom(pix []byte, from int) {
if p.pixels == nil {
p.pixels = make([]byte, p.length)
p.pixels = make([]byte, 4*p.width*p.height)
}
copy(p.pixels[from:from+len(pix)], pix)
}
func (p *Pixels) At(i int) byte {
if i < 0 || p.length <= i {
panic(fmt.Sprintf("restorable: index out of range: %d for length: %d", i, p.length))
func (p *Pixels) At(i, j int) (byte, byte, byte, byte) {
if i < 0 || p.width <= i {
panic(fmt.Sprintf("restorable: index out of range: %d for the width: %d", i, p.width))
}
if j < 0 || p.height <= j {
panic(fmt.Sprintf("restorable: index out of range: %d for the height: %d", i, p.height))
}
if p.pixels != nil {
return p.pixels[i]
}
switch i % 4 {
case 0:
return p.color.R
case 1:
return p.color.G
case 2:
return p.color.B
case 3:
return p.color.A
default:
panic("not reached")
idx := 4 * (j*p.width + i)
return p.pixels[idx], p.pixels[idx+1], p.pixels[idx+2], p.pixels[idx+3]
}
return p.color.R, p.color.G, p.color.B, p.color.A
}
// drawTrianglesHistoryItem is an item for history of draw-image commands.
@ -165,7 +159,8 @@ func (i *Image) Extend(width, height int) *Image {
// Copy basePixels.
newImg.basePixels = &Pixels{
pixels: make([]byte, 4*width*height),
length: 4 * width * height,
width: width,
height: height,
}
pix := i.basePixels.pixels
idx := 0
@ -258,7 +253,8 @@ func (i *Image) fill(r, g, b, a byte) {
w, h := i.Size()
i.basePixels = &Pixels{
color: color.RGBA{r, g, b, a},
length: 4 * w * h,
width: w,
height: h,
}
i.drawTrianglesHistory = nil
i.stale = false
@ -349,7 +345,8 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
if x == 0 && y == 0 && width == w && height == h {
if i.basePixels == nil {
i.basePixels = &Pixels{
length: 4 * w * h,
width: w,
height: h,
}
}
i.basePixels.CopyFrom(pixels, 0)
@ -378,7 +375,8 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
idx := 4 * (y*w + x)
if i.basePixels == nil {
i.basePixels = &Pixels{
length: 4 * w * h,
width: w,
height: h,
}
}
for j := 0; j < height; j++ {
@ -455,8 +453,7 @@ func (i *Image) At(x, y int) (byte, byte, byte, byte) {
return 0, 0, 0, 0
}
idx := 4*x + 4*y*w
return i.basePixels.At(idx), i.basePixels.At(idx + 1), i.basePixels.At(idx + 2), i.basePixels.At(idx + 3)
return i.basePixels.At(x, y)
}
// makeStaleIfDependingOn makes the image stale if the image depends on target.
@ -471,10 +468,12 @@ func (i *Image) makeStaleIfDependingOn(target *Image) {
// readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state.
func (i *Image) readPixelsFromGPU() {
w, h := i.Size()
pix := i.image.Pixels()
i.basePixels = &Pixels{
pixels: pix,
length: len(pix),
width: w,
height: h,
}
i.drawTrianglesHistory = nil
i.stale = false
@ -578,7 +577,8 @@ func (i *Image) restore() error {
pix := gimg.Pixels()
i.basePixels = &Pixels{
pixels: pix,
length: len(pix),
width: w,
height: h,
}
}

View File

@ -45,9 +45,9 @@ func TestMain(m *testing.M) {
os.Exit(code)
}
func pixelsToColor(p *Pixels, index int) color.RGBA {
i := index * 4
return color.RGBA{p.At(i), p.At(i + 1), p.At(i + 2), p.At(i + 3)}
func pixelsToColor(p *Pixels, i, j int) color.RGBA {
r, g, b, a := p.At(i, j)
return color.RGBA{r, g, b, a}
}
func abs(x int) int {
@ -80,7 +80,7 @@ func TestRestore(t *testing.T) {
t.Fatal(err)
}
want := clr0
got := pixelsToColor(img0.BasePixelsForTesting(), 0)
got := pixelsToColor(img0.BasePixelsForTesting(), 0, 0)
if !sameColors(got, want, 1) {
t.Errorf("got %v, want %v", got, want)
}
@ -97,13 +97,15 @@ func TestRestoreWithoutDraw(t *testing.T) {
t.Fatal(err)
}
for i := 0; i < 1024*1024; i++ {
for j := 0; j < 1024; j++ {
for i := 0; i < 1024; i++ {
want := color.RGBA{0x00, 0x00, 0x00, 0x00}
got := pixelsToColor(img0.BasePixelsForTesting(), i)
got := pixelsToColor(img0.BasePixelsForTesting(), i, j)
if !sameColors(got, want, 0) {
t.Errorf("got %v, want %v", got, want)
}
}
}
}
func quadVertices(src *Image, sw, sh, x, y int) []float32 {
@ -139,7 +141,7 @@ func TestRestoreChain(t *testing.T) {
}
want := clr
for i, img := range imgs {
got := pixelsToColor(img.BasePixelsForTesting(), 0)
got := pixelsToColor(img.BasePixelsForTesting(), 0, 0)
if !sameColors(got, want, 1) {
t.Errorf("%d: got %v, want %v", i, got, want)
}
@ -186,7 +188,7 @@ func TestRestoreChain2(t *testing.T) {
if i == 8 || i == 9 {
want = clr7
}
got := pixelsToColor(img.BasePixelsForTesting(), 0)
got := pixelsToColor(img.BasePixelsForTesting(), 0, 0)
if !sameColors(got, want, 1) {
t.Errorf("%d: got %v, want %v", i, got, want)
}
@ -228,22 +230,22 @@ func TestRestoreOverrideSource(t *testing.T) {
{
"0",
clr1,
pixelsToColor(img0.BasePixelsForTesting(), 0),
pixelsToColor(img0.BasePixelsForTesting(), 0, 0),
},
{
"1",
clr1,
pixelsToColor(img1.BasePixelsForTesting(), 0),
pixelsToColor(img1.BasePixelsForTesting(), 0, 0),
},
{
"2",
clr0,
pixelsToColor(img2.BasePixelsForTesting(), 0),
pixelsToColor(img2.BasePixelsForTesting(), 0, 0),
},
{
"3",
clr0,
pixelsToColor(img3.BasePixelsForTesting(), 0),
pixelsToColor(img3.BasePixelsForTesting(), 0, 0),
},
}
for _, c := range testCases {
@ -365,7 +367,7 @@ func TestRestoreComplexGraph(t *testing.T) {
if c.out[i] == '*' {
want = color.RGBA{0xff, 0xff, 0xff, 0xff}
}
got := pixelsToColor(c.image.BasePixelsForTesting(), i)
got := pixelsToColor(c.image.BasePixelsForTesting(), i, 0)
if !sameColors(got, want, 1) {
t.Errorf("%s[%d]: got %v, want %v", c.name, i, got, want)
}
@ -426,7 +428,7 @@ func TestRestoreRecursive(t *testing.T) {
if c.out[i] == '*' {
want = color.RGBA{0xff, 0xff, 0xff, 0xff}
}
got := pixelsToColor(c.image.BasePixelsForTesting(), i)
got := pixelsToColor(c.image.BasePixelsForTesting(), i, 0)
if !sameColors(got, want, 1) {
t.Errorf("%s[%d]: got %v, want %v", c.name, i, got, want)
}
@ -543,55 +545,66 @@ func TestClear(t *testing.T) {
img.ReplacePixels(make([]byte, 4*4*4), 1, 1, 2, 2)
cases := []struct {
Index int
Want color.RGBA
i int
j int
want color.RGBA
}{
{
Index: 0,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 0,
j: 0,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 3,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 3,
j: 0,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 4,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 0,
j: 1,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 5,
Want: color.RGBA{0, 0, 0, 0},
i: 1,
j: 1,
want: color.RGBA{0, 0, 0, 0},
},
{
Index: 7,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 3,
j: 1,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 8,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 0,
j: 2,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 10,
Want: color.RGBA{0, 0, 0, 0},
i: 2,
j: 2,
want: color.RGBA{0, 0, 0, 0},
},
{
Index: 11,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 3,
j: 2,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 12,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 0,
j: 3,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
{
Index: 15,
Want: color.RGBA{0xff, 0xff, 0xff, 0xff},
i: 3,
j: 3,
want: color.RGBA{0xff, 0xff, 0xff, 0xff},
},
}
for _, c := range cases {
got := pixelsToColor(img.BasePixelsForTesting(), c.Index)
want := c.Want
got := pixelsToColor(img.BasePixelsForTesting(), c.i, c.j)
want := c.want
if got != want {
t.Errorf("base pixel [%d]: got %v, want %v", c.Index, got, want)
t.Errorf("base pixel (%d, %d): got %v, want %v", c.i, c.j, got, want)
}
}
}
@ -613,26 +626,29 @@ func TestReplacePixelsOnly(t *testing.T) {
img0.ReplacePixels([]byte{5, 6, 7, 8}, 0, 0, 1, 1)
// BasePixelsForTesting is available without GPU accessing.
for i := 0; i < w*h; i++ {
for j := 0; j < h; j++ {
for i := 0; i < w; i++ {
idx := j*w + i
var want color.RGBA
switch {
case i == 0:
case idx == 0:
want = color.RGBA{5, 6, 7, 8}
case i%5 == 0:
case idx%5 == 0:
want = color.RGBA{1, 2, 3, 4}
}
got := pixelsToColor(img0.BasePixelsForTesting(), i)
got := pixelsToColor(img0.BasePixelsForTesting(), i, j)
if !sameColors(got, want, 0) {
t.Errorf("got %v, want %v", got, want)
}
}
}
ResolveStaleImages()
if err := RestoreIfNeeded(); err != nil {
t.Fatal(err)
}
want := color.RGBA{1, 2, 3, 4}
got := pixelsToColor(img1.BasePixelsForTesting(), 0)
got := pixelsToColor(img1.BasePixelsForTesting(), 0, 0)
if !sameColors(got, want, 0) {
t.Errorf("got %v, want %v", got, want)
}