Created
November 23, 2020 05:51
-
-
Save prl900/58cdd4d59ed08dbfda10c8224cc238f4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"image" | |
"image/color" | |
"image/png" | |
"log" | |
"math/rand" | |
"os" | |
"runtime" | |
"runtime/pprof" | |
"time" | |
) | |
// Configuration | |
const ( | |
// Position and height | |
px = -0.5557506 | |
py = -0.55560 | |
ph = 0.000000001 | |
//px = -2 | |
//py = -1.2 | |
//pw = 2.5 | |
// Quality | |
imgWidth = 1920 | |
imgHeight = 1080 | |
maxIter = 1500 | |
samples = 20 | |
linearMixing = true | |
showProgress = true | |
profileCpu = true | |
) | |
const ( | |
ratio = float64(imgWidth) / float64(imgHeight) | |
) | |
func main() { | |
log.Println("Allocating image...") | |
img := image.NewRGBA(image.Rect(0, 0, imgWidth, imgHeight)) | |
log.Println("Rendering...") | |
start := time.Now() | |
render(img) | |
end := time.Now() | |
log.Println("Done rendering in", end.Sub(start)) | |
log.Println("Encoding image...") | |
f, err := os.Create("result.png") | |
if err != nil { | |
panic(err) | |
} | |
err = png.Encode(f, img) | |
if err != nil { | |
panic(err) | |
} | |
log.Println("Done!") | |
} | |
func render(img *image.RGBA) { | |
if profileCpu { | |
f, err := os.Create("profile.prof") | |
if err != nil { | |
panic(err) | |
} | |
pprof.StartCPUProfile(f) | |
defer pprof.StopCPUProfile() | |
} | |
jobs := make(chan int) | |
for i := 0; i < runtime.NumCPU(); i++ { | |
go func () { | |
for y := range jobs { | |
for x := 0; x < imgWidth; x++ { | |
var r, g, b int | |
for i := 0; i < samples; i++ { | |
nx := ph * ratio * ((float64(x) + rand.Float64()) / float64(imgWidth)) + px | |
ny := ph * ((float64(y) + rand.Float64()) / float64(imgHeight)) + py | |
c := paint(mandelbrotIter(nx, ny, maxIter)) | |
if linearMixing { | |
r += int(RGBToLinear(c.R)) | |
g += int(RGBToLinear(c.G)) | |
b += int(RGBToLinear(c.B)) | |
} else { | |
r += int(c.R) | |
g += int(c.G) | |
b += int(c.B) | |
} | |
} | |
var cr, cg, cb uint8 | |
if linearMixing { | |
cr = LinearToRGB(uint16(float64(r) / float64(samples))) | |
cg = LinearToRGB(uint16(float64(g) / float64(samples))) | |
cb = LinearToRGB(uint16(float64(b) / float64(samples))) | |
} else { | |
cr = uint8(float64(r) / float64(samples)) | |
cg = uint8(float64(g) / float64(samples)) | |
cb = uint8(float64(b) / float64(samples)) | |
} | |
img.SetRGBA(x, y, color.RGBA{ R: cr, G: cg, B: cb, A: 255 }) | |
} | |
} | |
}() | |
} | |
for y := 0; y < imgHeight; y++ { | |
jobs <- y | |
if showProgress { | |
fmt.Printf("\r%d/%d (%d%%)", y, imgHeight, int(100*(float64(y) / float64(imgHeight)))) | |
} | |
} | |
if showProgress { | |
fmt.Printf("\r%d/%[1]d (100%%)\n", imgHeight) | |
} | |
} | |
func paint(r float64, n int) color.RGBA { | |
insideSet := color.RGBA{ R: 255, G: 255, B: 255, A: 255 } | |
if r > 4 { | |
return hslToRGB(float64(n) / 800 * r, 1, 0.5) | |
} | |
return insideSet | |
} | |
func mandelbrotIter(px, py float64, maxIter int) (float64, int) { | |
var x, y, xx, yy, xy float64 | |
for i := 0; i < maxIter; i++ { | |
xx, yy, xy = x * x, y * y, x * y | |
if xx + yy > 4 { | |
return xx + yy, i | |
} | |
x = xx - yy + px | |
y = 2 * xy + py | |
} | |
return xx + yy, maxIter | |
} | |
// by u/Boraini | |
//func mandelbrotIterComplex(px, py float64, maxIter int) (float64, int) { | |
// var current complex128 | |
// pxpy := complex(px, py) | |
// | |
// for i := 0; i < maxIter; i++ { | |
// magnitude := cmplx.Abs(current) | |
// if magnitude > 2 { | |
// return magnitude * magnitude, i | |
// } | |
// current = current * current + pxpy | |
// } | |
// | |
// magnitude := cmplx.Abs(current) | |
// return magnitude * magnitude, maxIter | |
//} | |
// https://github.com/ncruces/go-image/blob/v0.1.0/imageutil/srgb.go | |
var rgb2lin = [...]uint16{ | |
0x0000, 0x0014, 0x0028, 0x003c, 0x0050, 0x0063, 0x0077, 0x008b, | |
0x009f, 0x00b3, 0x00c7, 0x00db, 0x00f1, 0x0108, 0x0120, 0x0139, | |
0x0154, 0x016f, 0x018c, 0x01ab, 0x01ca, 0x01eb, 0x020e, 0x0232, | |
0x0257, 0x027d, 0x02a5, 0x02ce, 0x02f9, 0x0325, 0x0353, 0x0382, | |
0x03b3, 0x03e5, 0x0418, 0x044d, 0x0484, 0x04bc, 0x04f6, 0x0532, | |
0x056f, 0x05ad, 0x05ed, 0x062f, 0x0673, 0x06b8, 0x06fe, 0x0747, | |
0x0791, 0x07dd, 0x082a, 0x087a, 0x08ca, 0x091d, 0x0972, 0x09c8, | |
0x0a20, 0x0a79, 0x0ad5, 0x0b32, 0x0b91, 0x0bf2, 0x0c55, 0x0cba, | |
0x0d20, 0x0d88, 0x0df2, 0x0e5e, 0x0ecc, 0x0f3c, 0x0fae, 0x1021, | |
0x1097, 0x110e, 0x1188, 0x1203, 0x1280, 0x1300, 0x1381, 0x1404, | |
0x1489, 0x1510, 0x159a, 0x1625, 0x16b2, 0x1741, 0x17d3, 0x1866, | |
0x18fb, 0x1993, 0x1a2c, 0x1ac8, 0x1b66, 0x1c06, 0x1ca7, 0x1d4c, | |
0x1df2, 0x1e9a, 0x1f44, 0x1ff1, 0x20a0, 0x2150, 0x2204, 0x22b9, | |
0x2370, 0x242a, 0x24e5, 0x25a3, 0x2664, 0x2726, 0x27eb, 0x28b1, | |
0x297b, 0x2a46, 0x2b14, 0x2be3, 0x2cb6, 0x2d8a, 0x2e61, 0x2f3a, | |
0x3015, 0x30f2, 0x31d2, 0x32b4, 0x3399, 0x3480, 0x3569, 0x3655, | |
0x3742, 0x3833, 0x3925, 0x3a1a, 0x3b12, 0x3c0b, 0x3d07, 0x3e06, | |
0x3f07, 0x400a, 0x4110, 0x4218, 0x4323, 0x4430, 0x453f, 0x4651, | |
0x4765, 0x487c, 0x4995, 0x4ab1, 0x4bcf, 0x4cf0, 0x4e13, 0x4f39, | |
0x5061, 0x518c, 0x52b9, 0x53e9, 0x551b, 0x5650, 0x5787, 0x58c1, | |
0x59fe, 0x5b3d, 0x5c7e, 0x5dc2, 0x5f09, 0x6052, 0x619e, 0x62ed, | |
0x643e, 0x6591, 0x66e8, 0x6840, 0x699c, 0x6afa, 0x6c5b, 0x6dbe, | |
0x6f24, 0x708d, 0x71f8, 0x7366, 0x74d7, 0x764a, 0x77c0, 0x7939, | |
0x7ab4, 0x7c32, 0x7db3, 0x7f37, 0x80bd, 0x8246, 0x83d1, 0x855f, | |
0x86f0, 0x8884, 0x8a1b, 0x8bb4, 0x8d50, 0x8eef, 0x9090, 0x9235, | |
0x93dc, 0x9586, 0x9732, 0x98e2, 0x9a94, 0x9c49, 0x9e01, 0x9fbb, | |
0xa179, 0xa339, 0xa4fc, 0xa6c2, 0xa88b, 0xaa56, 0xac25, 0xadf6, | |
0xafca, 0xb1a1, 0xb37b, 0xb557, 0xb737, 0xb919, 0xbaff, 0xbce7, | |
0xbed2, 0xc0c0, 0xc2b1, 0xc4a5, 0xc69c, 0xc895, 0xca92, 0xcc91, | |
0xce94, 0xd099, 0xd2a1, 0xd4ad, 0xd6bb, 0xd8cc, 0xdae0, 0xdcf7, | |
0xdf11, 0xe12e, 0xe34e, 0xe571, 0xe797, 0xe9c0, 0xebec, 0xee1b, | |
0xf04d, 0xf282, 0xf4ba, 0xf6f5, 0xf933, 0xfb74, 0xfdb8, 0xffff, | |
} | |
var lin2rgb = [...]uint16{ | |
0x0000, 0x0cfc, 0x15f9, 0x1c6b, 0x21ce, 0x2671, 0x2a93, 0x2e53, | |
0x31c6, 0x34fb, 0x37fd, 0x3ad3, 0x3d83, 0x4013, 0x4286, 0x44e0, | |
0x4722, 0x4950, 0x4b6b, 0x4d75, 0x4f6f, 0x515b, 0x5339, 0x550a, | |
0x56d0, 0x588b, 0x5a3c, 0x5be3, 0x5d82, 0x5f17, 0x60a5, 0x622b, | |
0x63a9, 0x6521, 0x6692, 0x67fd, 0x6962, 0x6ac1, 0x6c1a, 0x6d6f, | |
0x6ebe, 0x7008, 0x714e, 0x7290, 0x73cc, 0x7505, 0x763a, 0x776b, | |
0x7898, 0x79c1, 0x7ae7, 0x7c0a, 0x7d29, 0x7e45, 0x7f5e, 0x8074, | |
0x8187, 0x8297, 0x83a4, 0x84af, 0x85b7, 0x86bd, 0x87c0, 0x88c0, | |
0x89be, 0x8aba, 0x8bb4, 0x8cab, 0x8da1, 0x8e94, 0x8f85, 0x9074, | |
0x9161, 0x924d, 0x9336, 0x941e, 0x9503, 0x95e7, 0x96ca, 0x97aa, | |
0x9889, 0x9967, 0x9a42, 0x9b1d, 0x9bf5, 0x9ccc, 0x9da2, 0x9e76, | |
0x9f49, 0xa01b, 0xa0eb, 0xa1b9, 0xa287, 0xa353, 0xa41e, 0xa4e7, | |
0xa5b0, 0xa677, 0xa73d, 0xa802, 0xa8c5, 0xa988, 0xaa49, 0xab09, | |
0xabc8, 0xac87, 0xad44, 0xae00, 0xaebb, 0xaf75, 0xb02d, 0xb0e5, | |
0xb19d, 0xb253, 0xb308, 0xb3bc, 0xb46f, 0xb522, 0xb5d3, 0xb684, | |
0xb734, 0xb7e3, 0xb891, 0xb93e, 0xb9ea, 0xba96, 0xbb41, 0xbbeb, | |
0xbc94, 0xbd3d, 0xbde4, 0xbe8b, 0xbf32, 0xbfd7, 0xc07c, 0xc120, | |
0xc1c3, 0xc266, 0xc308, 0xc3a9, 0xc44a, 0xc4ea, 0xc589, 0xc628, | |
0xc6c6, 0xc763, 0xc800, 0xc89c, 0xc937, 0xc9d2, 0xca6d, 0xcb06, | |
0xcb9f, 0xcc38, 0xccd0, 0xcd67, 0xcdfe, 0xce94, 0xcf2a, 0xcfbf, | |
0xd053, 0xd0e7, 0xd17b, 0xd20e, 0xd2a0, 0xd332, 0xd3c3, 0xd454, | |
0xd4e5, 0xd574, 0xd604, 0xd693, 0xd721, 0xd7af, 0xd83c, 0xd8c9, | |
0xd956, 0xd9e2, 0xda6d, 0xdaf8, 0xdb83, 0xdc0d, 0xdc97, 0xdd20, | |
0xdda9, 0xde32, 0xdeba, 0xdf41, 0xdfc8, 0xe04f, 0xe0d6, 0xe15b, | |
0xe1e1, 0xe266, 0xe2eb, 0xe36f, 0xe3f3, 0xe477, 0xe4fa, 0xe57c, | |
0xe5ff, 0xe681, 0xe702, 0xe784, 0xe804, 0xe885, 0xe905, 0xe985, | |
0xea04, 0xea83, 0xeb02, 0xeb80, 0xebfe, 0xec7c, 0xecf9, 0xed76, | |
0xedf3, 0xee6f, 0xeeeb, 0xef67, 0xefe2, 0xf05d, 0xf0d8, 0xf152, | |
0xf1cc, 0xf246, 0xf2bf, 0xf338, 0xf3b1, 0xf429, 0xf4a1, 0xf519, | |
0xf591, 0xf608, 0xf67f, 0xf6f6, 0xf76c, 0xf7e2, 0xf858, 0xf8cd, | |
0xf942, 0xf9b7, 0xfa2c, 0xfaa0, 0xfb14, 0xfb88, 0xfbfc, 0xfc6f, | |
0xfce2, 0xfd54, 0xfdc7, 0xfe39, 0xfeab, 0xff1d, 0xff8e, 0xffff, | |
} | |
func RGBToLinear(rgb uint8) uint16 { | |
return rgb2lin[rgb] | |
} | |
func LinearToRGB(lin uint16) uint8 { | |
mul := uint64(lin) * 0xff0100 | |
div := uint32(mul >> 32) | |
l := uint32(lin2rgb[uint8(div)]) | |
return uint8((uint64(257 * l + uint32(uint64(uint32(mul)) * 257 >> 32) * | |
(uint32(lin2rgb[uint8(div + 1)]) - l ) + 0x8100) * 0x1fc05f9) >> 41) | |
} | |
func hueToRGB(p, q, t float64) float64 { | |
if t < 0 { t += 1 } | |
if t > 1 { t -= 1 } | |
switch { | |
case t < 1.0 / 6.0: | |
return p + (q - p) * 6 * t | |
case t < 1.0 / 2.0: | |
return q | |
case t < 2.0 / 3.0: | |
return p + (q - p) * (2.0 / 3.0 - t) * 6 | |
default: | |
return p | |
} | |
} | |
func hslToRGB(h, s, l float64) color.RGBA { | |
var r, g, b float64 | |
if s == 0 { | |
r, g, b = l, l, l | |
} else { | |
var q, p float64 | |
if l < 0.5 { | |
q = l * (1 + s) | |
} else { | |
q = l + s - l * s | |
} | |
p = 2 * l - q | |
r = hueToRGB(p, q, h + 1.0 / 3.0) | |
g = hueToRGB(p, q, h) | |
b = hueToRGB(p, q, h - 1.0 / 3.0) | |
} | |
return color.RGBA{ R: uint8(r * 255), G: uint8(g * 255), B: uint8(b * 255), A: 255 } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment