mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
text/v2: rename Glyph -> Cluster
This also changes AppendClusters to return cluster info even if a cluster doesn't have a glyph.
This commit is contained in:
parent
800101da90
commit
f0d23de3d3
@ -61,15 +61,15 @@ type Game struct {
|
||||
counter int
|
||||
kanjiText []rune
|
||||
kanjiTextColor color.RGBA
|
||||
glyphs []text.Glyph
|
||||
clusters []text.Cluster
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
// Initialize the glyphs for special (colorful) rendering.
|
||||
if len(g.glyphs) == 0 {
|
||||
if len(g.clusters) == 0 {
|
||||
op := &text.LayoutOptions{}
|
||||
op.LineSpacingInPixels = mplusNormalFace.Size * 1.5
|
||||
g.glyphs = text.AppendGlyphs(g.glyphs, sampleText, mplusNormalFace, op)
|
||||
g.clusters = text.AppendClusters(g.clusters, sampleText, mplusNormalFace, op)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -121,13 +121,16 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
{
|
||||
const x, y = 240, 360
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
// g.glyphs is initialized by text.AppendGlyphs.
|
||||
// g.glyphs is initialized by text.AppendClusters
|
||||
// You can customize how to render each glyph.
|
||||
// In this example, multiple colors are used to render glyphs.
|
||||
for i, gl := range g.glyphs {
|
||||
for i, c := range g.clusters {
|
||||
if c.Image == nil {
|
||||
continue
|
||||
}
|
||||
op.GeoM.Reset()
|
||||
op.GeoM.Translate(x, y)
|
||||
op.GeoM.Translate(gl.X, gl.Y)
|
||||
op.GeoM.Translate(c.X, c.Y)
|
||||
op.ColorScale.Reset()
|
||||
r := float32(1)
|
||||
if i%3 == 0 {
|
||||
@ -142,7 +145,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
b = 0.5
|
||||
}
|
||||
op.ColorScale.Scale(r, g, b, 1)
|
||||
screen.DrawImage(gl.Image, op)
|
||||
screen.DrawImage(c.Image, op)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,8 +291,8 @@ func (g *GoTextFace) hasGlyph(r rune) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// appendGlyphsForLine implements Face.
|
||||
func (g *GoTextFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
|
||||
// appendClustersForLine implements Face.
|
||||
func (g *GoTextFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster {
|
||||
origin := fixed.Point26_6{
|
||||
X: float64ToFixed26_6(originX),
|
||||
Y: float64ToFixed26_6(originY),
|
||||
@ -300,23 +300,23 @@ func (g *GoTextFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffse
|
||||
_, gs := g.Source.shape(line, g)
|
||||
for _, glyph := range gs {
|
||||
img, imgX, imgY := g.glyphImage(glyph, origin)
|
||||
if img != nil {
|
||||
glyphs = append(glyphs, Glyph{
|
||||
StartIndexInBytes: indexOffset + glyph.startIndex,
|
||||
EndIndexInBytes: indexOffset + glyph.endIndex,
|
||||
GID: uint32(glyph.shapingGlyph.GlyphID),
|
||||
Image: img,
|
||||
X: float64(imgX),
|
||||
Y: float64(imgY),
|
||||
})
|
||||
}
|
||||
// Append a glyph even if img is nil.
|
||||
// This is necessary to return index information for control characters.
|
||||
clusters = append(clusters, Cluster{
|
||||
StartIndexInBytes: indexOffset + glyph.startIndex,
|
||||
EndIndexInBytes: indexOffset + glyph.endIndex,
|
||||
GID: uint32(glyph.shapingGlyph.GlyphID),
|
||||
Image: img,
|
||||
X: float64(imgX),
|
||||
Y: float64(imgY),
|
||||
})
|
||||
origin = origin.Add(fixed.Point26_6{
|
||||
X: glyph.shapingGlyph.XAdvance,
|
||||
Y: -glyph.shapingGlyph.YAdvance,
|
||||
})
|
||||
}
|
||||
|
||||
return glyphs
|
||||
return clusters
|
||||
}
|
||||
|
||||
func (g *GoTextFace) glyphImage(glyph glyph, origin fixed.Point26_6) (*ebiten.Image, int, int) {
|
||||
|
@ -105,7 +105,10 @@ func Draw(dst *ebiten.Image, text string, face Face, options *DrawOptions) {
|
||||
}
|
||||
|
||||
geoM := options.GeoM
|
||||
for _, g := range AppendGlyphs(nil, text, face, &options.LayoutOptions) {
|
||||
for _, g := range AppendClusters(nil, text, face, &options.LayoutOptions) {
|
||||
if g.Image == nil {
|
||||
continue
|
||||
}
|
||||
op := &options.DrawImageOptions
|
||||
op.GeoM.Reset()
|
||||
op.GeoM.Translate(g.X, g.Y)
|
||||
@ -114,16 +117,16 @@ func Draw(dst *ebiten.Image, text string, face Face, options *DrawOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// AppendGlyphs appends glyphs to the given slice and returns a slice.
|
||||
// AppendClusters appends glyphs to the given slice and returns a slice.
|
||||
//
|
||||
// AppendGlyphs is a low-level API, and you can use AppendGlyphs to have more control than Draw.
|
||||
// AppendGlyphs is also available to precache glyphs.
|
||||
// AppendClusters is a low-level API, and you can use AppendClusters to have more control than Draw.
|
||||
// AppendClusters is also available to precache glyphs.
|
||||
//
|
||||
// For the details of options, see Draw function.
|
||||
//
|
||||
// AppendGlyphs is concurrent-safe.
|
||||
func AppendGlyphs(glyphs []Glyph, text string, face Face, options *LayoutOptions) []Glyph {
|
||||
return appendGlyphs(glyphs, text, face, 0, 0, options)
|
||||
// AppendClusters is concurrent-safe.
|
||||
func AppendClusters(glyphs []Cluster, text string, face Face, options *LayoutOptions) []Cluster {
|
||||
return appendClusters(glyphs, text, face, 0, 0, options)
|
||||
}
|
||||
|
||||
// AppndVectorPath appends a vector path for glyphs to the given path.
|
||||
@ -136,13 +139,13 @@ func AppendVectorPath(path *vector.Path, text string, face Face, options *Layout
|
||||
})
|
||||
}
|
||||
|
||||
// appendGlyphs appends glyphs to the given slice and returns a slice.
|
||||
// appendClusters appends glyphs to the given slice and returns a slice.
|
||||
//
|
||||
// appendGlyphs assumes the text is rendered with the position (x, y).
|
||||
// appendClusters assumes the text is rendered with the position (x, y).
|
||||
// (x, y) might affect the subpixel rendering results.
|
||||
func appendGlyphs(glyphs []Glyph, text string, face Face, x, y float64, options *LayoutOptions) []Glyph {
|
||||
func appendClusters(glyphs []Cluster, text string, face Face, x, y float64, options *LayoutOptions) []Cluster {
|
||||
forEachLine(text, face, options, func(line string, indexOffset int, originX, originY float64) {
|
||||
glyphs = face.appendGlyphsForLine(glyphs, line, indexOffset, originX+x, originY+y)
|
||||
glyphs = face.appendClustersForLine(glyphs, line, indexOffset, originX+x, originY+y)
|
||||
})
|
||||
return glyphs
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ func (l *LimitedFace) hasGlyph(r rune) bool {
|
||||
return l.unicodeRanges.contains(r) && l.face.hasGlyph(r)
|
||||
}
|
||||
|
||||
// appendGlyphsForLine implements Face.
|
||||
func (l *LimitedFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
|
||||
return l.face.appendGlyphsForLine(glyphs, l.unicodeRanges.filter(line), indexOffset, originX, originY)
|
||||
// appendClustersForLine implements Face.
|
||||
func (l *LimitedFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster {
|
||||
return l.face.appendClustersForLine(clusters, l.unicodeRanges.filter(line), indexOffset, originX, originY)
|
||||
}
|
||||
|
||||
// appendVectorPathForLine implements Face.
|
||||
|
@ -102,15 +102,15 @@ func (m *MultiFace) hasGlyph(r rune) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// appendGlyphsForLine implements Face.
|
||||
func (m *MultiFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
|
||||
// appendClustersForLine implements Face.
|
||||
func (m *MultiFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster {
|
||||
for _, c := range m.splitText(line) {
|
||||
if c.faceIndex == -1 {
|
||||
continue
|
||||
}
|
||||
f := m.faces[c.faceIndex]
|
||||
t := line[c.textStartIndex:c.textEndIndex]
|
||||
glyphs = f.appendGlyphsForLine(glyphs, t, indexOffset, originX, originY)
|
||||
clusters = f.appendClustersForLine(clusters, t, indexOffset, originX, originY)
|
||||
if a := f.advance(t); f.direction().isHorizontal() {
|
||||
originX += a
|
||||
} else {
|
||||
@ -118,7 +118,7 @@ func (m *MultiFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset
|
||||
}
|
||||
indexOffset += len(t)
|
||||
}
|
||||
return glyphs
|
||||
return clusters
|
||||
}
|
||||
|
||||
// appendVectorPathForLine implements Face.
|
||||
|
@ -93,8 +93,8 @@ func (s *StdFace) hasGlyph(r rune) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// appendGlyphsForLine implements Face.
|
||||
func (s *StdFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
|
||||
// appendClustersForLine implements Face.
|
||||
func (s *StdFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster {
|
||||
s.copyCheck()
|
||||
|
||||
origin := fixed.Point26_6{
|
||||
@ -108,23 +108,25 @@ func (s *StdFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset i
|
||||
origin.X += s.f.Kern(prevR, r)
|
||||
}
|
||||
img, imgX, imgY, a := s.glyphImage(r, origin)
|
||||
if img != nil {
|
||||
// Adjust the position to the integers.
|
||||
// The current glyph images assume that they are rendered on integer positions so far.
|
||||
_, size := utf8.DecodeRuneInString(line[i:])
|
||||
glyphs = append(glyphs, Glyph{
|
||||
StartIndexInBytes: indexOffset + i,
|
||||
EndIndexInBytes: indexOffset + i + size,
|
||||
Image: img,
|
||||
X: float64(imgX),
|
||||
Y: float64(imgY),
|
||||
})
|
||||
}
|
||||
|
||||
// Adjust the position to the integers.
|
||||
// The current glyph images assume that they are rendered on integer positions so far.
|
||||
_, size := utf8.DecodeRuneInString(line[i:])
|
||||
|
||||
// Append a glyph even if img is nil.
|
||||
// This is necessary to return index information for control characters.
|
||||
clusters = append(clusters, Cluster{
|
||||
StartIndexInBytes: indexOffset + i,
|
||||
EndIndexInBytes: indexOffset + i + size,
|
||||
Image: img,
|
||||
X: float64(imgX),
|
||||
Y: float64(imgY),
|
||||
})
|
||||
origin.X += a
|
||||
prevR = r
|
||||
}
|
||||
|
||||
return glyphs
|
||||
return clusters
|
||||
}
|
||||
|
||||
func (s *StdFace) glyphImage(r rune, origin fixed.Point26_6) (*ebiten.Image, int, int, fixed.Int26_6) {
|
||||
|
@ -36,7 +36,7 @@ type Face interface {
|
||||
|
||||
hasGlyph(r rune) bool
|
||||
|
||||
appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph
|
||||
appendClustersForLine(glyphs []Cluster, line string, indexOffset int, originX, originY float64) []Cluster
|
||||
appendVectorPathForLine(path *vector.Path, line string, originX, originY float64)
|
||||
|
||||
direction() Direction
|
||||
@ -117,12 +117,12 @@ func adjustGranularity(x fixed.Int26_6, face Face) fixed.Int26_6 {
|
||||
return x / factor * factor
|
||||
}
|
||||
|
||||
// Glyph represents one glyph to render.
|
||||
type Glyph struct {
|
||||
// StartIndexInBytes is the start index in bytes for the given string at AppendGlyphs.
|
||||
// Cluster represents one grapheme cluster.
|
||||
type Cluster struct {
|
||||
// StartIndexInBytes is the start index in bytes for the given string at AppendClusters.
|
||||
StartIndexInBytes int
|
||||
|
||||
// EndIndexInBytes is the end index in bytes for the given string at AppendGlyphs.
|
||||
// EndIndexInBytes is the end index in bytes for the given string at AppendClusters.
|
||||
EndIndexInBytes int
|
||||
|
||||
// GID is an ID for a glyph of TrueType or OpenType font. GID is valid when the face is GoTextFace.
|
||||
@ -134,12 +134,12 @@ type Glyph struct {
|
||||
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 is determined in a sequence of characters given at AppendClusters.
|
||||
// The position's origin is the first character's origin 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 is determined in a sequence of characters given at AppendClusters.
|
||||
// The position's origin is the first character's origin position.
|
||||
Y float64
|
||||
}
|
||||
@ -245,10 +245,10 @@ func CacheGlyphs(text string, face Face) {
|
||||
|
||||
c := glyphVariationCount(face)
|
||||
|
||||
var buf []Glyph
|
||||
var buf []Cluster
|
||||
// Create all the possible variations (#2528).
|
||||
for i := 0; i < c; i++ {
|
||||
buf = appendGlyphs(buf, text, face, x, y, nil)
|
||||
buf = appendClusters(buf, text, face, x, y, nil)
|
||||
buf = buf[:0]
|
||||
|
||||
if face.direction().isHorizontal() {
|
||||
|
@ -40,7 +40,7 @@ over the lazy dog.`
|
||||
|
||||
f := text.NewStdFace(bitmapfont.Face)
|
||||
got := sampleText
|
||||
for _, g := range text.AppendGlyphs(nil, sampleText, f, nil) {
|
||||
for _, g := range text.AppendClusters(nil, sampleText, f, nil) {
|
||||
got = got[:g.StartIndexInBytes] + strings.Repeat(" ", g.EndIndexInBytes-g.StartIndexInBytes) + got[g.EndIndexInBytes:]
|
||||
}
|
||||
want := regexp.MustCompile(`\S`).ReplaceAllString(sampleText, " ")
|
||||
|
Loading…
Reference in New Issue
Block a user