gpu: add linear gradient

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
This commit is contained in:
Egon Elbre
2020-11-01 21:21:19 +02:00
committed by Elias Naur
parent 0641a34b24
commit f00f3a3359
10 changed files with 452 additions and 71 deletions
+5 -1
View File
@@ -70,7 +70,7 @@ func generate() error {
if ext := filepath.Ext(shader); ext != ".vert" && ext != ".frag" {
continue
}
const nvariants = 2
const nvariants = 3
var variants [nvariants]struct {
backend.ShaderSources
hlslSrc string
@@ -80,6 +80,10 @@ func generate() error {
FetchColorExpr: `_color`,
Header: `layout(binding=0) uniform Color { vec4 _color; };`,
},
{
FetchColorExpr: `mix(_color1, _color2, clamp(vUV.x, 0.0, 1.0))`,
Header: `layout(binding=0) uniform Gradient { vec4 _color1; vec4 _color2; };`,
},
{
FetchColorExpr: `texture(tex, vUV)`,
Header: `layout(binding=0) uniform sampler2D tex;`,
+21 -18
View File
@@ -16,6 +16,7 @@ const (
TypeImage
TypePaint
TypeColor
TypeLinearGradient
TypeArea
TypePointerInput
TypePass
@@ -29,24 +30,25 @@ const (
)
const (
TypeMacroLen = 1 + 4 + 4
TypeCallLen = 1 + 4 + 4
TypeTransformLen = 1 + 4*6
TypeLayerLen = 1
TypeRedrawLen = 1 + 8
TypeImageLen = 1 + 4*4
TypePaintLen = 1 + 4*4
TypeColorLen = 1 + 4
TypeAreaLen = 1 + 1 + 4*4
TypePointerInputLen = 1 + 1 + 1
TypePassLen = 1 + 1
TypeKeyInputLen = 1 + 1
TypeHideInputLen = 1
TypePushLen = 1
TypePopLen = 1
TypeAuxLen = 1
TypeClipLen = 1 + 4*4
TypeProfileLen = 1
TypeMacroLen = 1 + 4 + 4
TypeCallLen = 1 + 4 + 4
TypeTransformLen = 1 + 4*6
TypeLayerLen = 1
TypeRedrawLen = 1 + 8
TypeImageLen = 1 + 4*4
TypePaintLen = 1 + 4*4
TypeColorLen = 1 + 4
TypeLinearGradientLen = 1 + 8*2 + 4*2
TypeAreaLen = 1 + 1 + 4*4
TypePointerInputLen = 1 + 1 + 1
TypePassLen = 1 + 1
TypeKeyInputLen = 1 + 1
TypeHideInputLen = 1
TypePushLen = 1
TypePopLen = 1
TypeAuxLen = 1
TypeClipLen = 1 + 4*4
TypeProfileLen = 1
)
func (t OpType) Size() int {
@@ -59,6 +61,7 @@ func (t OpType) Size() int {
TypeImageLen,
TypePaintLen,
TypeColorLen,
TypeLinearGradientLen,
TypeAreaLen,
TypePointerInputLen,
TypePassLen,
Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+94
View File
@@ -1,10 +1,12 @@
package rendertest
import (
"image/color"
"math"
"testing"
"gioui.org/f32"
"gioui.org/internal/f32color"
"gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint"
@@ -194,3 +196,95 @@ func TestNegativeOverlaps(t *testing.T) {
r.expect(60, 122, colornames.White)
})
}
type Gradient struct {
From, To color.RGBA
}
var gradients = []Gradient{
{From: color.RGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xFF}, To: color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}},
{From: color.RGBA{R: 0x19, G: 0xFF, B: 0x19, A: 0xFF}, To: color.RGBA{R: 0xFF, G: 0x19, B: 0x19, A: 0xFF}},
{From: color.RGBA{R: 0xFF, G: 0x19, B: 0x19, A: 0xFF}, To: color.RGBA{R: 0x19, G: 0x19, B: 0xFF, A: 0xFF}},
{From: color.RGBA{R: 0x19, G: 0x19, B: 0xFF, A: 0xFF}, To: color.RGBA{R: 0x19, G: 0xFF, B: 0x19, A: 0xFF}},
{From: color.RGBA{R: 0x19, G: 0xFF, B: 0xFF, A: 0xFF}, To: color.RGBA{R: 0xFF, G: 0x19, B: 0x19, A: 0xFF}},
{From: color.RGBA{R: 0xFF, G: 0xFF, B: 0x19, A: 0xFF}, To: color.RGBA{R: 0x19, G: 0x19, B: 0xFF, A: 0xFF}},
}
func TestLinearGradient(t *testing.T) {
const gradienth = 8
// 0.5 offset from ends to ensure that the center of the pixel
// aligns with gradient from and to colors.
pixelAligned := f32.Rect(0.5, 0, 127.5, gradienth)
samples := []int{0, 12, 32, 64, 96, 115, 127}
run(t, func(ops *op.Ops) {
gr := pixelAligned
for _, g := range gradients {
paint.LinearGradientOp{
Stop1: f32.Pt(gr.Min.X, gr.Min.Y),
Color1: g.From,
Stop2: f32.Pt(gr.Max.X, gr.Min.Y),
Color2: g.To,
}.Add(ops)
paint.PaintOp{Rect: gr}.Add(ops)
gr = gr.Add(f32.Pt(0, gradienth))
}
}, func(r result) {
gr := pixelAligned
for _, g := range gradients {
from := f32color.RGBAFromSRGB(g.From)
to := f32color.RGBAFromSRGB(g.To)
for _, p := range samples {
exp := lerp(from, to, float32(p)/float32(r.img.Bounds().Dx()-1))
r.expect(p, int(gr.Min.Y+gradienth/2), exp.SRGB())
}
gr = gr.Add(f32.Pt(0, gradienth))
}
})
}
func TestLinearGradientAngled(t *testing.T) {
run(t, func(ops *op.Ops) {
paint.LinearGradientOp{
Stop1: f32.Pt(64, 64),
Color1: colornames.Black,
Stop2: f32.Pt(0, 0),
Color2: colornames.Red,
}.Add(ops)
paint.PaintOp{Rect: f32.Rect(0, 0, 64, 64)}.Add(ops)
paint.LinearGradientOp{
Stop1: f32.Pt(64, 64),
Color1: colornames.White,
Stop2: f32.Pt(128, 0),
Color2: colornames.Green,
}.Add(ops)
paint.PaintOp{Rect: f32.Rect(64, 0, 128, 64)}.Add(ops)
paint.LinearGradientOp{
Stop1: f32.Pt(64, 64),
Color1: colornames.Black,
Stop2: f32.Pt(128, 128),
Color2: colornames.Blue,
}.Add(ops)
paint.PaintOp{Rect: f32.Rect(64, 64, 128, 128)}.Add(ops)
paint.LinearGradientOp{
Stop1: f32.Pt(64, 64),
Color1: colornames.White,
Stop2: f32.Pt(0, 128),
Color2: colornames.Magenta,
}.Add(ops)
paint.PaintOp{Rect: f32.Rect(0, 64, 64, 128)}.Add(ops)
}, func(r result) {})
}
// lerp calculates linear interpolation with color b and p.
func lerp(a, b f32color.RGBA, p float32) f32color.RGBA {
return f32color.RGBA{
R: a.R*(1-p) + b.R*p,
G: a.G*(1-p) + b.G*p,
B: a.B*(1-p) + b.B*p,
A: a.A*(1-p) + b.A*p,
}
}