summaryrefslogtreecommitdiffstats
path: root/src/renderer.jl
blob: 1842dbbaba3d94907746adc077493e0088d501ef (plain) (blame)
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
using Tk
using Images
using ImageView
using Color

type FractalCanvas
    c::Canvas
    f::FractalExplorer.Fractal
    image::Array{HSV{Float64}, 2}

    function FractalCanvas(c::Canvas, range::(Float64, Float64, Float64, Float64), make_c::Function, step::Function)
        winsize = tuple(get_size(c)...)
        f = FractalExplorer.Fractal{Float64}(winsize, range, make_c, step)
        image = [ HSV(0, 0, 0) for y=1:winsize[2], x=1:winsize[1] ]
        fc = new(c, f, image)
        c.draw = function(x)
            props = Dict()
            img2 = ImageView.ImageSlice2d(fc.image, props)
            imgc = ImageView.ImageCanvas(ImageView.cairo_format(fc.image), props)
            imgc.c = fc.c
            ImageView.allocate_surface!(imgc, winsize[1], winsize[2])
            ImageView.rerender(imgc, img2)
            ImageView.resize(imgc, img2)
        end
        bind(c, "<Double-Button-1>", (path,x,y)->fractal(c, make_c, step, false))
        return fc
    end
end

mandelbrot(fc::FractalCanvas) = mandelbrot(fc.c)
function mandelbrot(canvas::Canvas = createwindow())
    return fractal(canvas, z -> z, (z, c) -> z.^2 + c)
end

julia(fc::FractalCanvas, c = 0) = julia(fc.c, c)
function julia(canvas::Canvas = createwindow(), c::Union(Number, Array{Number, 2}) = 0)
    return fractal(canvas, z -> c, (z, c) -> z.^2 + c)
end

fractal(make_c, step) = fractal(createwindow(), make_c, step)
fractal(fc::FractalCanvas, make_c, step) = fractal(fc.c, make_c, step)
function fractal(canvas::Canvas, make_c::Function, step::Function, should_wait=!isinteractive(), range=(-2.0, -2.0, 4.0, 4.0))
    fc = FractalCanvas(canvas, range, make_c, step)

    i = 0
    while true
        FractalExplorer.step(fc.f)
        new_pixels = (abs(fc.f.z) .> 2) & (fc.image .== HSV(0, 0, 0))
        fc.image[new_pixels] = HSV(i * 4, 1, 1)
        i = i + 1
        redraw(fc)
        if length(find(new_pixels)) <= 1
            break
        end
    end

    if should_wait
        cv = Condition()
        win = Tk.toplevel(fc.c)
        bind(win, "<Destroy>", e->notify(cv))
        wait(cv)
    end

    return fc
end

function createwindow(winsize::(Integer, Integer) = (640, 480))
    win = Toplevel("FractalExplorer", winsize[1], winsize[2], false)
    frame = Frame(win)
    pack(frame, expand=true, fill="both")
    canvas = Canvas(frame, winsize[1], winsize[2])
    pack(canvas, expand=true, fill="both")
    set_visible(win, true)
    # XXX this is needed because not calling view before get_size causes things
    # to fail for some reason? it shouldn't be necessary otherwise
    view(canvas, [ HSV(0, 0, 0) for y=1:winsize[2], x=1:winsize[1] ], interactive=false)
    return canvas
end

function redraw(fc::FractalCanvas)
    return view(fc.c, fc.image, interactive=false)
end