From 69dfd2e3a55419167975adc316f8126bc4737443 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 13 Feb 2020 13:02:41 +0100 Subject: [PATCH] op/paint: add support for efficient ImageOp subimages The new field ImageOp.Rect is initialized to cover the entire source image, but can be modified to draw only a section of it. Signed-off-by: Elias Naur --- gpu/gpu.go | 19 +++++++++++++------ internal/opconst/ops.go | 2 +- op/paint/paint.go | 7 +++++++ widget/material/image.go | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/gpu/gpu.go b/gpu/gpu.go index 8988d5b7..51f69e3b 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -116,6 +116,7 @@ type clipOp struct { // imageOpData is the shadow of paint.ImageOp. type imageOpData struct { + rect image.Rectangle src *image.RGBA handle interface{} } @@ -148,7 +149,18 @@ func decodeImageOp(data []byte, refs []interface{}) imageOpData { if handle == nil { return imageOpData{} } + bo := binary.LittleEndian return imageOpData{ + rect: image.Rectangle{ + Min: image.Point{ + X: int(bo.Uint32(data[1:])), + Y: int(bo.Uint32(data[5:])), + }, + Max: image.Point{ + X: int(bo.Uint32(data[9:])), + Y: int(bo.Uint32(data[13:])), + }, + }, src: refs[0].(*image.RGBA), handle: handle, } @@ -736,12 +748,7 @@ func (d *drawState) materialFor(cache *resourceCache, rect f32.Rectangle, off f3 m.material = materialTexture dr := boundRectF(rect.Add(off)) sz := d.image.src.Bounds().Size() - sr := f32.Rectangle{ - Max: f32.Point{ - X: float32(sz.X), - Y: float32(sz.Y), - }, - } + sr := toRectF(d.image.rect) if dx := float32(dr.Dx()); dx != 0 { // Don't clip 1 px width sources. if sdx := sr.Dx(); sdx > 1 { diff --git a/internal/opconst/ops.go b/internal/opconst/ops.go index aac1bcfc..927da93e 100644 --- a/internal/opconst/ops.go +++ b/internal/opconst/ops.go @@ -35,7 +35,7 @@ const ( TypeTransformLen = 1 + 4*2 TypeLayerLen = 1 TypeRedrawLen = 1 + 8 - TypeImageLen = 1 + TypeImageLen = 1 + 4*4 TypePaintLen = 1 + 4*4 TypeColorLen = 1 + 4 TypeAreaLen = 1 + 1 + 4*4 diff --git a/op/paint/paint.go b/op/paint/paint.go index 296a75e2..3ac472b3 100644 --- a/op/paint/paint.go +++ b/op/paint/paint.go @@ -16,6 +16,7 @@ import ( // ImageOp sets the material to an image. type ImageOp struct { + Rect image.Rectangle uniform bool color color.RGBA src *image.RGBA @@ -48,6 +49,7 @@ func NewImageOp(src image.Image) ImageOp { bounds := src.Bounds() if bounds.Min == (image.Point{}) && src.Stride == bounds.Dx()*4 { return ImageOp{ + Rect: src.Bounds(), src: src, handle: new(int), } @@ -82,6 +84,11 @@ func (i ImageOp) Add(o *op.Ops) { } data := o.Write(opconst.TypeImageLen, i.src, i.handle) data[0] = byte(opconst.TypeImage) + bo := binary.LittleEndian + bo.PutUint32(data[1:], uint32(i.Rect.Min.X)) + bo.PutUint32(data[5:], uint32(i.Rect.Min.Y)) + bo.PutUint32(data[9:], uint32(i.Rect.Max.X)) + bo.PutUint32(data[13:], uint32(i.Rect.Max.Y)) } func (c ColorOp) Add(o *op.Ops) { diff --git a/widget/material/image.go b/widget/material/image.go index 7b5bd56e..4f442512 100644 --- a/widget/material/image.go +++ b/widget/material/image.go @@ -30,7 +30,7 @@ func (t *Theme) Image(img paint.ImageOp) Image { } func (im Image) Layout(gtx *layout.Context) { - size := im.Src.Size() + size := im.Src.Rect.Size() wf, hf := float32(size.X), float32(size.Y) w, h := gtx.Px(unit.Dp(wf*im.Scale)), gtx.Px(unit.Dp(hf*im.Scale)) cs := gtx.Constraints