初期化処理


インスタンスの生成

DirectX コンポーネントは、まずその実体を生成しなければなりません
実体、すなわちインスタンスは、オブジェクト指向のクラスに相当するもので
インスタンスはオブジェクトと、それを制御するためのメソッドを持っています

アプリケーションはインスタンス生成関数を用いて実体への参照を取得します
C 言語で言うならば、すなわちインスタンスへのポインタを得るということになります
このポインタは、メソッドのアドレスを含むメンバを保持していると考えることができます
それを呼び出せば、インスタンスを制御することができるということです

Win32 API との違いは、機能ごとにパッケージ化されていることです
DirectX は様々なインスタンスの型を用意しているのです
オブジェクト指向におけるクラスに極めて似た存在と考えてかまいません

しかし、最初の時点で型の実体は存在してません
インスタンス生成関数を呼び出して、はじめて初期化され、実体がメモリ上に作られます
アプリケーションが取得するポインタは、実体型のポインタではなく
実体を制御するために必要なメソッドのコレクションであり
アプリケーションから見れば、実体がどのような実装を持っているかは興味がありません

ということは、インスタンスへのポインタ型は、型定義のみということになります
これは、オブジェクト指向におけるインターフェイス型そのものであり
実際に、DirectX ではこれをインターフェイスと呼びます
これは COM の世界のお話ですが、COM オブジェクトとはインターフェイスを提供するのです

オブジェクト指向におけるインターフェイス型とは
宣言のみのメソッドコレクションを持つ、実体の無い抽象クラスを表します
このインターフェイスに互換性のあるインスタンスは
その実体がどのようなフィールド、メソッドの実装を持っているかに関係なく
インターフェイスで宣言されているメソッドを確実に呼び出すことができるのです

DirectX プログラミングでは、インターフェイスを関数で生成、取得し
インターフェイスからメソッドの実装を呼び出して実体を制御するという方法になります

DirectX Graphics を使うために、最初にコンパイラの設定を行います
必ず D3d8.lib インクルードライブラリをリンカに指定します
そして、ソースには d3d8.h ヘッダファイルをインクルードしてください
これらの準備が整ったら、いよいよ、実際のプログラミングに移ります

実際に描画処理を行うには、デバイスを初期化する必要があります
そのために、まず最初に IDirect3D8 を取得しなければなりません
これには Direct3DCreate8() 関数を呼び出します

IDirect3D8* Direct3DCreate8(UINT SDKVersion);

SDKVersion には、常に D3D_SDK_VERSION を指定します
成功すれば IDirect3D8 インターフェイスのポインタ、そうでなければ NULL が返ります

IDirect3D8 インターフェイスは、デバイスの作成や情報の取得機能を提供します
DirectX Graphics は、描画処理のためにデバイスを作成しなければなりません
そのためには、グラフィック・アダプタの選択や動作を指定する必要があります

デバイスは IDirect3DDevice8 型のインターフェイスで表され
作成には IDirect3D8::CreateDevice() メソッドを使います
HRESULT CreateDevice(
	UINT Adapter , D3DDEVTYPE DeviceType ,
	HWND  hFocusWindow , DWORD BehaviorFlags,
	D3DPRESENT_PARAMETERS* pPresentationParameters ,
	IDirect3DDevice8** ppReturnedDeviceInterface
);
Adapter には、使用するグラフィック・アダプタを選択します
この値は、「0 〜 インストールされているデバイスの数 - 1」 以内のインデックス値です
D3DADAPTER_DEFAULT を指定すれば、プライマリアダプタが選択されます

DeviceType には、D3DDEVTYPE 列挙型を指定します
この列挙型は、デバイスのタイプを指定する定数を提供しています(下記参照)

hFocusWindow には、アプリケーションウィンドウのハンドルを指定します
ウィンドウモードの場合、このウィンドウのクライアント領域にクリップされます

BehaviorFlags は、デバイスの動作を表すフラグを指定します
この引数には、以下の定数の組み合わせを指定することができます

定数解説
D3DCREATE_FPU_PRESERVE 不動小数点ユニット FPU の例外を可能とすることを
アプリケーションが必要としていることを示す
ただし、パフォーマンスが低下することがある
D3DCREATE_HARDWARE_VERTEXPROCESSING 頂点処理をハードウェアで行う
D3DCREATE_MIXED_VERTEXPROCESSING 頂点処理を、ハードウェアとソフトウェアの両方で行う
D3DCREATE_MULTITHREADED 安全なマルチスレッドであることを要求する
マルチスレッドアプリケーションの場合に指定する
ただし、パフォーマンスが低下することがある
D3DCREATE_PUREDEVICE 頂点処理のためのエミュレーションサービスを行わない
すなわち、常にデバイスによる頂点処理を行う
D3DCREATE_SOFTWARE_VERTEXPROCESSING 頂点処理をソフトウェアで行う
D3DCREATE_DISABLE_DRIVER_MANAGEMENT ドライバの代わりに、Direct3D がリソース管理を行う
DirectX7 以下で使用します

pPresentationParameters には、デバイスの状態を示した
D3DPRESENT_PARAMETERS 構造体へのポインタを指定します
ppReturnedDeviceInterface は、作成されたインターフェイスのポインタを受ける
ポインタのポインタを指定します

メソッドが成功すれば D3D_OK が、そうでなければエラー値が返ります
このメソッドが返すエラー値には、以下のものが考えられます

定数解説
D3DERR_INVALIDCALL メソッドが無効である
おそらく、パラメータの指定が間違っている
D3DERR_NOTAVAILABLE このデバイスは指定の機能をサポートしない
D3DERR_OUTOFVIDEOMEMORY 操作の実行に必要なビデオメモリない

D3DDEVTYPE 列挙型は、次のように定義されています
typedef enum _D3DDEVTYPE {
    D3DDEVTYPE_HAL         = 1,
    D3DDEVTYPE_REF         = 2,
    D3DDEVTYPE_SW          = 3,

    D3DDEVTYPE_FORCE_DWORD = 0xffffffff
} D3DDEVTYPE;
D3DDEVTYPE_HAL は、ハードウェアで描画処理を行うことを示します
高速で動作し、場合によっては座標変換などの演算もハードウェアで行います

D3DDEVTYPE_REF はリファレンス・ラスタライザと呼ばれるドライバで
D3DDEVTYPE_SW はソフトウェアで処理を行うことを表します
これらは、ハードウェアに依存しないので全ての機能を使うことができますが
その代わり、HAL で処理する時に比べ低速になります
D3DDEVTYPE_FORCE_DWORD メンバは、使われることはありません

D3DPRESENT_PARAMETERS 構造体は次のように定義されています
typedef struct _D3DPRESENT_PARAMETERS_ {
    UINT                    BackBufferWidth;
    UINT                    BackBufferHeight;
    D3DFORMAT               BackBufferFormat;
    UINT                    BackBufferCount;

    D3DMULTISAMPLE_TYPE     MultiSampleType;

    D3DSWAPEFFECT           SwapEffect;
    HWND                    hDeviceWindow;
    BOOL                    Windowed;
    BOOL                    EnableAutoDepthStencil;
    D3DFORMAT               AutoDepthStencilFormat;
    DWORD                   Flags;

    UINT                    FullScreen_RefreshRateInHz;
    UINT                    FullScreen_PresentationInterval;

} D3DPRESENT_PARAMETERS;
BackBufferWidth にはバッファの横幅を
BackBufferHeight にはバッファの高さを指定します
これらの値は、ダブルバッファリングを行う時のバッファの矩形に使用されます

通常、フルスクリーンモードの場合は画面解像度をここで指定します
ウィンドウモードであれば、0 を指定することで
自動的にクライアント領域のサイズが選択されます

BackBufferFormat メンバは、バッファのサーフェスフォーマットを指定します
これは D3DFORMAT 列挙型の値を指定しなければなりません(下記参照)
サーフェスとは、描画処理のための高速なグラフィックメモリのことを指します

BackBufferCount は確保するバッファの数を指定します
例えば、1 を指定すればダブルバッファ、2 ならばトリプルバッファリングとなります
このようなバッファの断層や動作を合わせてスワップチェーンと呼びます

MultiSampleType はマルチサンプルを行う時に指定します
この値は D3DMULTISAMPLE 列挙型の値を指定します(下記参照)
SwapEffect で D3DSWAPEFFECT_DISCARD が指定されていない場合は
必ず D3DMULTISAMPLE_NONE を指定します

SwapEffect はダブルバッファリング時のスワップ動作を指定します
スワップ動作とは、バッファをどのように表示するかという動作を表します
この値は D3DSWAPEFFECT 列挙型の値を指定します(以下参照)

hDeviceWindow には対象のウィンドウハンドルを指定します
NULL を指定すれば、フォーカスウィンドウが対象となります
Windowed はフルスクリーンかウィンドウモードかを示すブール値を指定します
TRUE であればウィンドウモード、FALSE ならばフルスクリーンモードを意味します

EnableAutoDepthStencil が TRUE ならば、深度ステンシルバッファを作成します
AutoDepthStencilFormat は、自動深度ステンシルサーフェスのフォーマットを指定します
EnableAutoDepthStencil が FALSE の場合、このメンバは無視されます

Flags メンバには 0 または D3DPRESENTFLAG_LOCKABLE_BACKBUFFER を指定します
アプリケーションがバックバッファを直接ロックする必要がある場合に後者を指定します

FullScreen_RefreshRateInHz はリフレッシュレートを指定します
ウィンドウモードの場合、このメンバは無視されます
リフレッシュレートには、次の定数を指定することもできます

定数解説
D3DPRESENT_RATE_DEFAULT ランタイムはプレゼンテーション速度を選択する
ウィンドウ モードの場合は、現在の速度を使用する
D3DPRESENT_RATE_UNLIMITED プレゼンテーション速度は
ハードウェアがフレームを提供できる速さで動作する

これらの定数以外でリフレッシュレートを指定するには
グラフィックアダプタの正確な情報を取得する必要があります

FullScreen_PresentationInterval にはスワップ動作の最大レートを指定します
このメンバには、以下の定数のいずれかを指定することができます

定数解説
D3DPRESENT_INTERVAL_DEFAULT デフォルトの値 (0)
D3DPRESENT_INTERVAL_IMMEDIATE プレゼンテーション処理に直接影響する場合がある
ドライバは垂直帰線間隔を待たない
D3DPRESENT_INTERVAL_ONE ドライバは垂直帰線間隔を待つ
プレゼンテーション処理への影響は
スクリーン リフレッシュほど頻繁ではない
D3DPRESENT_INTERVAL_TWO ドライバは垂直帰線間隔を待つ
プレゼンテーション処理への影響は
スクリーン リフレッシュ (1 回おき) ほど頻繁ではない
D3DPRESENT_INTERVAL_THREE ドライバは垂直帰線間隔を待つ
プレゼンテーション処理への影響は
スクリーン リフレッシュ (2 回おき) ほど頻繁ではない
D3DPRESENT_INTERVAL_FOUR ドライバは垂直帰線間隔を待つ
プレゼンテーション処理への影響は
スクリーン リフレッシュ (3 回おき) ほど頻繁ではない

さて、これでこの構造体の説明は終わりです
たの見慣れない列挙型も含んでいるため、複雑に見えますが
実際には必要なメンバだけを設定し、他は 0 で初期化すれば十分でしょう

深度ステンシルバッファやリフレッシュレートなど、聞きなれない用語が出ています
これらの DirectX の描画技術や、3次元に関連した技術はこれから少しずつ解説します
そのため、今はこれらのメンバは使いません

D3DFORMAT 列挙型は次のように定義されています
typedef enum _D3DFORMAT {
    D3DFMT_UNKNOWN              =   0,

    D3DFMT_R8G8B8               =  20,
    D3DFMT_A8R8G8B8             =  21,
    D3DFMT_X8R8G8B8             =  22,
    D3DFMT_R5G6B5               =  23,
    D3DFMT_X1R5G5B5             =  24,
    D3DFMT_A1R5G5B5             =  25,
    D3DFMT_A4R4G4B4             =  26,
    D3DFMT_R3G3B2               =  27,
    D3DFMT_A8                   =  28,
    D3DFMT_A8R3G3B2             =  29,
    D3DFMT_X4R4G4B4             =  30,

    D3DFMT_A8P8                 =  40,
    D3DFMT_P8                   =  41,

    D3DFMT_L8                   =  50,
    D3DFMT_A8L8                 =  51,
    D3DFMT_A4L4                 =  52,

    D3DFMT_V8U8                 =  60,
    D3DFMT_L6V5U5               =  61,
    D3DFMT_X8L8V8U8             =  62,
    D3DFMT_Q8W8V8U8             =  63,
    D3DFMT_V16U16               =  64,
    D3DFMT_W11V11U10            =  65,

    D3DFMT_UYVY                 =  MAKEFOURCC('U', 'Y', 'V', 'Y'),
    D3DFMT_YUY2                 =  MAKEFOURCC('Y', 'U', 'Y', '2'),
    D3DFMT_DXT1                 =  MAKEFOURCC('D', 'X', 'T', '1'),
    D3DFMT_DXT2                 =  MAKEFOURCC('D', 'X', 'T', '2'),
    D3DFMT_DXT3                 =  MAKEFOURCC('D', 'X', 'T', '3'),
    D3DFMT_DXT4                 =  MAKEFOURCC('D', 'X', 'T', '4'),
    D3DFMT_DXT5                 =  MAKEFOURCC('D', 'X', 'T', '5'),

    D3DFMT_D16_LOCKABLE         =  70,
    D3DFMT_D32                  =  71,
    D3DFMT_D15S1                =  73,
    D3DFMT_D24S8                =  75,
    D3DFMT_D16                  =  80,
    D3DFMT_D24X8                =  77,
    D3DFMT_D24X4S4              =  79,

    D3DFMT_VERTEXDATA           = 100,
    D3DFMT_INDEX16              = 101,
    D3DFMT_INDEX32              = 102,

    D3DFMT_FORCE_DWORD          = 0xFFFFFFFF
} D3DFORMAT;
この列挙型の各メンバの意味は次のようになっています

メンバ解説
D3DFMT_UNKNOWN サーフェス フォーマットは不明である
D3DFMT_R8G8B8 24 ビットの RGB ピクセル フォーマット
D3DFMT_A8R8G8B8 アルファ付きの 32 ビット ARGB ピクセル フォーマット
D3DFMT_X8R8G8B8 32 ビットの RGB ピクセル フォーマットで
そのうち 8 ビットは各色のために確保されている
D3DFMT_R5G6B5 16 ビットの RGB ピクセル フォーマット
D3DFMT_X1R5G5B5 16 ビットのピクセル フォーマットで
そのうち 5 ビットは各色のために確保されている
D3DFMT_A1R5G5B5 16 ビットのピクセル フォーマットで
各色に 5 ビットが、アルファ (透過型テクセル) に 1 ビットが、それぞれ確保されている
D3DFMT_A4R4G4B4 16 ビットの ARGB ピクセル フォーマット
D3DFMT_R3G3B2 8 ビットの RGB テクスチャ フォーマット
D3DFMT_A8 8 ビットのアルファのみ
D3DFMT_A8R3G3B2 16 ビットの ARGB テクスチャ フォーマット
D3DFMT_X4R4G4B4 16 ビットの RGB ピクセル フォーマットで
そのうち 4 ビットは各色のために確保されている
D3DFMT_A8P8 サーフェスは、8 ビットのアルファが付いた 8 ビットのカラー インデックス付き
D3DFMT_P8 サーフェスは、8 ビットのカラー インデックス付き
D3DFMT_L8 8 ビットの輝度のみ
D3DFMT_A8L8 16 ビットのアルファ輝度
D3DFMT_A4L4 8 ビットのアルファ輝度
D3DFMT_V8U8 16 ビットのバンプマップ フォーマット
D3DFMT_L6V5U5 輝度の付いた 16 ビットのバンプマップ フォーマット
D3DFMT_X8L8V8U8 輝度付きの 32 ビット バンプマップ フォーマットで
8 ビットは各要素のために確保されている
D3DFMT_Q8W8V8U8 32 ビットのバンプマップ フォーマット
D3DFMT_V16U16 32 ビットのバンプマップ フォーマット
D3DFMT_W11V11U10 32 ビットのバンプマップ フォーマット
D3DFMT_UYVY UYVY フォーマット (PC98 準拠)
D3DFMT_YUY2 YUY2 フォーマット (PC98 準拠)
D3DFMT_DXT1 DXT1 圧縮テクスチャ フォーマット
D3DFMT_DXT2 DXT2 圧縮テクスチャ フォーマット
D3DFMT_DXT3 DXT3 圧縮テクスチャ フォーマット
D3DFMT_DXT4 DXT4 圧縮テクスチャ フォーマット
D3DFMT_DXT5 DXT5 圧縮テクスチャ フォーマット
D3DFMT_D16_LOCKABLE 16 ビットの Z バッファ ビット深度
これはアプリケーションでロック可能なサーフェス フォーマットである
D3DFMT_D32 32 ビットの Z バッファ ビット深度
D3DFMT_D15S1 16 ビットの Z バッファ ビット深度で
15 ビットが深度チャネルに、1 ビットがステンシル チャネルに確保されている
D3DFMT_D24S8 32 ビットの Z バッファ ビット深度で
24 ビットが深度チャネルに、8 ビットがステンシル チャネルに確保されている
D3DFMT_D16 16 ビットの Z バッファ ビット深度
D3DFMT_D24X8 32 ビットの Z バッファ ビット深度で
24 ビットが深度チャネルに確保されている
D3DFMT_D24X4S4 32 ビットの Z バッファ ビット深度で
24 ビットが深度チャネルに、4 ビットがステンシル チャネルに確保されている
D3DFMT_VERTEXDATA 頂点バッファ サーフェスを記述する
D3DFMT_INDEX16 16 ビットのインデックス バッファのビット深度
D3DFMT_INDEX32 32 ビットのインデックス バッファのビット深度
D3DFMT_FORCE_DWORD この列挙型を強制的に 32 ビット サイズにコンパイルする
この値は使用されていない

D3DMULTISAMPLE_TYPE 列挙型は次のように定義されています
この列挙型は、マルチサンプリングレベルをフルスクリーンモード時に指定します
typedef enum _D3DMULTISAMPLE_TYPE {
    D3DMULTISAMPLE_NONE            =  0,
    D3DMULTISAMPLE_2_SAMPLES       =  2,
    D3DMULTISAMPLE_3_SAMPLES       =  3,
    D3DMULTISAMPLE_4_SAMPLES       =  4,
    D3DMULTISAMPLE_5_SAMPLES       =  5,
    D3DMULTISAMPLE_6_SAMPLES       =  6,
    D3DMULTISAMPLE_7_SAMPLES       =  7,
    D3DMULTISAMPLE_8_SAMPLES       =  8,
    D3DMULTISAMPLE_9_SAMPLES       =  9,
    D3DMULTISAMPLE_10_SAMPLES      = 10,
    D3DMULTISAMPLE_11_SAMPLES      = 11,
    D3DMULTISAMPLE_12_SAMPLES      = 12,
    D3DMULTISAMPLE_13_SAMPLES      = 13,
    D3DMULTISAMPLE_14_SAMPLES      = 14,
    D3DMULTISAMPLE_15_SAMPLES      = 15,
    D3DMULTISAMPLE_16_SAMPLES      = 16,

    D3DMULTISAMPLE_FORCE_DWORD     = 0xffffffff
} D3DMULTISAMPLE_TYPE;
この列挙型のメンバは、次のような意味を持っています

メンバ解説
D3DMULTISAMPLE_NONE いずれのレベルのフルシーン マルチサンプリングも利用できない
D3DMULTISAMPLE_2_SAMPLES 〜
D3DMULTISAMPLE_16_SAMPLES
そのレベルのフルシーン マルチサンプリングを利用できる
D3DMULTISAMPLE_FORCE_DWORD この列挙型を強制的に 32 ビット サイズにコンパイルする
この値は使用されていない

D3DSWAPEFFECT 列挙型は次のように定義されています
この列挙型は、スワップエフェクトについて定義しています
typedef enum _D3DSWAPEFFECT {
    D3DSWAPEFFECT_DISCARD         = 1,
    D3DSWAPEFFECT_FLIP            = 2,
    D3DSWAPEFFECT_COPY            = 3,
    D3DSWAPEFFECT_COPY_VSYNC      = 4,

    D3DSWAPEFFECT_FORCE_DWORD     = 0xFFFFFFFF
} D3DSWAPEFFECT;
この列挙型のメンバは、次のような意味を持ちます
今はスワップエフェクトやマルチサンプリングは行わないので、参考までに見てください

メンバ解説
D3DSWAPEFFECT_DISCARD スワップ エフェクトの D3DSWAPEFFECT_FLIP
D3DSWAPEFFECT_COPY、または D3DSWAPEFFECT_COPY_VSYNC を使って
スワップ チェーンを作成した場合、ランタイムは IDirect3DDevice8::Present 処理が
バック バッファの内容に一切影響しないことを保証する
ただし、ウィンドウ スワップ チェーンのフリップ セマンティクスや
フルスクリーン スワップ チェーンのコピー セマンティクスを実装する際などには
この保証を満たすためにかなりのビデオ メモリのオーバーヘッドや
処理のオーバーヘッドが伴うことがある
アプリケーションでは
D3DSWAPEFFECT_DISCARD スワップ エフェクトを使うことで
これらのオーバーヘッドを回避することができ
最も効率的なスワップ チェーンの表現方法を、ディスプレイ ドライバ側で選択できる
また、これは、D3DPRESENT_PARAMETERS の MultiSampleType メンバに
D3DMULTISAMPLE_NONE 以外の値を指定した際に
使用できる唯一のスワップ エフェクトである

D3DSWAPEFFECT_FLIP を使用するスワップ チェーンと同様
D3DSWAPEFFECT_DISCARD を使用するスワップ チェーンは複数の
バック バッファを含んでいることがあり
これらのバッファには IDirect3DDevice8::GetBackBuffer
または IDirect3DSwapChain8::GetBackBuffer を使ってアクセスできる
スワップ チェーンは待ち行列として見なすことができ
この待ち行列の中では、次の Present 処理で表示されるバック バッファに
常にインデックス 0 が付き、いったん表示されたバッファは待ち行列から破棄される

このスワップ エフェクトを使用するアプリケーションでは
破棄されるバック バッファの内容を推測することはできないため
バック バッファ全体を更新した後で Present 処理を呼び出す必要がある
これは強制的なことではないが、デバッグ バージョンのランタイムは
破棄されるバック バッファの内容を任意のデータで上書きできるので
開発者はアプリケーションがバック バッファ サーフェス全体を
正しく更新していることを確認できる

フルスクリーン スワップ チェーンの場合
デバイスまたはスワップ チェーンの作成時に
D3DPRESENT_PARAMETERS 構造体の
FullScreen_PresentationInterval メンバに
割り当てられた値によってプレゼンテーション レートが決まる
この値が D3DPRESENT_INTERVAL_IMMEDIATE でない場合
プレゼンテーションはモニタの垂直同期と同期される
ウィンドウ スワップ チェーンの場合、プレゼンテーションは
コピー処理によって実装されて、常に即座に実行される
D3DSWAPEFFECT_FLIP スワップ チェーンには複数のバック バッファが含まれることがあり
フロント バッファを含む巡回待ち行列として見なすことができる
この待ち行列の中では
バック バッファに常に 0 から N - 1 (N はバック バッファの数) までの
連続した数字が付けられる
したがって、0 はプレゼンテーションされる最も古いバッファを示す
Present が呼び出されると、待ち行列が「循環」されて
フロント バッファがバック バッファ (N - 1) になり
バック バッファ 0 が新しいフロント バッファになる
フルスクリーン スワップ チェーンの場合
デバイスまたはスワップ チェーンの作成時に
D3DPRESENT_PARAMETERS 構造体の
FullScreen_PresentationInterval メンバに
割り当てられた値によってプレゼンテーション レートが決まる
この値が D3DPRESENT_INTERVAL_IMMEDIATE でない場合
プレゼンテーションはモニタの垂直同期と同期される
ウィンドウ スワップ チェーンの場合、フリッピングはコピー処理によって実装され
プレゼンテーションは常に即座に実行される
D3DSWAPEFFECT_COPY スワップ エフェクトは、単一のバック バッファを構成する
スワップ チェーンに対してのみ指定できる
ウィンドウ スワップ チェーンの場合もフルスクリーン スワップ チェーンの場合も
ランタイムはコピーベースの Present 処理によるセマンティクスを保証する
つまり、バック バッファの内容が変更されることはなく
フリップベースの Present 処理で行われるように
フロント バッファの内容で置き換えられることはない
ウィンドウ スワップ チェーンの場合、Present 処理によってバック バッファの内容が
ターゲット ウィンドウのクライアント領域に即座にコピーされる
コピー内容とディスプレイ アダプタの垂直帰線間隔との同期処理は行われないため
「テアリング」効果が現れることがある
ウィンドウ アプリケーションでは、そのようなテアリング効果を消したり
最小限に抑えるために、D3DSWAPEFFECT_COPY_VSYNC を使うことができる

フルスクリーン スワップ チェーンの場合、ランタイムはフリップ処理と
コピー処理の組み合わせを使ってPresent 処理を行う
したがって、プレゼンテーションはディスプレイ アダプタの垂直帰線と同期され
そのレートは選択されたプレゼンテーション間隔によって制御される
ただし、D3DPRESENT_INTERVAL_IMMEDIATE フラグで
指定されたスワップ チェーンは例外である
(D3DPRESENT_PARAMETERS 構造体の
FullScreen_PresentationInterval メンバの説明を参照すること)
この場合、Present 処理は垂直帰線を待機せずに
バック バッファの内容をフロント バッファに直接コピーする
D3DSWAPEFFECT_COPY_VSYNC D3DSWAPEFFECT_COPY と同様、このスワップ エフェクトは
単一のバック バッファで構成されるスワップ チェーンでのみ使用できる
上の D3DSWAPEFFECT_COPY で説明したように
スワップ チェーンに適用される Present 処理が
コピー セマンティクスを提示することが保証される
ウィンドウ スワップ チェーンの場合、Present 処理によってバック バッファの内容が
ターゲット ウィンドウのクライアント領域に即座にコピーされる
アダプタがディスプレイ上の転送先の矩形内でスキャンしている間
ランタイムはコピー処理を避けてテアリング効果を排除しようとする
また、ランタイムは、アダプタのリフレッシュ間隔の間に
コピー処理をせいぜい 1 回実行して、プレゼンテーションの頻度を制限する
ただし、アダプタがラスタ ステータスの報告機能をサポートしていない場合には
スワップ チェーンは D3DSWAPEFFECT_COPY スワップ エフェクトで
作成されたかのような働きをする
(D3DCAPS8 の Caps メンバについては
D3DCAPS_READ_SCANLINE フラグ値の説明を参照すること)


フルスクリーン スワップ チェーンの場合
D3DSWAPEFFECT_COPY_VSYNC は D3DSWAPEFFECT_COPY と同じである
ただし、D3DPRESENT_INTERVAL_IMMEDIATE フラグは
D3DSWAPEFFECT_COPY_VSYNC と共に使用した場合には何も効果がない
(D3DPRESENT_PARAMETERS 構造体の
FullScreen_PresentationInterval メンバの説明を参照すること)
D3DSWAPEFFECT_FORCE_DWORD この列挙型を強制的に 32 ビット サイズにコンパイルする
この値は使用されていない

さて、D3DPRESENT_PARAMETERS 構造体の BackBufferFormat メンバには
指定したアダプタのサーフェスフォーマットを指定する必要があります
そのためには、ディスプレイモードを取得しなければなりません

ディスプレイモードの取得には
IDirect3D8::GetAdapterDisplayMode() メソッドを使います
HRESULT GetAdapterDisplayMode(
	UINT Adapter , D3DDISPLAYMODE* pMode
);
Adapter には、対象のアダプタのインデックスを指定します
D3DADAPTER_DEFAULT を指定すれば、プライマリアダプタが選択されます
pMode には D3DDISPLAYMODE 構造体へのポインタを指定します
成功すれば D3D_OK を、失敗すれば D3DERR_INVALIDCALL が返ります

D3DDISPLAYMODE 構造体は次のように定義されています
typedef struct _D3DDISPLAYMODE {
    UINT            Width;
    UINT            Height;
    UINT            RefreshRate;
    D3DFORMAT       Format;
} D3DDISPLAYMODE;
width にはスクリーンの幅、Height には高さを指定します
RefreshRate メンバはリフレッシュレートを指定します
このメンバが 0 であれば、アダプタデフォルトであることを示します
Format はディスプレイモードのサーフェスフォーマットを示す列挙型です

この構造体の Format メンバを、GetAdapterDisplayMode() で取得すれば
BackBufferFormat メンバを初期化し、デバイスを作ることができるようになります
これで、DirectX8 の初期化処理の基本的な事項を網羅したことになります

最初からずいぶん長い説明となったため、DirectX に嫌気がさしてしまったかもしれませんが
実際に行うのはインスタンスを生成し、構造体を初期化するというだけです
Win32 API でウィンドウを作るまでの初期化処理が、最初に学習した時は難しかったように
最初は面倒に思うかもしれませんが、これも慣れだと思ってください
(もちろん、本質を理解しなければいつまでたっても難しく感じるでしょう)

さて、COM オブジェクトのインターフェイスは使い終わったら破棄する必要があります
実体がブラックボックス化されているため、破棄する場合は明示的に指定する必要があります

実は全ての COM オブジェクトが提供するインターフェイスは
IUnknown インターフェイスをインプリメントしています
IUnknown インターフェイスは、解放処理のためのリファレンスカウンタを用意しています
インターフェイスが生成された時は、カウンタをインクリメントし
IUnknown::Release() メソッドが呼び出されるとデクリメントします
カウンタが 0 になれば、インターフェイスの実体がメモリから開放されるという仕組みです

ULONG Release();

メソッドは、新しいリファレンスカウントを返します
#include <windows.h>
#include <d3d8.h>
#define TITLE 	TEXT("Kitty on your lap")

IDirect3D8 * pDirect3D;
IDirect3DDevice8 * pD3Device;

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow) {
	MSG msg;
	HWND hWnd;
	WNDCLASS winc;
	D3DPRESENT_PARAMETERS d3dpp;
	D3DDISPLAYMODE d3ddm;

	pDirect3D = Direct3DCreate8(D3D_SDK_VERSION);
	pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT , &d3ddm);

	ZeroMemory(&d3dpp , sizeof (D3DPRESENT_PARAMETERS));
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.BackBufferCount = 1;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed = TRUE;

	winc.style 		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra		= winc.cbWndExtra = 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return 0;

	hWnd = CreateWindow(
		TEXT("KITTY") , TITLE , WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
		CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT ,
		NULL , NULL , hInstance , NULL
	);
	if (!hWnd) return 0;

	pDirect3D->CreateDevice(
		D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING , &d3dpp , &pD3Device
	);

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	pDirect3D->Release();
	pD3Device->Release();
	return msg.wParam;
}
このプログラムを実行すると、何の変哲もないウィンドウが表示されます
一見、通常の Win32 API プログラムに見えますが、何も描画していないだけで
クライアント領域は、すでに DirectX Graphics オブジェクトが適応されています

pDirect3D と pD3Device の2つのグローバル変数がインターフェイスです
pD3Device がデバイスインターフェイスとなります
このメソッドを制御すれば、様々な描画処理を行うことができます


Direct3DCreate8()

IDirect3D8* Direct3DCreate8(UINT SDKVersion);

IDirect3D8 インターフェイスを作成します

SDKVersion - 常に D3D_SDK_VERSION を指定します

戻り値 - IDirect3D8 のポインタ、失敗すれば NULL

IDirect3D8::CreateDevice()

HRESULT CreateDevice(
	UINT Adapter , D3DDEVTYPE DeviceType ,
	HWND  hFocusWindow , DWORD BehaviorFlags,
	D3DPRESENT_PARAMETERS* pPresentationParameters ,
	IDirect3DDevice8** ppReturnedDeviceInterface
);
ディスプレイアダプタのデバイスを作成します

Adapter - 使用するグラフィック・アダプタを選択します
DeviceType - D3DDEVTYPE 列挙型を指定します
hFocusWindow - アプリケーションウィンドウのハンドルを指定します
BehaviorFlags - デバイスの動作を表すフラグを指定します
pPresentationParameters - デバイスの状態を指定します
ppReturnedDeviceInterface - インターフェイスを受けるポインタのポインタを指定します

戻り値 - 成功すれば D3D_OK、そうでなければエラー値

BehaviorFlags には、以下の定数の組み合わせを指定することができます

定数解説
D3DCREATE_FPU_PRESERVE 不動小数点ユニット FPU の例外を可能とすることを
アプリケーションが必要としていることを示す
ただし、パフォーマンスが低下することがある
D3DCREATE_HARDWARE_VERTEXPROCESSING 頂点処理をハードウェアで行う
D3DCREATE_MIXED_VERTEXPROCESSING 頂点処理を、ハードウェアとソフトウェアの両方で行う
D3DCREATE_MULTITHREADED 安全なマルチスレッドであることを要求する
マルチスレッドアプリケーションの場合に指定する
ただし、パフォーマンスが低下することがある
D3DCREATE_PUREDEVICE 頂点処理のためのエミュレーションサービスを行わない
すなわち、常にデバイスによる頂点処理を行う
D3DCREATE_SOFTWARE_VERTEXPROCESSING 頂点処理をソフトウェアで行う
D3DCREATE_DISABLE_DRIVER_MANAGEMENT ドライバの代わりに、Direct3D がリソース管理を行う
DirectX7 以下で使用します

このメソッドが返すエラー値には、以下のものが考えられます

定数解説
D3DERR_INVALIDCALL メソッドが無効である
おそらく、パラメータの指定が間違っている
D3DERR_NOTAVAILABLE このデバイスは指定の機能をサポートしない
D3DERR_OUTOFVIDEOMEMORY 操作の実行に必要なビデオメモリない

IDirect3D8::GetAdapterDisplayMode()

HRESULT GetAdapterDisplayMode(
	UINT Adapter , D3DDISPLAYMODE* pMode
);
アダプターの現在のディスプレイモードを取得します

Adapter - 対象のアダプタのインデックスを指定します
pMode - D3DDISPLAYMODE 構造体へのポインタを指定します

戻り値 - 成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL

IUnknown::Release()

ULONG Release();

インターフェイスのリファレンスカウンタをデクリメントします
カウンタが 0 になれば、インターフェイスの実体はメモリから解放されます

戻り値 - 新しいリファレンスカウント



前のページへ戻る次のページへ