github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/example/audio/main.go (about)

     1  // Copyright 2015 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  
     5  // +build darwin linux
     6  
     7  // An app that makes a sound as the gopher hits the walls of the screen.
     8  //
     9  // Note: This demo is an early preview of Go 1.5. In order to build this
    10  // program as an Android APK using the gomobile tool.
    11  //
    12  // See http://godoc.org/golang.org/x/mobile/cmd/gomobile to install gomobile.
    13  //
    14  // Get the audio example and use gomobile to build or install it on your device.
    15  //
    16  //   $ go get -d golang.org/x/mobile/example/audio
    17  //   $ gomobile build golang.org/x/mobile/example/audio # will build an APK
    18  //
    19  //   # plug your Android device to your computer or start an Android emulator.
    20  //   # if you have adb installed on your machine, use gomobile install to
    21  //   # build and deploy the APK to an Android target.
    22  //   $ gomobile install golang.org/x/mobile/example/audio
    23  //
    24  // Additionally, you can run the sample on your desktop environment
    25  // by using the go tool.
    26  //
    27  //   $ go install golang.org/x/mobile/example/audio && audio
    28  //
    29  // On Linux, you need to install OpenAL developer library by
    30  // running the command below.
    31  //
    32  //   $ apt-get install libopenal-dev
    33  package main
    34  
    35  import (
    36  	"image"
    37  	"log"
    38  	"time"
    39  
    40  	_ "image/jpeg"
    41  
    42  	"golang.org/x/mobile/app"
    43  	"golang.org/x/mobile/asset"
    44  	"golang.org/x/mobile/event/lifecycle"
    45  	"golang.org/x/mobile/event/paint"
    46  	"golang.org/x/mobile/event/size"
    47  	"golang.org/x/mobile/exp/audio"
    48  	"golang.org/x/mobile/exp/f32"
    49  	"golang.org/x/mobile/exp/gl/glutil"
    50  	"golang.org/x/mobile/exp/sprite"
    51  	"golang.org/x/mobile/exp/sprite/clock"
    52  	"golang.org/x/mobile/exp/sprite/glsprite"
    53  	"golang.org/x/mobile/gl"
    54  )
    55  
    56  const (
    57  	width  = 72
    58  	height = 60
    59  )
    60  
    61  var (
    62  	startTime = time.Now()
    63  
    64  	images *glutil.Images
    65  	eng    sprite.Engine
    66  	scene  *sprite.Node
    67  
    68  	player *audio.Player
    69  
    70  	sz size.Event
    71  )
    72  
    73  func main() {
    74  	app.Main(func(a app.App) {
    75  		var glctx gl.Context
    76  		for e := range a.Events() {
    77  			switch e := a.Filter(e).(type) {
    78  			case lifecycle.Event:
    79  				switch e.Crosses(lifecycle.StageVisible) {
    80  				case lifecycle.CrossOn:
    81  					glctx, _ = e.DrawContext.(gl.Context)
    82  					onStart(glctx)
    83  					a.Send(paint.Event{})
    84  				case lifecycle.CrossOff:
    85  					onStop()
    86  					glctx = nil
    87  				}
    88  			case size.Event:
    89  				sz = e
    90  			case paint.Event:
    91  				if glctx == nil || e.External {
    92  					continue
    93  				}
    94  				onPaint(glctx)
    95  				a.Publish()
    96  				a.Send(paint.Event{}) // keep animating
    97  			}
    98  		}
    99  	})
   100  }
   101  
   102  func onStart(glctx gl.Context) {
   103  	images = glutil.NewImages(glctx)
   104  	eng = glsprite.Engine(images)
   105  	loadScene()
   106  
   107  	rc, err := asset.Open("boing.wav")
   108  	if err != nil {
   109  		log.Fatal(err)
   110  	}
   111  	player, err = audio.NewPlayer(rc, 0, 0)
   112  	if err != nil {
   113  		log.Fatal(err)
   114  	}
   115  }
   116  
   117  func onStop() {
   118  	eng.Release()
   119  	images.Release()
   120  	player.Close()
   121  }
   122  
   123  func onPaint(glctx gl.Context) {
   124  	glctx.ClearColor(1, 1, 1, 1)
   125  	glctx.Clear(gl.COLOR_BUFFER_BIT)
   126  	now := clock.Time(time.Since(startTime) * 60 / time.Second)
   127  	eng.Render(scene, now, sz)
   128  }
   129  
   130  func newNode() *sprite.Node {
   131  	n := &sprite.Node{}
   132  	eng.Register(n)
   133  	scene.AppendChild(n)
   134  	return n
   135  }
   136  
   137  func loadScene() {
   138  	gopher := loadGopher()
   139  	scene = &sprite.Node{}
   140  	eng.Register(scene)
   141  	eng.SetTransform(scene, f32.Affine{
   142  		{1, 0, 0},
   143  		{0, 1, 0},
   144  	})
   145  
   146  	var x, y float32
   147  	dx, dy := float32(1), float32(1)
   148  
   149  	n := newNode()
   150  	// TODO: Shouldn't arranger pass the size.Event?
   151  	n.Arranger = arrangerFunc(func(eng sprite.Engine, n *sprite.Node, t clock.Time) {
   152  		eng.SetSubTex(n, gopher)
   153  
   154  		if x < 0 {
   155  			dx = 1
   156  			boing()
   157  		}
   158  		if y < 0 {
   159  			dy = 1
   160  			boing()
   161  		}
   162  		if x+width > float32(sz.WidthPt) {
   163  			dx = -1
   164  			boing()
   165  		}
   166  		if y+height > float32(sz.HeightPt) {
   167  			dy = -1
   168  			boing()
   169  		}
   170  
   171  		x += dx
   172  		y += dy
   173  
   174  		eng.SetTransform(n, f32.Affine{
   175  			{width, 0, x},
   176  			{0, height, y},
   177  		})
   178  	})
   179  }
   180  
   181  func boing() {
   182  	player.Seek(0)
   183  	player.Play()
   184  }
   185  
   186  func loadGopher() sprite.SubTex {
   187  	a, err := asset.Open("gopher.jpeg")
   188  	if err != nil {
   189  		log.Fatal(err)
   190  	}
   191  	defer a.Close()
   192  
   193  	img, _, err := image.Decode(a)
   194  	if err != nil {
   195  		log.Fatal(err)
   196  	}
   197  	t, err := eng.LoadTexture(img)
   198  	if err != nil {
   199  		log.Fatal(err)
   200  	}
   201  	return sprite.SubTex{t, image.Rect(0, 0, 360, 300)}
   202  }
   203  
   204  type arrangerFunc func(e sprite.Engine, n *sprite.Node, t clock.Time)
   205  
   206  func (a arrangerFunc) Arrange(e sprite.Engine, n *sprite.Node, t clock.Time) { a(e, n, t) }