緊急企画DirectXを使おうの巻・その1


 今回は、「緊急企画」としてHSPでDirectXを使う方法について触れます。まあ別に緊急である意味はないですけど、いきなり飛んでDirectXの使い方だからね。それに最近ちっとも新しいことやっていないし。・・・いいのッ! 緊急なのッ!(←急な逆ギレ)

2001/06/02追記:いい加減情報が古くなってきたり変なことが書いてあったりするので一部HSPDXFIXと絡めて書き直すことにします。

●準備しよう
 つうことで、DirectXなのです。まず、マシンとかOSとかHSP本体以外に以下のものを用意してください。

 はーい、順に説明しましょう。まずプラグインは、HSP ver2.4g以降を使っているならダウンロードしたときに入ってるはずだから、問題ないよね。「DIRECTX」ってフォルダにあると思うよ。HSPDXFIX.DLLってのはHSPDXのバグ取り改良品のこと。ウチのダウンロードページより落としてね。詳細は追って説明するよ。
 じゃー次。DirectXは今の環境なら必ず入っているので問題ないでしょう。最新のバージョンを入れた方がいいとかってことは有りません(たぶん)。ヘッダはHSPDX(FIX).DLLと一緒に入っているはずなので、これも問題なし。ちなみにヘッダファイルとは外部命令の情報などをまとめたファイルのことです。

●プログラミングの手順
 これってマニュアルにも書いてあるから、なんか手抜きっぽくて申し訳ないけど、プログラムは以下のような手順で組むのだ。なお、どういう命令を使えばよいかは下の方にあるスクリプトと照合してね。

1.初期設定
  1. DirectXの初期化
     これをしなきゃDirectXはいつまでたっても使えません。まずDirectXを使用可の状態にし、続いてフルスクリーンに画面を変更します。ちなみに、DirectXで画面をフルスクリーンにするので従来のようにウィンドウやアイコン等が左上に寄ったりすることはありません(のはずだが、一部のアプリケーションは解像度を変更した際に影響を受けることがあるようで・・・)。
  2. エラー処理
     DirectXの初期化やフルスクリーンへの変更に失敗した状態で処理を続けるとどうなるかは定かではないし、怖くてできません(多分何事もなかったようにWindowsに戻ってくると思いますが)。
  3. 画面の初期化
     フルスクリーンしたての画面には、白黒のデスクトップ(一部)と変な模様が表示されています。これを消去してきれいにしましょう。でもこれって後でもできるからどっちでもいい気がするけどね。
     このあと、フルスクリーンに切り替わる際にディスプレイのモードも切り替わるのでウェイトを入れておくといいでしょう(画面がディスプレイに完全に表示される前に処理を行わないようにする。そうしないと目で確認できないうちから動き出すので出だしの確認が難しい)。

2.メイン処理

  1. 画面を消去
     es_clsで画面を消します。前に描画した画面が残っているので新たに書き直すわけです。ただし、画面全体を不透明な背景画像でコピーする場合はやらない方が速度を稼げます。
  2. 各種処理(画面描画以外)
     ごくごく普通に。べつにDirectXだからといって特に意識すべきことはありません。
  3. 画面描画
     もちろんBと平行して行っても問題ありません。注意すべきことは、ウィンドウの描画に使っていた命令(gcopy,boxfなど)は使えないということです。DirectX固有の命令のみで行ってください。
  4. 画面を更新
     DirectX使用時は描画命令を行った時点では画面表示は更新されず、es_syncという命令を実行してはじめて画面が書き変わります。常に「redraw 2」の状態になっていて、一通り描画を終えたら「redraw 1」に変更するのと同じようなものです。
  5. Windowsにタスクを渡す
     いくらDirectXを使っていようが、OSにタスクを渡してやることが約束です。ただし、es_sync命令はウェイトを兼ねているのでここでさらにウェイトをかける必要はないでしょう。
     余談ですが、HSPDXFIX使用時、awaitでウェイトを取らなければCPU使用率が常時100%になることはありません。
  6. 緊急脱出機能
     DirectX使用中は[Ctrl]+[Alt]+[Del]による強制終了はできませんので、特定の操作で終了するように処理を作っておかなくてはなりません。万が一忘れた場合はリセット以外に抜け出す術はないはずです。別にここである必要はないのですが。
     ・・・と書きましたが、[Alt]+[F4]にて中断することはできます。ただし、Windowsにタスクが渡っていることが条件となります。つまり、きちんとawaitを行っていれば脱出可能というわけです。

3.終了処理

 まあどちらでもよいのですが、最後に後始末を行っておきましょう。このとき、一瞬パレットが化けるのが気になる人は画面消去と更新を2回行うと効果的です。

●組み方
 以上簡単に手順を説明しましたが、ではどんな命令を使えばいいのかとか、そういう部分に突っ込んでいきたいと思います。

●画面描画の方法
 HSPのDirectXには点や線、丸といった図形を描画する命令はほとんどありませんので、ここでは「画像をコピーする方法」について触れます。

  1. ウィンドウのバッファに画像を読み込む
     DirectXのバッファに画像を転送するために、まず(DirectXを使わない通常の)バッファに画像を読み込みます。
  2. DirectXのオフスクリーンバッファに転送する
     そのまま「es_buffer p1,p2」を実行して画像をオフスクリーンバッファへ転送します。このとき、一緒にパレットも転送されます。パラメータp1はバッファのID、p2はVRAMとメインメモリのどっちに転送するかの指定です。通常は多くのユーザーに遊んで(利用して)もらうためにも「2」(VRAMにバッファを確保し、できなかった場合メインメモリに確保)を指定したほうがよいでしょう。
     バッファIDはHSPDXが0〜7(マニュアルには9までと書いてあるが、実際には7までしかとれません)、HSPDXFIXでは0〜63までとなっています。
     ちなみにメインメモリにバッファを確保した場合、そのバッファから画像をコピーする速度が低下するので覚悟しましょう。
  3. 座標等を設定する
     では、画像を画面に表示する準備です。あらかじめ「gmode p1,p2,p3」で転送モードとコピーする画像のサイズを指定しておきます。p1が転送モード(0:不透明、1〜2:透明)です。そして、「pos p1,p2」でコピーする位置を指定します。この辺は従来とほとんど一緒ですので、簡単ですね。ちなみに拡大(縮小)表示をしたい場合、「objsize p1,p2」で表示するサイズを指定しておく必要があります(マニュアルにはobjsizeがコピーする画像のサイズになり、gmodeが表示サイズになると記述されていますが、これは誤りです)。
  4. 表示!!
     そして、「es_copy p1,p2,p3」でバッファから画面へコピーしてめでたく画像が表示されるわけです。p1がバッファID、p2,p3でコピーする画像のある座標を指定します。

 異なるサイズの画像をコピーする場合、es_copy命令でコピーする画像サイズを指定することができないのでそのつど変更する必要がありますことと、objsizeの意味がウィンドウ描画のときと異なることを注意すれば、従来のウィンドウ描画とほぼ同じ間隔で使えます。

●透明色について
 画像を転送する際に色を抜く「透明色」ですが、HSPDXではバグでパレット0番の色しか使えません(黒である必要はありません。ビデオボードに依存するかもしれませんが)。HSPDXFIXではes_bufferの第3パラメータで任意の色を透明色に指定したり、黒を自動的に探し出したりできます。

●やってみよう
 てことで、簡単なサンプルを組んでみました。ランダムに「HOT SOUP PROCESSOR」という文字列を表示するというものです。DirectX使用版と未使用版の二つを用意しました。全部大文字で組んであるので、見づらいスクリプトですいません(^^;。

DirectX未使用 DirectX使用
RANDOMIZE
SCREEN 0,640,480,1
BUFFER 2,256,64,1
PICLOAD "FONT.BMP"
GSEL 0
CLS 4
GMODE 1,16,16
PALCOPY 2
COLOR 0,0,0

*MAIN
;REDRAW 2
STICK S,0
IF (S&128) : END
RND MOJIX,79
RND MOJIY,30
MOJI="HOT SOUP PROCESSOR"
GOSUB *FPUT
;REDRAW 1
AWAIT 0
GOTO *MAIN

*FPUT
STRLEN LNG,MOJI
REPEAT LNG,0
PEEK PMOJI,MOJI,CNT
PMOJI-=32
CPX=(PMOJI\16)*16
CPY=(PMOJI/16)*16
POS MOJIX*8,MOJIY*16
GCOPY 2,CPX,CPY,16,16
MOJIX+=2
IF MOJIX>78 : MOJIX=0:MOJIY=(MOJIY+1)\30
LOOP
RETURN
#include "HSPDX.AS"

RANDOMIZE
ES_INI
ES_SCREEN 640,480,8,0
IF STAT : GOTO *DDERR1
GOTO *START
*DDERR1
END

*START
BUFFER 2,256,64,1
PICLOAD "FONT.BMP"
ES_BUFFER 0,2
IF STAT : GOTO *DDERR1

GSEL 0
ES_CLS
ES_SYNC
WAIT 100
GMODE 0,16,16
COLOR 0,0,0

*MAIN
STICK S,0
IF (S&128) : GOTO *FINISH
RND MOJIX,79
RND MOJIY,30
MOJI="HOT SOUP PROCESSOR"
GOSUB *FPUT
MOJIX=0
MOJIY=0
MOJI=TM
STR MOJI
GOSUB *FPUT
ES_SYNC
TM=STAT
AWAIT 0
GOTO *MAIN

*FINISH
REPEAT 2
ES_CLS
ES_SYNC
AWAIT 0
LOOP
ES_BYE
END

*FPUT
STRLEN LNG,MOJI
REPEAT LNG,0
PEEK PMOJI,MOJI,CNT
PMOJI-=32
CPX=(PMOJI\16)*16
CPY=(PMOJI/16)*16
XX=MOJIX*8
YY=MOJIY*16
POS MOJIX*8,MOJIY*16
ES_COPY 0,CPX,CPY
MOJIX+=2
IF MOJIX>78 : MOJIX=0:MOJIY=(MOJIY+1)\30
LOOP
RETURN

 処理ごとに色分けをしてあるので、照らし合わせて変更点を探してみましょう。

 結論をいうと、そんなに変更点はありません(当たり前といえば、当たり前かもしれないけど)。マニュアルを読むとファーストインプレッションで投げ出したくなるかもしれませんが、サンプルプログラムをいじったりしてみれば意外と簡単だって事がわかるかと思いますので色々試してみましょう。

 なお、このスクリプトはフォントデータが無いのでこのままでは実行できません。ここに載せたスクリプトともう一つ別のスクリプトの2種類と一緒にフォントデータ(拙作「MZ味」の流用ですが)を同梱したものを用意しましたのでダウンロードして確認してみてください。
 で、実行してみるとわかりますが、バックバッファが2画面存在するせいで(多分)画面がチラチラします。同じ事を2回書き込めばちらつきはなくなりますが、処理が秒間30フレーム以下になってしまいDirectXを使う意味がなくなりますよね。ってことで画面は1フレームごとにes_clsで消しましょう。そして、こういう処理を行わないようにしましょう。っつうかダメなプログラム示してどうするって感じもしますが(^^;。

●オフスクリーンバッファについて
 オフスクリーンバッファというのはDirectXを使うときに画像を保存しておくバッファのことですが、このバッファのサイズはどれだけ割り当てられるのかということなどはキチンと把握しておかないとスプライトなどを使うときに誤動作の原因にもなりますので、ここにいろいろ書いておこうと思います。

●es_xferの使い方
 なんだか上の文章よくわかりませんね(^^;。この文章とあわせることでes_xferを使うときにこういうことに気をつけないと誤動作しちゃうよーっていうネタフリになるわけですが、es_xferの使い方を簡単に触れておきます。

  1. 前もって画面解像度と同じくらいのバッファを用意する
     ふつう画像を読み込んだバッファをつぶすようなことはしないので、下のスクリプトのようにカラのバッファを用意しておく必要が出てきます。これを忘れるとes_xferは役には立ってくれません。
    buffer 2,640,480,1
    cls 4
    es_buffer 0,2
  2. gmodeでサイズとモードを設定する
     ここはほかのグラフィック操作命令と一緒です。
  3. posでコピー先の座標を指定する
     間違えてはいけないのは、posはコピー先の座標を指定するということです。間違えてコピー元の座標を指定してしまうとうまく動かなくなります。
  4. es_xferでコピーする
     さらに気をつけてほしいのは、パラメータが転送先のバッファID、転送元のバッファID、転送元の画像の座標の順であるということです。特に最初の二つは間違えるとえらいことになりますので間違えちゃいけません。
     このとき、コピー先のバッファをはみ出したり(はみ出しは問題ないようです)、存在しないバッファへコピーしようとするとエラー(終了)になります。
     バッファIDは、es_bufferで割り当てたバッファのほかに、現在表示されている画面(-1)や描画中の画面(-2)を指定できます。描画中の画面を4倍に拡大して表示するには、下のようにします。
    gmode 0,160,120
    objsize 640,480
    pos 0,0
    es_xfer 0,-2,0,0
    pos 0,0
    es_zoom 0,0,0

 スプライトの使い方は第2回で。


戻る