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 }