diff --git a/go/Dockerfile b/go/Dockerfile new file mode 100644 index 0000000..9ece61b --- /dev/null +++ b/go/Dockerfile @@ -0,0 +1,8 @@ +FROM golang:1.14-alpine + +WORKDIR /go/src/app +COPY . . + +RUN go install + +CMD ["dancefloor"] diff --git a/go/go.mod b/go/go.mod new file mode 100644 index 0000000..a0db936 --- /dev/null +++ b/go/go.mod @@ -0,0 +1,3 @@ +module dancefloor + +go 1.14 diff --git a/go/go.sum b/go/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/go/main.go b/go/main.go new file mode 100644 index 0000000..5e17332 --- /dev/null +++ b/go/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "bytes" + "dancefloor/patterns" + "encoding/json" + "net/http" + "sync" +) + +var client http.Client +var lock sync.Mutex +var pattern Pattern + +var width, height int + +func main() { + width = 6 + height = 5 + + go drawLoop() + + SetPattern(&patterns.ScrollingText{Text: "Jake is the best!", Colour: [3]uint8{0, 0, 255}, Background: [3]uint8{24, 24, 24}}) + + select {} +} + +type Pattern interface { + Draw(width, height int) *[][]patterns.Colour +} + +func SetPattern(new Pattern) { + lock.Lock() + defer lock.Unlock() + pattern = new +} + +func draw() *[][]patterns.Colour { + lock.Lock() + defer lock.Unlock() + return pattern.Draw(width, height) +} + +func render(data *[][]patterns.Colour) { + content, err := json.Marshal(struct { + Data [][]patterns.Colour `json:"data"` + }{ + Data: *data, + }) + + if err != nil { + panic(err) + } + + req, err := http.NewRequest("PUT", "http://10.10.0.26:5000/update", bytes.NewReader(content)) + if err != nil { + panic(err) + } + req.Header.Add("Content-Type", "application/json") + + _, err = client.Do(req) + if err != nil { + panic(err) + } +} + +func drawLoop() { + for { + render(draw()) + } +} diff --git a/go/patterns/character.go b/go/patterns/character.go new file mode 100644 index 0000000..034310c --- /dev/null +++ b/go/patterns/character.go @@ -0,0 +1,303 @@ +package patterns + +// character maps referenced [y][x] +var masks = make(map[rune]*[5][]bool) + +type Character struct { + Character rune + Colour Colour + Background Colour + + initiated bool + drawn [][]Colour +} + +func (s *Character) Draw(width, height int) *[][]Colour { + if !s.initiated { + s.init(width, height) + s.initiated = true + } + return &s.drawn +} + +func (s *Character) init(width, height int) { + if width == 0 { + if _, ok := masks[s.Character]; ok { + width = len(masks[s.Character][0]) + } + } + + s.drawn = make([][]Colour, width) + for i := 0; i < width; i++ { + s.drawn[i] = make([]Colour, height) + for j := 0; j < height; j++ { + s.drawn[i][j] = s.Background + if val, ok := masks[s.Character]; ok { + y := 5 - j - 1 + if i < len(val[y]) && val[y][i] { + s.drawn[i][j] = s.Colour + } + } + } + } +} + +func init() { + masks['a'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + } + masks['A'] = masks['a'] + + masks['b'] = &[5][]bool{ + {true, true, true, true, false}, + {true, false, false, false, true}, + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, true, true, true, false}, + } + masks['B'] = masks['b'] + + masks['c'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, false}, + {true, false, false, false, false}, + {true, false, false, false, false}, + {true, true, true, true, true}, + } + masks['C'] = masks['c'] + + masks['d'] = &[5][]bool{ + {true, true, true, true, false}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, true, true, true, false}, + } + masks['D'] = masks['d'] + + masks['e'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, false}, + {true, true, true, true, false}, + {true, false, false, false, false}, + {true, true, true, true, true}, + } + masks['E'] = masks['e'] + + masks['f'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, false}, + {true, true, true, true, false}, + {true, false, false, false, false}, + {true, false, false, false, false}, + } + masks['F'] = masks['f'] + + masks['g'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, false}, + {true, false, true, true, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + } + masks['G'] = masks['g'] + + masks['h'] = &[5][]bool{ + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + } + masks['H'] = masks['h'] + + masks['i'] = &[5][]bool{ + {true, true, true, true, true}, + {false, false, true, false, false}, + {false, false, true, false, false}, + {false, false, true, false, false}, + {true, true, true, true, true}, + } + masks['I'] = masks['i'] + + masks['j'] = &[5][]bool{ + {true, true, true, true}, + {false, false, true, false}, + {false, false, true, false}, + {true, false, true, false}, + {true, true, true, false}, + } + masks['J'] = masks['j'] + + masks['k'] = &[5][]bool{ + {true, false, false, true}, + {true, false, true, false}, + {true, true, false, false}, + {true, false, true, false}, + {true, false, false, true}, + } + masks['K'] = masks['k'] + + masks['l'] = &[5][]bool{ + {true, false, false, false, false}, + {true, false, false, false, false}, + {true, false, false, false, false}, + {true, false, false, false, false}, + {true, true, true, true, true}, + } + masks['L'] = masks['l'] + + masks['m'] = &[5][]bool{ + {true, false, false, false, true}, + {true, true, false, true, true}, + {true, false, true, false, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + } + masks['M'] = masks['m'] + + masks['n'] = &[5][]bool{ + {true, false, false, false, true}, + {true, true, false, false, true}, + {true, false, true, false, true}, + {true, false, false, true, true}, + {true, false, false, false, true}, + } + masks['N'] = masks['n'] + + masks['o'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + } + masks['O'] = masks['o'] + + masks['p'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + {true, false, false, false, false}, + {true, false, false, false, false}, + } + masks['P'] = masks['p'] + + masks['q'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, false, true, true}, + {true, true, true, true, true}, + } + masks['Q'] = masks['q'] + + masks['r'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + {true, false, false, true, false}, + {true, false, false, false, true}, + } + masks['R'] = masks['r'] + + masks['s'] = &[5][]bool{ + {true, true, true, true, true}, + {true, false, false, false, false}, + {true, true, true, true, true}, + {false, false, false, false, true}, + {true, true, true, true, true}, + } + masks['S'] = masks['s'] + + masks['t'] = &[5][]bool{ + {true, true, true, true, true}, + {false, false, true, false, false}, + {false, false, true, false, false}, + {false, false, true, false, false}, + {false, false, true, false, false}, + } + masks['T'] = masks['t'] + + masks['u'] = &[5][]bool{ + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, true, true, true, true}, + } + masks['U'] = masks['u'] + + masks['v'] = &[5][]bool{ + {true, false, false, false, true}, + {true, false, false, false, true}, + {false, true, false, true, false}, + {false, true, false, true, false}, + {false, false, true, false, false}, + } + masks['V'] = masks['v'] + + masks['w'] = &[5][]bool{ + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, false, false, true}, + {true, false, true, false, true}, + {true, true, false, true, true}, + } + masks['W'] = masks['w'] + + masks['x'] = &[5][]bool{ + {true, false, false, false, true}, + {false, true, false, true, false}, + {false, false, true, false, false}, + {false, true, false, true, false}, + {true, false, false, false, true}, + } + masks['X'] = masks['x'] + + masks['y'] = &[5][]bool{ + {true, false, false, false, true}, + {false, true, false, true, false}, + {false, false, true, false, false}, + {false, false, true, false, false}, + {false, false, true, false, false}, + } + masks['Y'] = masks['y'] + + masks['z'] = &[5][]bool{ + {true, true, true, true, true}, + {false, false, false, true, false}, + {false, false, true, false, false}, + {false, true, false, false, false}, + {true, true, true, true, true}, + } + masks['Z'] = masks['z'] + + masks[' '] = &[5][]bool{ + {false}, + {false}, + {false}, + {false}, + {false}, + } + + masks['.'] = &[5][]bool{ + {false}, + {false}, + {false}, + {false}, + {true}, + } + + masks['!'] = &[5][]bool{ + {true}, + {true}, + {true}, + {false}, + {true}, + } +} diff --git a/go/patterns/patterns.go b/go/patterns/patterns.go new file mode 100644 index 0000000..03ccef5 --- /dev/null +++ b/go/patterns/patterns.go @@ -0,0 +1,3 @@ +package patterns + +type Colour [3]uint8 diff --git a/go/patterns/scrolling_text.go b/go/patterns/scrolling_text.go new file mode 100644 index 0000000..a482435 --- /dev/null +++ b/go/patterns/scrolling_text.go @@ -0,0 +1,59 @@ +package patterns + +type ScrollingText struct { + Text string + Colour Colour + Background Colour + + initiated bool + fullRender [][]Colour + step int + substep int +} + +func (s *ScrollingText) Draw(width, height int) *[][]Colour { + if !s.initiated { + s.init(width, height) + s.initiated = true + } + + out := s.fullRender[s.step : s.step+width] + + s.substep++ + s.substep %= 12 + if s.substep == 0 { + s.step++ + s.step %= len(s.fullRender) - width + } + return &out +} + +func (s *ScrollingText) init(width, height int) { + // add extra cells so it flows in from the right + for i := 0; i < width-1; i++ { + s.fullRender = append(s.fullRender, s.blankCol(height)) + } + + var c rune + for _, c = range s.Text { + subpattern := Character{Character: c, Colour: s.Colour, Background: s.Background} + drawnSubpattern := subpattern.Draw(0, height) + for _, v := range *drawnSubpattern { + s.fullRender = append(s.fullRender, v) + } + s.fullRender = append(s.fullRender, s.blankCol(height)) + } + + // add extra cells to avoid overflow + for i := 0; i < width-1; i++ { + s.fullRender = append(s.fullRender, s.blankCol(height)) + } +} + +func (s *ScrollingText) blankCol(height int) (col []Colour) { + col = make([]Colour, height) + for j := 0; j < height; j++ { + col[j] = s.Background + } + return +} \ No newline at end of file diff --git a/go/patterns/solid_colour.go b/go/patterns/solid_colour.go new file mode 100644 index 0000000..3680acb --- /dev/null +++ b/go/patterns/solid_colour.go @@ -0,0 +1,16 @@ +package patterns + +type SolidColour struct { + Colour +} + +func (p *SolidColour) Draw(width, height int) *[][][3]uint8 { + out := make([][][3]uint8, width) + for i := 0; i < width; i++ { + out[i] = make([][3]uint8, height) + for j := 0; j < height; j++ { + out[i][j] = p.Colour + } + } + return &out +} \ No newline at end of file diff --git a/go/patterns/super_rgb.go b/go/patterns/super_rgb.go new file mode 100644 index 0000000..5e142ff --- /dev/null +++ b/go/patterns/super_rgb.go @@ -0,0 +1,25 @@ +package patterns + +type SuperRgb struct { + Brightness uint8 + iteration int +} + +func (p *SuperRgb) Draw(width, height int) *[][]Colour { + out := make([][]Colour, width) + for i := 0; i < width; i++ { + out[i] = make([]Colour, height) + for j := 0; j < height; j++ { + switch (i + j + p.iteration/12) % 4 { + case 0, 2: + out[i][j] = [3]uint8{p.Brightness, 0, 0} + case 1: + out[i][j] = [3]uint8{0, p.Brightness, 0} + case 3: + out[i][j] = [3]uint8{0, 0, p.Brightness} + } + } + } + p.iteration++ + return &out +}