まずサーフェイスへ直接アクセスするとはどういう事なのかを簡単に説明します。
サーフェイスは、ビデオメモリもしくはシステムメモリ内に作成されます。メモリは1次元配列で
管理されており、DirectDrawでは、サーフェイスが存在しているメモリの先頭アドレス
を取得する事が出来ます。ですから、このアドレスを操作して、1次元配列と同じようにサーフェイス扱う事ができると言うわけです。
と言っても、使用するのは「点を描く」と言った処理程度でしょう。
では、実際にサーフェイスへの先頭アドレスを取得する方法を記述します。サンプルコードを見てみましょう。
今回はサーフェイス作成時にも使用した構造体「DDSURFACEDESC」型を使用するので、最初にこれを初期化
しておきます(ZeroMemory等)。そうしたら、サーフェイスのメンバである「Lock」という関数を呼び出します。
サーフェイスをロックする事により、サーフェイスへの先頭アドレスが取得出来ます。では、Lockの構文を書いておきます。
| 書式 | HRESULT Lock( LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags, HANDLE hEvent );
|
| lpDestRect | ロックしたい領域を識別するRECT構造体のアドレス。NULLであれば、全サーフェスがロックされる |
| lpDDSurfaceDesc | サーフェスについての情報を格納する DDSURFACEDESC 構造体へのポインタ。 |
| dwFlags |
| DDLOCK_SURFACEMEMORYPTR | 指定した矩形の先頭への有効なメモリ ポインタを返さなければならないことを表すフラグ。矩形が指定されない場合、一番上のサーフェスへのポインタが返される。 |
| DDLOCK_WAIT | 何らかの原因によってロック(アドレス取得)が出来ない場合に、出来るまで待つという指定 |
|
| hEvent | 現在は使用していないのでNULLを指定しなければならないらしい |
| 戻り値 |
成功した場合はDD_OKが返ってくるらしい。
|
こうすると、DDSURFACEDESC構造体のメンバであるlpSurfaceに、サーフェイスの先頭アドレスが格納されるので、
そのアドレスをあらかじめ用意しておいたunsigned char型(256色なので)のポインタ変数pへ代入してやります。
では、このポインタの扱い方(サーフェイスへのアクセス)を説明します。前にも記述しましたが、
メモリは1次元配列で構成されているので、「座標X、Yへ5を代入」という場合にp[y][x]=5;とは書けません。
メモリは座標(0,0)から右へ順に行き、突き当たったらY座標が1ドット下へいき、X座標が0になる・・・を繰り返す形で
存在しています(謎。ですから、p[0]が(0,0)になります。それで、本来ならばp[640]が座標(0,1)つまりp[x+y*640]というように考えるはずなのですが
ビデオカードによっては、自動的にサーフェイスの横幅を少し増やして、そこをキャッシュとして使用するものがあります。
そして、DDSURFACEDESC構造体のメンバであるlPitchには、このキャッシュの部分を含めた正確な横幅が格納されています。
ですから、サーフェイスメモリへアクセスするにはp[x+y*desc.lPitch]と表すのが正確となります。
一通り、アクセスし終えたら、ロックを解除してやる必要があります。
| 書式 | HRESULT Unlock( LPVOID lpSurfaceData );
|
| lpSurfaceData | Lockによって取得され、アンロックすべきサーフェスのアドレス。このパラメータは、対応する Lock 呼び出しで lpDestRect パラメータに NULL を渡して全サーフェスをロックした場合に限り、NULL とする。
ちなみに、全体をロックしなかった場合は、desc.lpSurfaceを引き渡す事になります。
|
| 戻り値 |
成功した場合はDD_OKが返ってくるらしい。
|
これで、一通り終わりです。実際にサーフェイスへアクセスするのは、ロックからアンロックする間だけにして下さい。
ロックしてサーフェイスポインタを取得し、直ぐにアンロックしてしまった後に、サーフェイスへアクセスする事は一応出来ますが、
ビデオカードによっては上手くいかない場合があるので、止めた方がいいです(確認済み)。それと、ロックという処理は、結構遅いので
1ループに1度というのが理想です。1ループに何度もロック、アンロックを繰り返すのは速度低下の原因となります。
それから、ロックしたあと、アンロックしないと、そのサーフェイスへの書き込み(GDIやBltFast等による転送)が不自由になるので注意して下さい。
ちなみに、ビデオメモリ内のサーフェイスへのアクセス(読み込み&書き込み)は非常に遅いので、一度システムメモリ内へコピーし、システムメモリ内をいじってから、ビデオメモリ内のサーフェイスへ
転送する方がいいかもしれません。