ゲームフレームワーク的なものを作る。(7)〜Textureインターフェイスとスプライト描画メソッド〜
前回「ゲームフレームワーク的なものを作る。(6)〜スプライト描画〜 - while( c++ );」のサンプルでは、Direct3DのIDirect3DTexture9インターフェイスとID3DXSpriteインターフェイスを直接使って描画を行っていましたが、フレームワーク利用者に対してDirectXなどの具体的な描画エンジンは隠蔽したいですし、今後はOpenGLもサポートしていく予定なので、まずはテクスチャインターフェイスを導入します。
Textureインターフェイス
とりあえず仮想デストラクタとテクスチャサイズを返すメソッドを持たせます。
/** * テクスチャインターフェイス */ class ITexture : public IStringizable //ストリームへ出力可能 { public: /** * デストラクタ */ virtual ~ITexture(){} public: /** * サイズを取得 */ virtual Size GetSize()const = 0; };
Direct3DによるTextureクラスの実装
Graphicsクラス側で生成したテクスチャをコンストラクタで渡して初期化しています。
/** * テクスチャクラス(Direct3Dによる実装) */ class Texture : public ITexture { // ------------------------------------------------------------------------------- // 生成と破棄 // ------------------------------------------------------------------------------- public: /** * コンストラクタ */ Texture( IDirect3DTexture9* instance, const std::string& filename ); /** * デストラクタ */ ~Texture(); // ------------------------------------------------------------------------------- // ITexture実装 // ------------------------------------------------------------------------------- public: Size GetSize()const{ return size; } // ------------------------------------------------------------------------------- // 基本機能 // ------------------------------------------------------------------------------- public: /** * IDirect3DTexture9の実体を取得 */ IDirect3DTexture9* GetInstance()const{ return instance; } /** * ファイル名を取得 */ std::string GetFileName()const{ return filename; } private: IDirect3DTexture9* instance; ///< IDirect3DTexture9の実体 std::string filename; ///< ファイル名 Size size; ///< テクスチャサイズ // ------------------------------------------------------------------------------- // IStringizable実装 // ------------------------------------------------------------------------------- private: /** * 文字列への変換 */ std::string to_string()const; // ------------------------------------------------------------------------------- // コピー禁止 // ------------------------------------------------------------------------------- private: Texture( const Texture& ); Texture& operator=( const Texture& ); };
/** * コンストラクタ * * @param instance 生成済みのテクスチャ * @param filename ファイル名 */ Texture::Texture( IDirect3DTexture9* instance, const std::string& filename ) : instance( instance ) , filename( filename ) { //テクスチャサイズ取得 D3DSURFACE_DESC desc; instance->GetLevelDesc( 0, &desc ); size.width = desc.Width; size.height = desc.Height; } /** * デストラクタ */ Texture::~Texture() { instance->Release(); } /** * 文字列への変換。とりあえずファイル名とサイズを出力 */ std::string Texture::to_string()const { std::stringstream ss; ss << "[ " << filename << " ]" << size; return ss.str(); }
Graphicsクラスにスプライト描画メソッドを追加する
画像ファイルからstd::shared_ptr
- CreateTexture(ファイル名)
- std::shared_ptr
を返す
- std::shared_ptr
- BeginSprite
- スプライト描画開始。以降、AddSprite()で内部のバッファにスプライトを追加しEndSprite()で一気にまとめて描画する。
- AddSprite
- 内部バッファにスプライトを追加する。
- Textureインターフェイス(std::shared_ptr)、Rect、Color、MatrixStackを指定。
- EndSprite
- バッファ内のスプライトをまとめて描画。
typedef std::shared_ptr< ITexture > TexturePtr; /** * Graphicsクラス */ class Graphics { /*略*/ private: /** * スプライト描画オブジェクトの生成 */ ID3DXSprite* CreateSprite(); public: /** * 画像ファイルからテクスチャを生成 */ TexturePtr CreateTexture( const std::string& filename ); // ------------------------------------------------------------------------------- // スプライト描画機能 // ------------------------------------------------------------------------------- public: /** * スプライト描画開始。以降、AddSpriteにより内部バッファにスプライトを追加。 */ void BeginSprite(); /** * スプライト描画終了。内部のバッファに溜めてあるスプライトリストをバックバッファへ出力。 */ void EndSprite(); /** * バッファにスプライトを追加。 */ void AddSprite( const TexturePtr& texture, const Rect& rect, const Color& color, const MatrixStackPtr& matrix_stack ); private: std::shared_ptr< ID3DXSprite > sprite; ///< スプライト描画担当 };
AddSprite()はTextureインターフェイスのshared_ptrでテクスチャを受け取るので、内部の描画時にstd::static_pointer_cast
/** * 画像ファイルからテクスチャを生成 * * @param filename ファイル名 * @return 生成したテクスチャを指すスマートポインタ */ TexturePtr Graphics::CreateTexture( const std::string& filename ) { IDirect3DTexture9* texture = nullptr; HRESULT hr = D3DXCreateTextureFromFile( device.get(), filename.c_str(), &texture ); if( FAILED( hr ) )throw std::runtime_error( "D3DXCreateTextureFromFile[" + filename + "]" ); return TexturePtr( new Texture( texture, filename ) ); } /** * スプライト描画オブジェクトの生成 * * @return スプライト描画オブジェクトを指すスマートポインタ */ ID3DXSprite* Graphics::CreateSprite() { ID3DXSprite* sprite = nullptr; HRESULT hr = D3DXCreateSprite( device.get(), &sprite ); if( FAILED( hr ) )throw std::runtime_error( "D3DXCreateSprite" ); return sprite; } /** * スプライト描画開始。以降、AddSpriteにより内部バッファにスプライトを追加。 */ void Graphics::BeginSprite() { sprite->Begin( D3DXSPRITE_ALPHABLEND ); } /** * スプライト描画終了。内部のバッファに溜めてあるスプライトリストをバックバッファへ出力。 */ void Graphics::EndSprite() { sprite->End(); } /** * バッファにスプライトを追加。 * * @param texture テクスチャ * @param rect 描画元矩形 * @param color 合成する色 * @param matrix_stack 行列スタック */ void Graphics::AddSprite( const TexturePtr& texture, const Rect& rect, const Color& color, const MatrixStackPtr& matrix_stack ) { RECT r = { rect.left, rect.top, rect.right, rect.bottom }; //デフォルトで矩形の中心を回転の中心とする D3DXVECTOR3 center( rect.Width() / 2.0f, rect.Height() / 2.0f, 0.0f ); sprite->SetTransform( matrix_stack->GetTop() ); sprite->Draw( std::static_pointer_cast< Texture >( texture )->GetInstance(), &r, ¢er, nullptr, color.to_A8R8G8B8() ); }
使い方
graphics.Clear(); if( graphics.BeginScene() ) { graphics.BeginSprite(); //背景の描画 matrix_stack->Push(); { matrix_stack->TranslateLocal( 360.0f, 240.0f, 0.0f ); graphics.AddSprite( texture, Rect( 0, 0, 720, 480 ), Color( 1.0f, 1.0f, 1.0f, 1.0f ), matrix_stack ); } matrix_stack->Pop(); //ミクの描画 // マウス位置に描画 matrix_stack->Push(); { matrix_stack->TranslateLocal( static_cast< float >( mouse_pos.x ), static_cast< float >( mouse_pos.y ), 0.0f ); matrix_stack->RotateYawPitchRollLocal( 0.0f, 0.0f, rotate ); matrix_stack->ScaleLocal( 1.0f, 1.0f, 1.0f ); //ネギの描画 // ミクを中心に自転しながら公転する matrix_stack->Push(); { matrix_stack->RotateYawPitchRollLocal( 0.0f, 0.0f, rotate ); matrix_stack->TranslateLocal( 100.0f, 0.0f, 0.0f ); matrix_stack->RotateYawPitchRollLocal( 0.0f, 0.0f, rotate ); matrix_stack->ScaleLocal( 1.0f, 1.0f, 1.0f ); graphics.AddSprite( texture2, Rect( 128, 0, 256, 128 ), Color( 1.0f, 1.0f, 1.0f, 1.0f ), matrix_stack ); } matrix_stack->Pop(); graphics.AddSprite( texture2, Rect( 0, 0, 128, 128 ), Color( 1.0f, 1.0f, 1.0f, 1.0f ), matrix_stack ); } matrix_stack->Pop(); graphics.EndSprite(); //debug std::stringstream ss; ss << "texture:" << texture << std::endl << "texture2:" << texture2 << std::endl ; graphics.DrawString( Point( 0, 0 ), ss.str(), Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); graphics.EndScene(); } graphics.Update();
ダウンロード
- framework08(ITexture).zip
- VC++2010 ExpressEdition、DirectX SDK(February 2010)で動作確認
- 「はちゅねミク」の画像は、三次元CG@七葉(http://nanoha.kirara.st/3dcg/)からお借りしたモデルを使用しています。
Graphicsクラスに行列スタック制御メソッドを追加する
行列スタック用インターフェイスを作るか、Graphicsの機能として行列スタックを制御するか迷ったのですが、とりあえずGraphicsクラスにメソッドを追加しておきます。
- Push()
- topをコピーしてpush
- Pop()
- pop
- Scale( x, y, z )
- topに左からスケーリング行列を掛ける
- Rotate( x, y, z )
- topに左から回転行列を掛ける
- Translate( x, y, z )
- topに左から平行移動行列を掛ける
/** * Graphicsクラス */ class Graphics { /*略*/ // ------------------------------------------------------------------------------- // 行列スタック制御機能 // ------------------------------------------------------------------------------- public: /** * topをコピーしてpush */ void Push(); /** * pop */ void Pop(); /** * Ms * top */ void Scale( float x, float y, float z ); /** * Mr * top */ void Rotate( float x, float y, float z ); /** * Mt * top */ void Translate( float x, float y, float z ); private: std::shared_ptr< ID3DXMatrixStack > matrix_stack; ///< 行列スタック制御 };
/** * スタックトップをコピーしてpush */ void Graphics::Push() { matrix_stack->Push(); } /** * スタックトップをpop */ void Graphics::Pop() { matrix_stack->Pop(); } /** * Ms * top */ void Graphics::Scale( float x, float y, float z ) { matrix_stack->ScaleLocal( x, y, z ); } /** * Mr * top */ void Graphics::Rotate( float x, float y, float z ) { matrix_stack->RotateYawPitchRollLocal( x, y, z ); } /** * Mt * top */ void Graphics::Translate( float x, float y, float z ) { matrix_stack->TranslateLocal( x, y, z ); }
使い方
ちょっとGraphicsクラスに機能が集中しているような気もしますが。
graphics.Clear(); if( graphics.BeginScene() ) { //シーンの描画 ; graphics.BeginSprite(); //背景の描画 graphics.Push(); { graphics.Translate( 360.0f, 240.0f, 0.0f ); graphics.AddSprite( texture, Rect( 0, 0, 720, 480 ), Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); } graphics.Pop(); //ミクの描画 // マウス位置に描画 graphics.Push(); { graphics.Translate( static_cast< float >( mouse_pos.x ), static_cast< float >( mouse_pos.y ), 0.0f ); graphics.Rotate( 0.0f, 0.0f, rotate ); graphics.Scale( 1.0f, 1.0f, 1.0f ); //ネギの描画 // ミクを中心に自転しながら公転する graphics.Push(); { graphics.Rotate( 0.0f, 0.0f, rotate ); graphics.Translate( 100.0f, 0.0f, 0.0f ); graphics.Rotate( 0.0f, 0.0f, rotate ); graphics.Scale( 1.0f, 1.0f, 1.0f ); graphics.AddSprite( texture2, Rect( 128, 0, 256, 128 ), Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); } graphics.Pop(); graphics.AddSprite( texture2, Rect( 0, 0, 128, 128 ), Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); } graphics.Pop(); graphics.EndSprite(); //debug std::stringstream ss; ss << "texture:" << texture << std::endl << "texture2:" << texture2 << std::endl ; graphics.DrawString( Point( 0, 0 ), ss.str(), Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); graphics.EndScene(); } graphics.Update();
ダウンロード
- framework08(MatrixStack).zip
- VC++2010 ExpressEdition、DirectX SDK(February 2010)で動作確認
- 「はちゅねミク」の画像は、三次元CG@七葉(http://nanoha.kirara.st/3dcg/)からお借りしたモデルを使用しています。