-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.lua
145 lines (128 loc) · 5.5 KB
/
main.lua
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
local cn = require("lib/complex")
local Bitmap = require("lib/lua-bitmap")
local cli = require("lib/cli-command")
local path = "./"
local command = cli.buildCommandString({...})
if (cli.getSwitch(command, "?", "help")) then
print("Usage: lua main.lua [options]")
print("Options:")
print(" -w, --width <width> Width of the image [Default: 900]")
print(" -h, --height <height> Height of the image [Default: 600]")
print("")
print(" -r, --real <real> Real part of the center point [Default: -0.5]")
print(" -i, --imag <imag> Imaginary part of the center point [Default: 0]")
print(" -z, --zoom <zoom> Zoom level [Default: 0]")
print(" -n, --iterations <iter> Maximum number of iterations [Default: 255]")
print("")
print(" -o, --output <file> Output file path [Default: "..path.."mandel-<width>x<height>.bmp]")
print(" -x, --interactive Interactive mode")
print(" -b, --black Black inside the set")
print(" -v, --verbose Verbose output")
print(" -p, --progress Show progress")
print(" -?, --help Show this help")
return
end
local width = tonumber(cli.getArgument(command, "w", "width") or 900)
local height = tonumber(cli.getArgument(command, "h", "height") or 600)
local realCenter = tonumber(cli.getArgument(command, "r", "real") or -0.5)
local imaginaryCenter = tonumber(cli.getArgument(command, "i", "imag") or 0)
local zoom = tonumber(cli.getArgument(command, "z", "zoom") or 0)
local maxIterations = tonumber(cli.getArgument(command, "n", "iterations") or 255)
local filePath = cli.getArgument(command, "o", "output") or path.."mandel-"..width.."x"..height..".bmp"
local interactive = cli.getSwitch(command, "x", "interactive") and true
local blackInside = cli.getSwitch(command, "b", "black") and true
local verbose = cli.getSwitch(command, "v", "verbose")
local progressReporting = cli.getSwitch(command, "p", "progress")
local keepInsideWhite
function easingFunction(x)
if x >= 1 then
return 1 * keepInsideWhite
else
return 1 - math.exp(-(maxIterations / 40 / math.max(zoom, 1)) * x)
end
end
local bmp = Bitmap.empty_bitmap(width, height, false)
local running = true
while running do
if verbose then
print("Generating Mandelbrot set with parameters:")
print("Width: "..width)
print("Height: "..height)
print("Center Point: "..realCenter.." + "..imaginaryCenter.."i")
print("Zoom: e^"..zoom.." = "..math.exp(zoom))
print("Max iterations: "..maxIterations)
print("Black inside: "..tostring(blackInside))
print("Location command: -r "..realCenter.." -i "..imaginaryCenter.." -z "..zoom.." -n "..maxIterations)
end
if blackInside then
keepInsideWhite = 0
else
keepInsideWhite = 1
end
local center = cn.new(realCenter, imaginaryCenter)
local aspectRatio = width / height
zoomE = math.exp(zoom)
local topLeft = cn.new(center.r - (aspectRatio / zoomE), center.i + (1 / zoomE))
local bottomRight = cn.new(center.r + (aspectRatio / zoomE), center.i - (1 / zoomE))
local realWidth = bottomRight.r - topLeft.r
local imaginaryHeight = topLeft.i - bottomRight.i
for y = 0, height-1 do
local imaginaryCoordinate = topLeft.i - y/height * imaginaryHeight
for x = 0, width-1 do
local realCoordinate = topLeft.r + x/width * realWidth
local c = cn.new(realCoordinate, imaginaryCoordinate)
local z = cn.new(0, 0)
local i = 0
while i < maxIterations and cn.mag(z) < 1000000000000 do
z = cn.add(cn.pow(z, 2), c)
i = i + 1
end
local ni = i/maxIterations
local grayScaleValue = easingFunction(ni) * 255
bmp:set_pixel(x, y, grayScaleValue, grayScaleValue, grayScaleValue)
end
if progressReporting then
print("Progress: "..(math.floor(y/height*10000)/100).."%\r")
end
end
if verbose then
print("Calculations done, writing to file...")
print("Total time: "..string.format("%.2f", os.clock()).."s")
end
io.open(filePath, "w"):write(bmp:tostring())
print("Done writing image to "..filePath)
while interactive do
print("Enter 'wasd+-erv' to generate another image or enter 'q' to quit")
local input = io.read(1)
if input == "q" then
running = false
break
elseif input == "+" then
zoom = zoom + 0.1
elseif input == "-" then
zoom = zoom - 0.1
elseif input == "w" then
imaginaryCenter = imaginaryCenter + imaginaryHeight/10
elseif input == "s" then
imaginaryCenter = imaginaryCenter - imaginaryHeight/10
elseif input == "a" then
realCenter = realCenter - realWidth/10
elseif input == "d" then
realCenter = realCenter + realWidth/10
elseif input == "b" then
blackInside = not blackInside
elseif input == "e" then
maxIterations = maxIterations * 1.1
elseif input == "r" then
maxIterations = maxIterations / 1.1
elseif input == "v" then
print("Toggled verbose option")
verbose = not verbose
elseif input == "\n" then
break
end
end
if not interactive then
running = false
end
end