diff --git a/Dockerfile b/Dockerfile index 1f83675..980c2b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ - FROM deadbeef.codes:5000/raspberrypi3-alpine:3.7 +FROM deadbeef.codes:5000/raspberrypi3-alpine:3.7 COPY mandelmapper /usr/bin EXPOSE 6161:6161 CMD mandelmapper diff --git a/render.go b/render.go index 6b30f73..29764c2 100644 --- a/render.go +++ b/render.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "image" "image/color" "image/png" @@ -24,22 +23,9 @@ const ( var ( colors []color.RGBA + queue = make(chan pixel) ) -func mandelbrot(c complex128) uint16 { - - var z complex128 - - for i := 0; i < Iterations; i++ { - z = z*z + c - if cmplx.IsNaN(z) { - return uint16(i) - } - } - - return Iterations -} - type pixel struct { out *image.RGBA x, y int @@ -48,7 +34,22 @@ type pixel struct { wg *sync.WaitGroup } -var queue = make(chan pixel) +func init() { + http.HandleFunc("/mandelbrot/", renderTile) +} + +func main() { + runtime.GOMAXPROCS(runtime.NumCPU()) + + for i := 0; i < runtime.GOMAXPROCS(0); i++ { + go computeThread() + } + + colorStep := float64(Iterations) + colors = interpolateColors("Plan9", colorStep) + + log.Fatal(http.ListenAndServe(":6161", nil)) +} func computeThread() { for p := range queue { @@ -63,18 +64,70 @@ func computeThread() { } } -func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) +//interpolateColors accepts a color palette and number of desired colors and builds a slice of colors by interpolating the gaps +func interpolateColors(paletteCode string, numberOfColors float64) []color.RGBA { + var factor float64 + steps := []float64{} + cols := []uint32{} + interpolated := []uint32{} + interpolatedColors := []color.RGBA{} + for _, v := range palette.ColorPalettes { + factor = 1.0 / numberOfColors + switch v.Keyword { + case paletteCode: + if paletteCode != "" { + for index, col := range v.Colors { + if col.Step == 0.0 && index != 0 { + stepRatio := float64(index+1) / float64(len(v.Colors)) + step := float64(int(stepRatio*100)) / 100 // truncate to 2 decimal precision + steps = append(steps, step) + } else { + steps = append(steps, col.Step) + } + r, g, b, a := col.Color.RGBA() + r /= 0xff + g /= 0xff + b /= 0xff + a /= 0xff + uintColor := uint32(r)<<24 | uint32(g)<<16 | uint32(b)<<8 | uint32(a) + cols = append(cols, uintColor) + } + var min, max, minColor, maxColor float64 + if len(v.Colors) == len(steps) && len(v.Colors) == len(cols) { + for i := 0.0; i <= 1; i += factor { + for j := 0; j < len(v.Colors)-1; j++ { + if i >= steps[j] && i < steps[j+1] { + min = steps[j] + max = steps[j+1] + minColor = float64(cols[j]) + maxColor = float64(cols[j+1]) + uintColor := cosineInterpolation(maxColor, minColor, (i-min)/(max-min)) + interpolated = append(interpolated, uint32(uintColor)) + } + } + } + } + for _, pixelValue := range interpolated { + r := pixelValue >> 24 & 0xff + g := pixelValue >> 16 & 0xff + b := pixelValue >> 8 & 0xff + a := 0xff - for i := 0; i < runtime.GOMAXPROCS(0); i++ { - go computeThread() + interpolatedColors = append(interpolatedColors, color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}) + } + } + } } + return interpolatedColors +} - colorStep := float64(Iterations) - colors = interpolateColors("Plan9", colorStep) - fmt.Println(len(colors)) +func cosineInterpolation(c1, c2, mu float64) float64 { + mu2 := (1 - math.Cos(mu*math.Pi)) / 2.0 + return c1*(1-mu2) + c2*mu2 +} - log.Fatal(http.ListenAndServe(":6161", nil)) +func linearInterpolation(c1, c2, mu uint32) uint32 { + return c1*(1-mu) + c2*mu } func renderTile(w http.ResponseWriter, r *http.Request) { @@ -103,9 +156,7 @@ func renderTile(w http.ResponseWriter, r *http.Request) { } var wg sync.WaitGroup - wg.Add(Size * Size) - img := image.NewRGBA(image.Rect(0, 0, Size, Size)) for x := 0; x < Size; x++ { @@ -116,114 +167,17 @@ func renderTile(w http.ResponseWriter, r *http.Request) { } wg.Wait() - - /* - ip := GetOutboundIP() - addLabel(img, 20, 30, fmt.Sprintf("rendered by \n%s", ip.String())) - addLabel(img, 20, 30, fmt.Sprintf("%s/%s/%s.png", components[1], components[2], components[3])) - */ w.Header().Set("Content-Type", "image/png") png.Encode(w, img) } -func init() { - http.HandleFunc("/mandelbrot/", renderTile) -} - -func interpolateColors(paletteCode string, numberOfColors float64) []color.RGBA { - var factor float64 - steps := []float64{} - cols := []uint32{} - interpolated := []uint32{} - interpolatedColors := []color.RGBA{} - - for _, v := range palette.ColorPalettes { - factor = 1.0 / numberOfColors - switch v.Keyword { - case paletteCode: - if paletteCode != "" { - for index, col := range v.Colors { - if col.Step == 0.0 && index != 0 { - stepRatio := float64(index+1) / float64(len(v.Colors)) - step := float64(int(stepRatio*100)) / 100 // truncate to 2 decimal precision - steps = append(steps, step) - } else { - steps = append(steps, col.Step) - } - r, g, b, a := col.Color.RGBA() - r /= 0xff - g /= 0xff - b /= 0xff - a /= 0xff - uintColor := uint32(r)<<24 | uint32(g)<<16 | uint32(b)<<8 | uint32(a) - cols = append(cols, uintColor) - } - - var min, max, minColor, maxColor float64 - if len(v.Colors) == len(steps) && len(v.Colors) == len(cols) { - for i := 0.0; i <= 1; i += factor { - for j := 0; j < len(v.Colors)-1; j++ { - if i >= steps[j] && i < steps[j+1] { - min = steps[j] - max = steps[j+1] - minColor = float64(cols[j]) - maxColor = float64(cols[j+1]) - uintColor := cosineInterpolation(maxColor, minColor, (i-min)/(max-min)) - interpolated = append(interpolated, uint32(uintColor)) - } - } - } - } - - for _, pixelValue := range interpolated { - r := pixelValue >> 24 & 0xff - g := pixelValue >> 16 & 0xff - b := pixelValue >> 8 & 0xff - a := 0xff - - interpolatedColors = append(interpolatedColors, color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}) - } - } +func mandelbrot(c complex128) uint16 { + var z complex128 + for i := 0; i < Iterations; i++ { + z = z*z + c + if cmplx.IsNaN(z) { + return uint16(i) } } - - return interpolatedColors + return Iterations } - -func cosineInterpolation(c1, c2, mu float64) float64 { - mu2 := (1 - math.Cos(mu*math.Pi)) / 2.0 - return c1*(1-mu2) + c2*mu2 -} - -func linearInterpolation(c1, c2, mu uint32) uint32 { - return c1*(1-mu) + c2*mu -} - -//Adds a text label to an image -/* -func addLabel(img *image.RGBA, x, y int, label string) { - col := color.RGBA{255, 255, 255, 255} - point := fixed.Point26_6{fixed.Int26_6(x * 64), fixed.Int26_6(y * 64)} - - d := &font.Drawer{ - Dst: img, - Src: image.NewUniform(col), - Face: basicfont.Face7x13, - Dot: point, - } - d.DrawString(label) -} - - -func GetOutboundIP() net.IP { - conn, err := net.Dial("udp", "8.8.8.8:80") - if err != nil { - log.Fatal(err) - } - defer conn.Close() - - localAddr := conn.LocalAddr().(*net.UDPAddr) - - return localAddr.IP -} -*/