forked from quasilyte/ge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
texture_line.go
152 lines (125 loc) · 3.29 KB
/
texture_line.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package ge
import (
"image"
"math"
"github.com/hajimehoshi/ebiten/v2"
"github.com/quasilyte/gmath"
)
type TextureLine struct {
BeginPos Pos
EndPos Pos
Shader Shader
texture *Texture
imageCache *imageCache
colorScale ColorScale
colorM ebiten.ColorM
colorsChanged bool
Visible bool
disposed bool
}
func NewTextureLine(ctx *Context, begin, end Pos) *TextureLine {
return &TextureLine{
Visible: true,
BeginPos: begin,
EndPos: end,
imageCache: &ctx.imageCache,
colorScale: defaultColorScale,
}
}
func (l *TextureLine) SetTexture(tex *Texture) {
l.texture = tex
}
func (l *TextureLine) IsDisposed() bool {
return l.disposed
}
func (l *TextureLine) Dispose() {
l.disposed = true
}
func (l *TextureLine) BoundsRect() gmath.Rect {
pos1 := l.BeginPos.Resolve()
pos2 := l.EndPos.Resolve()
x0 := pos1.X
x1 := pos2.X
y0 := pos1.Y
y1 := pos2.Y
if x0 > x1 {
x0, x1 = x1, x0
}
if y0 > y1 {
y0, y1 = y1, y0
}
return gmath.Rect{Min: gmath.Vec{X: x0, Y: y0}, Max: gmath.Vec{X: x1, Y: y1}}
}
func (l *TextureLine) Draw(screen *ebiten.Image) {
}
func (l *TextureLine) DrawWithOffset(screen *ebiten.Image, offset gmath.Vec) {
if !l.Visible {
return
}
if l.colorsChanged {
l.colorsChanged = false
l.recalculateColorM()
}
pos1 := l.BeginPos.Resolve()
pos2 := l.EndPos.Resolve()
origin := gmath.Vec{Y: l.texture.height * 0.5}
angle := pos1.AngleToPoint(pos2)
// Maybe use sin+cos to compute the length?
// TODO: compare sin+cos vs sqrt performance.
length := gmath.ClampMax(math.Round(pos1.DistanceTo(pos2)), l.texture.width)
if length == 0 {
return
}
var drawOptions ebiten.DrawImageOptions
drawOptions.GeoM.Translate(-origin.X, -origin.Y)
drawOptions.GeoM.Rotate(float64(angle))
drawOptions.GeoM.Translate(origin.X, origin.Y)
drawOptions.GeoM.Translate(pos1.X, pos1.Y)
drawOptions.GeoM.Translate(offset.X, offset.Y)
drawOptions.ColorM = l.colorM
bounds := image.Rectangle{
Max: image.Point{X: int(length), Y: int(l.texture.height)},
}
subImage := l.imageCache.UnsafeSubImage(l.texture.image, bounds)
shaderEnabled := l.Shader.Enabled && !l.Shader.IsNil()
if !shaderEnabled {
screen.DrawImage(subImage, &drawOptions)
} else {
var drawDest *ebiten.Image
var options ebiten.DrawRectShaderOptions
usesColor := l.colorScale != defaultColorScale
if usesColor {
drawDest = l.imageCache.NewTempImage(bounds.Dx(), bounds.Dy())
} else {
drawDest = screen
options.GeoM = drawOptions.GeoM
}
options.CompositeMode = drawOptions.CompositeMode
options.Images[0] = subImage
options.Images[1] = l.Shader.Texture1.Data
options.Images[2] = l.Shader.Texture2.Data
options.Images[3] = l.Shader.Texture3.Data
options.Uniforms = l.Shader.shaderData
drawDest.DrawRectShader(bounds.Dx(), bounds.Dy(), l.Shader.compiled, &options)
if usesColor {
screen.DrawImage(drawDest, &drawOptions)
}
}
}
func (l *TextureLine) GetAlpha() float32 {
return l.colorScale.A
}
func (l *TextureLine) SetAlpha(a float32) {
if l.colorScale.A == a {
return
}
l.colorScale.A = a
l.colorsChanged = true
}
func (l *TextureLine) recalculateColorM() {
var colorM ebiten.ColorM
if l.colorScale != defaultColorScale {
colorM.Scale(float64(l.colorScale.R), float64(l.colorScale.G), float64(l.colorScale.B), float64(l.colorScale.A))
}
l.colorM = colorM
}