Zigでマンデルブロ集合

zigが流行ってると聞いて。人類に手動メモリ管理はまだ早いんだよな。もっと脳が進化してくれないと難しい。足りない脳でやってくしかないのだ現代人たる我(々?)は。

SDLのビルドでつまづいたりした。自分でbuild.zigいじるのいやだったので、パッケージマネージャーであるところのgyroを使ってみたけどうまく動かなかった。直接git cloneして/libsにでも突っ込んどけばなんとかなるっぽい。SDL2-develもルートに置いとけば勝手に見てくれるっぽい。SDL.zigがビルド用のSdkを用意してくれてるのでそれ任せ。

const std = @import("std");
const SDL = @import("sdl2");
const math = std.math;
const complex = math.complex;

pub fn main() !void {
    try SDL.init(.{
        .video = true,
        .events = true,
        .audio = true,
    });
    defer SDL.quit();

    const height = 800;
    const width = 800;

    var window = try SDL.createWindow(
        "SDL.zig",
        .{ .centered = {} },
        .{ .centered = {} },
        width,
        height,
        .{ .vis = .shown },
    );
    defer window.destroy();

    var renderer = try SDL.createRenderer(window, null, .{ .accelerated = true });
    defer renderer.destroy();

    var texture = try SDL.createTexture(renderer, .rgba8888, .streaming, width, height);
    defer texture.destroy();

    var buf = std.mem.zeroes([width * height * 4]u8);
    var y: f32 = -2;
    var x: f32 = -2;
    var i: usize = 0;
    while (i < width * height * 4) : (i += 4) {
        const m = mandelbrot(x, y, 255);
        const c = @intCast(u8, m);
        const b = @floatToInt(u8, @fabs(@floor(x * @intToFloat(f32, m))) / 255);
        buf[i + 0] = c;
        buf[i + 1] = b;
        buf[i + 2] = c;
        buf[i + 3] = c;

        x += 0.005;
        if ((i / 4) % width == 0) {
            x = -2;
            y += 0.005;
        }
    }

    try texture.update(&buf, 4 * width, null);

    mainLoop: while (true) {
        while (SDL.pollEvent()) |ev| {
            switch (ev) {
                .quit => {
                    break :mainLoop;
                },
                .key_down => |key| {
                    switch (key.scancode) {
                        .q => break :mainLoop,
                        else => {},
                    }
                },
                else => {},
            }
        }

        try renderer.setColorRGB(0, 0, 0);
        try renderer.clear();
        try renderer.copy(texture, null, null);
        renderer.present();
    }
}

fn mandelbrot(x: f32, y: f32, limit: u32) u32 {
    const c = math.Complex(f32).init(x, y);
    var z = math.Complex(f32).init(0.0, 0.0);
    var n: u32 = 0;
    while (n < limit) : (n += 1) {
        z = z.mul(z).add(c);

        if (complex.abs(z) > 2) {
            return n;
        }
    }
    return 0;
}