main.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright 2022 The Ebitengine 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. "fmt"
  17. "image"
  18. "image/color"
  19. "log"
  20. "math"
  21. "github.com/hajimehoshi/ebiten/v2"
  22. "github.com/hajimehoshi/ebiten/v2/ebitenutil"
  23. "github.com/hajimehoshi/ebiten/v2/inpututil"
  24. "github.com/hajimehoshi/ebiten/v2/vector"
  25. )
  26. const (
  27. screenWidth = 640
  28. screenHeight = 480
  29. )
  30. type Game struct {
  31. counter int
  32. aa bool
  33. showCenter bool
  34. }
  35. func (g *Game) Update() error {
  36. g.counter++
  37. if inpututil.IsKeyJustPressed(ebiten.KeyA) {
  38. g.aa = !g.aa
  39. }
  40. if inpututil.IsKeyJustPressed(ebiten.KeyC) {
  41. g.showCenter = !g.showCenter
  42. }
  43. return nil
  44. }
  45. func (g *Game) Draw(screen *ebiten.Image) {
  46. target := screen
  47. joins := []vector.LineJoin{
  48. vector.LineJoinMiter,
  49. vector.LineJoinMiter,
  50. vector.LineJoinBevel,
  51. vector.LineJoinRound,
  52. }
  53. caps := []vector.LineCap{
  54. vector.LineCapButt,
  55. vector.LineCapRound,
  56. vector.LineCapSquare,
  57. }
  58. ow, oh := target.Bounds().Dx(), target.Bounds().Dy()
  59. size := min(ow/(len(joins)+1), oh/(len(caps)+1))
  60. offsetX, offsetY := (ow-size*len(joins))/2, (oh-size*len(caps))/2
  61. // Render the lines on the target.
  62. for j, cap := range caps {
  63. for i, join := range joins {
  64. r := image.Rect(i*size+offsetX, j*size+offsetY, (i+1)*size+offsetX, (j+1)*size+offsetY)
  65. miterLimit := float32(5)
  66. if i == 1 {
  67. miterLimit = 10
  68. }
  69. g.drawLine(target, r, cap, join, miterLimit)
  70. }
  71. }
  72. msg := fmt.Sprintf(`FPS: %0.2f, TPS: %0.2f
  73. Press A to switch anti-aliasing.
  74. Press C to switch to draw the center lines.`, ebiten.ActualFPS(), ebiten.ActualTPS())
  75. ebitenutil.DebugPrint(screen, msg)
  76. }
  77. func (g *Game) drawLine(screen *ebiten.Image, region image.Rectangle, cap vector.LineCap, join vector.LineJoin, miterLimit float32) {
  78. c0x := float64(region.Min.X + region.Dx()/4)
  79. c0y := float64(region.Min.Y + region.Dy()/4)
  80. c1x := float64(region.Max.X - region.Dx()/4)
  81. c1y := float64(region.Max.Y - region.Dy()/4)
  82. r := float64(min(region.Dx(), region.Dy()) / 4)
  83. a0 := 2 * math.Pi * float64(g.counter) / (16 * ebiten.DefaultTPS)
  84. a1 := 2 * math.Pi * float64(g.counter) / (9 * ebiten.DefaultTPS)
  85. var path vector.Path
  86. sin0, cos0 := math.Sincos(a0)
  87. sin1, cos1 := math.Sincos(a1)
  88. path.MoveTo(float32(r*cos0+c0x), float32(r*sin0+c0y))
  89. path.LineTo(float32(-r*cos0+c0x), float32(-r*sin0+c0y))
  90. path.LineTo(float32(r*cos1+c1x), float32(r*sin1+c1y))
  91. path.LineTo(float32(-r*cos1+c1x), float32(-r*sin1+c1y))
  92. // Draw the main line in white.
  93. op := &vector.StrokeOptions{}
  94. op.LineCap = cap
  95. op.LineJoin = join
  96. op.MiterLimit = miterLimit
  97. op.Width = float32(r / 2)
  98. vector.StrokePath(screen, &path, color.White, g.aa, op)
  99. // Draw the center line in red.
  100. if g.showCenter {
  101. op.Width = 1
  102. vector.StrokePath(screen, &path, color.RGBA{0xff, 0, 0, 0xff}, g.aa, op)
  103. }
  104. }
  105. func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
  106. return screenWidth, screenHeight
  107. }
  108. func main() {
  109. var g Game
  110. ebiten.SetWindowSize(screenWidth, screenHeight)
  111. ebiten.SetWindowTitle("Lines (Ebitengine Demo)")
  112. if err := ebiten.RunGame(&g); err != nil {
  113. log.Fatal(err)
  114. }
  115. }