main.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright 2020 The Ebiten Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package main
  15. import (
  16. "bytes"
  17. "image/color"
  18. "log"
  19. "math"
  20. "github.com/hajimehoshi/ebiten/v2"
  21. "github.com/hajimehoshi/ebiten/v2/ebitenutil"
  22. "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
  23. "github.com/hajimehoshi/ebiten/v2/inpututil"
  24. "github.com/hajimehoshi/ebiten/v2/text/v2"
  25. "github.com/hajimehoshi/ebiten/v2/vector"
  26. )
  27. const (
  28. screenWidth = 640
  29. screenHeight = 480
  30. )
  31. const sampleText = ` The quick brown fox jumps
  32. over the lazy dog.`
  33. var (
  34. mplusFaceSource *text.GoTextFaceSource
  35. mplusNormalFace *text.GoTextFace
  36. mplusBigFace *text.GoTextFace
  37. )
  38. func init() {
  39. s, err := text.NewGoTextFaceSource(bytes.NewReader(fonts.MPlus1pRegular_ttf))
  40. if err != nil {
  41. log.Fatal(err)
  42. }
  43. mplusFaceSource = s
  44. mplusNormalFace = &text.GoTextFace{
  45. Source: mplusFaceSource,
  46. Size: 24,
  47. }
  48. mplusBigFace = &text.GoTextFace{
  49. Source: mplusFaceSource,
  50. Size: 32,
  51. }
  52. }
  53. type Game struct {
  54. glyphs []text.Glyph
  55. showOrigins bool
  56. }
  57. func (g *Game) Update() error {
  58. // Initialize the glyphs for special (colorful) rendering.
  59. if len(g.glyphs) == 0 {
  60. op := &text.LayoutOptions{}
  61. op.LineSpacing = mplusNormalFace.Size * 1.5
  62. g.glyphs = text.AppendGlyphs(g.glyphs, sampleText, mplusNormalFace, op)
  63. }
  64. if inpututil.IsKeyJustPressed(ebiten.KeyO) {
  65. g.showOrigins = !g.showOrigins
  66. }
  67. return nil
  68. }
  69. func (g *Game) Draw(screen *ebiten.Image) {
  70. ebitenutil.DebugPrint(screen, "Press O to show/hide origins")
  71. gray := color.RGBA{0x80, 0x80, 0x80, 0xff}
  72. {
  73. const x, y = 20, 20
  74. w, h := text.Measure(sampleText, mplusNormalFace, mplusNormalFace.Size*1.5)
  75. vector.DrawFilledRect(screen, x, y, float32(w), float32(h), gray, false)
  76. op := &text.DrawOptions{}
  77. op.GeoM.Translate(x, y)
  78. op.LineSpacing = mplusNormalFace.Size * 1.5
  79. text.Draw(screen, sampleText, mplusNormalFace, op)
  80. }
  81. {
  82. const x, y = 20, 120
  83. w, h := text.Measure(sampleText, mplusBigFace, mplusBigFace.Size*1.5)
  84. vector.DrawFilledRect(screen, x, y, float32(w), float32(h), gray, false)
  85. op := &text.DrawOptions{}
  86. op.GeoM.Translate(x, y)
  87. op.LineSpacing = mplusBigFace.Size * 1.5
  88. text.Draw(screen, sampleText, mplusBigFace, op)
  89. }
  90. {
  91. const x, y = 20, 220
  92. op := &text.DrawOptions{}
  93. op.GeoM.Rotate(math.Pi / 4)
  94. op.GeoM.Translate(x, y)
  95. op.Filter = ebiten.FilterLinear
  96. op.LineSpacing = mplusNormalFace.Size * 1.5
  97. text.Draw(screen, sampleText, mplusNormalFace, op)
  98. }
  99. {
  100. const x, y = 160, 220
  101. const lineSpacingInPixels = 80
  102. w, h := text.Measure(sampleText, mplusBigFace, lineSpacingInPixels)
  103. vector.DrawFilledRect(screen, x, y, float32(w), float32(h), gray, false)
  104. op := &text.DrawOptions{}
  105. // Add the width as the text rendering region's upper-right position comes to (0, 0)
  106. // when the horizontal alignment is right. The alignment is specified later (PrimaryAlign).
  107. op.GeoM.Translate(x+w, y)
  108. op.LineSpacing = lineSpacingInPixels
  109. // The primary alignment for the left-to-right direction is a horizontal alignment, and the end means the right.
  110. op.PrimaryAlign = text.AlignEnd
  111. text.Draw(screen, sampleText, mplusBigFace, op)
  112. }
  113. {
  114. const x, y = 240, 360
  115. op := &ebiten.DrawImageOptions{}
  116. // g.glyphs is initialized by text.AppendGlyphs.
  117. // You can customize how to render each glyph.
  118. // In this example, multiple colors are used to render glyphs.
  119. for i, gl := range g.glyphs {
  120. if gl.Image == nil {
  121. continue
  122. }
  123. op.GeoM.Reset()
  124. op.GeoM.Translate(x, y)
  125. op.GeoM.Translate(gl.X, gl.Y)
  126. op.ColorScale.Reset()
  127. r := float32(1)
  128. if i%3 == 0 {
  129. r = 0.5
  130. }
  131. g := float32(1)
  132. if i%3 == 1 {
  133. g = 0.5
  134. }
  135. b := float32(1)
  136. if i%3 == 2 {
  137. b = 0.5
  138. }
  139. op.ColorScale.Scale(r, g, b, 1)
  140. screen.DrawImage(gl.Image, op)
  141. }
  142. if g.showOrigins {
  143. for _, gl := range g.glyphs {
  144. vector.DrawFilledCircle(screen, x+float32(gl.OriginX), y+float32(gl.OriginY), 2, color.RGBA{0xff, 0, 0, 0xff}, true)
  145. }
  146. }
  147. }
  148. }
  149. func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
  150. return screenWidth, screenHeight
  151. }
  152. func main() {
  153. ebiten.SetWindowSize(screenWidth, screenHeight)
  154. ebiten.SetWindowTitle("Text (Ebitengine Demo)")
  155. if err := ebiten.RunGame(&Game{}); err != nil {
  156. log.Fatal(err)
  157. }
  158. }