ゲームフレームワーク的なものを作る。(8)〜描画エンジンの抽象化〜
描画エンジンの抽象化
windowsでゲームを作る場合、「Direct3D」か「OpenGL」を選択することになりますが、どちらも使ったことがある人であれば、誰もが一度はインターフェイスを用意して両方扱えるようにしたいと思うはず。
で、今回は上記のような単純なインターフェイスと実装クラスを作るのではなく、「ウィンドウ」と「描画機能」を組み合わせた「Viewクラス」を作ります。
WindowクラスとIGraphicsインターフェイスを継承したView抽象クラス
とりあえずWindowクラスは既存のものを使い、新たにIGraphicsインターフェイスを追加します。
class ITexture; typedef std::shared_ptr< ITexture > TexturePtr; /** * スプライト描画機能 */ class ISprite { public: /** * スプライト描画開始。以降、AddSpriteにより内部バッファにスプライトを追加。 */ virtual void BeginSprite() = 0; /** * スプライト描画終了。内部のバッファに溜めてあるスプライトリストをバックバッファへ出力。 */ virtual void EndSprite() = 0; /** * バッファにスプライトを追加。 */ virtual void AddSprite( const TexturePtr& texture, const Rect& rect, const Color& color ) = 0; }; /** * 行列スタック制御機能 */ class IMatrixStack { public: /** * スタックトップをコピーしてpush */ virtual void Push() = 0; /** * スタックトップをpop */ virtual void Pop() = 0; /** * Ms * top */ virtual void Scale( float x, float y, float z ) = 0; /** * Mr * top */ virtual void Rotate( float x, float y, float z ) = 0; /** * Mt * top */ virtual void Translate( float x, float y, float z ) = 0; }; /** * IGraphicsインターフェイス */ class IGraphics : public ISprite //スプライト描画機能 , public IMatrixStack //行列スタック制御機能 { public: /** * シーンのクリア */ virtual void Clear() = 0; /** * シーンのレンダリング開始 */ virtual bool BeginScene() = 0; /** * シーンのレンダリング終了 */ virtual void EndScene() = 0; /** * 画面の更新 */ virtual void Update() = 0; public: /** * 文字列の描画 */ virtual void DrawString( const Point& p, const String& str, const Color& color ) = 0; /** * 画像ファイルからテクスチャを生成 */ virtual TexturePtr CreateTexture( const String& filename ) = 0; };
次に、上記のWindowクラスとIGraphicsインターフェイスを組み合わせたViewクラスを作ります。
Viewは抽象クラスで、IGraphicsインタフェイスの実装は派生クラスのDirect3DViewとOpenGLViewで行います。
#include "Window.h" #include "graphics/IGraphics.h" /** * Windowと描画機能を組み合わせたView抽象クラス */ class View : public Window , public IGraphics { public: View( const String& title, const Size& client_size ) : Window( title, client_size ) {} virtual ~View(){} };
使い方
main関数、Gameクラスの記述が多少変わります。
int main() { Application::Initialize(); try { //ゲーム用ウィンドウの生成と描画エンジンの初期化 Direct3DView view( "hoge", Size( 720, 480 ) ); //OpenGLView view( "hoge", Size( 720, 480 ) ); //ゲームを初期化して、ゲームループを開始する Game game( &view ); //ゲームループ // ウィンドウが閉じられるまで1フレームの処理を繰り返す while( !view.IsClosed() ) { //1フレームの処理 game.Run(); //メッセージキューにある全てのwindowsイベントを処理する Application::DoEvents(); } } catch( std::exception& e ) { std::cout << e.what() << std::endl; } catch( ... ) { std::cout << "予期せぬ例外" << std::endl; } Application::Finalize(); return 0; }
/** * ゲーム1フレームの処理を行う */ void Game::Run() { //シーンの実行 ; //バックバッファをクリアし、シーンのレンダリングを開始する //レンダリング終了後、画面を更新する view->Clear(); if( view->BeginScene() ) { view->BeginSprite(); //描画 view->Push(); { view->Translate( x, y, 0.0f ); view->AddSprite( texture, rect, color ); } view->Pop(); view->EndSprite(); view->EndScene(); } view->Update(); }
ダウンロード
- framework09(View).zip
- VC++2010 ExpressEdition、DirectX SDK(February 2010)で動作確認
- 「はちゅねミク」の画像は、三次元CG@七葉(http://nanoha.kirara.st/3dcg/)からお借りしたモデルを使用しています。
次回予定
ViewをOpenGLで実装したOpenGLViewクラスを作る予定です。