ゆとりーなの日記

日記的な事を書いて行くと思はれる

何かが始まる

よりにもよってこの時期に何か始まるらしいです。この時期に。今日の夜21時かららしいです。詳しくはyappyの日記にて。今回は敢えてリンクは貼りません。Google先生で検索してyappyの日記の表示を上に上げましょう。
さて、今日の雑記。Direct3Dでは事ある毎にとある構造体の初期化が必要になります。

D3DPRESENT_PARAMETERS parameters;
ZeroMemory(&parameters, sizeof(parameters)); 
parameters.BackBufferCount        = 1;
parameters.hDeviceWindow          = window_handle;
parameters.Windowed               = is_window_mode;
parameters.BackBufferFormat       = is_window_mode ? D3DFMT_UNKNOWN : D3DFMT_X8R8G8B8;
parameters.BackBufferWidth        = width;
parameters.BackBufferHeight       = height;
parameters.SwapEffect             = D3DSWAPEFFECT_DISCARD;
parameters.EnableAutoDepthStencil = TRUE;
parameters.AutoDepthStencilFormat = D3DFMT_D24S8;

まあかなり適当な初期化ですが、うちの環境ではこれで動きます。この初期化、IDirect3DDevice9の初期化の他にもデバイスロスト時のリセット、ウィンドウ、フルスクリーンモードの切り替えにも行う必要があります。まあグローバルに置いておいて、必要な時に必要な所だけ変更してもいいんですが、それだと不都合があるので今回は毎回ローカルに宣言して初期化することにしました。
で、このコード、長いです。こんなのを何か所もコピペするのは美しくないので関数に纏めるわけです。

void initPresentParameters(HWND window_handle, int width, int height, bool is_window_mode, D3DPRESENT_PARAMETERS *parameters) {
  ZeroMemory(parameters, sizeof(parameters)); 
  parameters->BackBufferCount        = 1;
  parameters->hDeviceWindow          = window_handle;
  parameters->Windowed               = is_window_mode;
  parameters->BackBufferFormat       = is_window_mode ? D3DFMT_UNKNOWN : D3DFMT_X8R8G8B8;
  parameters->BackBufferWidth        = width;
  parameters->BackBufferHeight       = height;
  parameters->SwapEffect             = D3DSWAPEFFECT_DISCARD;
  parameters->EnableAutoDepthStencil = TRUE;  
  parameters->AutoDepthStencilFormat = D3DFMT_D24S8;
}

構造体のコピーは頭悪いのでD3DPRESENT_PARAMETERSはポインタか参照渡しにするのが残当ですが、Googleスタイル読んだ後の湧いた状態の私はポインタを選択してしまいました。所謂参照は必ずconstを付けるってやつです。まあ関数内部で変更するものには&を付けた方が呼び出しもとで分かり易いという理屈もあることはあるので。あと構造体だとポインタ渡しでも*要らないので頭がこんがらがりにくい気がします。でも詰みました。上のコード、コンパイルエラーにはなりませんが、実行時に落ちます。上のコードで初期化したD3DPRESENT_PARAMETERSを使ってIDirect3D9::CreateDeviceメソッドを呼ぶと必ずFAILEDします。原因は単純です。

ZeroMemory(parameters, sizeof(parameters)); 

構造体ZeroMemoryは殆どのメンバは0で問題ないので変更しないやつは0で埋めてしまえという乱暴な考えのもとよく使われる技法です。はい。上のコードではポインタのサイズ分、多分4バイト位しか0で埋められません。何故型を入れなかったか、Googleスタイルに変数を入れようと書いてあったからですよ。
というわけで、

ZeroMemory(parameters, sizeof(*parameters)); 

これで解決を見るわけですかね。しかしポインタは矢張り危険でした。

追記1:わいてるの正しい漢字表記は湧いてるではなく沸いてるだそうです。
追記2:残当は辞書に載ってるものだと思っていた(実際人に訊かれた時に辞書で引けと言ってしまった)のにGoogle先生に訊いてみても引っかかるのは、はぐりん氏のブログ・・・。