1
0
Fork 0
leet/draw.go

98 lines
2.0 KiB
Go

package main // import "github.com/serverwentdown/leet"
import (
"log"
"time"
ws2811 "github.com/rpi-ws281x/rpi-ws281x-go"
)
// TODO: full-sized grid with multiple channels mapped onto the grid
const (
MAX_LAYERS = 10
)
type Drawer struct {
Length int
layers [][]uint32
device *ws2811.WS2811
}
func NewDrawer(length int) (*Drawer, error) {
opt := ws2811.DefaultOptions
opt.Channels[0].LedCount = length
opt.Channels[0].Brightness = 255
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
}
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
}
d.layers[layer][i] = dot
}
}
func (d *Drawer) Draw() error {
timeMixStart := time.Now()
for i := 0; i < d.Length; i++ {
dot := mix(d.layers, i)
d.device.Leds(0)[i] = dot
}
timeMixEnd := time.Now()
if err := d.device.Render(); err != nil {
return err
}
log.Printf("mix took %d milliseconds", timeMixEnd.Sub(timeMixStart)/1000/1000)
return nil
}
func mix(layers [][]uint32, i int) uint32 {
var base uint32
for _, layer := range layers {
if i >= len(layer) {
continue
}
base = mixColors(layer[i], base)
}
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
}