From 0061c73a89aa026b9c0dbe326c20ae8e08c0ca7b Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 1 Jun 2019 12:43:33 +0200 Subject: [PATCH] ui: split OpImage into OpImage and OpDraw In preparation for an OpColor (and future OpGradient and similar). Label and Editor no longer take an explicit source image. They draw with the current image. Signed-off-by: Elias Naur --- ui/app/internal/gpu/gpu.go | 27 ++++++++----- ui/draw/draw.go | 83 +++++++++++++++++++++++--------------- ui/internal/ops/ops.go | 5 ++- ui/text/editor.go | 6 +-- ui/text/label.go | 3 +- ui/widget/image.go | 3 +- 6 files changed, 78 insertions(+), 49 deletions(-) diff --git a/ui/app/internal/gpu/gpu.go b/ui/app/internal/gpu/gpu.go index 5266ac1a..1bec7c1a 100644 --- a/ui/app/internal/gpu/gpu.go +++ b/ui/app/internal/gpu/gpu.go @@ -66,6 +66,10 @@ type drawOps struct { zimageOps []imageOp pathOps []*pathOp pathOpCache []pathOp + + // Current OpImage image and rect, if any. + img image.Image + imgRect image.Rectangle } type drawState struct { @@ -692,13 +696,18 @@ loop: case ops.TypeImage: var op gdraw.OpImage op.Decode(data, r.Refs) + d.img = op.Img + d.imgRect = op.Rect + case ops.TypeDraw: + var op gdraw.OpDraw + op.Decode(data, r.Refs) off := t.Transform(f32.Point{}) clip := clip.Intersect(op.Rect.Add(off)) if clip.Empty() { continue } bounds := boundRectF(clip) - mat := materialFor(d.cache, op, off, bounds) + mat := d.materialFor(d.cache, op.Rect, off, bounds) if bounds.Min == (image.Point{}) && bounds.Max == d.viewport && mat.opaque && mat.material == materialColor { // The image is a uniform opaque color and takes up the whole screen. // Scrap images up to and including this image and set clear color. @@ -745,16 +754,16 @@ func expandPathOp(p *pathOp, clip image.Rectangle) { } } -func materialFor(cache *resourceCache, op gdraw.OpImage, off f32.Point, clip image.Rectangle) material { +func (d *drawOps) materialFor(cache *resourceCache, rect f32.Rectangle, off f32.Point, clip image.Rectangle) material { var m material - if uniform, ok := op.Src.(*image.Uniform); ok { + if uniform, ok := d.img.(*image.Uniform); ok { m.material = materialColor m.color = gamma(uniform.RGBA()) m.opaque = m.color[3] == 1.0 } else { m.material = materialTexture - dr := boundRectF(op.Rect.Add(off)) - sr := op.SrcRect + dr := boundRectF(rect.Add(off)) + sr := d.imgRect if dx := dr.Dx(); dx != 0 { // Don't clip 1 px width sources. if sdx := sr.Dx(); sdx > 1 { @@ -769,16 +778,16 @@ func materialFor(cache *resourceCache, op gdraw.OpImage, off f32.Point, clip ima sr.Max.Y -= ((dr.Max.Y-clip.Max.Y)*sdy + dy/2) / dy } } - tex, exists := cache.get(op.Src) + tex, exists := cache.get(d.img) if !exists { t := &texture{ - src: op.Src, + src: d.img, } - cache.put(op.Src, t) + cache.put(d.img, t) tex = t } m.texture = tex.(*texture) - m.uvScale, m.uvOffset = texSpaceTransform(sr, op.Src.Bounds().Size()) + m.uvScale, m.uvOffset = texSpaceTransform(sr, d.img.Bounds().Size()) } return m } diff --git a/ui/draw/draw.go b/ui/draw/draw.go index de10c062..d4ff8c26 100644 --- a/ui/draw/draw.go +++ b/ui/draw/draw.go @@ -14,58 +14,77 @@ import ( ) type OpImage struct { - Rect f32.Rectangle - Src image.Image - SrcRect image.Rectangle + Img image.Image + Rect image.Rectangle +} + +type OpDraw struct { + Rect f32.Rectangle } func (i OpImage) Add(o *ui.Ops) { data := make([]byte, ops.TypeImageLen) data[0] = byte(ops.TypeImage) bo := binary.LittleEndian - ref := o.Ref(i.Src) + ref := o.Ref(i.Img) bo.PutUint32(data[1:], uint32(ref)) - bo.PutUint32(data[5:], math.Float32bits(i.Rect.Min.X)) - bo.PutUint32(data[9:], math.Float32bits(i.Rect.Min.Y)) - bo.PutUint32(data[13:], math.Float32bits(i.Rect.Max.X)) - bo.PutUint32(data[17:], math.Float32bits(i.Rect.Max.Y)) - bo.PutUint32(data[21:], uint32(i.SrcRect.Min.X)) - bo.PutUint32(data[25:], uint32(i.SrcRect.Min.Y)) - bo.PutUint32(data[29:], uint32(i.SrcRect.Max.X)) - bo.PutUint32(data[33:], uint32(i.SrcRect.Max.Y)) + bo.PutUint32(data[5:], uint32(i.Rect.Min.X)) + bo.PutUint32(data[9:], uint32(i.Rect.Min.Y)) + bo.PutUint32(data[13:], uint32(i.Rect.Max.X)) + bo.PutUint32(data[17:], uint32(i.Rect.Max.Y)) o.Write(data) } -func (i *OpImage) Decode(d []byte, refs []interface{}) { +func (i *OpImage) Decode(data []byte, refs []interface{}) { bo := binary.LittleEndian - if ops.OpType(d[0]) != ops.TypeImage { + if ops.OpType(data[0]) != ops.TypeImage { panic("invalid op") } - ref := int(bo.Uint32(d[1:])) - r := f32.Rectangle{ - Min: f32.Point{ - X: math.Float32frombits(bo.Uint32(d[5:])), - Y: math.Float32frombits(bo.Uint32(d[9:])), - }, - Max: f32.Point{ - X: math.Float32frombits(bo.Uint32(d[13:])), - Y: math.Float32frombits(bo.Uint32(d[17:])), - }, - } + ref := int(bo.Uint32(data[1:])) sr := image.Rectangle{ Min: image.Point{ - X: int(bo.Uint32(d[21:])), - Y: int(bo.Uint32(d[25:])), + X: int(bo.Uint32(data[5:])), + Y: int(bo.Uint32(data[9:])), }, Max: image.Point{ - X: int(bo.Uint32(d[29:])), - Y: int(bo.Uint32(d[33:])), + X: int(bo.Uint32(data[13:])), + Y: int(bo.Uint32(data[17:])), }, } *i = OpImage{ - Rect: r, - Src: refs[ref].(image.Image), - SrcRect: sr, + Img: refs[ref].(image.Image), + Rect: sr, + } +} + +func (d OpDraw) Add(o *ui.Ops) { + data := make([]byte, ops.TypeDrawLen) + data[0] = byte(ops.TypeDraw) + bo := binary.LittleEndian + bo.PutUint32(data[1:], math.Float32bits(d.Rect.Min.X)) + bo.PutUint32(data[5:], math.Float32bits(d.Rect.Min.Y)) + bo.PutUint32(data[9:], math.Float32bits(d.Rect.Max.X)) + bo.PutUint32(data[13:], math.Float32bits(d.Rect.Max.Y)) + o.Write(data) +} + +func (d *OpDraw) Decode(data []byte, refs []interface{}) { + bo := binary.LittleEndian + if ops.OpType(data[0]) != ops.TypeDraw { + panic("invalid op") + } + r := f32.Rectangle{ + Min: f32.Point{ + X: math.Float32frombits(bo.Uint32(data[1:])), + Y: math.Float32frombits(bo.Uint32(data[5:])), + }, + Max: f32.Point{ + X: math.Float32frombits(bo.Uint32(data[9:])), + Y: math.Float32frombits(bo.Uint32(data[13:])), + }, + } + *d = OpDraw{ + Rect: r, } } diff --git a/ui/internal/ops/ops.go b/ui/internal/ops/ops.go index 3070286e..768d83bd 100644 --- a/ui/internal/ops/ops.go +++ b/ui/internal/ops/ops.go @@ -28,6 +28,7 @@ const ( TypeRedraw TypeClip TypeImage + TypeDraw TypePointerHandler TypeKeyHandler TypeHideInput @@ -42,7 +43,8 @@ const ( TypeLayerLen = 1 TypeRedrawLen = 1 + 8 TypeClipLen = 1 + 4 - TypeImageLen = 1 + 4 + 4*4 + 4*4 + TypeImageLen = 1 + 4 + 4*4 + TypeDrawLen = 1 + 4*4 TypePointerHandlerLen = 1 + 4 + 4 + 1 TypeKeyHandlerLen = 1 + 4 + 1 TypeHideInputLen = 1 @@ -58,6 +60,7 @@ var typeLengths = [...]int{ TypeRedrawLen, TypeClipLen, TypeImageLen, + TypeDrawLen, TypePointerHandlerLen, TypeKeyHandlerLen, TypeHideInputLen, diff --git a/ui/text/editor.go b/ui/text/editor.go index 9afae1ea..8bcb55c7 100644 --- a/ui/text/editor.go +++ b/ui/text/editor.go @@ -20,7 +20,6 @@ import ( ) type Editor struct { - Src image.Image Face Face Alignment Alignment SingleLine bool @@ -175,7 +174,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens { ops.Begin() ui.OpTransform{Transform: ui.Offset(lineOff)}.Add(ops) draw.OpClip{Path: path}.Add(ops) - draw.OpImage{Rect: toRectF(clip).Sub(lineOff), Src: e.Src, SrcRect: e.Src.Bounds()}.Add(ops) + draw.OpDraw{Rect: toRectF(clip).Sub(lineOff)}.Add(ops) ops.End().Add(ops) } if e.focused { @@ -199,8 +198,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens { }) carRect = clip.Intersect(carRect) if !carRect.Empty() { - img := draw.OpImage{Src: e.Src, Rect: toRectF(carRect), SrcRect: e.Src.Bounds()} - img.Add(ops) + draw.OpDraw{Rect: toRectF(carRect)}.Add(ops) } } if blinking { diff --git a/ui/text/label.go b/ui/text/label.go index ac02f4d2..d79a59be 100644 --- a/ui/text/label.go +++ b/ui/text/label.go @@ -17,7 +17,6 @@ import ( type Label struct { Face Face - Src image.Image Alignment Alignment Text string @@ -106,7 +105,7 @@ func (l Label) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens { ops.Begin() ui.OpTransform{Transform: ui.Offset(off)}.Add(ops) draw.OpClip{Path: path}.Add(ops) - draw.OpImage{Rect: lclip, Src: l.Src, SrcRect: l.Src.Bounds()}.Add(ops) + draw.OpDraw{Rect: lclip}.Add(ops) ops.End().Add(ops) } return dims diff --git a/ui/widget/image.go b/ui/widget/image.go index 3eaef624..727a6618 100644 --- a/ui/widget/image.go +++ b/ui/widget/image.go @@ -27,6 +27,7 @@ func (im Image) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens { dr := f32.Rectangle{ Max: f32.Point{X: float32(d.X), Y: float32(d.Y)}, } - draw.OpImage{Rect: dr, Src: im.Src, SrcRect: im.Rect}.Add(ops) + draw.OpImage{Img: im.Src, Rect: im.Rect}.Add(ops) + draw.OpDraw{Rect: dr}.Add(ops) return layout.Dimens{Size: d, Baseline: d.Y} }