-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrenderable.go
121 lines (107 loc) · 3.84 KB
/
renderable.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package graphics2d
import (
"image"
"image/color"
"image/draw"
)
// Renderable represents a set of shapes and the images to fill them. In other words, enough information to be
// able to render something. This structure is used to build complex multicolored objects in a composable way.
type Renderable struct {
Shapes []*Shape
Clips []*Shape
Fillers []image.Image
}
// NewRenderable creates a new instance with the given shape and filler image.
func NewRenderable(shape *Shape, filler image.Image, xfm *Aff3) *Renderable {
res := &Renderable{}
res.AddShape(shape, filler, xfm)
return res
}
// AddShape adds the given shape and filler to the Renderable after being transformed.
func (r *Renderable) AddShape(shape *Shape, filler image.Image, xfm *Aff3) *Renderable {
return r.AddClippedShape(shape, nil, filler, xfm)
}
// AddClippedShape adds the given shape, clip and filler to the Renderable after being transformed.
func (r *Renderable) AddClippedShape(shape, clip *Shape, filler image.Image, xfm *Aff3) *Renderable {
if xfm != nil {
r.Shapes = append(r.Shapes, shape.Transform(xfm))
if clip != nil {
r.Clips = append(r.Clips, clip.Transform(xfm))
} else {
r.Clips = append(r.Clips, nil)
}
} else {
r.Shapes = append(r.Shapes, shape)
r.Clips = append(r.Clips, clip)
}
r.Fillers = append(r.Fillers, filler)
return r
}
// AddColoredShape adds the given shape and color to the Renderable after being transformed.
func (r *Renderable) AddColoredShape(shape *Shape, col color.Color, xfm *Aff3) *Renderable {
return r.AddClippedColoredShape(shape, nil, col, xfm)
}
// AddClippedColoredShape adds the given shape, clip and color to the Renderable after being transformed.
func (r *Renderable) AddClippedColoredShape(shape, clip *Shape, col color.Color, xfm *Aff3) *Renderable {
return r.AddClippedShape(shape, clip, image.NewUniform(col), xfm)
}
// AddPennedShape adds the given shape and pen to the Renderable after being transformed.
func (r *Renderable) AddPennedShape(shape *Shape, pen *Pen, xfm *Aff3) *Renderable {
return r.AddClippedPennedShape(shape, nil, pen, xfm)
}
// AddClippedPennedShape adds the given shape, clip and pen to the Renderable after being transformed.
func (r *Renderable) AddClippedPennedShape(shape, clip *Shape, pen *Pen, xfm *Aff3) *Renderable {
if pen.Stroke != nil {
shape = shape.ProcessPaths(pen.Stroke)
}
if pen.Xfm != nil {
shape = shape.Transform(pen.Xfm)
}
return r.AddClippedShape(shape, clip, pen.Filler, xfm)
}
// AddRenderable allows another renderable to be concatenated (post transform) to the current one.
func (r *Renderable) AddRenderable(rend *Renderable, xfm *Aff3) *Renderable {
for i, shape := range rend.Shapes {
r.AddClippedShape(shape, rend.Clips[i], rend.Fillers[i], xfm)
}
return r
}
// Render renders the shapes in the renderable with their respective fillers after being transformed.
func (r *Renderable) Render(img draw.Image, xfm *Aff3) {
for i, shape := range r.Shapes {
clip := r.Clips[i]
if xfm != nil {
if clip == nil {
RenderShape(img, shape.Transform(xfm), r.Fillers[i])
} else {
RenderClippedShape(img, shape.Transform(xfm), clip.Transform(xfm), r.Fillers[i])
}
} else if clip == nil {
RenderShape(img, shape, r.Fillers[i])
} else {
RenderClippedShape(img, shape, clip, r.Fillers[i])
}
}
}
// Image renders the shapes in the renderable with their respective fillers.
func (r *Renderable) Image() *image.RGBA {
rect := r.Bounds()
img := image.NewRGBA(rect)
for i, shape := range r.Shapes {
clip := r.Clips[i]
if clip == nil {
RenderShape(img, shape, r.Fillers[i])
} else {
RenderClippedShape(img, shape, clip, r.Fillers[i])
}
}
return img
}
// Bounds returns the extent of the renderable.
func (r *Renderable) Bounds() image.Rectangle {
rect := image.Rectangle{}
for _, shape := range r.Shapes {
rect = rect.Union(shape.Bounds())
}
return rect
}