「プログラムでシダを描画する」をD言語+SDL2+dubで描画する

空前のシダブームということで、私もD言語とSDL2.0でシダを描いてみました。

# 元ネタ

* [プログラムでシダを描画する - 強火で進め](http://d.hatena.ne.jp/nakamura001/20140505/1399316565)
* [「プログラムでシダを描画する」一覧](http://qiita.com/qt-luigi/items/b22204c7ef73260324bd)

# ソースコード

```d:source/app.d
module dshida.main;

import std.c.string;
import std.exception;
import std.random;
import std.stdio;
import std.string;

import derelict.sdl2.sdl;

/// ウィンドウの幅
enum WIDTH = 640;

/// ウィンドウの高さ
enum HEIGHT = 640;

/// ウィンドウタイトル
immutable TITLE = "D Shida";

/// 再帰レベル
enum N = 20;

/// 背景色
enum BackColor : Uint8 {
    R = Uint8.max,
    G = Uint8.max,
    B = Uint8.max,
    A = Uint8.max,
}

/// 描画色
enum PlotColor : Uint8 {
    R = 0,
    G = Uint8.max,
    B = 0,
    A = Uint8.max,
}

/// 描画用スケール・オフセット
enum {
    SCALE_X = WIDTH,
    SCALE_Y = -HEIGHT,
    OFFSET_X = WIDTH / 2,
    OFFSET_Y = HEIGHT
}

/// 座標変換関数
auto transform(alias A, alias B, alias C)(typeof(A) x, typeof(A) y) {
    return A * x + B * y + C;
}

alias transform!( 0.836,  0.044,    0.0  ) W1x;
alias transform!(-0.044,  0.836,    0.169) W1y;
alias transform!(-0.141,  0.302,    0.0  ) W2x;
alias transform!( 0.302,  0.141,    0.127) W2y;
alias transform!( 0.141, -0.302,    0.0  ) W3x;
alias transform!( 0.302,  0.141,    0.169) W3y;
alias transform!( 0.0,    0.0,      0.0  ) W4x;
alias transform!( 0.0,    0.175337, 0.0  ) W4y;

/// 描画関数
void f(alias plot)(size_t k, double x, double y) {
    if(0 < k) {
        f!plot(k - 1, W1x(x, y), W1y(x, y));
        if(uniform(0, 3) == 0) f!plot(k - 1, W2x(x, y), W2y(x, y));
        if(uniform(0, 3) == 0) f!plot(k - 1, W3x(x, y), W3y(x, y));
        if(uniform(0, 3) == 0) f!plot(k - 1, W4x(x, y), W4y(x, y));
    } else {
        plot(x, y);
    }
}

/// SDLのロード
static this() {
    DerelictSDL2.load();
}

/// メイン関数
void main() {
    // SDL初期化
    enforceSdl(SDL_Init(SDL_INIT_EVERYTHING) == 0);
    scope(exit) SDL_Quit();
    
    // ウィンドウの生成・表示
    auto window = enforceSdl(SDL_CreateWindow(
            toStringz(TITLE),
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            WIDTH,
            HEIGHT,
            SDL_WINDOW_SHOWN));
    scope(exit) SDL_DestroyWindow(window);

    // レンダラーの生成
    auto renderer = enforceSdl(SDL_CreateRenderer(
            window,
            -1,
            SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
    scope(exit) SDL_DestroyRenderer(renderer);

    // 画面クリア
    SDL_SetRenderDrawColor(
            renderer,
            BackColor.R,
            BackColor.G,
            BackColor.B,
            BackColor.A);
    enforceSdl(SDL_RenderClear(renderer) == 0);

    // 点の描画用関数
    void plot(double x, double y) {
        SDL_RenderDrawPoint(renderer, cast(int)(x * SCALE_X + OFFSET_X), cast(int)(y * SCALE_Y + OFFSET_Y));
    }

    // 描画実行
    SDL_SetRenderDrawColor(
            renderer,
            PlotColor.R,
            PlotColor.G,
            PlotColor.B,
            PlotColor.A);
    f!plot(N, 0.0, 0.0);
    SDL_RenderPresent(renderer);

    // イベントループ
    mainLoop: for(SDL_Event event; SDL_WaitEvent(&event);) {
        switch(event.type) {
            // マウスボタンクリックやウィンドウクローズで終了
            case SDL_MOUSEBUTTONDOWN:
            case SDL_QUIT:
                break mainLoop;
            default:
                break;
        }
    }
}

/**
 *  SDLのエラーメッセージの取得
 *
 *  Returns:
 *      SDLのエラーメッセージ。エラーが無ければnull。
 */
@trusted string getSdlMessage() {
    if(auto msg = SDL_GetError()) {
        return msg[0 .. strlen(msg)].idup;
    } else {
        return null;
    }
}

/**
 *  SDL関数のエラーチェック
 *
 *  Params:
 *      value = SDL関数の戻り値か、エラーチェック結果。
 *  Returns:
 *      エラーが発生していなければvalue。
 *  Throws:
 *      Exception エラーが発生していた場合にスローされる。
 */
T enforceSdl(T)(T value, string file = __FILE__, size_t line = __LINE__) {
    return enforce(value, getSdlMessage(), file, line);
}
```

```json:dub.json
{
	"name": "dshida",
        "targetType": "executable",
	"description": "A fractal shida implementation written by D language.",
	"copyright": "Copyright © 2014, outlandkarasu",
	"authors": ["outlandkarasu"],
	"dependencies": {
                "derelict-sdl2": "~master"
	}
}
```

# 実行結果

![D Shida](https://qiita-image-store.s3.amazonaws.com/0/3735/5a18deaf-3f4d-e236-3f34-4029ca791a13.png)