1206 lines
25 KiB
Go
1206 lines
25 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
"image/png"
|
|
"math"
|
|
"math/rand"
|
|
"os"
|
|
)
|
|
|
|
var palette = map[byte][3]uint8{
|
|
'0': {0, 0, 0}, '1': {0, 0, 128}, '2': {0, 128, 0},
|
|
'3': {0, 128, 128}, '4': {128, 0, 0}, '5': {128, 0, 128},
|
|
'6': {128, 128, 0}, '7': {192, 192, 192}, '8': {128, 128, 128},
|
|
'9': {0, 0, 255}, 'a': {0, 255, 0}, 'b': {0, 255, 255},
|
|
'c': {255, 0, 0}, 'd': {255, 0, 255}, 'e': {255, 255, 0},
|
|
'f': {255, 255, 255},
|
|
}
|
|
|
|
var (
|
|
bright = []byte("9abcdef")
|
|
dark = []byte("012345")
|
|
mid = []byte("6789abcd")
|
|
all = []byte("0123456789abcdef")
|
|
)
|
|
|
|
func u4(n int) byte {
|
|
return "0123456789abcdef"[n&0xF]
|
|
}
|
|
|
|
func randColor(pool []byte) byte {
|
|
if pool == nil {
|
|
pool = all
|
|
}
|
|
return pool[rand.Intn(len(pool))]
|
|
}
|
|
|
|
func hexToRGB(c byte) [3]uint8 {
|
|
if v, ok := palette[c]; ok {
|
|
return v
|
|
}
|
|
return [3]uint8{0, 0, 0}
|
|
}
|
|
|
|
func effToPixels(eff map[int]string) [][]color.RGBA {
|
|
pixels := make([][]color.RGBA, 31)
|
|
for i := 0; i < 31; i++ {
|
|
row := make([]color.RGBA, 88)
|
|
rowStr := eff[i+1]
|
|
for j := 0; j < 88; j++ {
|
|
if j < len(rowStr) {
|
|
rgb := hexToRGB(rowStr[j])
|
|
row[j] = color.RGBA{rgb[0], rgb[1], rgb[2], 255}
|
|
} else {
|
|
row[j] = color.RGBA{0, 0, 0, 255}
|
|
}
|
|
}
|
|
pixels[i] = row
|
|
}
|
|
return pixels
|
|
}
|
|
|
|
var sin = []byte("01122334455666777888889999999999998888777666554433221100")
|
|
|
|
var sinAltInt = []int{
|
|
6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11,
|
|
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11,
|
|
10, 10, 10, 9, 9, 9, 9, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3,
|
|
2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
|
|
1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7,
|
|
}
|
|
|
|
func arrayRandomize(ref []byte, colorSet string) []byte {
|
|
mapping := make(map[byte]byte)
|
|
hexChars := []byte("0123456789abcdef")
|
|
if colorSet != "" {
|
|
colors := []byte{}
|
|
for i := 0; i < len(colorSet); i++ {
|
|
if colorSet[i] != ' ' {
|
|
colors = append(colors, colorSet[i])
|
|
}
|
|
}
|
|
for _, h := range hexChars {
|
|
mapping[h] = colors[rand.Intn(len(colors))]
|
|
}
|
|
} else {
|
|
for _, h := range hexChars {
|
|
mapping[h] = u4(rand.Intn(16))
|
|
}
|
|
}
|
|
result := make([]byte, len(ref))
|
|
for i, x := range ref {
|
|
if v, ok := mapping[x]; ok {
|
|
result[i] = v
|
|
} else {
|
|
result[i] = x
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func effectSinRand() map[int]string {
|
|
eff := make(map[int]string)
|
|
s := []string{"f a", "a b d", "a b", "a f", "c d", "e 5", "b c f"}
|
|
meow := arrayRandomize(sin, s[rand.Intn(len(s))])
|
|
a := 0
|
|
for i := 1; i < 32; i += 2 {
|
|
eff[i] = ""
|
|
eff[i+1] = ""
|
|
for j := 1; j < 45; j++ {
|
|
idx := (a * 2) % len(meow)
|
|
l := meow[idx]
|
|
eff[i] += string([]byte{l, l})
|
|
eff[i+1] += string([]byte{l, l})
|
|
a++
|
|
if a >= len(meow) {
|
|
a = 0
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSinRandWorse() map[int]string {
|
|
eff := make(map[int]string)
|
|
length := rand.Intn(99)
|
|
meow := make([]byte, length)
|
|
for i := range meow {
|
|
meow[i] = '0'
|
|
}
|
|
meow = arrayRandomize(meow, "a b c d e f")
|
|
a := 0
|
|
for i := 1; i < 32; i += 2 {
|
|
eff[i+1] = "0"
|
|
eff[i] = ""
|
|
for j := 1; j < 45; j++ {
|
|
var idx int
|
|
if len(meow) > 0 {
|
|
idx = (a * 2) % len(meow)
|
|
}
|
|
var l byte = '0'
|
|
if len(meow) > 0 {
|
|
l = meow[idx]
|
|
}
|
|
eff[i] += string([]byte{l, l})
|
|
eff[i+1] += string([]byte{l, l})
|
|
a++
|
|
if a >= length {
|
|
a = 0
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSin2() map[int]string {
|
|
eff := make(map[int]string)
|
|
c := []string{"a f", "e 5", "d c", "d b"}
|
|
randa := c[rand.Intn(len(c))]
|
|
randb := c[rand.Intn(len(c))]
|
|
randc := c[rand.Intn(len(c))]
|
|
randd := c[rand.Intn(len(c))]
|
|
rd := []byte{randd[0], randd[2]}
|
|
ra := []byte{randa[0], randa[2]}
|
|
rb := []byte{randb[0], randb[2]}
|
|
rc := []byte{randc[0], randc[2]}
|
|
for i := 1; i < 32; i++ {
|
|
eff[i] = ""
|
|
for j := 1; j < 89; j++ {
|
|
x := 15
|
|
if j-1 < len(sinAltInt) {
|
|
x = sinAltInt[j-1] + 15
|
|
}
|
|
switch {
|
|
case x == i-10:
|
|
eff[i] += string(rd[0])
|
|
case x == i-9:
|
|
eff[i] += string(rd[1])
|
|
case x == i-8:
|
|
eff[i] += string(rd[0])
|
|
case x == i:
|
|
eff[i] += string(ra[0])
|
|
case x == i+1:
|
|
eff[i] += string(ra[1])
|
|
case x == i+2:
|
|
eff[i] += string(ra[0])
|
|
case x == i+10:
|
|
eff[i] += string(rb[0])
|
|
case x == i+11:
|
|
eff[i] += string(rb[1])
|
|
case x == i+12:
|
|
eff[i] += string(rb[0])
|
|
case x == i+20:
|
|
eff[i] += string(rc[0])
|
|
case x == i+21:
|
|
eff[i] += string(rc[1])
|
|
case x == i+22:
|
|
eff[i] += string(rc[0])
|
|
default:
|
|
eff[i] += "0"
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectRand() map[int]string {
|
|
eff := make(map[int]string)
|
|
for i := 1; i < 32; i += 2 {
|
|
eff[i] = ""
|
|
eff[i+1] = ""
|
|
for j := 1; j < 45; j++ {
|
|
a := u4(rand.Intn(5) + 10)
|
|
eff[i] += string([]byte{a, a})
|
|
eff[i+1] += string([]byte{a, a})
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSpeccy() map[int]string {
|
|
eff := make(map[int]string)
|
|
b := rand.Intn(3) + 3
|
|
for i := 1; i < 32; i++ {
|
|
eff[i] = ""
|
|
for j := 1; j < 11; j++ {
|
|
eff[i] += "0"
|
|
}
|
|
a := 10 + i
|
|
j := 11
|
|
for ; j < 89; j++ {
|
|
if a == j {
|
|
break
|
|
}
|
|
eff[i] += "0"
|
|
}
|
|
for ; j < 89; j++ {
|
|
if i < 6 && j < 40 {
|
|
eff[i] += "0"
|
|
} else {
|
|
eff[i] += string(u4(((j - a) % b) + 10))
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSpeccy2x() map[int]string {
|
|
eff := make(map[int]string)
|
|
b := rand.Intn(3) + 3
|
|
for i := 1; i < 32; i++ {
|
|
eff[i] = ""
|
|
for j := 1; j < 11; j++ {
|
|
eff[i] += "0"
|
|
}
|
|
a := 10 + i
|
|
j := 11
|
|
for ; j < 89; j++ {
|
|
if a == j {
|
|
break
|
|
}
|
|
eff[i] += "0"
|
|
}
|
|
for ; j < 89; j += 2 {
|
|
if i < 6 && j < 40 {
|
|
eff[i] += "00"
|
|
} else {
|
|
c := u4(((j - a) % b) + 10)
|
|
eff[i] += string([]byte{c, c})
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSpeccy2xPride() map[int]string {
|
|
eff := make(map[int]string)
|
|
c := []string{"e d a 2 6 b", "5 9 5 c", "0 e 9 2", "0e cc 5b"}
|
|
bStr := c[rand.Intn(len(c))]
|
|
b := []string{}
|
|
for i := 0; i < len(bStr); {
|
|
if bStr[i] == ' ' {
|
|
i++
|
|
continue
|
|
}
|
|
if i+1 < len(bStr) && bStr[i+1] != ' ' {
|
|
b = append(b, bStr[i:i+2])
|
|
i += 2
|
|
} else {
|
|
b = append(b, bStr[i:i+1])
|
|
i++
|
|
}
|
|
}
|
|
w := []int{4, 6, 8, 10, 12, 16, 24}
|
|
width := w[rand.Intn(len(w))]
|
|
for i := 1; i < 32; i++ {
|
|
eff[i] = ""
|
|
for j := 1; j < 11; j++ {
|
|
eff[i] += "0"
|
|
}
|
|
a := 10 + i
|
|
j := 11
|
|
for ; j < 89; j++ {
|
|
if a == j {
|
|
break
|
|
}
|
|
eff[i] += "0"
|
|
}
|
|
for ; j < 89; j += 2 {
|
|
if i < 6 && j < 40 {
|
|
eff[i] += "00"
|
|
} else {
|
|
idx := ((i - j) / width) % len(b)
|
|
if idx < 0 {
|
|
idx = -idx
|
|
}
|
|
d := b[idx]
|
|
if len(d) == 2 {
|
|
eff[i] += d
|
|
} else {
|
|
eff[i] += d + d
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectCheckerboard() map[int]string {
|
|
eff := make(map[int]string)
|
|
s := []byte("abcdef5")
|
|
c := s[rand.Intn(len(s))]
|
|
for i := 1; i < 32; i++ {
|
|
eff[i] = ""
|
|
if (i%4)/2 == 0 {
|
|
eff[i] += "00"
|
|
}
|
|
for j := 1; j < 89; j++ {
|
|
if j%2 == 0 {
|
|
eff[i] += "00"
|
|
} else {
|
|
eff[i] += string([]byte{c, c})
|
|
}
|
|
}
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectHorizontalStripes() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, rand.Intn(5)+2)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
thickness := rand.Intn(4) + 1
|
|
for i := 1; i < 32; i++ {
|
|
c := colors[(i/thickness)%len(colors)]
|
|
eff[i] = string(bytes.Repeat([]byte{c}, 88))
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectVerticalStripes() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, rand.Intn(7)+2)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
thickness := rand.Intn(7) + 2
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
row[j-1] = colors[(j/thickness)%len(colors)]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectDiagonalStripes() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, rand.Intn(4)+2)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
slope := rand.Intn(4) + 1
|
|
div := rand.Intn(6) + 3
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
idx := ((i + j*slope) / div) % len(colors)
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectGradientHorizontal() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(bright)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if j < 44 {
|
|
if rand.Float64() > (float64(j) / 44.0) {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
} else {
|
|
if rand.Float64() > (float64(j-44) / 44.0) {
|
|
row[j-1] = c2
|
|
} else {
|
|
row[j-1] = c1
|
|
}
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectGradientVertical() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(bright)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
t := float64(i-1) / 30.0
|
|
for j := 1; j < 89; j++ {
|
|
if rand.Float64() > t {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectPlasma() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 4)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
scale1 := rand.Float64()*0.3 + 0.1
|
|
scale2 := rand.Float64()*0.3 + 0.1
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
v := math.Sin(float64(i)*scale1) + math.Cos(float64(j)*scale2) + math.Sin(float64(i+j)*0.1)
|
|
idx := int((v+2)*float64(len(colors))/4.0) % len(colors)
|
|
if idx < 0 {
|
|
idx = -idx
|
|
}
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectNoise() map[int]string {
|
|
eff := make(map[int]string)
|
|
pool := append([]byte{}, bright...)
|
|
pool = append(pool, mid...)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
row[j-1] = randColor(pool)
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectDitheredNoise() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(bright)
|
|
threshold := rand.Float64()*0.4 + 0.3
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if rand.Float64() > threshold {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectScanlines() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if i%2 == 0 {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectCrosshatch() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
period := rand.Intn(6) + 3
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if i%period == 0 || j%period == 0 {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectZigzag() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 3)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
period := rand.Intn(7) + 4
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
z := (i + (j % (period * 2))) / period
|
|
row[j-1] = colors[z%len(colors)]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectRainbow() map[int]string {
|
|
eff := make(map[int]string)
|
|
rainbow := []byte("ce a9d5b")
|
|
thickness := rand.Intn(4) + 2
|
|
for i := 1; i < 32; i++ {
|
|
c := rainbow[(i/thickness)%len(rainbow)]
|
|
eff[i] = string(bytes.Repeat([]byte{c}, 88))
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectRainbowVertical() map[int]string {
|
|
eff := make(map[int]string)
|
|
rainbow := []byte("ce a9d5b")
|
|
thickness := rand.Intn(9) + 4
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
row[j-1] = rainbow[(j/thickness)%len(rainbow)]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectWaveHorizontal() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(bright)
|
|
freq := rand.Float64()*0.3 + 0.1
|
|
amp := rand.Intn(6) + 3
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
waveCenter := 15 + int(float64(amp)*math.Sin(float64(i)*freq))
|
|
for j := 1; j < 89; j++ {
|
|
dist := abs(j - waveCenter)
|
|
if dist < 3 {
|
|
row[j-1] = c1
|
|
} else if dist < 6 {
|
|
row[j-1] = c2
|
|
} else {
|
|
row[j-1] = '0'
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectWaveVertical() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 4)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
freq := rand.Float64()*0.2 + 0.1
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
v := int(2*math.Sin(float64(j)*freq) + 2)
|
|
row[j-1] = colors[v%len(colors)]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectCircles() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 5)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
cx, cy := 44.0, 15.0
|
|
div := rand.Float64()*3.0 + 3.0
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
dist := math.Sqrt(math.Pow(float64(j)-cx, 2) + math.Pow(float64(i)-cy, 2))
|
|
idx := int(dist/div) % len(colors)
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectRadialGradient() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
cx, cy := 44.0, 15.0
|
|
maxDist := math.Sqrt(44*44 + 15*15)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
dist := math.Sqrt(math.Pow(float64(j)-cx, 2) + math.Pow(float64(i)-cy, 2))
|
|
t := dist / maxDist
|
|
if rand.Float64() > t {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectDiamond() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 3)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
size := rand.Intn(7) + 4
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
d := (abs(i-16) + abs(j-44)) / size
|
|
row[j-1] = colors[d%len(colors)]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectTriangles() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 3)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
period := rand.Intn(9) + 6
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
t := float64(j%period) / float64(period)
|
|
if t < 0.33 {
|
|
row[j-1] = colors[0]
|
|
} else if t < 0.66 {
|
|
row[j-1] = colors[1]
|
|
} else {
|
|
row[j-1] = colors[2]
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectBorder() map[int]string {
|
|
eff := make(map[int]string)
|
|
border := randColor(bright)
|
|
fill := randColor(dark)
|
|
bw := rand.Intn(4) + 2
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if i <= bw || i > 31-bw || j <= bw || j > 88-bw {
|
|
row[j-1] = border
|
|
} else {
|
|
row[j-1] = fill
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectDots() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
spacing := rand.Intn(6) + 5
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if (i%spacing) == (spacing/2) && (j%spacing) == (spacing/2) {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectMaze() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
block := rand.Intn(7) + 4
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
bx := (j / block) % 2
|
|
by := (i / block) % 2
|
|
if bx^by == 1 {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectInterference() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 3)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
f1 := rand.Float64()*0.2 + 0.1
|
|
f2 := rand.Float64()*0.2 + 0.1
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
v := math.Sin(float64(i)*f1) * math.Sin(float64(j)*f2)
|
|
idx := 0
|
|
if v > 0.3 {
|
|
idx = 0
|
|
} else if v > -0.3 {
|
|
idx = 1
|
|
} else {
|
|
idx = 2
|
|
}
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectVoronoi() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 4)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
points := make([][2]int, 4)
|
|
for i := range points {
|
|
points[i] = [2]int{rand.Intn(69) + 10, rand.Intn(22) + 5}
|
|
}
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
minDist := 1<<30
|
|
nearest := 0
|
|
for idx, p := range points {
|
|
d := (j-p[0])*(j-p[0]) + (i-p[1])*(i-p[1])
|
|
if d < minDist {
|
|
minDist = d
|
|
nearest = idx
|
|
}
|
|
}
|
|
row[j-1] = colors[nearest]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSpiral() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 4)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
cx, cy := 44.0, 15.0
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
dx := float64(j) - cx
|
|
dy := float64(i) - cy
|
|
angle := math.Atan2(dy, dx)
|
|
dist := math.Sqrt(dx*dx + dy*dy)
|
|
spiral := (dist + angle*5) / 8
|
|
idx := int(spiral) % len(colors)
|
|
if idx < 0 {
|
|
idx = -idx
|
|
}
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectTartan() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(bright)
|
|
c3 := randColor(bright)
|
|
hPeriod := rand.Intn(9) + 6
|
|
vPeriod := rand.Intn(9) + 6
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
h := (i/(hPeriod/2))%2 == 0
|
|
v := (j/(vPeriod/2))%2 == 0
|
|
if h && v {
|
|
row[j-1] = c3
|
|
} else if h || v {
|
|
row[j-1] = c2
|
|
} else {
|
|
row[j-1] = c1
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectBricks() map[int]string {
|
|
eff := make(map[int]string)
|
|
brick := randColor(bright)
|
|
mortar := randColor(dark)
|
|
h := rand.Intn(4) + 3
|
|
w := rand.Intn(9) + 8
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
offset := (i / h) % 2 * (w / 2)
|
|
for j := 1; j < 89; j++ {
|
|
bx := (j + offset) % w
|
|
by := i % h
|
|
if bx == 0 || by == 0 {
|
|
row[j-1] = mortar
|
|
} else {
|
|
row[j-1] = brick
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectRipple() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 4)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
cx, cy := 44.0, 15.0
|
|
div := rand.Float64()*3.0 + 2.0
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
dist := math.Sqrt(math.Pow(float64(j)-cx, 2) + math.Pow(float64(i)-cy, 2))
|
|
idx := int(dist/div) % len(colors)
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectHeatMap() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := []byte("046ec")
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
v := (float64(i) / 31.0) * (float64(j) / 88.0)
|
|
idx := int(v*float64(len(colors))) % len(colors)
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectPixelSort() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 5)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 0, 88)
|
|
band := rand.Intn(9) + 4
|
|
pos := 0
|
|
for pos < 88 {
|
|
c := colors[rand.Intn(len(colors))]
|
|
w := rand.Intn(band-1) + 2
|
|
if pos+w > 88 {
|
|
w = 88 - pos
|
|
}
|
|
for k := 0; k < w; k++ {
|
|
row = append(row, c)
|
|
}
|
|
pos += w
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectLissajous() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
a := rand.Intn(4) + 2
|
|
b := rand.Intn(4) + 2
|
|
delta := rand.Float64() * math.Pi
|
|
curve := make(map[[2]int]bool)
|
|
for t := 0; t < 1000; t++ {
|
|
tt := float64(t) * 0.01
|
|
x := int(44 + 35*math.Sin(float64(a)*tt+delta))
|
|
y := int(15 + 10*math.Sin(float64(b)*tt))
|
|
if y >= 1 && y <= 31 && x >= 1 && x <= 88 {
|
|
curve[[2]int{x, y}] = true
|
|
}
|
|
}
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if curve[[2]int{j, i}] {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectTextured() map[int]string {
|
|
eff := make(map[int]string)
|
|
base := randColor(dark)
|
|
accent := randColor(bright)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if rand.Float64() < 0.15 {
|
|
row[j-1] = accent
|
|
} else {
|
|
row[j-1] = base
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectHalftone() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
dist := math.Sqrt(math.Pow(float64(j)-44, 2) + math.Pow(float64(i)-15, 2))
|
|
threshold := dist / 50.0
|
|
if rand.Float64() > threshold {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectPinstripe() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
if j%2 == 0 {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectSunburst() map[int]string {
|
|
eff := make(map[int]string)
|
|
colors := make([]byte, 6)
|
|
for i := range colors {
|
|
colors[i] = randColor(bright)
|
|
}
|
|
cx, cy := 44.0, 15.0
|
|
rays := rand.Intn(11) + 6
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
angle := math.Atan2(float64(i)-cy, float64(j)-cx)
|
|
idx := int((angle+math.Pi)/(2*math.Pi)*float64(rays)) % len(colors)
|
|
if idx < 0 {
|
|
idx = -idx
|
|
}
|
|
row[j-1] = colors[idx]
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectBayer() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(dark)
|
|
bayer := [4][4]int{
|
|
{0, 8, 2, 10},
|
|
{12, 4, 14, 6},
|
|
{3, 11, 1, 9},
|
|
{15, 7, 13, 5},
|
|
}
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
threshold := float64(bayer[(i-1)%4][(j-1)%4]) / 16.0
|
|
if threshold > 0.5 {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
func effectWoven() map[int]string {
|
|
eff := make(map[int]string)
|
|
c1 := randColor(bright)
|
|
c2 := randColor(bright)
|
|
c3 := randColor(dark)
|
|
period := rand.Intn(5) + 4
|
|
for i := 1; i < 32; i++ {
|
|
row := make([]byte, 88)
|
|
for j := 1; j < 89; j++ {
|
|
h := (i/period)%2 == 0
|
|
v := (j/period)%2 == 0
|
|
if h == v {
|
|
if h {
|
|
row[j-1] = c1
|
|
} else {
|
|
row[j-1] = c2
|
|
}
|
|
} else {
|
|
row[j-1] = c3
|
|
}
|
|
}
|
|
eff[i] = string(row)
|
|
}
|
|
return eff
|
|
}
|
|
|
|
var effects = []func() map[int]string{
|
|
effectSinRand,
|
|
effectSinRandWorse,
|
|
effectSin2, effectSin2, effectSin2,
|
|
effectRand,
|
|
effectSpeccy2x,
|
|
effectSpeccy2xPride, effectSpeccy2xPride,
|
|
effectCheckerboard,
|
|
effectHorizontalStripes, effectVerticalStripes, effectDiagonalStripes,
|
|
effectGradientHorizontal, effectGradientVertical, effectPlasma,
|
|
effectNoise, effectDitheredNoise, effectScanlines, effectCrosshatch,
|
|
effectZigzag, effectRainbow, effectRainbowVertical,
|
|
effectWaveHorizontal, effectWaveVertical, effectCircles,
|
|
effectRadialGradient, effectDiamond, effectTriangles, effectBorder,
|
|
effectDots, effectMaze, effectInterference, effectVoronoi,
|
|
effectSpiral, effectTartan, effectBricks, effectRipple,
|
|
effectHeatMap, effectPixelSort, effectLissajous, effectTextured,
|
|
effectHalftone, effectPinstripe, effectSunburst, effectBayer, effectWoven,
|
|
}
|
|
|
|
func compositeWithOverlay(basePixels [][]color.RGBA, overlayPath string) (image.Image, error) {
|
|
base := image.NewRGBA(image.Rect(0, 0, 88, 31))
|
|
for y, row := range basePixels {
|
|
for x, c := range row {
|
|
base.SetRGBA(x, y, c)
|
|
}
|
|
}
|
|
overlayFile, err := os.Open(overlayPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer overlayFile.Close()
|
|
overlay, err := png.Decode(overlayFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if overlay.Bounds().Dx() != 88 || overlay.Bounds().Dy() != 31 {
|
|
resized := image.NewRGBA(image.Rect(0, 0, 88, 31))
|
|
for y := 0; y < 31; y++ {
|
|
for x := 0; x < 88; x++ {
|
|
sx := x * overlay.Bounds().Dx() / 88
|
|
sy := y * overlay.Bounds().Dy() / 31
|
|
resized.Set(x, y, overlay.At(sx+overlay.Bounds().Min.X, sy+overlay.Bounds().Min.Y))
|
|
}
|
|
}
|
|
overlay = resized
|
|
}
|
|
result := image.NewRGBA(image.Rect(0, 0, 88, 31))
|
|
draw.Draw(result, result.Bounds(), base, image.Point{}, draw.Src)
|
|
draw.Draw(result, result.Bounds(), overlay, image.Point{}, draw.Over)
|
|
return result, nil
|
|
}
|
|
|
|
func abs(a int) int {
|
|
if a < 0 {
|
|
return -a
|
|
}
|
|
return a
|
|
}
|
|
|
|
func main() {
|
|
var overlayPath, outputPath string
|
|
flag.StringVar(&overlayPath, "overlay", "overlay.png", "Absolute path to the overlay PNG file")
|
|
flag.StringVar(&outputPath, "output", "button.png", "Absolute path for the output PNG file")
|
|
flag.Parse()
|
|
|
|
effectFunc := effects[rand.Intn(len(effects))]
|
|
eff := effectFunc()
|
|
pixels := effToPixels(eff)
|
|
result, err := compositeWithOverlay(pixels, overlayPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
out, err := os.Create(outputPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer out.Close()
|
|
if err := png.Encode(out, result); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Printf("Generated %s\n", outputPath)
|
|
}
|