// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build darwin linux // An app that draws a green triangle on a red background. // // Note: This demo is an early preview of Go 1.5. In order to build this // program as an Android APK using the gomobile tool. // // See http://godoc.org/golang.org/x/mobile/cmd/gomobile to install gomobile. // // Get the basic example and use gomobile to build or install it on your device. // // $ go get -d golang.org/x/mobile/example/basic // $ gomobile build golang.org/x/mobile/example/basic # will build an APK // // # plug your Android device to your computer or start an Android emulator. // # if you have adb installed on your machine, use gomobile install to // # build and deploy the APK to an Android target. // $ gomobile install golang.org/x/mobile/example/basic // // Switch to your device or emulator to start the Basic application from // the launcher. // You can also run the application on your desktop by running the command // below. (Note: It currently doesn't work on Windows.) // $ go install golang.org/x/mobile/example/basic && basic package main import ( "encoding/binary" "log" "golang.org/x/mobile/app" "golang.org/x/mobile/event/lifecycle" "golang.org/x/mobile/event/paint" "golang.org/x/mobile/event/size" "golang.org/x/mobile/event/touch" "golang.org/x/mobile/exp/app/debug" "golang.org/x/mobile/exp/f32" "golang.org/x/mobile/exp/gl/glutil" "golang.org/x/mobile/gl" ) var ( images *glutil.Images fps *debug.FPS program gl.Program position gl.Attrib offset gl.Uniform color gl.Uniform buf gl.Buffer green float32 touchX float32 touchY float32 ) func main() { app.Main(func(a app.App) { var glctx gl.Context visible, sz := false, size.Event{} for e := range a.Events() { switch e := a.Filter(e).(type) { case lifecycle.Event: switch e.Crosses(lifecycle.StageVisible) { case lifecycle.CrossOn: visible = true glctx, _ = e.DrawContext.(gl.Context) onStart(glctx) case lifecycle.CrossOff: visible = false onStop(glctx) } case size.Event: sz = e touchX = float32(sz.WidthPx / 2) touchY = float32(sz.HeightPx / 2) case paint.Event: onPaint(glctx, sz) a.Publish() if visible { // Drive the animation by preparing to paint the next frame // after this one is shown. // // TODO: is paint.Event the right thing to send? Should we // have a dedicated publish.Event type? Should App.Publish // take an optional event sender and send a publish.Event? a.Send(paint.Event{}) } case touch.Event: touchX = e.X touchY = e.Y } } }) } func onStart(glctx gl.Context) { var err error program, err = glutil.CreateProgram(glctx, vertexShader, fragmentShader) if err != nil { log.Printf("error creating GL program: %v", err) return } buf = glctx.CreateBuffer() glctx.BindBuffer(gl.ARRAY_BUFFER, buf) glctx.BufferData(gl.ARRAY_BUFFER, triangleData, gl.STATIC_DRAW) position = glctx.GetAttribLocation(program, "position") color = glctx.GetUniformLocation(program, "color") offset = glctx.GetUniformLocation(program, "offset") images = glutil.NewImages(glctx) fps = debug.NewFPS(images) } func onStop(glctx gl.Context) { glctx.DeleteProgram(program) glctx.DeleteBuffer(buf) fps.Release() images.Release() } func onPaint(glctx gl.Context, sz size.Event) { glctx.ClearColor(1, 0, 0, 1) glctx.Clear(gl.COLOR_BUFFER_BIT) glctx.UseProgram(program) green += 0.01 if green > 1 { green = 0 } glctx.Uniform4f(color, 0, green, 0, 1) glctx.Uniform2f(offset, touchX/float32(sz.WidthPx), touchY/float32(sz.HeightPx)) glctx.BindBuffer(gl.ARRAY_BUFFER, buf) glctx.EnableVertexAttribArray(position) glctx.VertexAttribPointer(position, coordsPerVertex, gl.FLOAT, false, 0, 0) glctx.DrawArrays(gl.TRIANGLES, 0, vertexCount) glctx.DisableVertexAttribArray(position) fps.Draw(sz) } var triangleData = f32.Bytes(binary.LittleEndian, 0.0, 0.4, 0.0, // top left 0.0, 0.0, 0.0, // bottom left 0.4, 0.0, 0.0, // bottom right ) const ( coordsPerVertex = 3 vertexCount = 3 ) const vertexShader = `#version 100 uniform vec2 offset; attribute vec4 position; void main() { // offset comes in with x/y values between 0 and 1. // position bounds are -1 to 1. vec4 offset4 = vec4(2.0*offset.x-1.0, 1.0-2.0*offset.y, 0, 0); gl_Position = position + offset4; }` const fragmentShader = `#version 100 precision mediump float; uniform vec4 color; void main() { gl_FragColor = color; }`