5-7 CDDPro90クラスを使おう!

CDDPro90クラスとはDirect3D9を使って2D表示をもっと簡単に表示するための自作ライブラリです。

このサイトでは描画処理にこのCDDPro90クラスを使っていますが、
これがどのようなライブラリなのかを理解するためにも、このページを一通り読んでおくことをお勧めします。
※ちなみにDDという名称は昔DirectDraw用として作っていたためで、今もその名残でDDという名前になっています

このライブラリはDirect3D9を利用しているためクラス名はCDDPro90となっていますが、
拡張性を考えて別名でCDDProとも定義されていますので、どちらの名前でも利用可能です。

このクラスは私的利用や商用利用に特に制限はありません。
またソースコードの改変なども自由ですが、これを利用して何か問題があった場合、
責任は取れないのでそのあたりを考慮して使用してください。
なおこのクラスはcharatbeatHDXなどの自作ソフトにも使われているので、
安定度はそれなりに期待出来ると思います。


■描画ライブラリによるDirect3Dの隠匿

CDDProクラスは内部的にDirect3D9を使用しています。
そしてこのクラスではDirect3Dの初期化やテクスチャのロード、
板ポリによるエフェクトを含めた描画処理などを行っています。

ロードしたテクスチャはこのクラス内に保持されており、
プログラム側からはロードした画像のサイズ取得以外、直接参照する必要はありません。

さらにロードしたテクスチャを描画する際も、特に自分で板ポリをで作って描画する必要は無く、
画像内の表示したい領域と表示先の座標、そして表示サイズなどを指定して描画するための関数が用意されているため、
プログラム側から見れば内部でDirect3Dを使っているということを意識する必要がありません。

このため例えばこのCDDProの中身をOpenGLなど別の描画エンジンを使って記述することで、
プログラム側はDirect3DだろうがOpenGLだろうが関係なくそのクラスの初期化と画像のロード、
そして描画関数を呼び出すだけで、結果的に同じ画面が描画出来るというわけです。

また当たり前ですが、描画ライブラリというのは描画に必要な処理だけが入ったライブラリであり、
特に音ゲー専用というわけではありません。

このためこのライブラリを他のゲームに使ったり、またOpenGL版も作っておくことで例えばスマフォ版も
同時に作ることが出来るわけですが、こういった作り方をクロスプラットフォームと言います。

ちなみに最近流行のユニティやアンリアルエンジンなどのクロスプラットフォームに対応したミドルウェアは、
プラットフォームごとに異なるハードウェア部分を内部で隠匿して共通のAPIとすることで、
1つのプログラムで全機種対応といったことが出来るようになっています。
※欠点としては、例えば一部のプラットフォームでしか対応していない機能は使うことが出来なかったり、
 新しい機能に対応するため古い機種は非サポートとなってしまったり、ソフトウェアでエミュレーション
 することで一応対応はしたが、処理がとても重くなって全然使えなかったりといった弊害もあり、
 全体的にこれらのミドルウェアは要求スペックが高すぎるという問題もあります


■何が出来るの?

まずこのクラスで出来ることを紹介します。

①IDirect3D9、IDirect3DDevice9オブジェクトの管理
②複数のテクスチャのロード
③テクスチャの表示したい部分の切り抜き指定
④シーンの開始と終了指示、フリップ処理
⑤切り抜きしたテクスチャの描画(拡大、縮小、回転、アルファ指定可)
⑥通常のアルファブレンドと加算合成の切り替え
⑦画面ロスト時のテクスチャの自動復元

ざっと見ると今まで説明した内容が全てつまっているような感じです。
これらのルーチンがあればもう一通りのゲームは作ることが出来ます。

またこのクラスでは、#pragma指定により自動的に必要なライブラリもリンクするようになっているため、
DirectX SDKのパスさえ通っていればDirect3D9を使っているという意識すら必要ありません。

■CDDPro90のダウンロード

CDDPro90ライブラリ v2.01 CDDPro90_v2.01.zip

サンプルプログラムなどで使用しているライブラリはこれより古い可能性があるため、
最新版は常にこちらからダウンロードするようにしてください。

※今まではSusieプラグインを経由したロードに対応するためのCSusieライブラリを提供していましたが、
 64bit版アプリではSusieプラグインが使用出来ないため現在は提供を取りやめています。
 そのためライブラリ内のSusieライブラリを使用するかの定数は常に0を設定してください

■サンプルプログラム

ここではCDDProクラスを使ったサンプルを見てみましょう。
このクラスを使用すればどれだけ簡単に2D表示が行えるかの参考になると思います。


サンプルのダウンロード

VisualStudio2010のプロジェクト
※VC2012、VC2013はこちら
CDDProSample_vs2010.zip
VisualStudio2015のプロジェクト CDDProSample_vs2015.zip

リリースビルドしたexeが入っているのでビルドせずとも実行することが出来ます。
※ビルド時に64bit版OSを使用している場合はこちらを参照してください

プログラム解説

このサンプルでは以下のことを行っています。
 ・背景画像として空を描画
 ・太陽のフレアを加算合成で回転しながら描画
 ・暗い雲を通常のアルファブレンドにて左からに右に移動表示

また画像は以下の3枚を使用しています。

空(1024x512)
 

太陽フレア(1024x1024)
 

雲(256x256)
 



以下がメインルーチンの処理部分です。
赤字で示したところがこのクラスを使用した部分となります。

/////////////////////////////////////////////////////////////////////////
// CDDPro90のサンプル
/////////////////////////////////////////////////////////////////////////
#include "CWindow.h"
#include "CDDPro90.h"

#define DEBUGMODE
#include "DEBUG.H"

CWindow     win;
CDDPro90    dd;
float       fX = -128.0f;       // 雲のX座標
int         iTimerCount = 0;    // カウンタ(0~359)

int WINAPI WinMain( HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdParam,int nCmdShow )
{
    INITDEBUG();
    CLEARDEBUG;

    if( !win.Create(hInstance,L"CDDProSample",TRUE,640,480) ) {
        DEBUG( "ウィンドウエラー\n" );
        return -1;
    }

    // Direct3D構築
    if( !dd.Create(win.hWnd,FALSE,640,480) ) {
        DEBUG( "Direct3D構築エラー\n" );
        return -1;
    }

    // テクスチャのロード
    dd.AddTexture( 0,"SKY.BMP" );
    dd.AddTexture( 1,"SUN.BMP" );
    dd.AddTexture( 2,"CLOUD.TGA" );

    // 切り抜き
    dd.SetPutRange( 0,0,  0, 0, 640, 480 );     // "SKY.BMP" 空
    dd.SetPutRange( 1,1,  0, 0,1024,1024 );     // "SUN.BMP" 太陽
    dd.SetPutRange( 2,2,  0, 0, 256, 180 );     // "CLOUD.TGA" 雲

    // メインループ
    MSG msg;
    while(1) {
        if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) ) {    // プログラム内のメッセージ処理
            if( msg.message==WM_QUIT )
                break;                                  // ALT+F4が押されたらメインを抜ける
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // カウンタ処理
        iTimerCount++;
        if( iTimerCount>359 )
            iTimerCount = 0;

        // 雲の座標
        fX += 1.0f;
        if( fX>800.0f )
            fX = -128.0f;

        // シーン開始
        dd.DrawBegin();

        // 空
        dd.Put( 0,0,0 );

        // 太陽
        dd.SetBlendOne( TRUE );
        dd.SetPutStatus( 1, 0.5f, 0.8f, (float)((sin(iTimerCount*3.14159f/180)*45)*3.14159/180) );
        dd.Put2( 1,320,240 );
        dd.SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

        // 雲
        float mul = (float)sin((double)iTimerCount*4*3.14159/180 ) / 4.0f + 0.75f;      // 拡大縮小(0.5~1.5)
        dd.SetPutStatus( 3, 1.0f, mul );
        dd.Put2( 2,fX,240 );

        // シーン終了・描画
        dd.DrawEnd();

        Sleep(8);                                       // CPUへのウエイト
    }


    dd.Delete();
    win.Delete();
    
    return 0;
}

パッと見ると分かると思いますが、ソースコードの量がかなり少なくなっています。
またDirect3Dの初期化やテクスチャの管理、描画処理が全てクラスの中で行われているため、
このソースコード上にはDirect3D9の関数は一切使っていません。

最後にCDDPro90のDelete()を呼び出すことで内部で管理しているテクスチャやDirect3D9が全て開放されるため、
このようにライブラリに用意されている関数を使うだけで、Direct3Dを使用していることをまったく意識しなくて済みます。