2022/06/08(水) [n年前の日記]
#1 [xlib] Xlibでタイルマップを描画
Xlibを使ってタイルマップ描画ができるか試してみた。タイルマップ描画ができれば、一気に2Dゲーム風の画面になる。はず。たぶん。おそらく。
環境は、Ubuntu Linux 20.04 LTS。Windows10 x64 21H2 + VMware Player 16.2.3 build-19376536 上で動かしてる。
こんな感じになった。
元画面は640x360。それを、ディスプレイ解像度 1440x900に拡大して描画してる。
BG相当を3枚も描画できれば、2Dゲーム風の画面を作るには十分過ぎるかなと。ファミコンやPCエンジンならBGが1面、メガドライブでもBGが2面だったし。
スーファミ(SFC)は何枚まで出せたんだろう。ググってみたらMode0からMode7まであったみたいだけど。Mode0が4枚まで出せたと書いてあるな…。ただ、1パレットが4色か…。
_Super Nintendo Entertainment System - Wikipedia
環境は、Ubuntu Linux 20.04 LTS。Windows10 x64 21H2 + VMware Player 16.2.3 build-19376536 上で動かしてる。
こんな感じになった。
元画面は640x360。それを、ディスプレイ解像度 1440x900に拡大して描画してる。
BG相当を3枚も描画できれば、2Dゲーム風の画面を作るには十分過ぎるかなと。ファミコンやPCエンジンならBGが1面、メガドライブでもBGが2面だったし。
スーファミ(SFC)は何枚まで出せたんだろう。ググってみたらMode0からMode7まであったみたいだけど。Mode0が4枚まで出せたと書いてあるな…。ただ、1パレットが4色か…。
_Super Nintendo Entertainment System - Wikipedia
◎ ソース。 :
ソースと使用画像は以下。
_09tilemap1.c
_scifi_bg_chip.xpm
一応、元画像(.png)も置いておきます。CC0 / Public Domain ってことで自由に使ってください。1チップ(1タイル) 64x64ドットが、8x8個並んでます。インデックスカラー画像、48色。だったはず。たぶん。

_scifi_bg_chip.png
コンパイルは以下。
実行は以下。
少し解説。
今回、今までのソースと違って、State という構造体を定義して、処理で利用する変数を全部その State の中に入れることにした。各関数に引数を渡すあたりの記述が面倒臭かったので、State のポインタを渡して全部の変数にアクセスできるようにしてしまえ、みたいな。
1枚の xpm を分割して複数の Pixmap を作るあたりは、split_pixmaps() という関数で処理してる。
ちょっとハマった点。マスク用のPixmapをコピー(XCopyArea)する時は、マスク用のGCを別途用意しないといけない。そのあたりを知らなかったもので、RGB部分とマスク部分の両方を同じGCで処理しようとして、エラーが出て悩んでしまった。RGB部分を持ってる Pixmap と、マスク用の Pixmap は深度(Depth)が違うので、GCも深度別に用意しないといけないのだとか。
タイルマップを描画するあたりは、draw_tilemap() で処理してる。
本来、この手の処理は、BG用の大きなバッファ(Pixmap)を用意しておいて、スクロールに応じて書き換えが必要な場所だけ書き換えて、そのBG用の大きなバッファをソースにして表示用バッファに描画、といった処理をしたほうが速度は稼げるのだけど。今回は面倒臭かったので、毎フレーム、愚直に、チップ(タイル)を何十個も描画し直すやり方を選んでしまった。まあ、これはこれで、BGのアニメーションはしやすかったりもするけれど…。
余談。タイルマップ用のデータは、Tiled 1.8.5 64bit版を使わせてもらいました。ありがたや。
_Tiled | Flexible level editor
ちなみに、Tiled から json でエクスポートするとタイル番号は1から始まるけれど、csv でエクスポートするとタイル番号は0から始まるのですな…。知らなかった…。
_09tilemap1.c
_scifi_bg_chip.xpm
一応、元画像(.png)も置いておきます。CC0 / Public Domain ってことで自由に使ってください。1チップ(1タイル) 64x64ドットが、8x8個並んでます。インデックスカラー画像、48色。だったはず。たぶん。

_scifi_bg_chip.png
コンパイルは以下。
gcc 09tilemap1.c -o 09tilemap1 -I /usr/include/X11 -lX11 -lXext -lm -lXpm
実行は以下。
./09tilemap1
少し解説。
今回、今までのソースと違って、State という構造体を定義して、処理で利用する変数を全部その State の中に入れることにした。各関数に引数を渡すあたりの記述が面倒臭かったので、State のポインタを渡して全部の変数にアクセスできるようにしてしまえ、みたいな。
1枚の xpm を分割して複数の Pixmap を作るあたりは、split_pixmaps() という関数で処理してる。
ちょっとハマった点。マスク用のPixmapをコピー(XCopyArea)する時は、マスク用のGCを別途用意しないといけない。そのあたりを知らなかったもので、RGB部分とマスク部分の両方を同じGCで処理しようとして、エラーが出て悩んでしまった。RGB部分を持ってる Pixmap と、マスク用の Pixmap は深度(Depth)が違うので、GCも深度別に用意しないといけないのだとか。
タイルマップを描画するあたりは、draw_tilemap() で処理してる。
本来、この手の処理は、BG用の大きなバッファ(Pixmap)を用意しておいて、スクロールに応じて書き換えが必要な場所だけ書き換えて、そのBG用の大きなバッファをソースにして表示用バッファに描画、といった処理をしたほうが速度は稼げるのだけど。今回は面倒臭かったので、毎フレーム、愚直に、チップ(タイル)を何十個も描画し直すやり方を選んでしまった。まあ、これはこれで、BGのアニメーションはしやすかったりもするけれど…。
余談。タイルマップ用のデータは、Tiled 1.8.5 64bit版を使わせてもらいました。ありがたや。
_Tiled | Flexible level editor
ちなみに、Tiled から json でエクスポートするとタイル番号は1から始まるけれど、csv でエクスポートするとタイル番号は0から始まるのですな…。知らなかった…。
◎ Core2Duo機でも動作確認してみた。 :
Intel Core2Duo E8400 (2コア, 3.0GHz) + NVIDIA GeForce 9500GT + Ubuntu Linux 20.04 LTS、ディスプレイ解像度 1920x1200 の環境でも動作確認してみた。今となっては非力なCPU+GPUのはずだけど、それでも大体 3〜 5msec で動いてたので、この程度の描画処理なら60FPSで動かせそうな気配がする。
もっとも、Ryzen 5 5600X + VMware Player + Ubuntu Linux 20.04 LTS、ディスプレイ解像度 1920x1080 では 0.9〜1.1msec で動いたので、Ryzen 5 5600X と比べると Core2Duo E8400 は 1/5 の速度、ということになるのだろうか。いやまあ、仮想PC上ではなくて実機上で動かしたら、また違う処理時間になるかもしれないけど。
もっとも、Ryzen 5 5600X + VMware Player + Ubuntu Linux 20.04 LTS、ディスプレイ解像度 1920x1080 では 0.9〜1.1msec で動いたので、Ryzen 5 5600X と比べると Core2Duo E8400 は 1/5 の速度、ということになるのだろうか。いやまあ、仮想PC上ではなくて実機上で動かしたら、また違う処理時間になるかもしれないけど。
◎ OpenGLを使うべきだろうか。 :
Xlib についてググったら、1985年頃に登場したものらしくて。
_Xlib - Wikipedia
そんなに古いライブラリ(?)を使ってもこのくらいの描画はできるのだな、という感想を持ったけれど、さすがにこういう感じの描画をしたいなら OpenGL だか glx だかを使うべきなのでは、という気もしてきた。
_GLX - Wikipedia
xscreensaver のドキュメント内でも、「高速な描画をしたいなら OpenGL/glx を使うことを検討すべきやで」みたいなことが書いてあった気もするし。
_Xlib - Wikipedia
そんなに古いライブラリ(?)を使ってもこのくらいの描画はできるのだな、という感想を持ったけれど、さすがにこういう感じの描画をしたいなら OpenGL だか glx だかを使うべきなのでは、という気もしてきた。
_GLX - Wikipedia
xscreensaver のドキュメント内でも、「高速な描画をしたいなら OpenGL/glx を使うことを検討すべきやで」みたいなことが書いてあった気もするし。
[ ツッコむ ]
以上です。