2010/05/05(水)Direct 3Dの初期化とか

適当に作ったformのpicturebox内部に描画するように作成
背景を適当に塗りつぶして、四角形(三角形×2)の描画

四角形の描画のため、頂点4つ分だけメモリ確保してます
もっと大きなものを書きたければそれだけメモリ確保する必要あり

namespace書いてないとか、this->を書いてあるとか丁寧に書いてます。
適当に省略してください。
あと、ブログに載せるとき一部編集してます(変数名とか)
直し忘れとかあったらごめんなさい

プロジェクトの設定

[プロジェクト] - [xxxのプロパティ Alt+F7]の共通プロパティの参照に

  • Microsoft.DirectX
  • Microsoft.DirectX.Direct3D

を追加

使う変数の定義

public ref class Form1 : public System::Windows::Forms::Form
{
private:
    Microsoft::DirectX::Direct3D::Device^ dxDevice;
    Microsoft::DirectX::Direct3D::PresentParameters^ dxPresentParameters;
    array<Microsoft::DirectX::Direct3D::CustomVertex::TransformedColoredTextured, 1>^ dxVertexs;
    Microsoft::DirectX::Direct3D::VertexBuffer^ dxVertexBuffer;
    System::Timers::Timer^ dxRefreshTimer;
}

上から、描画のためのデバイス、そのパラメータ、描画のための頂点座標配列、ビデオメモリ上のメモリバッファ、再描画のためのタイマー

コンストラクタ

Form1(void)
{
    InitializeComponent();
    InitializeDirectX(); // 追加
}

DirextXのための初期化ルーチンを呼び出すように追加。初期化ルーチンの内容は次。

初期化ルーチン

void InitializeDirectX(void)
{
    // パラメータ
    this->dxPresentParameters = gcnew Microsoft::DirectX::Direct3D::PresentParameters();
    this->dxPresentParameters->Windowed = true;
    this->dxPresentParameters->SwapEffect = Microsoft::DirectX::Direct3D::SwapEffect::Discard;
    this->dxPresentParameters->PresentationInterval = Microsoft::DirectX::Direct3D::PresentInterval::Immediate;

    // デバイスの作成
    this->dxDevice = gcnew Microsoft::DirectX::Direct3D::Device(0,
                     Microsoft::DirectX::Direct3D::DeviceType::Hardware, 
                     this->pictureBox1,  // 表示するコントロールまたはウィンドウを渡す
                     Microsoft::DirectX::Direct3D::CreateFlags::SoftwareVertexProcessing,
                     this->dxPresentParameters);
    this->dxDevice->RenderState->Lighting = false; // 光源なし

    // 描画用の頂点配列のメモリ確保
    this->dxVertexs= gcnew array<Microsoft::DirectX::Direct3D::CustomVertex::TransformedColoredTextured, 1>(4);
    this->dxVertexBuffer= gcnew Microsoft::DirectX::Direct3D::VertexBuffer(this->dxVertexs[0].GetType(), 
                       4,
                       this->dxDevice, 
                       Microsoft::DirectX::Direct3D::Usage::None, 
                       Microsoft::DirectX::Direct3D::VertexFormats::Normal,
                       Microsoft::DirectX::Direct3D::Pool::Managed);

    // 再描画用のタイマー設定
    this->dxRefreshTimer= gcnew System::Timers::Timer();
    this->dxRefreshTimer->Elapsed += gcnew System::Timers::ElapsedEventHandler(this, &Form1::RefreshTimer_Event);
    this->dxRefreshTimer->Interval = 1000.0 / 30.0; // 30[fps]
    this->dxRefreshTimer->Enabled = true;
}

強制的に再描画させるためにタイマーを設定

描画のためのルーチン

タイマーイベント用

System::Void RefreshTimer_Event(System::Object^ sender, System::Timers::ElapsedEventArgs^ e){
    this->pictureBox1_RePaint();
}

実際の再描画

System::Void pictureBox1_RePaint() {
    this->dxDevice->BeginScene(); // 描画開始
    this->dxDevice->Clear(Microsoft::DirectX::Direct3D::ClearFlags::Target,
                          System::Drawing::SystemColors::ActiveCaption, 1.0f, 0); // 一度画面を指定色でクリア
    this->drawBox(10.0, 10.0, 30.0+i, 30.0+i); // 四角形の描画
    this->dxDevice->EndScene();   // 描画終了

    try{
        this->dxDevice->Present(); // 画面に反映
    }catch(Microsoft::DirectX::Direct3D::DeviceLostException^ e){
        // 失敗 = デバイスが使えない状態
        // 今回は5秒後に再チャレンジ
        this->dxRefreshTimer->Interval = 5000; // 5[sec]

        // デバイスがリセットできる状態になったらリセット
        int result;
        if(!this->dxDevice->CheckCooperativeLevel(result)){
            if(result == (int)Microsoft::DirectX::Direct3D::ResultCode::DeviceNotReset){
                this->dxDevice->Reset(this->dxPresentParameters);
                this->dxRefreshTimer->Interval = 1000.0 / 15.0; // 15fpsに戻す
            }
        }
    }
}

描画補助(四角形の描画)

System::Void drawBox(float x, float y, float w, float h){

    // 頂点を指定する順番に注意(左上、右上、左下、右下)
    this->dxVertexs[0].X  = x;    this->dxVertexs[0].Y  = y;
    this->dxVertexs[0].Tu = 0;    this->dxVertexs[0].Tv = 0;
    this->dxVertexs[0].Z  = 0;    this->dxVertexs[0].Color = Color::Pink.ToArgb();
    this->dxVertexs[1].X  = x+w;  this->dxVertexs[1].Y  = y;
    this->dxVertexs[1].Tu = 1;    this->dxVertexs[1].Tv = 0;
    this->dxVertexs[1].Z  = 0;    this->dxVertexs[1].Color = Color::Pink.ToArgb();
    this->dxVertexs[2].X  = x;    this->dxVertexs[2].Y  = y+h;
    this->dxVertexs[2].Tu = 1;    this->dxVertexs[2].Tv = 1;
    this->dxVertexs[2].Z  = 0;    this->dxVertexs[2].Color = Color::AliceBlue.ToArgb();
    this->dxVertexs[3].X  = x+w;  this->dxVertexs[3].Y  = y+h;
    this->dxVertexs[3].Tu = 0;    this->dxVertexs[3].Tv = 1;
    this->dxVertexs[3].Z  = 0;    this->dxVertexs[3].Color = Color::AliceBlue.ToArgb();

    Microsoft::DirectX::GraphicsStream^ dxGraphicsStream = this->dxVertexBuffer->Lock(0, 0, Microsoft::DirectX::Direct3D::LockFlags::None);
    dxGraphicsStream->Write(this->dxVertexs); // 頂点座標をバッファに書き込み
    this->dxVertexBuffer->Unlock();

    this->dxDevice->SetStreamSource(0, this->dxVertexBuffer, 0);
    this->dxDevice->VertexFormat = Microsoft::DirectX::Direct3D::CustomVertex::TransformedColoredTextured::Format;
    this->dxDevice->DrawPrimitives(Microsoft::DirectX::Direct3D::PrimitiveType::TriangleStrip, 0, 2); // 描画
}

TriangleStripで三角形の描画を指定、それを2個描画することで四角形になる

参考

検索用

[DirectX] [Direct3D] [Visual Studio 2008] [.net] [cpp/cli] [c++]

2010/05/04(火)CPP/CLI + DirectX

辞書が欲しい
関数調べるのにわざわざネット繋ぐのだるい
世の中快適なブロードバンドばかりだと思うなー

それはいいとして、マネージコード上でDirectXを使うときの注意
普通に古い?DirectXのライブラリを使おうとするとローダー上でマネージコードを実行するなと怒られます

マネージ デバッグ アシスタント 'LoaderLock' では 'c:\Users\serika\Documents\Visual Studio 2008\Projects\MyDXApp\Debug\MyDXApp.exe' に問題を検出しました。
追加情報: DLL 'C:\Windows\assembly\GAC\Microsoft.DirectX.DirectDraw\1.0.2902.0__31bf3856ad364e35\Microsoft.DirectX.DirectDraw.dll' は、OS ローダー ロック内でマネージ実行を試行しています。DllMain またはイメージ初期化関数内でマネージ コードを実行しないでください。この動作は、アプリケーションをハングさせる原因になる可能性があります。

.NET開発者のためのDirectX連携手法の2ページ目によると、ライブラリが古いのが悪いらしい(汗

一応問題ないらしいので、[デバッグ] - [例外]の[Managed Debbuging Assistants] - [LorderLock]のチェックを外してしまえばよい模様

検索用

[Visual Studio 2008] [.net] [DirectX] [Direct Draw] [CPP] [CLI]