DOOM、Wolfenstein 3D、Quakeとid SoftwareクラシックFPS3部作をTOWNSに移植してきて、次は公式で発売予定だったもののWindows 95の登場による市場の変化で発売中止となってしまっていた「System Shock」のソースコードも公開されているのでSDLポート版をベースにFM TOWNS版でも作ろうかと思ってたんだが、思いのほか大苦戦してしまい結局頓挫してしまっている。
Quakeの時もそうだが、完成できたとしても正直CPUパワーが足らな過ぎて快適とは言い難い移植になることがわかりきっていたのもモチベーションが上がりづらく作業が進まなかった理由ではあるんだけど。
代わりと言ってはなんだけど、とりあえず簡単なデモプログラムでも作ることとした。
どちらともアルゴリズムがネット上に載っているし、TOWNSならではの機能を使ったわけでもなくCPUパワーゴリ押しのデモではあるんだが、CPU 486DX2 66MHz相当でも少々荷が重かったんで地味ながら最適化を施して完成。
実行ファイル & ソースコード ダウンロード先
Github - PSX DOOM Fire for FM TOWNS
PlayStation版「DOOM」のタイトル画面や一部ステージの背景で流れる炎エフェクトを再現するデモ。パッドのAボタンを押していく毎に火力が弱まり、Bボタンで再点火、RUNボタンで終了。
ちなみに、これが元ネタ
結構特徴的なエフェクトなんで印象に残るが、やっていることは単純で、
画面一番下ラインに明るい色を描いたら後は、
次フレームでその上ラインに下ラインの色をそのまま描くか色を暗くして描くか左右に散らして(風による揺らめきを表現)描くかを乱数で決める
ということを画面上部ラインまで延々と繰り返しているだけで表現できる。
が、この乱数っていうのが地味に重くてTOWNS標準のC言語コンパイラである「High C コンパイラ」に用意された乱数発生関数rand()を読み出して実装したところ動きがガクガクとなってしまった。
ということで自前で疑似乱数発生を作って(といってもUNIXのライブラリから借用)更にインライン化
static int rand_num = 1;
rand_num = rand_num * 1103515245 + 12345;
random = rand_num & 2147483647;
このデモだけでなく、乱数を使うTOWNS用ゲームやデモを作る時に有効なテクニックかもしれない。
「Water Ripple」
実行ファイル & ソースコード ダウンロード先
Github - Water Ripple on FM TOWNS
マウスを左クリックすると画像に波紋が広がって歪み、しばらく待っていればまた収まっていくデモ。マウスを動かせば波紋の作成位置が移動できる。右クリックで波紋全消去、左右クリック同時押しでプログラム終了。
元画像のテクスチャ(配列)と表示先のテクスチャ、更に波紋の強さを表すテクスチャを現在と前フレーム分で2枚用意して、波紋の広がりと減衰の計算、前フレームと波紋の強さに差異が出ているピクセルだったら波紋の強さから元画像のテクスチャの参照先を求めて表示先に書き込み、を繰り返す。
上記のPSX DOOM Fireよりも負荷のかかるデモで、表示先テクスチャに書き込む元画像テクスチャのアドレス計算が結構時間が食ってて、元ソースでは現在の座標から波紋の強さに応じて読み込み座標を計算するために486 CPUでは加減算よりも数十倍遅い乗除算を1回づつ使っている上に、読み込みアドレスがテクスチャ外にならないようにするために最大最小×X座標Y座標で合計4回のif文で範囲内かチェックを行っているが、TOWNS版デモでは
・「/ 1024」という除算は「>> 10」と10ビットシフトに置き換える(2乗定数の乗除算は1ビットシフト同一。High Cが出すOBJファイルを確認するとこの最適化が行われていなかったので手動シフト演算化)
・_max、_min関数というコンパイラ内部関数を使って最大最小値を求めて範囲内チェックを行う(if文によりもアセンブラレベルで比較命令が1命令節約できる)
・一時変数に入れたりせず配列の要素内でアドレス計算式を全部入れてしまう(High Cの最適化はあまり賢くないのか、無駄に変数の出し入れを行ってしまう)
といった具合に変更。
倍速とまではいかないまでもこれだけでも結構フレームレートに差が出た。
だが、まだ滑らかな速度ではなく波紋という感覚を得られるまでにはなっていない。