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