main.go 4.5 KB

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