DirectXで遊ぼう 上のページ

実は究極の使用方法かも? GDIのススメ
  1. 概要

    グラフィック制御APIとして標準搭載されているGDIを使う方法と、その活用方法を説明します。
    以下の内容について解説します。


  2. GDIは使えないっス

    GetDCで始まりReleaseで終わるGDI関数、はっきり言って制御は面倒です。 そのクセ、WM_PAINTメッセージからはBeginPaint,EndPaintと使い分けなくてはならないとか、用意されているAPIがBASIC以下の性能しか無いとか、 ペンの太さとかカラーとかいちいちオブジェクトを生成しないといかんとか、 マルチウィンドゥの掟により何かある度にウィンドゥ全体を更新しないといけないとか、 にも関わらず遅いとか・・・・・言い出したらキリが無いです。
    この遅さを回避するテはあるんです。
    DIBというビットマップ形式があるのですが、これは画像を直接いじる事ができます。 CreateDIBSection関数でこのDIBを作成する事で、そのビットマップを独自の描画ルーチン(Cでもアセンブラでも何でもOK)で描いて、最後にウィンドゥDCにBitBltするという手順。 描画ルーチンさえ高速に動けば、それなりの改善は望めるかもしれないです。
    だけどハードウェアレベルで描画可能であるDirectDrawには、それでも敵にはなりません。

  3. でも、使うのだ

    面倒・遅いのGDIですが、それでも完全に捨て去る事はできないのです。
    DirectDrawは画像転送を行う事に対して、マシンが持つ最も最適な方法で処理をしてくれます。 またカラーキー等を設定しておけばスプライトもハードウェアレベルで再現でき、将来的にはアルファブレンディングによって半透明化もできるようになります。
    反面、複雑な描画処理に関しては全くと言っていいほど、そのサポートは希薄です。
    GDIでいうMoveTo,LineTo等はありません。また、TextOutもありません。
    前者はほとんど使わないでしょうが、TextOutは例えばアドベンチャーゲームの文字列表示とかをやりたいときには、利用したくなる物です (最近、文字データをメモリ内にBMPで持っておき、それをBltするってのも出てきました。 でもあれってフルカラー環境でやってたら、ただのメモリの無駄遣いっす)。
    このようなケースの場合、GDIで処理した方が簡単にできるって事もあるのです。

  4. 多色はGDIから

    DirectDrawSurfaceは、ビデオカードに依存した形で画像領域が生成されます。 256色やフルカラーの場合は、全然問題ありません。 寧ろLockを介する事でサーフェイスを直接更新する事ができるので、GDIよりも制御は簡単です。
    しかし、Windowsにはもうひとつ表示モードがあります。 ハイカラーというモードで、実はこれが最も厄介なのです。
    ハイカラーは15bitもしくは16bitで構成された画像形式です。更に、RGBのビット構成が5:5:5とか6:5:5とか5:6:5とかビデオカードによって異なります。 幸いそれらのビット構成を知る手段は一応あるのですが、真面目にハイカラー対応を考えると数通りの処理ルーチンが必要になります。 つまり正常に動作するかどうかチェックしようと思ったら、全てのケースを想定して数々のビデオカードで動作チェックを行わなくてはなりません。
    ・・・・・Windowsって、そういうマシンだったっけ?
    ドライバを介することによって、コードが機種依存せずに処理ができるOSだったんじゃ無いの?
    でも、それは事実です。ガーン・・・・
    しかし!!
    それらを全て解決してくれる方法が実はあるのです。
    GDI関数を使って処理を行ってやると、この関数自身は機種依存せずに処理してくれます。
    具体的な方法としてはフルカラーDIBで転送した画像を生成しておき、それをGDI関数を通じてDirectDrawSurfaceにBitBltする。 何か手抜きクサイですが、この方法を使うと、ハイカラー以上の解像度ではそのモードを気にする事無く画像のサーフェイス展開ができるようになります。
    現在の主流は256色ですが、ビデオカードの性能向上に伴いそろそろ求められるグラフィックの質も上がっていくでしょう。
    そのときに発揮されるテクニックは、上に書いた通りのモノです。

  5. GDIを使うサンプル

    実際の使用方法ですけど、GDIさえ知ってれば別に難しい事はありません。
    ぶっちゃけた話、DirectDrawSurfaceからDCを取得できればあとはGDI関数を思う存分使用する事ができます。
    HDC dc;         // デバイスコンテキストハンドル
    HRESULT r;      // 関数の返値
    
    r = ddsurface->GetDC(&dc);
    if(r != DD_OK){
        //
        // GetDC失敗(r:エラーコード)
        //
    }
    //
    // ここで、取得したdcを利用してGDI関数を使用する
    //
    ddsurface->ReleaseDC(dc);
    
    取得したDCは、通常のDCと使い方が変わることはありません。
    それどころかCreateDC等で生成したDIBとのアクセスもできます。

  6. TextOutを作れるかい?

    デバイスコンテキストの取得方法は分かりました。
    多色のコンバートに使えるのも分かりました。
    「しかし、それがどうした?」って思った方いたら、GDIでいうTextOut関数をDirectDrawだけで再現してみてください。 あらかじめ文字チップを用意しておいて…は、今回は使っちゃダメ。 たとえて言うなら、アドベンチャーゲームを作る事を考えて見てください。
    つまり、漢字表示までチップでフォローできますか? ってコト。
    これがGDIなら、こんな風にするだけでできちゃいます。
    HDC dc;         // デバイスコンテキストハンドル
    HRESULT r;      // 関数の返値
    
    CHAR text[] = "
    
    r = ddsurface->GetDC(&dc);
    if(r == DD_OK){
        SetBkMode(dc,TRANSPARENT);              // GDI:背景モード
        TextOut(dc,100,100,text,lstrlen(text)); // GDI:文字列描画
        ddsurface->ReleaseDC(dc);
    }
    
    これで、もうGDIは使えないと思う事はできなくなりますね。




上のページ