~eliasnaur/gio

69dfd2e3a55419167975adc316f8126bc4737443 — Elias Naur 8 months ago fd5dfac
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 <mail@eliasnaur.com>
4 files changed, 22 insertions(+), 8 deletions(-)

M gpu/gpu.go
M internal/opconst/ops.go
M op/paint/paint.go
M widget/material/image.go
M gpu/gpu.go => gpu/gpu.go +13 -6
@@ 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 {

M internal/opconst/ops.go => internal/opconst/ops.go +1 -1
@@ 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

M op/paint/paint.go => op/paint/paint.go +7 -0
@@ 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) {

M widget/material/image.go => widget/material/image.go +1 -1
@@ 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