To avoid duplicate work when using macros and non-offset transforms,
cache also the new bounding boxes set up for them. The ops.Reader
already generates Keys for all operations, so use them in the cache.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
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>
Encode TransformOp as an Affince2D matrix instead and use that in gpu and io transform handling.
There are no changes to user facing API and so far only the offset part of the matrix is used.
This patch is a step towards full affine transformations.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
This is a first step towards supporting affine drawing transforms.
The rendering algorithm relies on quadratic curves that do not cross
x = 0 more than once, thus curves must be split after any rotation/shear
transforms. Move this logic and the generation of vertices to package gpu.
Also close all curves and draw zero-width edges as preparation for
transform since the will no longer implicitly be vertical with no
effect.
This commit will severely affect performance since vertexes are now
transformed also for cached items, using cpu resources.
Signed-off-by: Viktor <viktor.ogeman@gmail.com>
Converting
macro := op.Record(ops)
...
macro.Stop()
macro.Add()
to
macro := op.Record(ops)
...
call := macro.Stop()
call.Add(ops)
Which is more general (call.Add can take a different ops than the op.Record
that started it), and enforced the order between Stop and the subsequent Add.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The ability to invoke other operation lists belongs in the new CallOp.
While we're here, make MacroOp.Add use a pointer receiver to match the
other methods.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We'd like to improve the API of Flex, Stack and similar layouts
that use MacroOps internall. Unfortunately, the
func (m MacroOp) Add(o *Ops)
method causes the MacroOp to be allocated on the heap, ruining the
nice garbage-free property of layouts.
Fortunately, layouts don't need the feature that caused the heap
allocation: invoking operation lists different than the current.
CallOp separates the invoke-different-list semantic from MacroOp,
in preparation for removing the feature from MacroOp.
Signed-off-by: Elias Naur <mail@eliasnaur.com>