github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/example/tile/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 ignore
     6  //
     7  // This build tag means that "go install golang.org/x/exp/shiny/..." doesn't
     8  // install this example program. Use "go run main.go" to run it.
     9  
    10  // Tile demonstrates tiling a screen with textures.
    11  package main
    12  
    13  import (
    14  	"fmt"
    15  	"image"
    16  	"image/color"
    17  	"image/draw"
    18  	"log"
    19  	"sync"
    20  
    21  	"golang.org/x/exp/shiny/driver"
    22  	"golang.org/x/exp/shiny/screen"
    23  	"golang.org/x/image/font"
    24  	"golang.org/x/image/font/basicfont"
    25  	"golang.org/x/image/math/fixed"
    26  	"golang.org/x/mobile/event/key"
    27  	"golang.org/x/mobile/event/mouse"
    28  	"golang.org/x/mobile/event/paint"
    29  	"golang.org/x/mobile/event/size"
    30  )
    31  
    32  func main() {
    33  	driver.Main(func(s screen.Screen) {
    34  		w, err := s.NewWindow(nil)
    35  		if err != nil {
    36  			log.Fatal(err)
    37  		}
    38  		defer w.Release()
    39  
    40  		var (
    41  			pool = &tilePool{
    42  				screen:   s,
    43  				drawRGBA: drawRGBA,
    44  				m:        map[image.Point]*tilePoolEntry{},
    45  			}
    46  			dragging     bool
    47  			paintPending bool
    48  			drag         image.Point
    49  			origin       image.Point
    50  			sz           size.Event
    51  		)
    52  		for e := range w.Events() {
    53  			switch e := e.(type) {
    54  			case key.Event:
    55  				if e.Code == key.CodeEscape {
    56  					return
    57  				}
    58  
    59  			case mouse.Event:
    60  				p := image.Point{X: int(e.X), Y: int(e.Y)}
    61  				if e.Button == mouse.ButtonLeft && e.Direction != mouse.DirNone {
    62  					dragging = e.Direction == mouse.DirPress
    63  					drag = p
    64  				}
    65  				if !dragging {
    66  					break
    67  				}
    68  				origin = origin.Sub(p.Sub(drag))
    69  				drag = p
    70  				if origin.X < 0 {
    71  					origin.X = 0
    72  				}
    73  				if origin.Y < 0 {
    74  					origin.Y = 0
    75  				}
    76  				if !paintPending {
    77  					paintPending = true
    78  					w.Send(paint.Event{})
    79  				}
    80  
    81  			case paint.Event:
    82  				generation++
    83  				var wg sync.WaitGroup
    84  				for y := -(origin.Y & 0xff); y < sz.HeightPx; y += 256 {
    85  					for x := -(origin.X & 0xff); x < sz.WidthPx; x += 256 {
    86  						wg.Add(1)
    87  						go drawTile(&wg, w, pool, origin, x, y)
    88  					}
    89  				}
    90  				wg.Wait()
    91  				w.Publish()
    92  				paintPending = false
    93  				pool.releaseUnused()
    94  
    95  			case size.Event:
    96  				sz = e
    97  
    98  			case error:
    99  				log.Print(e)
   100  			}
   101  		}
   102  	})
   103  }
   104  
   105  func drawTile(wg *sync.WaitGroup, w screen.Window, pool *tilePool, origin image.Point, x, y int) {
   106  	defer wg.Done()
   107  	tp := image.Point{
   108  		(x + origin.X) >> 8,
   109  		(y + origin.Y) >> 8,
   110  	}
   111  	tex, err := pool.get(tp)
   112  	if err != nil {
   113  		log.Println(err)
   114  		return
   115  	}
   116  	screen.Copy(w, image.Point{x, y}, tex, tileBounds, draw.Src, nil)
   117  }
   118  
   119  func drawRGBA(m *image.RGBA, tp image.Point) {
   120  	draw.Draw(m, m.Bounds(), image.White, image.Point{}, draw.Src)
   121  	for _, p := range crossPoints {
   122  		m.SetRGBA(p.X, p.Y, crossColor)
   123  	}
   124  	d := font.Drawer{
   125  		Dst:  m,
   126  		Src:  image.Black,
   127  		Face: basicfont.Face7x13,
   128  		Dot:  fixed.P(0, 12),
   129  	}
   130  	d.DrawString(fmt.Sprint(tp))
   131  }
   132  
   133  var (
   134  	crossColor  = color.RGBA{0x7f, 0x00, 0x00, 0xff}
   135  	crossPoints = []image.Point{
   136  		{0x00, 0xfe},
   137  		{0x00, 0xff},
   138  		{0xfe, 0x00},
   139  		{0xff, 0x00},
   140  		{0x00, 0x00},
   141  		{0x01, 0x00},
   142  		{0x02, 0x00},
   143  		{0x00, 0x01},
   144  		{0x00, 0x02},
   145  
   146  		{0x80, 0x7f},
   147  		{0x7f, 0x80},
   148  		{0x80, 0x80},
   149  		{0x81, 0x80},
   150  		{0x80, 0x81},
   151  
   152  		{0x80, 0x00},
   153  
   154  		{0x00, 0x80},
   155  	}
   156  
   157  	generation int
   158  
   159  	tileSize   = image.Point{256, 256}
   160  	tileBounds = image.Rectangle{Max: tileSize}
   161  )
   162  
   163  type tilePoolEntry struct {
   164  	tex screen.Texture
   165  	gen int
   166  }
   167  
   168  type tilePool struct {
   169  	screen   screen.Screen
   170  	drawRGBA func(*image.RGBA, image.Point)
   171  
   172  	mu sync.Mutex
   173  	m  map[image.Point]*tilePoolEntry
   174  }
   175  
   176  func (p *tilePool) get(tp image.Point) (screen.Texture, error) {
   177  	p.mu.Lock()
   178  	v, ok := p.m[tp]
   179  	if v != nil {
   180  		v.gen = generation
   181  	}
   182  	p.mu.Unlock()
   183  
   184  	if ok {
   185  		return v.tex, nil
   186  	}
   187  	tex, err := p.screen.NewTexture(tileSize)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	buf, err := p.screen.NewBuffer(tileSize)
   192  	if err != nil {
   193  		tex.Release()
   194  		return nil, err
   195  	}
   196  	p.drawRGBA(buf.RGBA(), tp)
   197  	tex.Upload(image.Point{}, buf, tileBounds)
   198  	buf.Release()
   199  
   200  	p.mu.Lock()
   201  	p.m[tp] = &tilePoolEntry{
   202  		tex: tex,
   203  		gen: generation,
   204  	}
   205  	n := len(p.m)
   206  	p.mu.Unlock()
   207  
   208  	fmt.Printf("%4d textures; created  %v\n", n, tp)
   209  	return tex, nil
   210  }
   211  
   212  func (p *tilePool) releaseUnused() {
   213  	p.mu.Lock()
   214  	defer p.mu.Unlock()
   215  
   216  	for tp, v := range p.m {
   217  		if v.gen == generation {
   218  			continue
   219  		}
   220  		v.tex.Release()
   221  		delete(p.m, tp)
   222  		fmt.Printf("%4d textures; released %v\n", len(p.m), tp)
   223  	}
   224  }