| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -8,7 +8,6 @@ import (
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"sync"
 | 
					 | 
					 | 
					 | 
						"sync"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"golang.org/x/exp/shiny/driver"
 | 
					 | 
					 | 
					 | 
						"golang.org/x/exp/shiny/driver"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"golang.org/x/exp/shiny/imageutil"
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"golang.org/x/exp/shiny/screen"
 | 
					 | 
					 | 
					 | 
						"golang.org/x/exp/shiny/screen"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"golang.org/x/mobile/event/paint"
 | 
					 | 
					 | 
					 | 
						"golang.org/x/mobile/event/paint"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						"golang.org/x/mobile/event/size"
 | 
					 | 
					 | 
					 | 
						"golang.org/x/mobile/event/size"
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -17,13 +16,14 @@ import (
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					const DefaultPixelPitch = 12
 | 
					 | 
					 | 
					 | 
					const DefaultPixelPitch = 12
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					const windowTitle = "RGB led matrix emulator"
 | 
					 | 
					 | 
					 | 
					const windowTitle = "RGB led matrix emulator"
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					var margin = 10
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					type Emulator struct {
 | 
					 | 
					 | 
					 | 
					type Emulator struct {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						PixelPitch              int
 | 
					 | 
					 | 
					 | 
						PixelPitch              int
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						Gutter                  int
 | 
					 | 
					 | 
					 | 
						Gutter                  int
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						Width                   int
 | 
					 | 
					 | 
					 | 
						Width                   int
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						Height                  int
 | 
					 | 
					 | 
					 | 
						Height                  int
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						GutterColor             color.Color
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						PixelPitchToGutterRatio int
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						Margin                  int
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						leds []color.Color
 | 
					 | 
					 | 
					 | 
						leds []color.Color
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						w    screen.Window
 | 
					 | 
					 | 
					 | 
						w    screen.Window
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -35,11 +35,13 @@ type Emulator struct {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func NewEmulator(w, h, pixelPitch int, autoInit bool) *Emulator {
 | 
					 | 
					 | 
					 | 
					func NewEmulator(w, h, pixelPitch int, autoInit bool) *Emulator {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e := &Emulator{
 | 
					 | 
					 | 
					 | 
						e := &Emulator{
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							PixelPitch: pixelPitch,
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							Gutter:     int(float64(pixelPitch) * 0.66),
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							Width:                   w,
 | 
					 | 
					 | 
					 | 
							Width:                   w,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							Height:                  h,
 | 
					 | 
					 | 
					 | 
							Height:                  h,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							GutterColor:             color.Gray{Y: 20},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							PixelPitchToGutterRatio: 2,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							Margin:                  10,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						e.updatePixelPitchForGutter(pixelPitch / e.PixelPitchToGutterRatio)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if autoInit {
 | 
					 | 
					 | 
					 | 
						if autoInit {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							e.Init()
 | 
					 | 
					 | 
					 | 
							e.Init()
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -61,8 +63,12 @@ func (e *Emulator) Init() {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (e *Emulator) mainWindowLoop(s screen.Screen) {
 | 
					 | 
					 | 
					 | 
					func (e *Emulator) mainWindowLoop(s screen.Screen) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						var err error
 | 
					 | 
					 | 
					 | 
						var err error
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.s = s
 | 
					 | 
					 | 
					 | 
						e.s = s
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// Calculate initial window size based on whatever our gutter/pixel pitch currently is.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						dims := e.matrixWithMarginsRect()
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.w, err = s.NewWindow(&screen.NewWindowOptions{
 | 
					 | 
					 | 
					 | 
						e.w, err = s.NewWindow(&screen.NewWindowOptions{
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							Title:  windowTitle,
 | 
					 | 
					 | 
					 | 
							Title:  windowTitle,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							Width:  dims.Max.X,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							Height: dims.Max.Y,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						})
 | 
					 | 
					 | 
					 | 
						})
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if err != nil {
 | 
					 | 
					 | 
					 | 
						if err != nil {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -94,26 +100,68 @@ func (e *Emulator) mainWindowLoop(s screen.Screen) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (e *Emulator) drawContext(sz size.Event) {
 | 
					 | 
					 | 
					 | 
					func (e *Emulator) drawContext(sz size.Event) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.updatePixelPitch(sz.Size())
 | 
					 | 
					 | 
					 | 
						e.updatePixelPitchForGutter(e.calculateGutterForViewableArea(sz.Size()))
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for _, r := range imageutil.Border(sz.Bounds(), margin) {
 | 
					 | 
					 | 
					 | 
						// Fill entire background with white.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							e.w.Fill(r, color.White, screen.Src)
 | 
					 | 
					 | 
					 | 
						e.w.Fill(sz.Bounds(), color.White, screen.Src)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						// Fill matrix display rectangle with the gutter color.
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						e.w.Fill(e.matrixWithMarginsRect(), e.GutterColor, screen.Src)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// Set all LEDs to black.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						e.Apply(make([]color.Color, e.Width*e.Height))
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.w.Fill(sz.Bounds().Inset(margin), color.Black, screen.Src)
 | 
					 | 
					 | 
					 | 
					// Some formulas that allowed me to better understand the drawable area. I found that the math was
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.w.Publish()
 | 
					 | 
					 | 
					 | 
					// easiest when put in terms of the Gutter width, hence the addition of PixelPitchToGutterRatio.
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// PixelPitch = PixelPitchToGutterRatio * Gutter
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// DisplayWidth = (PixelPitch * LEDColumns) + (Gutter * (LEDColumns - 1)) + (2 * Margin)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// Gutter = (DisplayWidth - (2 * Margin)) / (PixelPitchToGutterRatio * LEDColumns + LEDColumns - 1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MMMMMMMMMMMMMMMM.....MMMM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGGGGGGGGGGGGGGG.....GGGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGLGLGLGLGLGLGLG.....GLGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGGGGGGGGGGGGGGG.....GGGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGLGLGLGLGLGLGLG.....GLGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGGGGGGGGGGGGGGG.....GGGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  .........................
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGGGGGGGGGGGGGGG.....GGGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGLGLGLGLGLGLGLG.....GLGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MGGGGGGGGGGGGGGG.....GGGM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  MMMMMMMMMMMMMMMM.....MMMM
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//  where:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//    M = Margin
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//    G = Gutter
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					//    L = LED
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// matrixWithMarginsRect Returns a Rectangle that describes entire emulated RGB Matrix, including margins.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					func (e *Emulator) matrixWithMarginsRect() image.Rectangle {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						upperLeftLED := e.ledRect(0, 0)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						lowerRightLED := e.ledRect(e.Width-1, e.Height-1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						return image.Rect(upperLeftLED.Min.X-e.Margin, upperLeftLED.Min.Y-e.Margin, lowerRightLED.Max.X+e.Margin, lowerRightLED.Max.Y+e.Margin)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (e *Emulator) updatePixelPitch(size image.Point) {
 | 
					 | 
					 | 
					 | 
					// ledRect Returns a Rectangle for the LED at col and row.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						maxLedSizeInX := (size.X - (margin * 2)) / e.Width
 | 
					 | 
					 | 
					 | 
					func (e *Emulator) ledRect(col int, row int) image.Rectangle {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						maxLedSizeInY := (size.Y - (margin * 2)) / e.Height
 | 
					 | 
					 | 
					 | 
						x := (col * (e.PixelPitch + e.Gutter)) + e.Margin
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						y := (row * (e.PixelPitch + e.Gutter)) + e.Margin
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						return image.Rect(x, y, x+e.PixelPitch, y+e.PixelPitch)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						maxLedSize := maxLedSizeInY
 | 
					 | 
					 | 
					 | 
					// calculateGutterForViewableArea As the name states, calculates the size of the gutter for a given viewable area.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if maxLedSizeInX < maxLedSizeInY {
 | 
					 | 
					 | 
					 | 
					// It's easier to understand the geometry of the matrix on screen when put in terms of the gutter,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							maxLedSize = maxLedSizeInX
 | 
					 | 
					 | 
					 | 
					// hence the shift toward calculating the gutter size.
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					func (e *Emulator) calculateGutterForViewableArea(size image.Point) int {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						maxGutterInX := (size.X - 2*e.Margin) / (e.PixelPitchToGutterRatio*e.Width + e.Width - 1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						maxGutterInY := (size.Y - 2*e.Margin) / (e.PixelPitchToGutterRatio*e.Height + e.Height - 1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if maxGutterInX < maxGutterInY {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							return maxGutterInX
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						return maxGutterInY
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.PixelPitch = 2 * (maxLedSize / 3.)
 | 
					 | 
					 | 
					 | 
					func (e *Emulator) updatePixelPitchForGutter(gutterWidth int) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.Gutter = maxLedSize / 3
 | 
					 | 
					 | 
					 | 
						e.PixelPitch = e.PixelPitchToGutterRatio * gutterWidth
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						e.Gutter = gutterWidth
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (e *Emulator) Geometry() (width, height int) {
 | 
					 | 
					 | 
					 | 
					func (e *Emulator) Geometry() (width, height int) {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -123,18 +171,11 @@ func (e *Emulator) Geometry() (width, height int) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					func (e *Emulator) Apply(leds []color.Color) error {
 | 
					 | 
					 | 
					 | 
					func (e *Emulator) Apply(leds []color.Color) error {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						defer func() { e.leds = make([]color.Color, e.Height*e.Width) }()
 | 
					 | 
					 | 
					 | 
						defer func() { e.leds = make([]color.Color, e.Height*e.Width) }()
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						var c color.Color
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for col := 0; col < e.Width; col++ {
 | 
					 | 
					 | 
					 | 
						for col := 0; col < e.Width; col++ {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							for row := 0; row < e.Height; row++ {
 | 
					 | 
					 | 
					 | 
							for row := 0; row < e.Height; row++ {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								x := col * (e.PixelPitch + e.Gutter)
 | 
					 | 
					 | 
					 | 
								c = e.At(col + (row * e.Width))
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								y := row * (e.PixelPitch + e.Gutter)
 | 
					 | 
					 | 
					 | 
								e.w.Fill(e.ledRect(col, row), c, screen.Over)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								x += margin * 2
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								y += margin * 2
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								color := e.At(col + (row * e.Width))
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								led := image.Rect(x, y, x+e.PixelPitch, y+e.PixelPitch)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								e.w.Fill(led, color, screen.Over)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
 
 |