main.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build darwin || linux || windows
  5. // An app that draws a green triangle on a red background.
  6. //
  7. // In order to build this program as an Android APK, using the gomobile tool.
  8. //
  9. // See http://godoc.org/golang.org/x/mobile/cmd/gomobile to install gomobile.
  10. //
  11. // Get the basic example and use gomobile to build or install it on your device.
  12. //
  13. // $ go get -d golang.org/x/mobile/example/basic
  14. // $ gomobile build golang.org/x/mobile/example/basic # will build an APK
  15. //
  16. // # plug your Android device to your computer or start an Android emulator.
  17. // # if you have adb installed on your machine, use gomobile install to
  18. // # build and deploy the APK to an Android target.
  19. // $ gomobile install golang.org/x/mobile/example/basic
  20. //
  21. // Switch to your device or emulator to start the Basic application from
  22. // the launcher.
  23. // You can also run the application on your desktop by running the command
  24. // below. (Note: It currently doesn't work on Windows.)
  25. //
  26. // $ go install golang.org/x/mobile/example/basic && basic
  27. package main
  28. import (
  29. "encoding/binary"
  30. "log"
  31. "golang.org/x/mobile/app"
  32. "golang.org/x/mobile/event/lifecycle"
  33. "golang.org/x/mobile/event/paint"
  34. "golang.org/x/mobile/event/size"
  35. "golang.org/x/mobile/event/touch"
  36. "golang.org/x/mobile/exp/app/debug"
  37. "golang.org/x/mobile/exp/f32"
  38. "golang.org/x/mobile/exp/gl/glutil"
  39. "golang.org/x/mobile/gl"
  40. )
  41. var (
  42. images *glutil.Images
  43. fps *debug.FPS
  44. program gl.Program
  45. position gl.Attrib
  46. offset gl.Uniform
  47. color gl.Uniform
  48. buf gl.Buffer
  49. green float32
  50. touchX float32
  51. touchY float32
  52. )
  53. func main() {
  54. app.Main(func(a app.App) {
  55. var glctx gl.Context
  56. var sz size.Event
  57. for e := range a.Events() {
  58. switch e := a.Filter(e).(type) {
  59. case lifecycle.Event:
  60. switch e.Crosses(lifecycle.StageVisible) {
  61. case lifecycle.CrossOn:
  62. glctx, _ = e.DrawContext.(gl.Context)
  63. onStart(glctx)
  64. a.Send(paint.Event{})
  65. case lifecycle.CrossOff:
  66. onStop(glctx)
  67. glctx = nil
  68. }
  69. case size.Event:
  70. sz = e
  71. touchX = float32(sz.WidthPx / 2)
  72. touchY = float32(sz.HeightPx / 2)
  73. case paint.Event:
  74. if glctx == nil || e.External {
  75. // As we are actively painting as fast as
  76. // we can (usually 60 FPS), skip any paint
  77. // events sent by the system.
  78. continue
  79. }
  80. onPaint(glctx, sz)
  81. a.Publish()
  82. // Drive the animation by preparing to paint the next frame
  83. // after this one is shown.
  84. a.Send(paint.Event{})
  85. case touch.Event:
  86. touchX = e.X
  87. touchY = e.Y
  88. }
  89. }
  90. })
  91. }
  92. func onStart(glctx gl.Context) {
  93. var err error
  94. program, err = glutil.CreateProgram(glctx, vertexShader, fragmentShader)
  95. if err != nil {
  96. log.Printf("error creating GL program: %v", err)
  97. return
  98. }
  99. buf = glctx.CreateBuffer()
  100. glctx.BindBuffer(gl.ARRAY_BUFFER, buf)
  101. glctx.BufferData(gl.ARRAY_BUFFER, triangleData, gl.STATIC_DRAW)
  102. position = glctx.GetAttribLocation(program, "position")
  103. color = glctx.GetUniformLocation(program, "color")
  104. offset = glctx.GetUniformLocation(program, "offset")
  105. images = glutil.NewImages(glctx)
  106. fps = debug.NewFPS(images)
  107. }
  108. func onStop(glctx gl.Context) {
  109. glctx.DeleteProgram(program)
  110. glctx.DeleteBuffer(buf)
  111. fps.Release()
  112. images.Release()
  113. }
  114. func onPaint(glctx gl.Context, sz size.Event) {
  115. glctx.ClearColor(1, 0, 0, 1)
  116. glctx.Clear(gl.COLOR_BUFFER_BIT)
  117. glctx.UseProgram(program)
  118. green += 0.01
  119. if green > 1 {
  120. green = 0
  121. }
  122. glctx.Uniform4f(color, 0, green, 0, 1)
  123. glctx.Uniform2f(offset, touchX/float32(sz.WidthPx), touchY/float32(sz.HeightPx))
  124. glctx.BindBuffer(gl.ARRAY_BUFFER, buf)
  125. glctx.EnableVertexAttribArray(position)
  126. glctx.VertexAttribPointer(position, coordsPerVertex, gl.FLOAT, false, 0, 0)
  127. glctx.DrawArrays(gl.TRIANGLES, 0, vertexCount)
  128. glctx.DisableVertexAttribArray(position)
  129. fps.Draw(sz)
  130. }
  131. var triangleData = f32.Bytes(binary.LittleEndian,
  132. 0.0, 0.4, 0.0, // top left
  133. 0.0, 0.0, 0.0, // bottom left
  134. 0.4, 0.0, 0.0, // bottom right
  135. )
  136. const (
  137. coordsPerVertex = 3
  138. vertexCount = 3
  139. )
  140. const vertexShader = `#version 100
  141. uniform vec2 offset;
  142. attribute vec4 position;
  143. void main() {
  144. // offset comes in with x/y values between 0 and 1.
  145. // position bounds are -1 to 1.
  146. vec4 offset4 = vec4(2.0*offset.x-1.0, 1.0-2.0*offset.y, 0, 0);
  147. gl_Position = position + offset4;
  148. }`
  149. const fragmentShader = `#version 100
  150. precision mediump float;
  151. uniform vec4 color;
  152. void main() {
  153. gl_FragColor = color;
  154. }`