diff --git a/examples/text/main.go b/examples/text/main.go index 377aad6f5..e5d84f183 100644 --- a/examples/text/main.go +++ b/examples/text/main.go @@ -19,10 +19,12 @@ import ( "log" "math" "math/rand" + "strings" "time" "golang.org/x/image/font" "golang.org/x/image/font/opentype" + "golang.org/x/image/math/fixed" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" @@ -87,19 +89,45 @@ func (g *Game) Update() error { return nil } +func boundString(face font.Face, str string) fixed.Rectangle26_6 { + str = strings.TrimRight(str, "\n") + lines := strings.Split(str, "\n") + if len(lines) == 0 { + return fixed.Rectangle26_6{} + } + + minX := fixed.I(0) + maxX := fixed.I(0) + for _, line := range lines { + a := font.MeasureString(face, line) + if maxX < a { + maxX = a + } + } + + m := face.Metrics() + minY := -m.Ascent + maxY := fixed.Int26_6(len(lines)-1)*m.Height + m.Descent + return fixed.Rectangle26_6{fixed.Point26_6{X: minX, Y: minY}, fixed.Point26_6{X: maxX, Y: maxY}} +} + +func fixed26_6ToFloat32(x fixed.Int26_6) float32 { + return float32(x>>6) + float32(x&((1<<6)-1))/(1<<6) +} + func (g *Game) Draw(screen *ebiten.Image) { gray := color.RGBA{0x80, 0x80, 0x80, 0xff} { const x, y = 20, 40 - b := text.BoundString(mplusNormalFont, sampleText) - vector.DrawFilledRect(screen, float32(b.Min.X+x), float32(b.Min.Y+y), float32(b.Dx()), float32(b.Dy()), gray, false) + b := boundString(mplusNormalFont, sampleText) + vector.DrawFilledRect(screen, fixed26_6ToFloat32(b.Min.X)+x, fixed26_6ToFloat32(b.Min.Y)+y, fixed26_6ToFloat32(b.Max.X-b.Min.X), fixed26_6ToFloat32(b.Max.Y-b.Min.Y), gray, false) text.Draw(screen, sampleText, mplusNormalFont, x, y, color.White) } { const x, y = 20, 140 - b := text.BoundString(mplusBigFont, sampleText) - vector.DrawFilledRect(screen, float32(b.Min.X+x), float32(b.Min.Y+y), float32(b.Dx()), float32(b.Dy()), gray, false) + b := boundString(mplusBigFont, sampleText) + vector.DrawFilledRect(screen, fixed26_6ToFloat32(b.Min.X)+x, fixed26_6ToFloat32(b.Min.Y)+y, fixed26_6ToFloat32(b.Max.X-b.Min.X), fixed26_6ToFloat32(b.Max.Y-b.Min.Y), gray, false) text.Draw(screen, sampleText, mplusBigFont, x, y, color.White) } { @@ -113,8 +141,8 @@ func (g *Game) Draw(screen *ebiten.Image) { { const x, y = 160, 240 const lineHeight = 80 - b := text.BoundString(text.FaceWithLineHeight(mplusBigFont, lineHeight), sampleText) - vector.DrawFilledRect(screen, float32(b.Min.X+x), float32(b.Min.Y+y), float32(b.Dx()), float32(b.Dy()), gray, false) + b := boundString(text.FaceWithLineHeight(mplusBigFont, lineHeight), sampleText) + vector.DrawFilledRect(screen, fixed26_6ToFloat32(b.Min.X)+x, fixed26_6ToFloat32(b.Min.Y)+y, fixed26_6ToFloat32(b.Max.X-b.Min.X), fixed26_6ToFloat32(b.Max.Y-b.Min.Y), gray, false) text.Draw(screen, sampleText, text.FaceWithLineHeight(mplusBigFont, lineHeight), x, y, color.White) } { diff --git a/text/text.go b/text/text.go index 16ea2911c..e277573d0 100644 --- a/text/text.go +++ b/text/text.go @@ -149,11 +149,6 @@ var textM sync.Mutex // // clr is the color for text rendering. // -// If you want to adjust the position of the text, these functions are useful: -// -// - text.BoundString: the rendered bounds of the given text. -// - golang.org/x/image/font.Face.Metrics: the metrics of the face. -// // The '\n' newline character puts the following text on the next line. // Line height is based on Metrics().Height of the font. // @@ -190,11 +185,6 @@ func Draw(dst *ebiten.Image, text string, face font.Face, x, y int, clr color.Co // Be careful that the origin point is not upper-left corner position of dst. // The default glyph color is white. op's ColorM adjusts the color. // -// If you want to adjust the position of the text, these functions are useful: -// -// - text.BoundString: the rendered bounds of the given text. -// - golang.org/x/image/font.Face.Metrics: the metrics of the face. -// // The '\n' newline character puts the following text on the next line. // Line height is based on Metrics().Height of the font. // @@ -286,6 +276,8 @@ func DrawWithOptions(dst *ebiten.Image, text string, face font.Face, options *eb // This is a known issue (#498). // // BoundString is concurrent-safe. +// +// Deprecated: as of v2.6. Use golang.org/x/image/font.BoundString instead, or use a face's Metrics (Ascent and Descent) and font.MeasureString instead. func BoundString(face font.Face, text string) image.Rectangle { textM.Lock() defer textM.Unlock()