簡易キー入力クラス

DirectInputを組み込むのが面倒だったので、簡易的なキー入力識別機構を作成してみた。


まずは管理用クラス。

// SimpleKeyInput.h

class CSimpleKeyInput
{
public:
    CSimpleKeyInput();
    virtual ~CSimpleKeyInput();

public:
    // キー入力情報をセットする。
    static void SetTrigger( int key );

    // キー入力情報をリセット。毎フレーム呼び出し。
    static void AllClear();

    // キー入力情報を取得する。
    static bool IsTrigger( int key );

private:
    static int   m_aTrigCount[0xff+1];  //< VK_xxの数だけ用意
};


// SimpleKeyInput.cpp

// キー入力情報をセットする。
void CSimpleKeyInput::SetTrigger( int key )
{
    m_aTrigCount[key]++;
}

// キー入力情報をリセット。毎フレーム呼び出し。
void CSimpleKeyInput::AllClear()
{
    ZeroMemory( m_aTrigCount, sizeof(m_aTrigCount) );
}

// キー入力情報を取得する。
bool CSimpleKeyInput::IsTrigger( int key )
{
    return ( m_aTrigCount[key] > 0 );
}


ウィンドウプロシージャでキー入力を取得。
wParamは0x00〜0xff(のはず)

    case WM_KEYDOWN:
    {
        CSimpleKeyInput::SetTrigger( wParam );
    }
    break;


データ取得時はキーの番号を指定。

    if( CSimpleKeyInput::IsTrigger( VK_F2 ) )
    {
        // ...
    }

    if( CSimpleKeyInput::IsTrigger( 'A' ) )
    {
        // ...
    }


0〜9、A〜ZはVK_xxと定義されていないので、自力で用意しておくと便利かもしれない。

// WinUser.h

/*
 * VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
 * 0x40 : unassigned
 * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
 */


押しっぱ判定が今はできないけれど、DirectInputを載せるまでのつなぎとして重宝しそう。

テクスチャのサイズ取得

引き続き2D関連実装中。
テクスチャ描画まではとりあえず完了。

元画像からテクスチャを作る際にUV値を直打ちで指定していたのだけど、
512x512のファイルでx=100, y=150の位置から50x50のサイズを切り取って矩形を・・・とかなると、
uが100.0f/512.0f、vが150.0f/512.0f、幅が50.0f/512.0fとかなって非常に面倒。

そこで、UV指定元の座標と切り取りのサイズだけを指定して、画像サイズは自動で持ってくる的なのを作ってみたら意外とあっさりできた。


■テクスチャサイズ取得。

// テクスチャIDからテクスチャのサイズを取得。
bool CTexManager::GetTexSizeFromTexID( s32 texID, s32* pX, s32* pY ) const
{
    LPDIRECT3DTEXTURE9 tex = m_paTex[texID]->GetTex();

    // テクスチャサイズの取得
    D3DSURFACE_DESC desc;

    if( FAILED( tex->GetLevelDesc( 0, &desc ) ))
    {
        return false;
    }

    *pX = desc.Width;
    *pY = desc.Height;

    return true;
}

※m_paTexはLPDIRECT3DTEXTURE9のラッパー的なもの


struct SpriteCreateParam
{
    s32 texID;            //< テクスチャID
    f32 pos_x;            //< 表示位置(x)
    f32 pos_y;            //< 表示位置(y)
    f32 disp_width;       //< 表示サイズ(w)
    f32 disp_height;      //< 表示サイズ(h)
    f32 use_x;            //< 画像内の切り取り開始位置(x)
    f32 use_y;            //< 画像内の切り取り開始位置(y)
    f32 use_w;            //< 画像内の切り取りサイズ(w)
    f32 use_h;            //< 画像内の切り取りサイズ(h)
};

static SpriteCreateParam s_spriteCreateParam[] =
{
    { TEXID_BASE, 0.0f, 0.0f, 38.0f, 43.0f, 696.0f, .0f, 38.0f, 43.0f },
};


これで元画像の座標指定のみでテクスチャ表示ができるように。

表示サイズは切り取りサイズと同じだったりすることがよくあるので、その辺り改善したいところ。

2D描画周り(2)

ひとまず2D表示は出来た。

白四角の描画指示と、赤四角の描画指示を行い、
最後に2D全体の描画指示をすることでDrawIndexedPrimitiveの呼び出しが一回で済んでいる・・はず。

fxファイルを使っているので、エフェクトのパス増えたら描画リストも増えるのか・・・?とかむしろパスごとに描画リスト・・・?とか色々頭をよぎったけどひとまずは置いておく。


ほぼ出来たってなったときに、DrawIndexedPrimitiveでエラー。
ネットで調べたら、DirectXデバッグモードが使えるとのことで使ってみたらなんとか解決。

今まで知らなかったけど、エラー情報とか色々出てなかなか便利。開発中は常時オンでもいいのかな。


[スタートメニュー → Microsoft DirectX SDKDirectX Utilities → DirectX Control Panel]

ランタイムをデバッグモードにして、Output LevelをMoreに寄せると良いみたい。

Direct3D9: (INFO) :MemFini!
Direct3D9: (ERROR) :Memory still allocated! Alloc count = 163
Direct3D9: (ERROR) :Current Process (pid) = 0000194c
Direct3D9: (ERROR) :Memory Address: 041107fc lAllocID=1 dwSize=00004bc4, ReturnAddr=5227d5ea (pid=0000194c)
Direct3D9: (ERROR) :Memory Address: 041153f4 lAllocID=2 dwSize=00000350, ReturnAddr=522802fa (pid=0000194c)
Direct3D9: (ERROR) :Memory Address: 0411577c lAllocID=3 dwSize=00000ef0, ReturnAddr=52286401 (pid=0000194c)
Direct3D9: (ERROR) :Memory Address: 0444a59c lAllocID=5 dwSize=0000a500, ReturnAddr=5228e508 (pid=0000194c)

・・・


そして今はアプリ終了時にメモリリーク情報が出てるという・・。

なんとかせねば。

2D描画周り

シーンのつなぎなどはある程度出来てきたけれど、よくよく考えると何も描画出来ないから切り替わりが分からない現状なのでひとまず2D描画関連を作成開始。

以前作ったコードを見ると、1個四角を描画する度にDrawPrimitiveが呼ばれていたため、旧コードを移植しつつ、1回のDrawPrimitiveで複数個描画出来るように変更中。

自前クラスのDraw関数を呼ぶ
↓
クラス内に描画リストとして描画情報を蓄積
↓
描画リストの内容を頂点バッファにコピー
↓
DrawPrimitiveで一気に描画

といった感じになりそう。

そもそもDrawPrimitiveでいいのか・・?
IndexedやらUPやら・・・


要勉強ですね。

作業再開

地震や停電等でバタバタしてましたが、ようやく作業できる状態となったので再開。


今はシーンやらを管理する部分を作成中。
シーンをIDで定義し、フロークラスを作ってその中で遷移を指示・・・という形になりそう。



ちなみに、私は都内住みで職場も都内なので、家の物が崩れた程度で大きな影響はありませんでした。

原発の問題など色々心配はありますが、まずは被災地の一刻も早い復興を願うばかりです。

Present関数

引き続きDirectX周りに取り組み中。

何も考えずに全てNULLにしていたPresent関数の引数について調べてみたところ、第一,第二引数で転送範囲を指定できるとのことで、試しにやってみた。

const int BACKBUFFER_WIDTH = 640;
const int BACKBUFFER_HEIGHT = 480;

RECT rect = { 0, 0, BACKBUFFER_WIDTH/2, BACKBUFFER_HEIGHT/2 };

m_pD3DDevice->Present( &rect, &rect, NULL, NULL );


予想通りにバックバッファの1/4を転送するようにできた。

出番があるか分からないけど知っておいて損はなさそう。


ただ、msdnを見てみると、

pSourceRect
[in] スワップ チェーンが D3DSWAPEFFECT_COPY で作成されている場合を除き、NULL を指定しなければならない値へのポインタ。

pDestRect
[in] スワップ チェーンが D3DSWAPEFFECT_COPY で作成されている場合を除き、NULL を指定しなければならない値へのポインタ。

と書いてあって、
今は D3DSWAPEFFECT_DISCARD で初期化しているのでややおかしい感じもする。
内部的に D3DSWAPEFFECT_COPY が呼ばれているとか?


もう少し調べる必要がありそう。


リンク(メモ)

template関数の定義

DirectXの初期化部分に取り組み中。

今回はシングルトンクラスで作成しているのだけど、破棄のところでいきなり詰まった。

// 終了処理。外部から呼び出す。
void CDirect3D::Destroy()
{
    if( !m_pInstance )
    {
        DEBUGLOG_FILE( "Direct3Dの初期化が行われていません。処理を行わずに返します。\n" );
        return;
    }

    m_pInstance->Local_Destroy();
    Utility::SafeDelete( m_pInstance );
}

error LNK2019: 未解決の外部シンボル "void __cdecl Utility::SafeDelete(class CDirect3D * &)" (??$SafeDelete@PAVCDirect3D@@@Utility@@YAXAAPAVCDirect3D@@@Z) が関数 "public: static void __cdecl CDirect3D::Destroy(void)" (?Destroy@CDirect3D@@SAXXZ) で参照されました。

旧コードからSafeDeleteを持ってくる時に、cpp側に関数の実装を移したのが問題だったもよう。
↓のようにこうなっていた。

// Utility.h

template <class T>
void SafeDelete( T& p );


// Utility.cpp

template <class T>
void Utility::SafeDelete( T& p )
{
    delete p;
    p = NULL;
}

実装をcpp側に書く方法を調べてみたけど、あまり良さそうなのが見つからず。
とりあえず元のようにヘッダ側にまとめるように修正。

// Utility.h

template <class T>
void SafeDelete( T& p )
{
    delete p;
    p = NULL;
}


これで通るかなと思ったら、次にこのエラー。

error C2248: 'CDirect3D::~CDirect3D' : private メンバー (クラス 'CDirect3D' で宣言されている) にアクセスできません。


シングルトン用にコンストラクタとデストラクタをprivateにしたことで、SafeDelete内でデストラクタが呼べなくなっていると。

マクロ版のSAFE_DELETEを作り、ここではこれを呼ぶことでひとまず解決。

#define SAFE_DELETE(p) delete p; p = 0;


templateの使い方がまだまだ分かってないなと自覚する結果になってしまった。
少しずつでも勉強していこう。