ホーム < ゲームつくろー! < DirectX技術編 < アニメーションの根っこ:オブジェクトを読み込む


その25 アニメーションの根っこ:オブジェクトを読み込む:サンプルプログラム


 DirectX技術編その25「アニメーションの根っこ:オブジェクトを読み込む」で説明した内容を踏まえたサンプルプログラムです。サンプルは2つあります。1つは「ID3DXAllocateHierarchyインターフェイス」の実装部分です。これはCAllocHierarchyBaseクラスとして与えられます。もう1つはCAllocHierarchyクラスを用いたサンプル例で、D3DXLoadMeshHierarxhyFromX関数によって取得されたD3DXFrame構造体からフレーム名を検索して画面に列挙します。


サンプルスクリーンショット(DirectXのサンプル内にあるTiny.xの解析結果)

 フレームの解析はFrameAnalizer関数内で行っています。子フレームもしくは兄弟フレームがあった場合は、この関数を再起的に呼び出しています。ちなみに、STLのstringをUnicode対応にするために、何だかやけに苦労しました(^-^;。


 以下のプログラムはtiny.xというXファイルをパスの通ったフォルダに置き、空のプロジェクトにコピペした後、AllocHierarchyBase.h及びAllocHierarchyBase.cppをプロジェクトに追加することで完全に動きます。別のxファイルにする場合はサンプルプログラム内のFilenameを書き換えてください。CAllocHierarchyBaseクラスを定義したファイルはこちらからダウンロードできます(AllocHierarchyBase_v102.lzh)。上からデバッグしていくと、何をしているか良くわかるように1つのソースで完結させています。今回のポイントになりそうなところは太文字で示されています。


○ CAllocHierarchyBaseクラスについて

 このクラスは、ユーザが派生クラスで機能を追加しやすいように、各登録をすべて仮想関数で定義しています。ボーンなどを追加する場合はこのクラスをさらに派生させることになります。また、デストラクタで生成した全ての変数を消去する仕組みになっています。よって、DestroyFrame関数及びDestroyMeshContainer関数は使いません。一度中をじっくり見れば、何をしているか分かると思います。

(2009. 5. 5追記)
 UMK様より「削除時に削除リストに登録した構造体のデストラクタが呼ばれない」というバグ報告を頂きました。それに伴いまして、v1.02からvoidポインタを直接deleteするのではなくて「deleter」というクラスに削除してもらうように実装を変更しました。

(もしうまく動かないようでしたら掲示板にてご連絡下さい)

// ID3DXAllocateHierarchyテストサンプルプログラム

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "AllocHierarchyBase.h"
#include <string>
#include <vector>

using namespace std;

// STLのstringを文字コード対応にするためgstringとtypedefする
#if _UNICODE
   typedef wstring gstring;
#else
   typedef string gstring;
#endif

typedef vector<gstring> StrVector;

TCHAR gName[100] = _T("ID3DXAllocateHierarchyテストサンプルプログラム");
TCHAR Filename[128] = _T("tiny.x");


// 文字コード対応文字列代入関数
void COPYSTR_To_STL( gstring &stl, const char *str )
{
#if _UNICODE
   TCHAR *Buf = _T("");
   int num = MultiByteToWideChar(CP_ACP, 0, str, -1, Buf, 0);
   Buf = new TCHAR[num];
   MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, Buf, num);
   stl = Buf;
   delete Buf;
#else
   stl = str;
#endif
}


// スペース挿入関数
gstring __SP(int num, int times=1){gstring s; int i;for(i=0;i<num*times;i++) s+=_T(" ");return s;}


// フレーム解析関数
void FrameAnalizer(D3DXFRAME *pFR, StrVector &sv, int level=0)
{
   // フレーム名取得
   gstring FrameName;
   COPYSTR_To_STL( FrameName, pFR->Name );
   gstring DBQ = _T("\"");
   FrameName = __SP(level,2) + DBQ + FrameName + DBQ + _T("\n");
   sv.push_back( FrameName );

   // メッシュコンテナチェック
   if(pFR->pMeshContainer!=NULL){
      gstring MCName;
      gstring Head = _T("   ---<MeshContainer>--- ");
      COPYSTR_To_STL( MCName, pFR->pMeshContainer->Name );
      MCName = __SP(level,2) + Head + DBQ + MCName + DBQ;
      sv.push_back( MCName );
   }

   // 子フレーム解析
   if(pFR->pFrameFirstChild!=NULL)
      FrameAnalizer( pFR->pFrameFirstChild, sv, level+1);

   // 兄弟フレーム解析
   if(pFR->pFrameSibling!=NULL)
      FrameAnalizer( pFR->pFrameSibling, sv, level );
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
   if(mes == WM_DESTROY) {PostQuitMessage(0); return 0;}
   return DefWindowProc(hWnd, mes, wParam, lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
   // アプリケーションの初期化
   MSG msg; HWND hWnd;
   WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
                                    (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
   if(!RegisterClassEx(&wcex))
      return 0;

   if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
                                    NULL, NULL, hInstance, NULL)))
      return 0;

   // Direct3Dの初期化
   LPDIRECT3D9 g_pD3D;
   LPDIRECT3DDEVICE9 g_pD3DDev;
   if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;

   D3DPRESENT_PARAMETERS d3dpp = {0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,
                                                      D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0}; 

   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
   {
      g_pD3D->Release();
      return 0;
   }

   // メッシュオブジェクトの読み込み
   CAllocHierarchyBase AH;   // ID3DXAllocateHierarchyの派生クラス
   D3DXFRAME* pFR;
   ID3DXAnimationController* pAC;
   if(FAILED(D3DXLoadMeshHierarchyFromX( Filename, D3DXMESH_MANAGED, g_pD3DDev, &AH, NULL, &pFR, &pAC))){
      g_pD3DDev->Release(); g_pD3D->Release();
      return 0;
   }

   // フレーム解析
   gstring fn(Filename); fn += _T("\n");
   StrVector strary;
   strary.push_back(fn);
   FrameAnalizer(pFR, strary, 1);

   // フォントの生成
   int fontsize = 12;
   D3DXFONT_DESC lf = {fontsize, 0, 0, 1, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS,
                        PROOF_QUALITY, FIXED_PITCH | FF_MODERN, _T("MS ゴシック")};

   // ID3DXFontコンポーネント生成
   LPD3DXFONT pD3DFont;
   if(FAILED(D3DXCreateFontIndirect(g_pD3DDev, &lf, &pD3DFont))){
      g_pD3DDev->Release();  g_pD3D->Release();
      return 0;
   }

   ShowWindow(hWnd, nCmdShow);

   // メッセージ ループ
   RECT r ={0,0,0,0};
   StrVector::iterator it;
   do{
      Sleep(1);
      if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){ DispatchMessage(&msg);}
         // Direct3Dの処理
         g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
         g_pD3DDev->BeginScene();

         // テキストの描画
         it = strary.begin();
         int i;
         for(i=0; it!=strary.end(); it++, i++){
               pD3DFont->DrawText(NULL, (*it).c_str(), -1, &r, DT_CALCRECT | DT_LEFT | DT_SINGLELINE, 0xffffffff);
               r.top = i*fontsize; r.bottom = (i+1)*fontsize;
               pD3DFont->DrawText(NULL, (*it).c_str(), -1, &r, DT_LEFT | DT_SINGLELINE, 0xffffff00);
         }
         g_pD3DDev->EndScene();
         g_pD3DDev->Present( NULL, NULL, NULL, NULL );
   }while(msg.message != WM_QUIT);

   pD3DFont->Release();
   g_pD3DDev->Release();
   g_pD3D->Release();

   return 0;
}