• D言語 + DirectXのサンプルの焼き直し

    2012年01月17日 21時43分
    前回のやつを色々いじくっていて思ったのが、
    Direct3Dは10以降が楽でいいなぁということです。


    Direct3D 10以降はここがスゴイ!
    • デバイスロストを気にしなくて良い
    • ウィンドウのリサイズが簡単
    • 標準でAlt + Enterも動いちゃう
    • シェーダが書きやすい


    最大のデメリットとしてWindows XPで動かないというのがありますが、
    さすがに発売から10年以上経ってるOSはもういいだろという気がしてきました。

    あと、2012年になっているというのに、
    「ハードウェア的には対応しているがドライバが作れないのでDirect3D 9までの対応です。」
    というGPUが未だ新製品として出てくることに不安を感じますが、
    とりあえず黙殺していいんじゃないかな・・・と思います。



    そういう訳で、Direct 3D 11のウィンドウリサイズ辺りの処理を書いてみて
    すこぶるテンションが上がったのでサンプルをアップしてみようと思います。

    スクリーンショット


    ソースです。
    Direct3D 11化してある以外は昔アップしたものとだいたい同じです。(昔アップしたのはDirect3D 9)

    ウィンドウリサイズが楽しかったので、大きい画面にしてみました。
    有名なフルHDテトリス(っぽいもの)になっています。
  • DirectX モジュール 1.0.1

    2011年12月26日 01時52分
    D言語(D2)用 DirectX モジュール

    dmd 2.057でtypedefが使えなくなったのでaliasに書き換えました。
  • D言語によるWebアプリの実装 その6

    2011年11月07日 20時04分
    前回の続き

    この辺りまでくると後は今までに出てきた要素を組み合わせるだけです。


    今回のソース


    スレッド作成と同じようにレス書き込みを作成し、
    スレッド一覧表示と同じようにレス一覧表示を作成します。

    特に解説すべきことも無いかと思います。



    ということで、今回で目標としていた「シンプルな掲示板の実装」が終わりました。


    俺たちの戦いはこれからだ!
  • D言語によるWebアプリの実装 その5

    2011年11月01日 20時41分
    前回の続き

    ブラウザでデータベースのデータを表示することが出来たので、
    次はブラウザからデータベースにデータを入れる方法です。


    今回のソース


    フォームオブジェクトの作成

    ブラウザからデータベースにデータを入れるには、
    フォームを作成してアプリに入力データを渡す必要があります。

    jp.ku6.bbs.form.ThreadBuildFrom.ThreadBuildFromがアプリでフォームを扱うためのクラスです。
    フォームとその部品クラスを利用して作成されており、
    送信されたフォームデータの管理、フォームの表示を行います。


    使用するフォームは、テキスト入力欄が3つと、送信ボタンが1つという構成とします。
    1class ThreadBuildFrom : Form
    2{
    3    /// スレッドタイトル
    4    TextInputField title;
    5
    6    /// >> 1の名前
    7    TextInputField name;
    8
    9    /// >> 1の内容
    10    TextInputField content;
    11
    12    /// 送信ボタン
    13    SubmitField submit;



    コンストラクタで基本設定を行っています。
    テンプレート上のs:idで使用するIDと、formタグのaction属性に設定するURLを指定します。
    1// テンプレートで使用するIDと、actionのURLを設定する
    2super("threadBuildForm", APPLICATION_ROOT_URI ~ "/ThreadBuild.html");



    次に各部品を作成しています。
    こちらもs:idで使用するID(リクエストパラメータ名にも使われます)と、
    表示用の名称を指定しています。
    表示用の名称はエラーメッセージ表示などに使用します。
    1title = new TextInputField(this"title""タイトル");



    入力用の部品には、Validator(入力チェック)とConverter(入力変換)を指定できます。
    ここではValidatorのみ、必須入力チェックと、最大長チェックを指定しています。
    1new RequiredValidator(title, REQUIRED_VALIDATOR_MESSAGE);
    2new MaximumLengthValidator(title, MAXLENGTH_VALIDATOR_MESSAGE, 256);

    指定の書き方がイマイチですが、部品と入力チェックを関連付けるためこのような書き方になっています。


    フォームの表示

    jp.ku6.bbs.view.ThreadBuildView.ThreadBuildViewクラスがフォーム画面の表示処理です。

    先ほど作成したThreadBuildFromをテンプレートエンジンに登録します。
    基となっているフォームと部品クラスが、テンプレートエンジンの拡張機能なので、簡単に登録することができます。
    1form_.assignToSweets(contents_);



    テンプレート上では、フォーム生成時に指定したIDを使います。
    <form s:id="threadBuildForm">


    各部品も同様です。
    <input s:id="title" type="text"/>


    部品に指定したValidatorはエラーメッセージを出力する場合があります。
    発生したエラーメッセージの配列は、s:idが'部品のID + Errors'で設定されます。
    また、個々のエラーメッセージは、s:idが'部品のID + Error'で設定されます。
    これを使い、エラーメッセージ表示は次のように記述します。
    <span s:id="titleErrors" class="errors"><span s:id="titleError"/><br /></span>



    送信されたフォームデータの受け取り

    jp.ku6.bbs.action.ThreadBuildAction.ThreadBuildActionが送信されたフォームデータの受け取り処理です。

    リクエストが来たら、フォームオブジェクトにデータを読み込ませます。
    1string execute(Request request, Response response)
    2{
    3    // リクエストオブジェクトからフォームのデータを読み出し
    4    form_.loadFromRequest(request);



    読み込み後、submitボタンオブジェクトを参照し、ボタンが押されたかを判定します。
    ボタンが押されているならばフォームの送信、
    そうでなければ他画面からのリンクによる遷移と判断します。
    リンクによる遷移の場合は、画面表示のためフォームをクリアしています。
    1if (!form_.submit.isSubmitted)
    2    form_.reset(); // フォームを初期化



    フォームの送信の場合は、Validatorでエラーが発生していないか確認します。
    エラーがあった場合は入力フォームを再度表示します。
    1if (!form_.hasError())



    エラーが無い場合は、入力されたデータをデータベースに保存します。
    各部品の入力値は、valueで参照します。
    1form_.title.value



    保存後はスレッド一覧ページにリダイレクトしています。
    1if (!form_.hasError())
    2{
    3    // 送信されたデータをデータベースに登録
    4    logic_.buildThread(form_.title.value, form_.name.value, form_.content.value);
    5
    6    // 一覧ページにリダイレクト
    7    response.redirect = APPLICATION_ROOT_URI ~ "/ThreadList.html";
    8
    9    return null;
    10}



    データベースへの保存

    前回と同様にSQLを発行するだけとなりますが、
    今回は実行するSQLに値を設定する必要があります。

    jp.ku6.bbs.dao.ResponseDao.ResponseDaoクラスにある処理を例にしますと、
    SQLに?を使ってプレースホルダを指定します。
    1insert_ = new Statement("INSERT INTO responses(id, thread_id, name, content, registered) VALUES(?, ?, ?, ?, ?)", transaction);


    そして、executeする前に、各プレースホルダに値を設定します。
    1statement.set(0u, entity.id);
    2statement.set(1u, entity.threadId);
    3statement.set(2u, entity.name);
    4statement.set(3u, entity.content);
    5statement.set(4u, entity.registered);
    6statement.execute();



    実行

    スタイルシート、テンプレートファイル、実行ファイルを更新してください。
    テンプレートファイルについては、フォーム画面のテンプレートも追加になっています。



    次回へ続く
  • D言語によるWebアプリの実装 その4

    2011年10月28日 18時54分
    前回の続き

    今表示されているデータはテンプレートに直接書いているダミーです。
    これをデータベースから取得して表示します。


    今回のソース


    データベースからデータを取るためには、
    データベースをインストールし、データを入れておかなければなりません。

    以前と同様、環境構築もかんたんに記載します。

    Firebirdインストール

    データベースはFirebirdを使います。

    Firebirdに必要なものをインストール
    # yum -y install libstdc++-4.4.4-13.el6.i686
    # yum -y install ncurses-libs-5.7-3.20090208.el6.i686


    Firebird公式からSuperserverをダウンロードしてインストール
    # wget http://sourceforge.net/projects/firebird/files/firebird-linux-amd64/2.5.1-Release/FirebirdSS-2.5.1.26351-0.amd64.rpm/download
    # rpm -ivh FirebirdSS-2.5.1.26351-0.amd64.rpm



    アプリ用データベース準備


    Webアプリ用のユーザーを作成
    # /opt/firebird/bin/gsec -user sysdba -pass XXXXXX -add bbs -pw bbs


    データベースファイル置き場を作成
    # mkdir /usr/local/bbs/database
    # chown firebird:firebird /usr/local/bbs/database


    isqlを起動
    # /opt/firebird/bin/isql


    データベースを作成します
    > create database '/usr/local/bbs/database/bbs.fdb' user 'bbs' password 'bbs';


    データベースに接続
    > connect '/usr/local/bbs/database/bbs.fdb' user 'bbs' password 'bbs';


    テーブル定義を流し込みます。
    CREATE SEQUENCE thread_sequence;
    
    CREATE TABLE threads
    (
        id INTEGER NOT NULL PRIMARY KEY,
        title VARCHAR(1024) NOT NULL,
        registered TIMESTAMP NOT NULL
    );
    
    
    CREATE SEQUENCE response_sequence;
    
    CREATE TABLE responses
    (
        id INTEGER NOT NULL PRIMARY KEY,
        thread_id INTEGER NOT NULL,
        name VARCHAR(256) NOT NULL,
        content VARCHAR(10240) NOT NULL,
        registered TIMESTAMP NOT NULL
    );


    データ取得用に適当なデータも入れておきます。
    INSERT INTO threads(id, title, registered)
    VALUES (next value for thread_sequence, 'homu', CURRENT_TIMESTAMP);
    INSERT INTO responses(id, thread_id, name, content, registered)
    VALUES (next value for response_sequence, 1, 'homuhomu', 'homuhomuhomu', CURRENT_TIMESTAMP);



    アプリからデータを取得

    SQLの実行は次の手順で行います。

    1. データベースへ接続
    2. 以下必要回数繰し
      1. トランザクションを開始
      2. 以下必要回数繰し
        1. SQL実行準備(メモリ確保等)
      3. 以下必要回数繰し
        1. SQLに変数をセット(必要であれば)
        2. SQL実行
        3. SQLの戻り値を取得(必要であれば)
      4. 以下必要回数繰し
        1. SQL終了処理(メモリ解放等)
      5. トランザクションを終了(コミット or ロールバック)
    3. データベースから切断


    データベースの接続はコネクションプールを利用し、
    必要になった時に接続、アプリ終了時に切断という動作になります。

    コネクションプールの作成と終了処理はjp.ku6.bbs.mainで行っています。
    1ConnectionPool connectionPool = new ConnectionPool(DATABASE_PATH, DATABASE_USER, DATABASE_PASS, 10);
    2scope(exit) connectionPool.shutdown();



    トランザクションの制御はjp.ku6.bbs.logic.ThreadLogic.ThreadLogicクラスで行っています。
    この辺りのクラス構成はJavaのサーブレットでよく見る形に近いかと思います。

    コネクションはプールから取って使う形なので、
    必要になった時に取得し、トランザクションオブジェクトにセットします。
    1transaction_.connection = connectionPool_.lend(3);
    2scope(exit)
    3{
    4    connectionPool_.collect(transaction_.connection);
    5    transaction_.connection = null;
    6}



    コネクションをセットしたらトランザクションを開始します。
    また、終了時にコミット・例外発生時にロールバックとしています。
    1transaction_.begin();
    2scope(failure) transaction_.rollback();
    3scope(success) transaction_.commit();




    SQLの実行はjp.ku6.bbs.dao.ThreadDao.ThreadDaoクラスで行います。

    SQLの準備と終了処理は次の通りです。
    1statement.prepare();
    2scope(exit) statement.finish();


    今回は特に引数をセットしないのでそのまま実行します。

    1auto result = statement.execute();


    SQLがSELECT系の場合は値を取得します。
    1レコード分データを取得するには、fetchを使います。
    1while (result.fetch())


    カラムのデータを取得するには、インデックス番号とデータ型を使って
    次のように取得します。
    1thread.id = result.get!(uint)(0);



    データの表示

    SQLを使って取得したデータはjp.ku6.bbs.model.Thread.Threadクラスの
    配列として受け取ります。

    これをViewに渡し、表示処理を作成します。

    表示処理については前回同様、各項目用のdelegateを作成し、
    出力処理を書くだけですので、基本的にはソースを参考ください。


    一点だけ特殊な箇所を説明します。ForeachProcessorテンプレートです。
    1ForeachProcessor!(Thread) threads;


    ForeachProcessor!(T)は、配列を出力するための補助処理です。
    配列の個数だけ繰り返し出力処理を行うと同時に、
    現在処理中の値をForeachProcessor!(T).currentにセットします。

    実際のコードとは違いますが、次のような処理になっています。
    1void process(SweetsPrinter printer, SweetsElement element, const(SweetsNode[]) children)
    2{
    3    for (index_ = 0; index_ < array.length; ++index_)
    4    {
    5        element.printStartTag(printer, false);
    6        foreach (child; children)
    7            child.print(printer);
    8        element.printEndTag(printer);
    9    }
    10}


    ForeachProcessor!(T)をセットしたタグの
    子タグにセットされたdelegateは、このForeachProcessor!(T).currentにアクセスすることで、
    現在の値を参照することができます。

    いちいちタグ処理のdelegateを書くのは面倒極まりないので、
    このように共通化出来る処理は予め作成しておくと便利です。


    実行

    例によってテンプレートファイルと実行ファイルを更新します。
    うまく表示されない場合はデータベースの接続周りを確認してみてください。



    次回へ続く