internal/rendertest: create test suit for drawing operations
Uses app/headless to create a set of test cases for drawing operations, including clipping textures and transforms. This commit tests for approximate pixel matches, if future changes affect local drawing operations it will be easy to change the reference images, it thus becomes and should be an intentional operation if changes lead to local changes in drawn results. Ideally we should be able to make the tests check for exact pixel matches down the line to ensure consistent results between platforms. Signed-off-by: Viktor <viktor.ogeman@gmail.com>
@@ -97,6 +97,29 @@ func BenchmarkDrawUI(b *testing.B) {
|
||||
finishBenchmark(b, w)
|
||||
}
|
||||
|
||||
func BenchmarkDrawUITransformed(b *testing.B) {
|
||||
// Like BenchmarkDraw UI but transformed at every frame
|
||||
gtx, w, th := setupBenchmark(b)
|
||||
drawCore(gtx, th)
|
||||
w.Frame(gtx.Ops)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
resetOps(gtx)
|
||||
|
||||
p := op.Push(gtx.Ops)
|
||||
angle := float32(math.Mod(float64(i)/1000, 0.05))
|
||||
a := f32.Affine2D{}.Shear(f32.Point{}, angle, angle).Rotate(f32.Point{}, angle)
|
||||
op.Affine(a).Add(gtx.Ops)
|
||||
|
||||
drawCore(gtx, th)
|
||||
|
||||
p.Pop()
|
||||
w.Frame(gtx.Ops)
|
||||
}
|
||||
finishBenchmark(b, w)
|
||||
}
|
||||
|
||||
func Benchmark1000Circles(b *testing.B) {
|
||||
// Benchmark1000Shapes draws 1000 individual shapes such that no caching between
|
||||
// shapes will be possible and resets buffers on each operation to prevent caching
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package rendertest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"golang.org/x/image/colornames"
|
||||
)
|
||||
|
||||
func TestPaintRect(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.Red)
|
||||
r.expect(49, 0, colornames.Red)
|
||||
r.expect(50, 0, colornames.White)
|
||||
r.expect(10, 50, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaintClippedRect(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
clip.Rect{Rect: f32.Rect(25, 25, 60, 60)}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.White)
|
||||
r.expect(24, 35, colornames.White)
|
||||
r.expect(25, 35, colornames.Red)
|
||||
r.expect(50, 0, colornames.White)
|
||||
r.expect(10, 50, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaintClippedCirle(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
r := float32(10)
|
||||
clip.Rect{Rect: f32.Rect(20, 20, 40, 40), SE: r, SW: r, NW: r, NE: r}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 30, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(21, 21, colornames.White)
|
||||
r.expect(25, 30, colornames.Red)
|
||||
r.expect(31, 30, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaintTexture(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
squares.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 80, 80)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.Blue)
|
||||
r.expect(79, 10, colornames.Green)
|
||||
r.expect(80, 0, colornames.White)
|
||||
r.expect(10, 80, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaintClippedTexture(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
squares.Add(o)
|
||||
clip.Rect{Rect: f32.Rect(0, 0, 40, 40)}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 80, 80)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(40, 40, colornames.White)
|
||||
r.expect(25, 35, colornames.Blue)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Package rendertest is intended for testing of drawing ops only.
|
||||
package rendertest
|
||||
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 546 B |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 374 B |
|
After Width: | Height: | Size: 470 B |
|
After Width: | Height: | Size: 539 B |
|
After Width: | Height: | Size: 571 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 392 B |
|
After Width: | Height: | Size: 387 B |
|
After Width: | Height: | Size: 374 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 511 B |
|
After Width: | Height: | Size: 408 B |
|
After Width: | Height: | Size: 376 B |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 864 B |
|
After Width: | Height: | Size: 375 B |
|
After Width: | Height: | Size: 384 B |
@@ -0,0 +1,144 @@
|
||||
package rendertest
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"golang.org/x/image/colornames"
|
||||
)
|
||||
|
||||
func TestTransformMacro(t *testing.T) {
|
||||
// testcase resulting from original bug when rendering layout.Stacked
|
||||
|
||||
// pre-build the text
|
||||
c := createText()
|
||||
|
||||
run(t, func(o *op.Ops) {
|
||||
|
||||
// render the first Stacked item
|
||||
m1 := op.Record(o)
|
||||
dr := f32.Rect(0, 0, 128, 50)
|
||||
paint.ColorOp{Color: colornames.Black}.Add(o)
|
||||
paint.PaintOp{Rect: dr}.Add(o)
|
||||
c1 := m1.Stop()
|
||||
|
||||
// Render the second stacked item
|
||||
m2 := op.Record(o)
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
// Simulate a draw text call
|
||||
stack := op.Push(o)
|
||||
op.TransformOp{}.Offset(f32.Pt(0, 10)).Add(o)
|
||||
|
||||
// Actually create the text clip-path
|
||||
c.Add(o)
|
||||
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(o)
|
||||
stack.Pop()
|
||||
|
||||
c2 := m2.Stop()
|
||||
|
||||
// Call each of them in a transform
|
||||
s1 := op.Push(o)
|
||||
op.TransformOp{}.Offset(f32.Pt(0, 0)).Add(o)
|
||||
c1.Add(o)
|
||||
s1.Pop()
|
||||
s2 := op.Push(o)
|
||||
op.TransformOp{}.Offset(f32.Pt(0, 0)).Add(o)
|
||||
c2.Add(o)
|
||||
s2.Pop()
|
||||
}, func(r result) {
|
||||
r.expect(5, 15, colornames.Red)
|
||||
r.expect(15, 15, colornames.Black)
|
||||
r.expect(11, 51, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepeatedPaintsZ(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
// Draw a rectangle
|
||||
paint.ColorOp{Color: colornames.Black}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 128, 50)}.Add(o)
|
||||
|
||||
builder := clip.Path{}
|
||||
builder.Begin(o)
|
||||
builder.Move(f32.Pt(0, 0))
|
||||
builder.Line(f32.Pt(10, 0))
|
||||
builder.Line(f32.Pt(0, 10))
|
||||
builder.Line(f32.Pt(-10, 0))
|
||||
builder.Line(f32.Pt(0, -10))
|
||||
builder.End().Add(o)
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(5, 5, colornames.Red)
|
||||
r.expect(11, 15, colornames.Black)
|
||||
r.expect(11, 51, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNoClipFromPaint(t *testing.T) {
|
||||
// ensure that a paint operation does not polute the state
|
||||
// by leaving any clip paths i place.
|
||||
run(t, func(o *op.Ops) {
|
||||
a := f32.Affine2D{}.Rotate(f32.Pt(20, 20), math.Pi/4)
|
||||
op.Affine(a).Add(o)
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(10, 10, 30, 30)}.Add(o)
|
||||
a = f32.Affine2D{}.Rotate(f32.Pt(20, 20), -math.Pi/4)
|
||||
op.Affine(a).Add(o)
|
||||
|
||||
paint.ColorOp{Color: colornames.Black}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(1, 1, colornames.Black)
|
||||
r.expect(20, 20, colornames.Black)
|
||||
r.expect(49, 49, colornames.Black)
|
||||
r.expect(51, 51, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func createText() op.CallOp {
|
||||
innerOps := new(op.Ops)
|
||||
m := op.Record(innerOps)
|
||||
builder := clip.Path{}
|
||||
builder.Begin(innerOps)
|
||||
builder.Move(f32.Pt(0, 0))
|
||||
builder.Line(f32.Pt(10, 0))
|
||||
builder.Line(f32.Pt(0, 10))
|
||||
builder.Line(f32.Pt(-10, 0))
|
||||
builder.Line(f32.Pt(0, -10))
|
||||
builder.End().Add(innerOps)
|
||||
return m.Stop()
|
||||
}
|
||||
|
||||
func drawChild(ops *op.Ops, text op.CallOp) op.CallOp {
|
||||
r1 := op.Record(ops)
|
||||
text.Add(ops)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(ops)
|
||||
return r1.Stop()
|
||||
}
|
||||
|
||||
func TestReuseStencil(t *testing.T) {
|
||||
txt := createText()
|
||||
run(t, func(ops *op.Ops) {
|
||||
c1 := drawChild(ops, txt)
|
||||
c2 := drawChild(ops, txt)
|
||||
|
||||
// lay out the children
|
||||
stack1 := op.Push(ops)
|
||||
c1.Add(ops)
|
||||
stack1.Pop()
|
||||
|
||||
stack2 := op.Push(ops)
|
||||
op.TransformOp{}.Offset(f32.Pt(0, 50)).Add(ops)
|
||||
c2.Add(ops)
|
||||
stack2.Pop()
|
||||
}, func(r result) {
|
||||
r.expect(5, 5, colornames.Black)
|
||||
r.expect(5, 55, colornames.Black)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package rendertest
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"golang.org/x/image/colornames"
|
||||
)
|
||||
|
||||
func TestPaintOffset(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
op.Offset(f32.Pt(10, 20)).Add(o)
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.White)
|
||||
r.expect(59, 30, colornames.Red)
|
||||
r.expect(60, 30, colornames.White)
|
||||
r.expect(10, 70, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaintRotate(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), -math.Pi/8)
|
||||
op.Affine(a).Add(o)
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(20, 20, 60, 60)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(40, 40, colornames.Red)
|
||||
r.expect(50, 19, colornames.Red)
|
||||
r.expect(59, 19, colornames.White)
|
||||
r.expect(21, 21, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPaintShear(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
a := f32.Affine2D{}.Shear(f32.Point{}, math.Pi/4, 0)
|
||||
op.Affine(a).Add(o)
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 40, 40)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(10, 30, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClipPaintOffset(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
clip.Rect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o)
|
||||
op.Offset(f32.Pt(20, 20)).Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 100, 100)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.White)
|
||||
r.expect(19, 19, colornames.White)
|
||||
r.expect(20, 20, colornames.Red)
|
||||
r.expect(30, 30, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClipOffset(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
op.Offset(f32.Pt(20, 20)).Add(o)
|
||||
clip.Rect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 100, 100)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.White)
|
||||
r.expect(29, 29, colornames.White)
|
||||
r.expect(30, 30, colornames.Red)
|
||||
r.expect(49, 49, colornames.Red)
|
||||
r.expect(50, 50, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClipScale(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
a := f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(2, 2)).Offset(f32.Pt(10, 10))
|
||||
op.Affine(a).Add(o)
|
||||
clip.Rect{Rect: f32.Rect(10, 10, 20, 20)}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 1000, 1000)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(19+10, 19+10, colornames.White)
|
||||
r.expect(20+10, 20+10, colornames.Red)
|
||||
r.expect(39+10, 39+10, colornames.Red)
|
||||
r.expect(40+10, 40+10, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClipRotate(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
op.Affine(f32.Affine2D{}.Rotate(f32.Pt(40, 40), -math.Pi/4)).Add(o)
|
||||
clip.Rect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 40, 100, 100)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(39, 39, colornames.White)
|
||||
r.expect(41, 41, colornames.Red)
|
||||
r.expect(50, 50, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOffsetTexture(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
op.Offset(f32.Pt(15, 15)).Add(o)
|
||||
squares.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(14, 20, colornames.White)
|
||||
r.expect(66, 20, colornames.White)
|
||||
r.expect(16, 64, colornames.Green)
|
||||
r.expect(64, 16, colornames.Green)
|
||||
})
|
||||
}
|
||||
|
||||
func TestOffsetScaleTexture(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
op.Offset(f32.Pt(15, 15)).Add(o)
|
||||
squares.Add(o)
|
||||
op.Affine(f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(2, 1))).Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(114, 64, colornames.Blue)
|
||||
r.expect(116, 64, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRotateTexture(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
squares.Add(o)
|
||||
a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), math.Pi/4)
|
||||
op.Affine(a).Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(30, 30, 50, 50)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(40, 40-12, colornames.Blue)
|
||||
r.expect(40+12, 40, colornames.Green)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRotateClipTexture(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
squares.Add(o)
|
||||
a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), math.Pi/8)
|
||||
op.Affine(a).Add(o)
|
||||
clip.Rect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(10, 10, 70, 70)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(0, 0, colornames.White)
|
||||
r.expect(37, 39, colornames.Green)
|
||||
r.expect(36, 39, colornames.Green)
|
||||
r.expect(35, 39, colornames.Green)
|
||||
r.expect(34, 39, colornames.Green)
|
||||
r.expect(33, 39, colornames.Green)
|
||||
})
|
||||
}
|
||||
|
||||
func TestComplicatedTransform(t *testing.T) {
|
||||
run(t, func(o *op.Ops) {
|
||||
squares.Add(o)
|
||||
|
||||
clip.Rect{Rect: f32.Rect(0, 0, 100, 100), SE: 50, SW: 50, NW: 50, NE: 50}.Add(o)
|
||||
|
||||
a := f32.Affine2D{}.Shear(f32.Point{}, math.Pi/4, 0)
|
||||
op.Affine(a).Add(o)
|
||||
clip.Rect{Rect: f32.Rect(0, 0, 50, 40)}.Add(o)
|
||||
|
||||
op.Offset(f32.Pt(-100, -100)).Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(100, 100, 150, 150)}.Add(o)
|
||||
}, func(r result) {
|
||||
r.expect(20, 5, colornames.White)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTransformOrder(t *testing.T) {
|
||||
// check the ordering of operations bot in affine and in gpu stack.
|
||||
run(t, func(o *op.Ops) {
|
||||
paint.ColorOp{Color: colornames.Red}.Add(o)
|
||||
|
||||
a := f32.Affine2D{}.Offset(f32.Pt(64, 64))
|
||||
op.Affine(a).Add(o)
|
||||
|
||||
b := f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(8, 8))
|
||||
op.Affine(b).Add(o)
|
||||
|
||||
c := f32.Affine2D{}.Offset(f32.Pt(-10, -10)).Scale(f32.Point{}, f32.Pt(0.5, 0.5))
|
||||
op.Affine(c).Add(o)
|
||||
paint.PaintOp{Rect: f32.Rect(0, 0, 20, 20)}.Add(o)
|
||||
}, func(r result) {
|
||||
// centered and with radius 40
|
||||
r.expect(64-41, 64, colornames.White)
|
||||
r.expect(64-39, 64, colornames.Red)
|
||||
r.expect(64+39, 64, colornames.Red)
|
||||
r.expect(64+41, 64, colornames.White)
|
||||
})
|
||||
}
|
||||
@@ -38,33 +38,40 @@ func init() {
|
||||
squares = paint.NewImageOp(im)
|
||||
}
|
||||
|
||||
func drawImage(size int, draw func(o *op.Ops)) (im *image.RGBA, err error) {
|
||||
func drawImage(size int, ops *op.Ops, draw func(o *op.Ops)) (im *image.RGBA, err error) {
|
||||
sz := image.Point{X: size, Y: size}
|
||||
w, err := headless.NewWindow(sz.X, sz.Y)
|
||||
if err != nil {
|
||||
return im, err
|
||||
}
|
||||
ops := new(op.Ops)
|
||||
draw(ops)
|
||||
w.Frame(ops)
|
||||
return w.Screenshot()
|
||||
}
|
||||
|
||||
func run(t *testing.T, f func(o *op.Ops)) result {
|
||||
img, err := drawImage(128, f)
|
||||
if err != nil {
|
||||
t.Error("error rendering:", err)
|
||||
func run(t *testing.T, f func(o *op.Ops), c func(r result)) {
|
||||
// draw a few times and check that it is correct each time, to
|
||||
// ensure any caching effects still generate the correct images.
|
||||
ok := true
|
||||
var img *image.RGBA
|
||||
var err error
|
||||
ops := new(op.Ops)
|
||||
for i := 0; i < 3; i++ {
|
||||
ops.Reset()
|
||||
img, err = drawImage(128, ops, f)
|
||||
if err != nil {
|
||||
t.Error("error rendering:", err)
|
||||
}
|
||||
// check for a reference image and make sure we are identical.
|
||||
ok = ok && verifyRef(t, img)
|
||||
c(result{t: t, img: img})
|
||||
}
|
||||
|
||||
// check for a reference image and make sure we are identical.
|
||||
ok := verifyRef(t, img)
|
||||
|
||||
if *dumpImages || !ok {
|
||||
if err := saveImage(t.Name()+".png", img); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
return result{t: t, img: img}
|
||||
}
|
||||
|
||||
func verifyRef(t *testing.T, img *image.RGBA) (ok bool) {
|
||||
|
||||