キワモノライブラリ「IVRAM」

(c) 2000 die(die@zonze.nu)



事の発端

ぉお、すごいぜ楽しいぜWonderWitch!!!

夢中になって情報に飢えてWitchTech MLを読んでいると、c.mosさんが一度だけ「(BIOSを使わず)IRAMに直接描画」と言う趣旨の書きこみをしているのを発見。ひょっとしてキャラクタ定義テーブルが見えている?と推測したが、まずは順当に(笑)、IRAMのアクセススピードを利用できないだろうかと考えた。

IRAMはSRAMよりも速いらしい。だからここにキャラクタデータを置いて、font_set_colordata()で一括設定すれば疑似的なVRAMになるんじゃないかってね。スタートアップルーチンはソースが提供されているので読むと、標準のjpn2はSPが0E00hから始まるのに、asc1だと2E00hから。それで思ったのは「asc1を使う事にしてSPを2000h引いてしまえば、IRAMが2000h使える。2000h(8192)と言ったら全キャラクタ定義に必要なメモリサイズ(512*16=8192)と同じ。」

よし、と思っていろいろやってみたのだが、どうもうまくいかない。挙動が変だし、そもそもBIOS呼び出し一回で全定義としてもかなり遅い。ところがこの変な挙動から最初の推測が甦った。「やっぱりキャラクタテーブルが見えてるんじゃないのか?」試しにfont_set_colordata()を呼ばないようにしてみる。それでも画面が変わる!当然だけどスピードも段違い。

あとはIRAMを片っ端から埋めて試すだけ(笑)。でも思ったより複雑な構成で画面のすべてを埋める事が出来ない。そこで思い出したのが、スタートアップルーチンで呼ばれているマニュアルに載っていない二つの画面BIOSルーチン。xxx_set_vram()なんていかにもって名前。何やっているかは分からんが、少なくともスタートアップルーチンの種類によって設定が違うようだ。というわけでいろいろ試すうち、実はデフォルトのjpn2ならすごくシンプルなマッピングになることが判明。ん〜遠回り。

重要情報(と言うか、これですべて)

jpn2スタートアップルーチンを使い、SCREEN2だけのシンプルな画面モードに設定した場合、0:0x2000((BYTE far*)0x00002000L)からキャラクタ定義メモリがマッピングされていると思われる。各キャラクタはfont_set_colordata()で使うフォーマットと同じ。

screen_set_char()を使って28x18分きれいにキャラクタを並べれば、キャラクタ単位のメモリアドレスは(y*28+x)*16+0x2000(縦に並べる場合は(x*18+y)*16+0x2000)という単純な式で求められる。0x200をセグメントにすれば0x2000をたす必要もない。

この情報はIVRAMライブラリに関係なく有用だと思う。画面BIOSなどを使いながらちょっとだけエフェクトをかけるとか、ベクタ系の描画を高速にしたい場合とか。

注:このライブラリを発表するためにいろいろ準備しているうちに、この情報自体は先に発表されちゃっています。したがって自慢することでもありません(^^;。

そしてIVRAM

上記の情報を応用して書いたのがIVRAMライブラリである。残念ながら人様にはとても勧められない代物である。なにしろ以下の事が出来なくなるのだ。

画面BIOSやテキストBIOSは一部を除いて使用できない(分かっていないと使えない)。
スプライト、画面の重ね合わせ、スクロールと言ったハードウェア機能は使用出来ない。(頑張れば使えるかもしれないが。)

ほら、使いものにならんでしょ(笑)?しかしここまで諦めた見返りとして、IVRAMは以下の機能を実現出来ます。

キャラクタ数512とかスプライト数128といった制限を無視した、完全ソフトウェアによるスプライト機能(ただしキャラクタ単位座標)。

きっとごく一部の方の眼が光ったことでしょう(笑)。あ、念のため書きますが、速くはないです、というか遅いです(泣)。それでも興味を持った方(うれしい)は、以下のファイルをダウンロードして、デモを実行してみてください。X十字,A,Bで操作、STARTで終了ね。キーセンスが辛いので各キーは押しっぱなしがお勧め(おいおい)。

iv101.zip(デモ、IVRAMソース付き、約54KB)

秒間およそ4フレーム(爆笑)しか出ていないデモなので、あらかじめ「遅い」と断言していますが、それでもなかなかのデモだと思いますよ(^^)。このデモはIVRAMの性能を知るために毎フレーム全画面更新をしてるのです。それも背景エフェクトのおまけ付きで、さらにハードウェアスプライトでは絶対無理な大量のキャラクタ表示を行った結果が4フレームなんです。

自慢モードは終了して(笑)、「うほぉ、これならこんなゲームが出来るぜ」と思い付くのでなければ、まったく不要な代物には違いないです。やっぱり自己満足。

レンダラー

便宜上スプライトと呼んでいる機能ですが、実際のIVRAM内部では「レンダラー」と言う機構によってスプライトを実現しています。IVRAMはキャラクタ(8x8)をすべての基本としているので、座標系も表示単位もキャラクタ単位なんですが、各キャラクタの描画はレンダラーによって行われます。例えばivs_add_sprite()という関数はキャラクタをそのフレームでのスプライトとして登録するものですが、IVRAM内部ではスプライト用のレンダラー関数も一緒に登録しています。

それだけではあまり意味のない機構ですが、特殊な描画を行いたい場合には専用のレンダラーを書けば、それを登録出来るようになるのです。もちろん重ね合わせ順位なんかは普通のスプライトと同じルール(あとから登録したもの勝ち)。デモでは背景エフェクト用にサンプルレンダラーを登録しています。背景タイルがキャラクタ切替えをしているようにも見えますが、実際にはパターンは一種類だけで、その上からレンダラーによってビット演算をしているのです。

この節で「登録」という言葉を使っていますが、ivs_add_sprite()などは呼ばれた時にはスプライト(レンダラー)情報に登録を行うだけで描画は行いません。各フレームの処理の最後でivs_end_render()を呼び出すと、登録されたすべてのレンダラーを呼び出して描画処理を行います。重ね合わせなどはバッファ上で行ってからキャラクタ定義メモリに転送するので、チラツキがかなり防止されているはずです。

仮想VRAM

IVRAMはivs_end_render()で一気に描画処理を行うために、レンダラーの登録用として仮想VRAMを用意する必要があります。仮想VRAMは「キャラクタ単位の最大重ね合わせ数*28*18*sizeof(WORD)」分のバッファです。デフォルトでは重ね合わせ数は4(IVS_OVERLAY_MIN)なので、実は4個までしか重ね合わせが出来ないということになります。それ以上重ねようとした場合は「下から2番目のレンダラーを取り除いて上は描画する」という処理をしているので、4個でもそれほど問題ないでしょう。(一応増やすことも出来ます)

仮想VRAMは、各キャラクタごとの配列になっており、登録したスプライト(レンダラー)情報へのインデックスが並んでいます。0xFFFFは終了フラグなので、4個未満の場合は最後に0xFFFFを置いておきます。先頭に0xFFFFがあればそのキャラクタの描画処理をしないという意味になります。また4個すべてが登録された時は終了フラグは必要ありません。

キャラクタ

ソフトウェアスプライトの常套手段として、描画は「マスクパターンでAND演算したあと、キャラクタパターンでOR演算する」という方法で行っています。これをbmpcnv.exeが出力した'BM'リソースをそのまま使って実現しようとすると、描画時にマスクパターンを作成しながら、ということになってしまいます。それじゃあんまりなので、読み込んだ'BM'データからIVRAM用のキャラクタデータを作成する関数を用意しています。しかしこれも問題があります。データの作成先はSRAMしか無理なので、結果的にデータセグメントを圧迫してしまいます。(ただでさえIVRAMはメモリを食うライブラリなのにね)

そこでもう一歩進めて、専用キャラクタデータをリソースとして扱えるようにしました。これならmmap()によって違うセグメントに配置できます。このリソースを'IV'リソースと呼びます。'IV'リソースを作るために、とりあえずbm2iv.exeというツールを添付してあります。このツールは'BM'リソースファイルを'IV'リソースファイルに変換するだけのものです。

このアイデアには先があります。'IV'リソースはマスクパターンと描画パターンを分離しているので、描画パターンの方は4色全部使えるはずです。でもこれに対応するためには、bmpcnvの段階で直接'IV'リソースを出力できなければなりません。bmpcnvはすでに派生版も発表されているようだし、どうしようかなぁ。

IVRAMの場合、デフォルトで4つまでキャラクタテーブルを登録出来ます。メインと背景用と敵キャラ用を別々で登録するという芸当も可能です(^^)

今後

とりあえず動くものが出来なきゃ意味ないぜ、という感じで作ったので、(たいしたことない)作者本人でもチューニングする余地がありそうです。でもその前にもうちょっと機能追加するつもり。少なくともテキスト表示は何とかしないと・・なんとかなるんだろうか?

謝辞

BANDAIさん、Quteさん、c.mosさん、ありがとう。


WWのページへ戻る