-
Notifications
You must be signed in to change notification settings - Fork 9
/
draw.go
99 lines (90 loc) · 2.79 KB
/
draw.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
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package font
import (
"image"
"image/color"
"image/draw"
"strings"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/text"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
m "github.com/divVerent/aaaaxy/internal/math"
)
// BoundString returns the bounding rectangle of the given text.
func (f Face) BoundString(str string) m.Rect {
rect := text.BoundString(f.Outline, str)
return m.Rect{
Origin: m.Pos{
X: rect.Min.X,
Y: rect.Min.Y,
},
Size: m.Delta{
DX: rect.Max.X - rect.Min.X,
DY: rect.Max.Y - rect.Min.Y,
},
}
}
// drawLine draws one line of text.
func drawLine(f font.Face, dst draw.Image, line string, x, y int, fg color.Color) {
switch dst := dst.(type) {
case *ebiten.Image:
// Use ebiten's glyph cache.
text.Draw(dst, line, f, x, y, fg)
default:
// No glyph cache.
d := font.Drawer{
Dst: dst,
Src: image.NewUniform(fg),
Face: f,
Dot: fixed.P(x, y),
}
d.DrawString(line)
}
}
// Draw draws the given text.
func (f Face) Draw(dst draw.Image, str string, pos m.Pos, centerX bool, fg, bg color.Color) {
// We need to do our own line splitting because
// we always want to center and ebiten would left adjust.
var totalBounds m.Rect
if !centerX {
totalBounds = f.BoundString(str)
}
fy := fixed.I(pos.Y)
for _, line := range strings.Split(str, "\n") {
lineBounds := f.BoundString(line)
// totalBounds: tX size tDX
// lineBouds: lX size lDX
// Want lX+d .. lX+lDX+d centered in tX .. tX+tDX
// Thus: lX+d - tX = tX+tDX - (lX+lDX+d)
// d = tX - lX + (tDX - lDX)/2.
x := pos.X + totalBounds.Origin.X - lineBounds.Origin.X + (totalBounds.Size.DX-lineBounds.Size.DX)/2
y := fy.Floor()
if _, _, _, a := bg.RGBA(); a != 0 {
drawLine(f.Outline, dst, line, x, y, bg)
}
// Draw the text itself.
drawLine(f.Face, dst, line, x, y, fg)
fy += f.Outline.Metrics().Height + 1 // Line height is 1 pixel above font height.
}
}
func (f Face) precache(dst *ebiten.Image, chars string) {
text.Draw(dst, chars, f.Face, 0, 0, color.NRGBA{R: 0, G: 0, B: 0, A: 0})
text.Draw(dst, chars, f.Outline, 0, 0, color.NRGBA{R: 0, G: 0, B: 0, A: 0})
}
func (f Face) recache(chars string) {
text.CacheGlyphs(f.Face, chars)
text.CacheGlyphs(f.Outline, chars)
}