1
0
Fork 0
leet/draw.go

98 lines
2.0 KiB
Go
Raw Normal View History

2019-04-12 15:11:11 +08:00
package main // import "github.com/serverwentdown/leet"
import (
"log"
"time"
2019-04-12 15:11:11 +08:00
ws2811 "github.com/rpi-ws281x/rpi-ws281x-go"
)
// TODO: full-sized grid with multiple channels mapped onto the grid
const (
MAX_LAYERS = 10
)
2019-04-12 15:11:11 +08:00
type Drawer struct {
Length int
2019-04-12 15:11:11 +08:00
layers [][]uint32
device *ws2811.WS2811
}
func NewDrawer(length int) (*Drawer, error) {
opt := ws2811.DefaultOptions
opt.Channels[0].LedCount = length
2019-04-19 17:09:09 +08:00
opt.Channels[0].Brightness = 255
2019-04-12 15:11:11 +08:00
d := &Drawer{}
d.Length = length
d.layers = make([][]uint32, MAX_LAYERS)
for i := range d.layers {
d.layers[i] = make([]uint32, length)
}
for i := range d.layers[0] {
d.layers[0][i] = 0xff000000
}
2019-04-12 15:11:11 +08:00
dev, err := ws2811.MakeWS2811(&opt)
if err != nil {
return nil, err
}
err = dev.Init()
if err != nil {
return nil, err
}
d.device = dev
return d, nil
}
func (d *Drawer) SetLayer(layer int32, dots []uint32) {
for i, dot := range dots {
if i > d.Length {
break
2019-04-12 15:11:11 +08:00
}
d.layers[layer][i] = dot
2019-04-12 15:11:11 +08:00
}
}
func (d *Drawer) Draw() error {
timeMixStart := time.Now()
for i := 0; i < d.Length; i++ {
2019-04-12 15:11:11 +08:00
dot := mix(d.layers, i)
d.device.Leds(0)[i] = dot
}
timeMixEnd := time.Now()
2019-04-12 15:11:11 +08:00
if err := d.device.Render(); err != nil {
return err
}
log.Printf("mix took %d milliseconds", timeMixEnd.Sub(timeMixStart)/1000/1000)
2019-04-12 15:11:11 +08:00
return nil
}
func mix(layers [][]uint32, i int) uint32 {
2019-04-12 15:11:11 +08:00
var base uint32
for _, layer := range layers {
if i >= len(layer) {
2019-04-19 17:09:09 +08:00
continue
}
base = mixColors(layer[i], base)
2019-04-12 15:11:11 +08:00
}
return base
}
func mixColors(a uint32, b uint32) uint32 {
// Extract channels
aa, ba := uint32(a>>24), uint32(b>>24)
ar, br := a&uint32(0x00FF0000)>>16, b&uint32(0x00FF0000)>>16
ag, bg := a&uint32(0x0000FF00)>>8, b&uint32(0x0000FF00)>>8
ab, bb := a&uint32(0x000000FF), b&uint32(0x000000FF)
// Apply alpha computation to each channel
oa := uint32(ba*(255-aa)/255 + aa)
or := uint32(br*ba*(255-aa)/(255*255) + ar*aa/255)
og := uint32(bg*ba*(255-aa)/(255*255) + ag*aa/255)
ob := uint32(bb*ba*(255-aa)/(255*255) + ab*aa/255)
return (oa << 24) | (or << 16) | (og << 8) | ob
}