Skip to content

Instantly share code, notes, and snippets.

@suapapa
Last active December 14, 2020 13:47
Show Gist options
  • Save suapapa/d570273588f340abe966d89582c9daab to your computer and use it in GitHub Desktop.
Save suapapa/d570273588f340abe966d89582c9daab to your computer and use it in GitHub Desktop.
xmas-tree
package main
import (
"image"
"image/color"
"log"
"math"
"math/rand"
"time"
"periph.io/x/periph/conn/display"
"periph.io/x/periph/conn/spi/spireg"
"periph.io/x/periph/devices/apa102"
"periph.io/x/periph/host"
)
const (
starCnt = 30
)
type Star struct {
c color.Color
lifeTime time.Time
}
type Stars struct {
cnt int
stars []Star
img *image.NRGBA
}
func NewStars(cnt int) *Stars {
return &Stars{
cnt: cnt,
stars: make([]Star, cnt),
img: image.NewNRGBA(image.Rect(0, 0, cnt, 1)),
}
}
func (s *Stars) Refresh(t time.Time) image.Image {
for i, b := range s.stars {
if b.lifeTime.Before(t) {
s.stars[i].c = &HSV{
H: rand.Float64(),
S: rand.Float64(),
V: 1.0,
}
s.stars[i].lifeTime = t.Add(
time.Second + time.Duration(rand.Intn(2000))*time.Millisecond,
)
}
}
for x := 0; x < s.cnt; x++ {
s.img.SetNRGBA(x, 0, NRGBA(s.stars[x].c))
}
return s.img
}
// HSV represents HSV color space
type HSV struct {
H, S, V float64
}
// RGBA implements color.Color interface
func (c *HSV) RGBA() (r, g, b, a uint32) {
fr, fg, fb := c.rgb()
r = uint32(math.Round(fr * 0xffffffff))
g = uint32(math.Round(fg * 0xffffffff))
b = uint32(math.Round(fb * 0xffffffff))
a = 0xffffffff
return
}
func (c *HSV) rgb() (r, g, b float64) {
if c.S == 0 { //HSV from 0 to 1
r = c.V * 255
g = c.V * 255
b = c.V * 255
} else {
h := c.H * 6
if h == 6 {
h = 0
} //H must be < 1
i := math.Floor(h) //Or ... var_i = floor( var_h )
v1 := c.V * (1 - c.S)
v2 := c.V * (1 - c.S*(h-i))
v3 := c.V * (1 - c.S*(1-(h-i)))
if i == 0 {
r = c.V
g = v3
b = v1
} else if i == 1 {
r = v2
g = c.V
b = v1
} else if i == 2 {
r = v1
g = c.V
b = v3
} else if i == 3 {
r = v1
g = v2
b = c.V
} else if i == 4 {
r = v3
g = v1
b = c.V
} else {
r = c.V
g = v1
b = v2
}
}
return r, g, b
}
func init() {
rand.Seed(time.Now().UnixNano())
}
func main() {
if _, err := host.Init(); err != nil {
log.Fatal(err)
}
d := getLEDs()
stars := NewStars(starCnt)
tk := time.NewTicker(time.Second / 10) // FPS
for t := range tk.C {
img := stars.Refresh(t)
if err := d.Draw(d.Bounds(), img, image.Point{}); err != nil {
log.Fatal(err)
}
}
}
// getLEDs returns an *apa102.Dev, or fails back to *screen.Dev if no SPI port
// is found.
func getLEDs() display.Drawer {
s, err := spireg.Open("")
if err != nil {
panic(err)
}
// Change the option values to see their effects.
var dispOpts = &apa102.Opts{
NumPixels: starCnt, // 150 LEDs is a common strip length.
Intensity: 128, // Full blinding power.
Temperature: 5000, // More pleasing white balance than NeutralTemp.
DisableGlobalPWM: false, // Use full 13 bits range.
}
d, err := apa102.New(s, dispOpts)
if err != nil {
log.Fatal(err)
}
return d
}
// NRGBA convert color.Color to color.NRGBA
func NRGBA(c color.Color) color.NRGBA {
r, g, b, _ := c.RGBA()
fr, fg, fb := float64(r), float64(g), float64(b)
return color.NRGBA{
R: uint8(math.Round(fr * 0xff)),
G: uint8(math.Round(fg * 0xff)),
B: uint8(math.Round(fb * 0xff)),
A: 0xff,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment