-
Notifications
You must be signed in to change notification settings - Fork 0
/
donut.go
105 lines (95 loc) · 2.48 KB
/
donut.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package main
import (
"flag"
"fmt"
"image"
"image/gif"
"log"
"os"
"time"
"github.com/ejacobg/donut/frame"
"golang.org/x/term"
)
var (
GIF = flag.String("gif", "", "Generate a GIF file with the given name")
steps = flag.Int("steps", 200, "Number of frames to generate")
delay = flag.Int("delay", 50, "Delay between frames, in milliseconds")
width = flag.Int("width", 100, "Width of the GIF file, if needed")
height = flag.Int("height", 100, "Height of the GIF file, if needed")
)
func main() {
flag.Parse()
genGIF := GIF != nil && *GIF != ""
var f frame.Frame
var min int
rect := image.Rect(0, 0, *width, *height)
palette := frame.Gray16Palette()
g := &gif.GIF{
Config: image.Config{ColorModel: palette, Width: *width, Height: *height},
BackgroundIndex: 0,
}
if genGIF {
f = &frame.GIF{
Image: image.NewPaletted(rect, palette),
SF: frame.Gray16SF,
}
} else {
width, height, err := term.GetSize(int(os.Stdin.Fd()))
if err != nil {
log.Fatalln(err)
}
if width < height {
min = width
} else {
// If we're constrained by height, we subtract 1 because fmt.Println adds an extra line.
// If we don't do this, we get artifacts when multiple renders occur.
min = height - 1
}
f = frame.NewASCII(min, min, frame.ASCIISF)
}
torus := frame.DefaultTorus()
scene := frame.Scene{
Width: min,
Height: min,
K2: 5.0,
LX: 0.0,
LY: 1.0,
LZ: -1.0,
}
if genGIF {
scene.Width, scene.Height = *width, *height
}
scene.CalculateK1(torus.R1, torus.R2)
// How much the angles should change between each step.
// Move this inside the Torus struct?
startA, startB := 15.0, 25.0
stepA, stepB := 0.07, 0.03
for {
var s int
for s, torus.A, torus.B = 0, startA, startB; s < *steps; s, torus.A, torus.B = s+1, torus.A+stepA, torus.B+stepB {
f.Reset() // Should the Render function clear the frame instead of doing it here?
frame.Render(f, torus, scene)
switch v := f.(type) {
case *frame.GIF:
g.Image = append(g.Image, v.Image)
g.Delay = append(g.Delay, *delay/10)
g.Disposal = append(g.Disposal, gif.DisposalBackground)
v.Image = image.NewPaletted(rect, palette)
case *frame.ASCII:
v.Print(os.Stdout)
fmt.Printf("\033[%dF", min)
}
if !genGIF {
time.Sleep(time.Duration(*delay) * time.Millisecond)
}
}
if genGIF {
break
}
}
file, _ := os.OpenFile(*GIF, os.O_WRONLY|os.O_CREATE, 0600)
defer func(file *os.File) {
_ = file.Close()
}(file)
_ = gif.EncodeAll(file, g)
}