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]

2009/01/22(木)Visual C# 2008

VC++は一通りかじってあるけど、.NETを使ってフォームアプリケーションを作ろうとするとさっぱり分かりません。
google先生で十分かと思ってたけど、適当なマニュアル本買ってきて読んだ方がいいかなぁ。

2007/06/27(水)リフレクション

リフレクションを利用したオブジェクトの複製の例.
実行時にオブジェクトのメタデータからコンストラクタを取得しています.

using namespace System;

class hoge;
class huga: public hoge;
class piyo: public hoge;

int main()
{
  hoge ^obj;
  hoge ^obj2;

  Type ^type;
  ConstructorInfo^ constructorInfoObj;

  obj = gcnew huga();
  type = obj->GetType(); // 型情報(メタデータ)の取得
  constructorInfoObj = type->GetConstructor(System::Type::EmptyTypes); // 引数無しのコンストラクタの取得
  obj = (hoge^)constructorInfoObj->Invoke(nullptr); // 引数無しでコンストラクタを呼び出す

  // ここで obj は huga のオブジェクトになってる

  obj = gcnew piyo();
  type = obj->GetType(); // 型情報(メタデータ)の取得
  constructorInfoObj = type->GetConstructor(System::Type::EmptyTypes); // 引数無しのコンストラクタの取得
  obj = (hoge^)constructorInfoObj->Invoke(nullptr); // 引数無しでコンストラクタを呼び出す

  // ここで obj は piyo のオブジェクトになってる

  return 0;
}

2007/06/02(土)3日

プログラムを作り始めて早3日.
.NETの方言にも少しずつ慣れてきました.

で,思ったこと.
以前のシンプルだったC言語はどこへ行った...

良きに計らいすぎ

なにがどうなっているのやらさっぱり.関数呼び出しなのか,変数への代入なのか.
確かにプロパティは便利なんだけど,ゲッター,セッターを定義する場合,プロパティ名とは別に変数が必要になるし.プロパティ名と同名の変数が使えれば管理が楽なのに.

文法も機能も複雑化.

ガベージコレクションを使うために以前は__gcで修飾してたけど,2005から(?)は^とか%とかrefとかいろいろ増えた.

ヘッダ至上主義?

実行ファイルの最適化の為なのか,ヘッダファイルでほとんど済ませてしまう.
cppファイルはヘッダファイルをコンパイルする為のものに成り下がってます.

増えた機能は使わなくてもプログラムは書けるのでCLIを意識しなければいいんだろうけど,それだとwindowsプログラムが書けなくなる.
個人的には純粋なC++程度が一番使いやすかった.独自拡張で機能を増やすのもいいけれど,そのせいで覚えにくくなるのも困る.

以前はC言語覚えれば他の言語に応用できると言ってたけど,オブジェクト指向の流行を考えると素直にJavaやっておいたほうがいいかもしれませんね.

2007/05/31(木)VC独自仕様?

^とかいう修飾子が増えてました.
ガベージコレクションできちんと追跡できるようになったポインタのようです.

VS 2005 EEドキュメント中の"C++ Language Reference"に説明が載っていますが,これって.NETの独自拡張ですよね?
CLR用,というかメモリ管理のための拡張が意外と多そうです.
勝手にメモリを解放してもらえるのは楽だけど,仕様がいろいろ追加されていて追いかけるのが大変.

メモ

1: ref class myclass {
2:     int i;
3: };
4: int main(void){
5:     myclass ^obj = gcnew myclass();
6:     int %ti = obj->i;
7:     ti = 100;
8:     return 0;
9: }

1:マネージ型としてクラスを定義
 こうしておくと,マネージドヒープ上にクラスを構築できる.
5:マネージ型はnewではなく,gcnewを使う
 受け取るポインタ側も*ではなく,^を使う
6:マネージドヒープ上の値を参照する場合,&ではなく,%になる

従来のC++で書くとこんな感じ.
メモリ削除をガベージコレクションに任せずに自分で削除する必要がある.

1: class myclass {
2:     int i;
3: };
4: int main(void){
5:     myclass *obj = new myclass();
6:     int &ti = obj->i;
7:     ti = 100;
8:     delete obj;
9:     return 0;
10: }

2007/05/31(木).NET

いつまでのVC6を使ってるのもなんなので,VC++ 2005 EEを使ってみることにしました.
で,最初に思ったこと.

何したらいいの?(汗)

結構,というか,根本的に変わってますね.
今までWindows APIとかMFCでプログラムを組んでいたので,.NETのメソッドは全然わからない.一応,GUIはある程度さわっていたので仕組みは分かるのですが,目的のメソッドがどこにあるのか分かりません.
MSDN ライブラリを参考に作り始めてはみたものの,プログラムを書く時間より,メソッドを探している時間の方が圧倒的に長くなってます.

VS2005 アカデミックなら5000円で買えるので買ってしまおうかな.
って,アカデミックライセンスって大学出ると使えなくなってしまうのかな?
それだと意味無いので無難にStandardのUpgradeのほうがいいのか.