forked from gopxl/pixel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sprite.go
119 lines (103 loc) · 3.15 KB
/
sprite.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
package pixel
import "image/color"
// Sprite is a drawable frame of a Picture. It's anchored by the center of it's Picture's frame.
//
// Frame specifies a rectangular portion of the Picture that will be drawn. For example, this
// creates a Sprite that draws the whole Picture:
//
// sprite := pixel.NewSprite(pic, pic.Bounds())
//
// Note, that Sprite caches the results of MakePicture from Targets it's drawn to for each Picture
// it's set to. What it means is that using a Sprite with an unbounded number of Pictures leads to a
// memory leak, since Sprite caches them and never forgets. In such a situation, create a new Sprite
// for each Picture.
type Sprite struct {
tri *TrianglesData
frame Rect
d Drawer
matrix Matrix
mask RGBA
}
// NewSprite creates a Sprite from the supplied frame of a Picture.
func NewSprite(pic Picture, frame Rect) *Sprite {
tri := MakeTrianglesData(6)
s := &Sprite{
tri: tri,
d: Drawer{Triangles: tri, Cached: true},
}
s.matrix = IM
s.mask = Alpha(1)
s.Set(pic, frame)
return s
}
// Set sets a new frame of a Picture for this Sprite.
func (s *Sprite) Set(pic Picture, frame Rect) {
s.d.Picture = pic
if frame != s.frame {
s.frame = frame
s.calcData()
}
}
// SetCached makes the sprite cache all the
// incoming pictures if the argument is true, and
// doesn't make it do that if the argument is false.
func (s *Sprite) SetCached(cached bool) {
s.d.Cached = cached
}
// Picture returns the current Sprite's Picture.
func (s *Sprite) Picture() Picture {
return s.d.Picture
}
// Frame returns the current Sprite's frame.
func (s *Sprite) Frame() Rect {
return s.frame
}
// Draw draws the Sprite onto the provided Target. The Sprite will be transformed by the given Matrix.
//
// This method is equivalent to calling DrawColorMask with nil color mask.
func (s *Sprite) Draw(t Target, matrix Matrix) {
s.DrawColorMask(t, matrix, nil)
}
// DrawColorMask draws the Sprite onto the provided Target. The Sprite will be transformed by the
// given Matrix and all of it's color will be multiplied by the given mask.
//
// If the mask is nil, a fully opaque white mask will be used, which causes no effect.
func (s *Sprite) DrawColorMask(t Target, matrix Matrix, mask color.Color) {
dirty := false
if matrix != s.matrix {
s.matrix = matrix
dirty = true
}
if mask == nil {
mask = Alpha(1)
}
rgba := ToRGBA(mask)
if rgba != s.mask {
s.mask = rgba
dirty = true
}
if dirty {
s.calcData()
}
s.d.Draw(t)
}
func (s *Sprite) calcData() {
var (
center = s.frame.Center()
horizontal = V(s.frame.W()/2, 0)
vertical = V(0, s.frame.H()/2)
)
(*s.tri)[0].Position = Vec{}.Sub(horizontal).Sub(vertical)
(*s.tri)[1].Position = Vec{}.Add(horizontal).Sub(vertical)
(*s.tri)[2].Position = Vec{}.Add(horizontal).Add(vertical)
(*s.tri)[3].Position = Vec{}.Sub(horizontal).Sub(vertical)
(*s.tri)[4].Position = Vec{}.Add(horizontal).Add(vertical)
(*s.tri)[5].Position = Vec{}.Sub(horizontal).Add(vertical)
for i := range *s.tri {
(*s.tri)[i].Color = s.mask
(*s.tri)[i].Picture = center.Add((*s.tri)[i].Position)
(*s.tri)[i].Intensity = 1
(*s.tri)[i].Position = s.matrix.Project((*s.tri)[i].Position)
}
s.d.Dirty()
}