text: Add AppendGlyphs and Glyphs

Closes #1767
Closes #1871
This commit is contained in:
Hajime Hoshi 2021-11-12 00:54:15 +09:00
parent 3eb444f211
commit 732b125349
2 changed files with 91 additions and 0 deletions

View File

@ -79,9 +79,14 @@ type Game struct {
counter int
kanjiText []rune
kanjiTextColor color.RGBA
glyphs []text.Glyph
}
func (g *Game) Update() error {
// Initialize the glyphs for special (colorful) rendering.
if len(g.glyphs) == 0 {
g.glyphs = text.AppendGlyphs(g.glyphs, mplusNormalFont, sampleText)
}
return nil
}
@ -115,6 +120,33 @@ func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DrawRect(screen, float64(b.Min.X+x), float64(b.Min.Y+y), float64(b.Dx()), float64(b.Dy()), gray)
text.Draw(screen, sampleText, text.FaceWithLineHeight(mplusBigFont, lineHeight), x, y, color.White)
}
{
const x, y = 240, 400
op := &ebiten.DrawImageOptions{}
// g.glyphs is initialized by text.AppendGlyphs.
// You can customize how to render each glyph.
// In this example, multiple colors are used to render glyphs.
for i, gl := range g.glyphs {
op.GeoM.Reset()
op.GeoM.Translate(x, y)
op.GeoM.Translate(gl.X, gl.Y)
op.ColorM.Reset()
r := 1.0
if i%3 == 0 {
r = 0.5
}
g := 1.0
if i%3 == 1 {
g = 0.5
}
b := 1.0
if i%3 == 2 {
b = 0.5
}
op.ColorM.Scale(r, g, b, 1)
screen.DrawImage(gl.Image, op)
}
}
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {

View File

@ -392,3 +392,62 @@ func (f faceWithLineHeight) Metrics() font.Metrics {
m.Height = f.lineHeight
return m
}
// Glyphs is infomation to render one glyph.
type Glyph struct {
// Rune is a character for this glyph.
Rune rune
// Image is an image for this glyph.
// Image is a grayscale image i.e. RGBA values are the same.
Image *ebiten.Image
// X is the X position to render this glyph.
// The position is determined in a sequence of characters given at AppendGlyphs.
// The position's origin is the first character's dot ('.') position.
X float64
// Y is the Y position to render this glyph.
// The position is determined in a sequence of characters given at AppendGlyphs.
// The position's origin is the first character's dot ('.') position.
Y float64
}
// AppendGlyphs appends the glyph information to glyphs.
// You can render each glyphs as you like. See examples/text for an example of AppendGlyphs.
func AppendGlyphs(glyphs []Glyph, face font.Face, text string) []Glyph {
textM.Lock()
defer textM.Unlock()
var pos fixed.Point26_6
prevR := rune(-1)
faceHeight := face.Metrics().Height
for _, r := range text {
if prevR >= 0 {
pos.X += face.Kern(prevR, r)
}
if r == '\n' {
pos.X = 0
pos.Y += faceHeight
prevR = rune(-1)
continue
}
if img := getGlyphImage(face, r); img != nil {
b := getGlyphBounds(face, r)
glyphs = append(glyphs, Glyph{
Rune: r,
Image: img,
X: math.Floor(fixed26_6ToFloat64(pos.X + b.Min.X)),
Y: math.Floor(fixed26_6ToFloat64(pos.Y + b.Min.Y)),
})
}
pos.X += glyphAdvance(face, r)
prevR = r
}
return glyphs
}