2013年2月26日火曜日

頂点属性の取り扱いなんて翻訳時に自動化できるんです

開発中のOpenGLラッパーライブラリーとしてのlibWRP-GLEW頂点属性の取り扱いを翻訳時に自動化する仕組みを実装してコミットしました。

現状のlibWRP-GLEWの実装でのユーザーコードのサンプルライブラリーコードの要点?っぽいなにかをメモするなど。

ユーザーコードのサンプル(関連主要部位を抜粋):

// 頂点属性の定義。
// for GLSL: in vec2 position
using va_pos2f       = GLEW::vertex
< array<GL::GLfloat, 2>
>;

// for GLSL: in vec2 position; in vec2 texture_coordination;
using va_pos2f_tex2f = GLEW::vertex
< array<GL::GLfloat, 2>
, array<GL::GLfloat, 2>
>;

// モデルオブジェクトの生成
// 2D図形: しかく (インデックスバッファーなし)
auto m1 = glew.create_model<va_pos2f_tex2f, GLEW::usage_static_draw, GLEW::mode_line_loop>(
  { { {{ -.5f, -.5f }}, {{0,0}} }
  , { {{  .5f, -.5f }}, {{1,0}} }
  , { {{  .5f,  .5f }}, {{1,1}} }
  , { {{ -.5f,  .5f }}, {{0,1}} }
  }
);

// 2D図形: ほし (インデックスバッファーあり)
auto m2 = glew.create_model<va_f2, GLEW::usage_static_draw, GLEW::mode_line_strip>(
  { { {{ std::sin(pif * 2 / 5 * 1), std::cos(pif * 2 / 5 * 1) }} }
  , { {{ std::sin(pif * 2 / 5 * 2), std::cos(pif * 2 / 5 * 2) }} }
  , { {{ std::sin(pif * 2 / 5 * 3), std::cos(pif * 2 / 5 * 3) }} }
  , { {{ std::sin(pif * 2 / 5 * 4), std::cos(pif * 2 / 5 * 4) }} }
  , { {{ std::sin(pif * 2 / 5 * 5), std::cos(pif * 2 / 5 * 5) }} }
  },
  { { 0, 2, 4, 1, 3, 0 } }
);

// 描画
// 頂点属性の設定もライブラリーが翻訳時によしなにしてくれています。
glew.invoke(m1);
glew.invoke(m2);

ユーザーコードとしてはこんな感じで使えるので、複数ヶ所で頂点属性をユーザーが意識する必要がありません!やったね、きっとバグが減るよ!睡眠時間が増えるよ!

(※描画時に必要な頂点属性に基づいたストライドやオフセットや要素型に関する設定はすべてinvoke関数の中で翻訳時に解決されていますヽ(´ー`)ノ)

ライブラリーコードの要点メモ:

  • vertex型
  • model_v, model_vi型(autoで受けてるm1やm2、モデルデータ型の中身の型)
    • libWRP-GLEW / include / WonderRabbitProject / GLEW / model.hpp
      • ありがとうauto
      • インデックスバッファーの有無で実は2種類用意してたりする
        • 生成はlibWRP-GLEWのメインインスタンス本体から行い、分岐
        • 頂点データ群から頂点バッファーを生成、保持、デストラクト
        • インデックスデータ群からインデックスバッファーを生成、保持、デストラクト
      • 翻訳時にバッファーのusageや描画モードを保持
        • 描画モードは描画コードの定義時にも明示して変更可能
      • 描画機能の実装提供
        • ライブラリーの用途を描画に限って考えていないのでdrawとかpresentとかじゃなくてinvokeって関数
        • 翻訳時にvertex型から描画に必要な頂点属性周りのAPI設定を自動解決
           → ::detail::model_invoke_vertex_attribute_pointer
          • ありがとうSFINAE(…とconstexprとdecltypeとstd::declvalとstd::integral_constantと…)
実装途中にBoost.MPLで型情報を管理しかけたけど、最終的に完全に自前実装しても現実的なコストとコード量で収まりそうだったので基本的にはC++標準ライブラリーの範疇だけで動作します。それはそれで却って良かったかな?

ともかく、C++11の新機能群のおかげさまさま、variadic template、constexpr、auto、decltype、…それにもちろん以前からあるSFINAEからRAIIまで、C++だからこそできる「翻訳時にできる事は翻訳時に仕込んで置く」、そんな事が簡単にできました( ´∀`)

…毎日何かしら記憶喪失になってたりうっかりしたコードを書いてたりでこくめーかんとかかげろーに登場する様な様々なトラップにやられた様な感覚になった記憶もありますが、だいじょうぶ、C++、かんたん、こわくない、てんぷれーと、めたぷろぐらみんぐ!!ばくれつ、ねいてぃぶ・ぱわー!!ばくはつ、こんぱいるたいむ!!

(※注:じっさいにはこの程度のメタプログラミングではコンパイルタイムはばくはつしませんだいじょうぶです。予兆は感じられるかもしれませんが、大丈夫です。)

0 件のコメント:

コメントを投稿