Files
gio/internal/ops/ops.go
T
Viktor 24951a7ee7 gpu, op, internal/ops: add affine transformations
Add support for affine transformations. The key changes are outlined
below.

- Painting/clipping with rectangles is handled by, for complex
  transforms, creating clipping paths representing the transformed
  rectangle and using a larger bounding box. Cover/Blit shaders updated
  correspondingly to correctly map texture cordinates from the new
  bounding boxes.
- Since path splitting must happen on CPU the transforms must happen CPU
  side as well - offsets removed from shaders.
- Complex transforms will lead to different path splitting which means
  that GPU arrays can no longer be cached if the transform has changed.
  Thus the current transform is added as a key to the cache.
- Add a public API to op for setting Affine transformations.

There are a number of optimizations that could be explored further but
which are left out now:
- Caching also of CPU operations (e.g path splitting & transforms) and
  not only caching the GPU arrays.
- Allow for re-use of cached GPU vertices if the transformation change
  is a pure offset / scaling since the splitting is then the same.

Signed-off-by: Viktor <viktor.ogeman@gmail.com>
2020-06-21 11:17:53 +02:00

67 lines
1.7 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package ops
import (
"encoding/binary"
"math"
"gioui.org/f32"
"gioui.org/internal/opconst"
)
const QuadSize = 4 * 2 * 3
type Quad struct {
From, Ctrl, To f32.Point
}
func (q Quad) Transform(t f32.Affine2D) Quad {
q.From = t.Transform(q.From)
q.Ctrl = t.Transform(q.Ctrl)
q.To = t.Transform(q.To)
return q
}
func EncodeQuad(d []byte, q Quad) {
bo := binary.LittleEndian
bo.PutUint32(d[0:], math.Float32bits(q.From.X))
bo.PutUint32(d[4:], math.Float32bits(q.From.Y))
bo.PutUint32(d[8:], math.Float32bits(q.Ctrl.X))
bo.PutUint32(d[12:], math.Float32bits(q.Ctrl.Y))
bo.PutUint32(d[16:], math.Float32bits(q.To.X))
bo.PutUint32(d[20:], math.Float32bits(q.To.Y))
}
func DecodeQuad(d []byte) (q Quad) {
bo := binary.LittleEndian
q.From.X = math.Float32frombits(bo.Uint32(d[0:]))
q.From.Y = math.Float32frombits(bo.Uint32(d[4:]))
q.Ctrl.X = math.Float32frombits(bo.Uint32(d[8:]))
q.Ctrl.Y = math.Float32frombits(bo.Uint32(d[12:]))
q.To.X = math.Float32frombits(bo.Uint32(d[16:]))
q.To.Y = math.Float32frombits(bo.Uint32(d[20:]))
return
}
func DecodeTransform(d []byte) (t f32.Affine2D) {
if opconst.OpType(d[0]) != opconst.TypeTransform {
panic("invalid op")
}
if len(d) < 1+6*4 {
panic("too short buffer")
}
return decodeAffine2D(d[1:])
}
func decodeAffine2D(data []byte) f32.Affine2D {
bo := binary.LittleEndian
a := math.Float32frombits(bo.Uint32(data))
b := math.Float32frombits(bo.Uint32(data[4*1:]))
c := math.Float32frombits(bo.Uint32(data[4*2:]))
d := math.Float32frombits(bo.Uint32(data[4*3:]))
e := math.Float32frombits(bo.Uint32(data[4*4:]))
f := math.Float32frombits(bo.Uint32(data[4*5:]))
return f32.NewAffine2D(a, b, c, d, e, f)
}