diff --git a/examples/text/main.go b/examples/text/main.go index a7e44d908..37322c606 100644 --- a/examples/text/main.go +++ b/examples/text/main.go @@ -21,7 +21,9 @@ import ( "math" "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" + "github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/text/v2" "github.com/hajimehoshi/ebiten/v2/vector" ) @@ -58,10 +60,8 @@ func init() { } type Game struct { - counter int - kanjiText []rune - kanjiTextColor color.RGBA - glyphs []text.Glyph + glyphs []text.Glyph + showOrigins bool } func (g *Game) Update() error { @@ -71,10 +71,15 @@ func (g *Game) Update() error { op.LineSpacing = mplusNormalFace.Size * 1.5 g.glyphs = text.AppendGlyphs(g.glyphs, sampleText, mplusNormalFace, op) } + if inpututil.IsKeyJustPressed(ebiten.KeyO) { + g.showOrigins = !g.showOrigins + } return nil } func (g *Game) Draw(screen *ebiten.Image) { + ebitenutil.DebugPrint(screen, "Press O to show/hide origins") + gray := color.RGBA{0x80, 0x80, 0x80, 0xff} { @@ -147,6 +152,12 @@ func (g *Game) Draw(screen *ebiten.Image) { op.ColorScale.Scale(r, g, b, 1) screen.DrawImage(gl.Image, op) } + + if g.showOrigins { + for _, gl := range g.glyphs { + vector.DrawFilledCircle(screen, x+float32(gl.OriginX), y+float32(gl.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } } diff --git a/examples/texti18n/main.go b/examples/texti18n/main.go index 779490dc3..3eb2b5dc0 100644 --- a/examples/texti18n/main.go +++ b/examples/texti18n/main.go @@ -23,7 +23,9 @@ import ( "golang.org/x/text/language" "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" + "github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/text/v2" "github.com/hajimehoshi/ebiten/v2/vector" ) @@ -109,13 +111,19 @@ const ( ) type Game struct { + showOrigins bool } func (g *Game) Update() error { + if inpututil.IsKeyJustPressed(ebiten.KeyO) { + g.showOrigins = !g.showOrigins + } return nil } func (g *Game) Draw(screen *ebiten.Image) { + ebitenutil.DebugPrint(screen, "Press O to show/hide origins") + gray := color.RGBA{0x80, 0x80, 0x80, 0xff} { @@ -133,6 +141,13 @@ func (g *Game) Draw(screen *ebiten.Image) { op := &text.DrawOptions{} op.GeoM.Translate(float64(x), float64(y)) text.Draw(screen, arabicText, f, op) + + if g.showOrigins { + op := &text.LayoutOptions{} + for _, g := range text.AppendGlyphs(nil, arabicText, f, op) { + vector.DrawFilledCircle(screen, float32(x)+float32(g.OriginX), float32(y)+float32(g.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } { const hindiText = "चूंकि मानव परिवार के सभी सदस्यों के जन्मजात गौरव और समान" @@ -147,6 +162,13 @@ func (g *Game) Draw(screen *ebiten.Image) { op := &text.DrawOptions{} op.GeoM.Translate(float64(x), float64(y)) text.Draw(screen, hindiText, f, op) + + if g.showOrigins { + op := &text.LayoutOptions{} + for _, g := range text.AppendGlyphs(nil, hindiText, f, op) { + vector.DrawFilledCircle(screen, float32(x)+float32(g.OriginX), float32(y)+float32(g.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } { const myanmarText = "လူခပ်သိမ်း၏ မျိုးရိုးဂုဏ်သိက္ခာနှင့်တကွ" @@ -161,6 +183,13 @@ func (g *Game) Draw(screen *ebiten.Image) { op := &text.DrawOptions{} op.GeoM.Translate(float64(x), float64(y)) text.Draw(screen, myanmarText, f, op) + + if g.showOrigins { + op := &text.LayoutOptions{} + for _, g := range text.AppendGlyphs(nil, myanmarText, f, op) { + vector.DrawFilledCircle(screen, float32(x)+float32(g.OriginX), float32(y)+float32(g.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } { const thaiText = "โดยที่การยอมรับนับถือเกียรติศักดิ์ประจำตัว" @@ -175,6 +204,13 @@ func (g *Game) Draw(screen *ebiten.Image) { op := &text.DrawOptions{} op.GeoM.Translate(float64(x), float64(y)) text.Draw(screen, thaiText, f, op) + + if g.showOrigins { + op := &text.LayoutOptions{} + for _, g := range text.AppendGlyphs(nil, thaiText, f, op) { + vector.DrawFilledCircle(screen, float32(x)+float32(g.OriginX), float32(y)+float32(g.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } { const mongolianText = "ᠬᠦᠮᠦᠨ ᠪᠦᠷ ᠲᠥᠷᠥᠵᠦ ᠮᠡᠨᠳᠡᠯᠡᠬᠦ\nᠡᠷᠬᠡ ᠴᠢᠯᠥᠭᠡ ᠲᠡᠢ᠂ ᠠᠳᠠᠯᠢᠬᠠᠨ" @@ -194,6 +230,14 @@ func (g *Game) Draw(screen *ebiten.Image) { op.GeoM.Translate(float64(x), float64(y)) op.LineSpacing = lineSpacing text.Draw(screen, mongolianText, f, op) + + if g.showOrigins { + op := &text.LayoutOptions{} + op.LineSpacing = lineSpacing + for _, g := range text.AppendGlyphs(nil, mongolianText, f, op) { + vector.DrawFilledCircle(screen, float32(x)+float32(g.OriginX), float32(y)+float32(g.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } { const japaneseText = "あのイーハトーヴォの\nすきとおった風、\n夏でも底に冷たさを\nもつ青いそら…\nあHello World.あ" @@ -212,6 +256,14 @@ func (g *Game) Draw(screen *ebiten.Image) { op.GeoM.Translate(float64(x), float64(y)) op.LineSpacing = lineSpacing text.Draw(screen, japaneseText, f, op) + + if g.showOrigins { + op := &text.LayoutOptions{} + op.LineSpacing = lineSpacing + for _, g := range text.AppendGlyphs(nil, japaneseText, f, op) { + vector.DrawFilledCircle(screen, float32(x)+float32(g.OriginX), float32(y)+float32(g.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true) + } + } } } diff --git a/text/v2/gotext.go b/text/v2/gotext.go index 7b42576dd..527bd0810 100644 --- a/text/v2/gotext.go +++ b/text/v2/gotext.go @@ -304,10 +304,11 @@ 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.Add(fixed.Point26_6{ + o := origin.Add(fixed.Point26_6{ X: glyph.shapingGlyph.XOffset, Y: -glyph.shapingGlyph.YOffset, - })) + }) + img, imgX, imgY := g.glyphImage(glyph, o) // Append a glyph even if img is nil. // This is necessary to return index information for control characters. glyphs = append(glyphs, Glyph{ @@ -317,6 +318,8 @@ func (g *GoTextFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffse Image: img, X: float64(imgX), Y: float64(imgY), + OriginX: fixed26_6ToFloat64(o.X), + OriginY: fixed26_6ToFloat64(o.Y), }) origin = origin.Add(fixed.Point26_6{ X: glyph.shapingGlyph.XAdvance, diff --git a/text/v2/gox.go b/text/v2/gox.go index 625215d82..d101d2dc7 100644 --- a/text/v2/gox.go +++ b/text/v2/gox.go @@ -124,6 +124,8 @@ func (s *GoXFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset i Image: img, X: float64(imgX), Y: float64(imgY), + OriginX: fixed26_6ToFloat64(origin.X), + OriginY: fixed26_6ToFloat64(origin.Y), }) origin.X += a prevR = r diff --git a/text/v2/text.go b/text/v2/text.go index 97d996e62..834a3f340 100644 --- a/text/v2/text.go +++ b/text/v2/text.go @@ -141,6 +141,12 @@ type Glyph struct { // The position is determined in a sequence of characters given at AppendGlyphs. // The position's origin is the first character's origin position. Y float64 + + // OriginX is the X position of the origin of this glyph. + OriginX float64 + + // OriginY is the Y position of the origin of this glyph. + OriginY float64 } // Advance returns the advanced distance from the origin position when rendering the given text with the given face.