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