headless_test.go raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 package headless
4
5 import (
6 "image"
7 "image/color"
8 "testing"
9
10 "github.com/p9c/p9/pkg/gel/gio/f32"
11 "github.com/p9c/p9/pkg/gel/gio/internal/f32color"
12 "github.com/p9c/p9/pkg/gel/gio/op"
13 "github.com/p9c/p9/pkg/gel/gio/op/clip"
14 "github.com/p9c/p9/pkg/gel/gio/op/paint"
15 )
16
17 func TestHeadless(t *testing.T) {
18 w, release := newTestWindow(t)
19 defer release()
20
21 sz := w.size
22 col := color.NRGBA{A: 0xff, R: 0xca, G: 0xfe}
23 var ops op.Ops
24 paint.ColorOp{Color: col}.Add(&ops)
25 // Paint only part of the screen to avoid the glClear optimization.
26 paint.FillShape(&ops, col, clip.Rect(image.Rect(0, 0, sz.X-100, sz.Y-100)).Op())
27 if err := w.Frame(&ops); err != nil {
28 t.Fatal(err)
29 }
30
31 img, err := w.Screenshot()
32 if err != nil {
33 t.Fatal(err)
34 }
35 if isz := img.Bounds().Size(); isz != sz {
36 t.Errorf("got %v screenshot, expected %v", isz, sz)
37 }
38 if got := img.RGBAAt(0, 0); got != f32color.NRGBAToRGBA(col) {
39 t.Errorf("got color %v, expected %v", got, f32color.NRGBAToRGBA(col))
40 }
41 }
42
43 func TestClipping(t *testing.T) {
44 w, release := newTestWindow(t)
45 defer release()
46
47 col := color.NRGBA{A: 0xff, R: 0xca, G: 0xfe}
48 col2 := color.NRGBA{A: 0xff, R: 0x00, G: 0xfe}
49 var ops op.Ops
50 paint.ColorOp{Color: col}.Add(&ops)
51 clip.RRect{
52 Rect: f32.Rectangle{
53 Min: f32.Point{X: 50, Y: 50},
54 Max: f32.Point{X: 250, Y: 250},
55 },
56 SE: 75,
57 }.Add(&ops)
58 paint.PaintOp{}.Add(&ops)
59 paint.ColorOp{Color: col2}.Add(&ops)
60 clip.RRect{
61 Rect: f32.Rectangle{
62 Min: f32.Point{X: 100, Y: 100},
63 Max: f32.Point{X: 350, Y: 350},
64 },
65 NW: 75,
66 }.Add(&ops)
67 paint.PaintOp{}.Add(&ops)
68 if err := w.Frame(&ops); err != nil {
69 t.Fatal(err)
70 }
71
72 img, err := w.Screenshot()
73 if err != nil {
74 t.Fatal(err)
75 }
76 if *dumpImages {
77 if err := saveImage("clip.png", img); err != nil {
78 t.Fatal(err)
79 }
80 }
81 bg := color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}
82 tests := []struct {
83 x, y int
84 color color.NRGBA
85 }{
86 {120, 120, col},
87 {130, 130, col2},
88 {210, 210, col2},
89 {230, 230, bg},
90 }
91 for _, test := range tests {
92 if got := img.RGBAAt(test.x, test.y); got != f32color.NRGBAToRGBA(test.color) {
93 t.Errorf("(%d,%d): got color %v, expected %v", test.x, test.y, got, f32color.NRGBAToRGBA(test.color))
94 }
95 }
96 }
97
98 func TestDepth(t *testing.T) {
99 w, release := newTestWindow(t)
100 defer release()
101 var ops op.Ops
102
103 blue := color.NRGBA{B: 0xFF, A: 0xFF}
104 paint.FillShape(&ops, blue, clip.Rect(image.Rect(0, 0, 50, 100)).Op())
105 red := color.NRGBA{R: 0xFF, A: 0xFF}
106 paint.FillShape(&ops, red, clip.Rect(image.Rect(0, 0, 100, 50)).Op())
107 if err := w.Frame(&ops); err != nil {
108 t.Fatal(err)
109 }
110
111 img, err := w.Screenshot()
112 if err != nil {
113 t.Fatal(err)
114 }
115 if *dumpImages {
116 if err := saveImage("depth.png", img); err != nil {
117 t.Fatal(err)
118 }
119 }
120 tests := []struct {
121 x, y int
122 color color.NRGBA
123 }{
124 {25, 25, red},
125 {75, 25, red},
126 {25, 75, blue},
127 }
128 for _, test := range tests {
129 if got := img.RGBAAt(test.x, test.y); got != f32color.NRGBAToRGBA(test.color) {
130 t.Errorf("(%d,%d): got color %v, expected %v", test.x, test.y, got, f32color.NRGBAToRGBA(test.color))
131 }
132 }
133 }
134
135 func newTestWindow(t *testing.T) (*Window, func()) {
136 t.Helper()
137 sz := image.Point{X: 800, Y: 600}
138 w, err := NewWindow(sz.X, sz.Y)
139 if err != nil {
140 t.Skipf("headless windows not supported: %v", err)
141 }
142 return w, func() {
143 w.Release()
144 }
145 }
146