複天一流:どんな手を使ってでも問題解決を図るブログ

宮本武蔵の五輪書の教えに従い、どんな手を使ってでも問題解決を図るブログです(特に、科学、数学、工学の問題についてですが)

DOOM(Game)のソースコンパイルにチャレンジ

DOOMとは

Nanosaurのコンパイル成功に触発され、今度はDOOMに挑戦することにした。まずはDOOMについてまとめておこう。

DOOMのパッケージ(arhive.orgより拝借)

DOOMid Softwareの名作である。現存する全ての歩行型3Dシューティングの基礎はDOOMにあるといっていいだろう。DOOM酔いで1日棒にふった人もかなりいるのではないだろうか?最近の3Dシューティングがどうなっているかはやったことがないので知らないが、今の子供たちは生まれつきDOOM酔いに適応したのだろうか、それともDOOM酔いがなくなるようにプログラミングが向上したのか、「ゲーム酔い」はいま世間ではあまり問題になってないみたいである(そうでもないらしい)。

その登場は1993年の年末、つまり日本のバブル景気終盤の頃であり、初めての格安DOS/V機である富士通のFM-Vが大ヒットした頃である。この時代のCPUはintel 386だった(i386)。そしてLinuxに初めて触った頃であり、インターネットが初めて世の中にやってきた頃である。

友人がもっていた(MS-DOSで操作する)IBM Think Padにインストールされたデモ版のDOOMを最初にみたときは衝撃であった。制限があるとはいえ、これが無料で遊べるなんて素晴らしい世の中になったものだ、と感動した。この当時、大学の研究者以外にはまだインターネットが公開されていなかったので、友人は電話回線を利用して(パソコン通信と呼ばれていた)を使ってゲームファイルをアメリカのid Softwareのサイトからダウンロードしたといっていた。大学の研究室では先輩がLinux版を大学のマシンにこっそりインストールしていた。どちらもデモ版(フリー)だったので、最初のステージしかプレイできなかった。

DOOMのステージは、wadファイルという定義ファイルによって制御されるため、デモ版ではたどり着けないステージに行くためには秋葉原のジャンクゲーム店に行ってアメリカから空輸したCD-ROMを手に入れるか、英文で手紙を書いたりして直接輸入するか、あるいは電子メールで連絡をとってパスワードを教えてもらってロックを解除するほかはなかった。実は注文方法についてはデモ版でGAME OVERになったときに毎回表示されるのだが、ドルで銀行振込したりVISAカードで購入する方法を調べるよりは、秋葉原にいって歩き回る方を私は選んだ(当時はクレジットカードを使っている人は日本にはまだあまりいなかったと思う)。線路沿いの広大な空き地(JRが解放した車両倉庫の跡)の角にあったボロボロのビルの1Fの中古ゲーム店で、DOOMのすべてのステージに行けるwadファイルを見つけた時は、喜びの雄叫びをあげたかもしれない。あの空き地には現在UDXなどが建っていて、あの時の場末の雰囲気も面影も完全に消滅した。

さっそく家に戻ってwadファイルを流し込み、デモ版を解放して一日中化け物たちを打ちまくった。3、4日後、羊の巨人のような最後の敵をやっつけたとき、なんだかしらない満足感があった。FD(フロッピーディスク)の容量の関係でCD-ROMのコピーができなかったので、そのまま友人に譲った。DOOMとはそれで「おさらば」のつもりであった。

DOOMの移植

(wikipediaによると)id Softwareプログラマの一人がLinux向けにソースコードを公開したのが1994年だという。発売の翌年というのはある意味驚きである。Doomのチーフプログラマーで、id Softwareの創立メンバーのJ.カーマックはオープンソース運動に賛同しているらしいから、その影響もあったのではないかと予想する。ただし、このLinux向けソースコードid Softwareの正式リリースではなく、あくまで「個人的趣味」として「黙認」されていた感じらしい。

id SoftwareGPLに基づき、正式にDoomソースコードを公開したのは1997年とある。その後、OSXなど様々なプラットフォームにも移植されてきたようであるが、ゲームの面白さとコードのオープンさが相まって、CPUチップが載っているありとあらゆる機械へのインストールを目指すマニアが世界中で発生した("Can it run Doom?"プロジェクト)。今調べただけでもオシロスコープや(不用品の中古らしき)ATMなど様々ある(笑)。現在のコンピューター環境に対してもChocolate Doomなど3、4のプロジェクトがあって、いろいろなバージョンが存在するようである。Doomの面白さは「Can it run Doom?」にもある。

そこでまずは、id SoftwareのLinux向けに公開したオリジナルのソースコードをgithubから手に入れて、先日インストールしたRaspberry PI OS Desktopでコンパイルしてみることにした。

Linux DOOM (linuxxdoom)

id Softwareが正式に認めているオープンソースコードはLinux向けのものであり、現在のコンピュータ環境でも動くバージョンは無数にあるが、それはすべてこのオリジナルソースコードから派生したものである。その関係性は、wikipediaによくまとめられている。

https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Doom_source_ports.svg/640px-Doom_source_ports.svg.png (Doomの移植版の関係性:wikipediaより

まずはgithubからソースコードをダウンロードする。

git clone https://github.com/id-Software/DOOM.git

おー!、これがソースコードか、という感動がある。Makefileをのぞいてみるが、非常にわかりやすい。

コンパイルするには

cd linuxdoom-1.104
mkdir linux
make

とやる。しかし、Raspberry PI OS desktopの場合「エラー」が出て止まってしまう。

X11環境で利用されているらしい"XShm.h"というヘッダーファイルがないという。これを解決するには

sudo apt install retroarch

とやってからmakeすると解決できる。

これでいけるかな、と淡い期待をもって再度makeすると今度はerrornos.hの関係でエラーが出て止まってしまう。 実は、このエラーは「有名なバグ」であった。検索するとたくさんの情報が引っかかってくる。

これだけ有名なのだからid softwareは修正したgitを公開してくれてもよさそうなものだが、そこは「これが対処できる人だけが先に進んでください」という、まさにDoomのスピリットで対応しているようである。つまり、自分で解決しないと先のステージに行けないのだ。

とはいえ、調べてみるとerrornos.hのバグ以外にも数箇所でソースコードの修正が必要になることが(世界中のハッカーによって)指摘されていて、それはid Softwareのgithubでも「情報」として公開されている。X11のカラーマップに関連するものだというが、私には理解できないので、言われた通りにi_video.cとi_sound.cに修正を入れたのみである。

github.com

また、次のような指摘もあるので、自分でエディターを開いて修正を加えた。

github.com

さらに、id SoftwareからMakefileについての変更が提示されている(あまり影響はないと思われるが)。

github.com

これらの修正をすべて自分で行って再コンパイルすると.....linuxxdoomというバイナリファイルが出来上がった!

しかしX11の問題があって動かない

コンパイルに成功したらもうDOOM in Raspberry PI OS はもうすぐそこである。喜び勇んで

./linuxxdoom

とたたくと、予想外のことが起こる。

Error: W_InitFiles: no files found

というエラーメッセージが表示され、"segmentation fault"となってプログラムが落ちてしまう。がっくりである。

対処法を検索してみると、「ゲームステージの設定ファイルであるwadファイルがないよ」という意味であった。id Softwareはコードは公開したが、wadファイルは「自分で探してね」ということらしく、gitパッケージには含まれていなかったのだ。ネット検索してみると、archive.orgにたんまりと保管されていた(もはやDOOMのwadファイルはNewtonのプリンキピアと同類の扱いである!)。

archive.org

linuxxdoomの場合は、実行コマンド"linuxxdoom"が存在するディレクトリにwadファイルを入れるだけでよい。特に読み込ませたり、コンパイルし直す必要はないという。archive.orgからダウンロードするとzip形式で圧縮されているので、unzipで解凍する。出てきたDOOM.WADをlinuxdoom-1.10/linuxフォルダに移動させ、ふたたび./linuxxdoomを叩く。ところが、再び"Error: W_InitFiles: no files found"と出てしまって、ゲームが始まらない。

さらに調べると、MS-DOSバージョンでは"DOOM.WAD"と全てが大文字のファイル名になっているが、linuxxdoomでは、"doom.wad"と小文字に変更しなくてはならないのだという。仕方ないので、

mv DOOM.WAD doom.wad
./linuxxdoom

と叩く。初期化プロセスはかなりの部分を通過するようになったものの、残念ながら画面設定の初期化のところで別のエラーが出てしまった.....

ST_Init: Init satus bar.
Error: xdoom currently only supports 256-color PseudoColor screens
Segmentation fault

またもや起動しない。調べてみると、どうやらこれはX11、つまりX-Windowシステム関連のエラーのようである。

昔もstartxの設定で随分つまづいたものである。自分が持っているCRTモニターの仕様を調べ(周波数や解像度など)、それに合うようにX-windowの設定ファイルを(画面が映るまで)延々と修正し続けた。まさか、ふたたびあの頃に戻ることになるとは思わなかった。しかし、DOOMがあの頃のアプリである以上、これは避けて通れない問題であろう。

Raspberry PI OS desktopのX-window システム

Linuxはもともとはコマンドラインインターフェイス(CLI)であり、MS-DOSと似たような感じだった。その後にWidows 95が現れたりして、ようやくmacOSOS9)に近いようなGUIベースのOSへと進化したが、LinuxはX-windowというシステムを利用してGUI化が進んだ。GNOMEKDEなど様々なデスクトップ環境が登場したが、Raspberry PI OSは、LXDT(Lightweight X11 Desktop Environment)というデスクトップ環境が採用されている。

すでにLXDTが動いている最中に、ターミナルからstartxとやると画面が乱れ再起動を余儀なくされるであろう。無理に再起動すると、Raspberry PIGUIでログインできなくなるという不具合が知られている。対処法は(こちらで紹介されているが)一旦、CLIに戻り(ctrl+alt+f1などを押す)、そこからログインしなおして、$HOMEにある.xsession-errorsなどのX-windows関係の設定ファイルを消去してからリブートすると回復できる。回復したら、今度は事前にCLIに入ってからstartxとやり直せば、GUIでデスクトップが起動してくれ安堵するだろう。

さて、調べてみるとlinuxxdoomはdepth=8(つまり$28=256$色)のカラーマップをもったX11環境で作動するように設定されているという。そのためには、CLIから

startx -- -depth 8

と(昔ならば)やればよかったのだが、今時のLinuxディストリビューションではうまくいかないようである。Raspberry PI OSの場合は、シンプルにstartxと打てばちゃんと動き出すのだが、"startx -- -depth 8"とやるとエラーが出てしまってX-windowが起動しない。これではlinuxxdoomは動かないのである。

まずは、Raspberry PI OSのX-window環境がどんなカラーマップになっているか調べてみることにする。

xdpyinfo| grep depth| grep root

> depth of root window: 24 planes

つまり、24ビット(16777216色!)である。この計算は、

echo '2^(24)'|bc -ql

で確認できる。現代のコンピュータは(安物のASUSといえども)とんでもない進歩を遂げたものである! しかし、これはDOOMからしてみれば「扱いきれない」ほどの情報量である。エラーが出るのは当然であろう。

などと余裕をかましている場合ではない。せっかくコンパイルできたlinuxdoomを、X環境の今昔不一致だけの理由で動かせないのは非常にもどかしいものがある。

XephyrでX-windowをネストする方法

検索を重ねていくと、Xephyrというコマンドがあり、それを使ってlinuxdoomを起動させているハッカーが多いことがわかった。これは、X-windowの中でX-windowを開くという、いわゆる「ネスティング」コマンドである。DOS-boxなどに近い考え方、つまりエミュレータのようなものである。

Raspberry PI OSにはデフォルトでは含まれていないので、インストールする。

sudo apt install xserver-xephyr

Xephyrは使い方がちょっと難しく最初はかなり困惑したが、わかってしまえば、なんのことはないが、X-windowのよい復習になったので下にまとめておく(昔はX-windowの使い方は完全に理解していたのだが、利用しないと忘れてしまうものである)。

X-windowシステムではDisplayという概念が適用されていて、まず自分自身のマシンの表示装置のDisplayを":0"とラベルする。

echo $DISPLAY

> :0

という出力が得られるはずである。もともとは、リモートでつないだサブマシンにもX-windowの環境を(通信で)送り込むのが目的で、DISPLAY=:1などが定義されていたし、いまでもvncなどで利用される。たとえば、Raspberry PI(ハードウェア)の場合、一度プログラムが完成すれば、デスクトップ環境は不要となり、LEDの制御などに特化して利用することになる。その場合は、X-windowのような負荷の高いサービスは止めてしまうことが多いだろう。しかし、プログラムに問題があったとき、Windlows11やmacOSからリモートでRaspberry Piのハードウェアに接続してメンテナンスやデバッグを行いたい場合があるだろう。このときvncを使ってX-windowをWin11やmacOSに引き込み、Raspberry PiGUI環境をwindowやmacで利用するために適用するのがDISPLAY=:1のX-windowである。

Xephyrでも、ことなるDISPLAYの番号をもったX-windowを(オリジナルのX-windowの中に)立ち上げる。vncを:1で使っていることを想定し、:2で設定する場合は、

Xephyr :2 -ac -screen 640x400x8 -reset -terminate -title DOOM &

とする。こうすると、メインスクリーンに(DOOMと題された)黒いウィンドウが開く。-screenの次の引数が重要である。解像度を640x400とし、そのカラー深度を8ビット(つまり256色)に設定するのである。これがstartx -- -depth 8と同じ効果を持っている。

この状態にしてから、linuxxdoomを叩いても同じエラーが出てしまうだけである。というのも、そのlinuxxdoomはDISPLAY=:0、つまり自分のメインスクリーンに表示されるからである。linuxdoomをXephyrが開いたDISPLAY=:2で起動するためには次のようにコマンドを打つ。

DISPLAY=:2 ./linuxxdoom

「さあ、これでいよいよ!」と思って期待したが、なぜか同じエラーが出てゲームは起動しない。ここで、手も足も出ない状態になってしまった。原理的にはこれで正しいはずである。どこも間違ってないと思う。検索したHPでの成功例をみると、この段階でちゃんとdoomは起動している。なにが問題なのであろうか?

XMatchVisualInfoの構文の謎

ここからが大変であった。いくつかネットで検索した事項を試してみたがまったく効果なし。なぜ起動できている人が世の中にいるのか、全く不思議であった。そこで、ソースコードを少しいじって何が問題になっているか分析してみることにした。

まずは、最初から「?」と思っていた部分である。これはid Softwaregithubで教示されていたデバッグ法である(そのリンクは上ですでに示したものと同じである)。i_video.cで次のようなバグがあるとgithubやその他のネット文書では指摘があり、8から4に変更せよ、とある。私は何も考えずに言われた通りにしていたのだが、なんとなく「8ビットだから8のままでいいんじゃないの?」と最初から薄々感じていたのである。id Softwaregithubの情報をスクリーンショットしたのが次の図である。

id Softwaregithubの文書より

まずはこのXMathVisualInfo関数の意味について調べてみた。これはXlibで定義されている関数で、Xのスクリーンの状態を確認するためのものである。与えたスクリーン状態に適合するものがあれば非零値を返し、適合するものがなければ零値を返すという関数である。そして私が着目する位置にある引数の8とか4という数字は、予想通り、カラーマップの深度つまりdepthであった!手に入れたバグ情報では「これを4ビットに修正せよ」とあるが、8ビットで動かすのがDoomのデフォルトのはずだから、ここを8に戻して再コンパイルするか、Xephyrで-screen 640x400x4として動かせば、Doomが起動できるはずだ。とはいえ、後者を選んだ場合、色数が24=16色しかでないので、惨めな色彩となるであろう。

実はネットで集めた情報には、この色の乏しさに悩む相談を議論しているものがあり、なるほどね、と思った次第である。ちなみに、この相談では解決に至らなかったが、今の私なら解決法を教えてあげることができる!(「上から目線」ができるようになった!)

www.doomworld.com

ということで、ソースコードのi_video.cを開き、4に直した部分を8に戻してコンパイルし直し、Xephyrを用いてdepth=8で起動させたのが、下のスクリーンショットである。つまり、Raspberry PI OS desktopで、ついにlinuxdoomが起動したのである!(効果音とBGMはまだならないが)

Rapberry PI OS desktopで起動した、オリジナルのlinuxxdoom

起動後の解像度の問題の解決方法

しかし、なぜか異様に画面が小さい。実はこの問題についてもネットではすでに話題になっていたらしいが、解決法を提示したHPは最初なかなか見つからなかった。 sauparna.sdf.org

こちらのブログでも「画面が小さすぎる」と苦情を言っている(が、動くだけで嬉しいとも言っている)。

この問題に関しては、ここで解決策を見つけることができた。結局、解像度のモードをオプションで指定するだけで解決である。

ということで、デバッグデバッグをして再コンパイルした後に、次のコマンドによってlinuxxdoomはRaspberry PI OS desktopで、キチンと起動させることができる。

$ Xephyr :2 -ac -screen 640x400x8 -reset -terminate -title DOOM &
$ DISPLAY=:2 ./linuxxdoom -2

解像度を倍々であげたいときは、オプションを-3, -4とすれば良い。linuxxdoomのデフォルトの解像度は320x200なのであった。それだけのことである。

ついに起動したlinuxxdoom!

ということで、わが貧弱ASUSノートPCに搭載したRaspberry PI OS desktopで起動したlinuxxdoomのスクリーンショットをいくつか披露して、今回のプロジェクトは一旦完了である。