Contents

レンダリングエンジン設計(4)

前回の続きになります。

レンダリングエンジンの設計(4)

ウインドウの生成

では、何はともあれウインドウを生成しないとゲームは始まりません。
ここはいきなりOSに依存するロジックになるので、マルチプラットフォームでは各OS毎に処理が分岐する部分になります。
WindowsではWinAPI(User32.dll)のCreateWindowExを呼ぶことになります。LinuxはX11とかWaylandとかまぁGUIがOSと結びついていないので自由奔放…、MacはCocoaみたいな感じですよね… (いや、Windows以外はそれほど詳しくないんですが)
まぁ暫定でウインドウ生成関数と破棄関数を定義します。
上手いこと抽象化しなくてはならないんですが、今のところ幅と高さのみ。必要に応じて今後変更しましょう。
それと、エディタでの描画等、既存のウインドウを描画先にできる必要もあるので、それも後回しにします。

ovlit_window OVLIT_CreateWindow(const ovlit_char8_t* title_utf8, int width, int height) OVLIT_NOEXCEPT;  
void OVLIT_DestroyWindow(ovlit_window window) OVLIT_NOEXCEPT;

で、ここで考えなければならないのが、戻り値の識別子である ovlit_window についてです。
今はウインドウですが、ここは例えばロードした画像を識別するのも同様なので、一律リソース管理というテーマにして考えます。

リソース管理

実装側はC++なので、リソースは普通に考えるとオブジェクトのインスタンスで管理するのが自然ですよね。

typedef void* ovlit_window; //この様に別名定義して、利用者側には実装を隠す

Window* window = new Window();
return reinterpret_cast<ovlit_window>(window);

単にvoid*だと、異なるリーソース間の代入が誤ってできてしまうので、以下のように不完全型を使って、種類を分けてしまうのがよくあるパターンでしょうか。ポインタとして使うだけならば、定義は必要ありません。
C++側で使うときはちゃんとreinterpret_castしてから使う。

typedef struct OVIT_WINDOW_HANDLE_ *ovlit_window;
typedef struct OVIT_TEXTURE_HANDLE_ *ovlit_texture;

解放側は型情報が必要なので、ちゃんと元の型にキャストしてから解放。
以下のようにできます。

delete reinterpret_cast<Window*>(handle);

但し、これは一番シンプルなケースに限ります。
今回作成するエンジンは、以前の記事で解説したように、レンダリングが別スレッドで非同期に実行される予定のため、即解放は出来ないのです。
リソースはいったんコマンドキューに貯められて、その後にレンダリングに使用されます。
DirectX12ではGPUの処理も非同期で実行されるために、GPUの描画が完了すると、初めてそのリソースは解放できるようになります。
とうことで、この時点でリソース管理の仕組みが必要になります。

描画エンジンとか言いながら、いつになったら描画できるのか…
まだまだ長い道のりです…(続きはまたこの章を更新します。)