DXライブラリをLinuxへ移植してみた

# はじめに

DXライブラリをLinuxでも動作するように移植してみました。

https://github.com/dragoon2014/dxlib-for-linux/

筆者は[DxLibのD言語バインディング](https://qiita.com/dragoon2014/items/3e62ef1877deb5effd4f)を作ったりしているのですが
ここ数年はもっぱらLinuxを使っているので実はあまりWindowsに触れていません。（ゲームするときくらい）
小物のGUIを作るのに重宝していてLinuxでも使いたいなーと思ったので移植してみました。
筆者は持っていませんがSteam Deck（Arch Linuxベースらしい）とかでも使えそうですね。

開発にはXubuntu 20.04を使用しています。

# アプローチ

DxLib移植の先駆者で有名所では[mauveさんのDxPortLib](https://github.com/mauvecow/DxPortLib)でしょうか。
すでに更新はされていないようですがSDLをバックエンドにしてLinuxやAndroidで動作していたようです。

今回の実装はDxLib自体の開発と似たアプローチ（だと思います）で
既存のコードに対してLinux向けの分岐を追加し、既存コードを流用することで
コード追加を最小にしつつよりプラットフォームに依存せず同じ挙動を取りやすくなっています。
DxLib自体が多くのプラットフォームをサポートしており、
特にAndroid向け部分がGLESを使っていたため
もしかしたらそのままLinux向けに流用できるのではないかと思ったところからスタートしました。

# TL;DR、とりあえず実行したい

後述のサンプル実行まで一括で実行できます

```
git clone https://github.com/dragoon2014/dxlib-for-linux
cd dxlib-for-linux
make patch
make -j4
cd samples
./samplesなんちゃら
```

以降はやった作業の流れです。

# 準備

DxLibのソースを落とすところから始まります。
執筆時点で最新の ~~3.22c~~ 3.22eを使用します。(3.23が出たようですね)

ソースを展開するときに注意しないといけないのは、
zipのファイル名および内容がcp932でエンコードされていることで
Linuxで迂闊に展開すると文字化けを起こして面倒なことになります。
以降特に明示しない限りすべてutf-8なソースとして扱います。
iconv対応（-Oオプションがあること）のunzipとnkfがあれば特に問題なく展開できます。
どちらもubuntuの標準リポジトリに含まれています。


```
unzip -O cp932 DxLibMake3_〜.zip
find DxLibMake -type f -exec nkf -w -Lu --overwrite {} +
```

ソースを展開したらとりあえず最小のテストコードを用意。

```
// samples/sample1_minimum.cpp
#include "DxLib.h"

int main(){
    if(DxLib_Init() == -1){
        return -1;
    }
    DxLib_End();
    return 0;
}
```

各cppをコンパイル、ライブラリ化、ライブラリとリンクして実行バイナリを生成の三段階でビルドできます。

```
# 各cppをコンパイル
g++ -o DxLibMake/DxGateway.o DxLibMake/DxGateway.cpp
g++ -o ...同じように...

# ライブラリ化
ar rcs DxLibMake/libDxLib.a DxLibMake/*.o

# 実行バイナリ生成
g++ -o test/test1 test/test1.cpp -I DxLibMake \
DxLibMake/libDxLib.a -lpthread -lz ...（以降必要なライブラリ）...
```

最終的なコマンドはMakefileを見てもらうとして、
実際に作業する際は

```
実行バイナリ生成
↑　↓
↑　実装不足分エラーが出る
↑　↓
不足してる関数を実装してるcppを探してコンパイル対象に追加
```

を延々繰り返します。

各ソースには環境依存箇所があり、/Windowsとか/Androidとかに分けられて記述されています。
当然Linuxに対応する箇所は用意されていませんのでここを独自に作成していきます。
幸いなことに、DxLib自体がマルチプラットフォーム向けな構造になっていて
不要な（開発者的には未実装な）機能をカットするDX_NON_〜が用意されていること、
足すべき箇所がわかっていることと、
冒頭にも書きましたがAndroidやiOS向けのコードを流用できそう（実際できた）なので、
ある程度は簡単に（面倒なだけ）移植ができます。

よりLinuxで使いやすそうな方をベースに過不足を修正していきます。
この辺は感覚ですが、基本AndroidベースでSoundとFontはiOSをベースにしました。
AndroidのコードとiOSのコードでそれぞれANDROIDとかIOSとか似た文字列をLINUXとかに一括置換します。

やっているうちに外部ライブラリを要求する箇所が出てくるので用意します。
脆弱性とかがあるのでなるべく最新版を使用します。
UseCLibの範囲はソースからでもパッケージからでも使えましたが
一部DxLib側でライブラリの内部ヘッダーを使用してしまっているためlibvorbisとlibjpegのファイルが必要です。
insufficient_include内にファイルをおいてください。
他に必要なライブラリ(libegl1-mesa-dev, libopenal-dev)はOSパッケージを使用しました。

なおBulletとLive2Dの対応は今の所保留してます。

さて、コンパイルが通ったところでウィンドウすら出ません。
以降はLinux独自の箇所の実装を行っていきます。

# 実装箇所

まずウィンドウ制御についてX11（今どきならWayland？まあxfceが対応したら）で実装していきます。
とはいえAndroidのコードをベースにウィンドウの生成を行うだけです。
GLESの箇所は驚くほど何も変えなくても動きました。
ところでなぜかDrawTriangleだけちゃんと描画されないようです、謎。
（サンプル：sample2_string_and_shape.cpp

![s2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51482/5494db86-d525-3627-5563-c36af8a67c99.png)

つづいて文字描写ですがASCIIの範囲であればDxLib内に（独自？）フォントが埋め込まれています。
WindowsであればＭＳ ゴシックが優先的に選ばれるので通常は見えないかと思います。
日本語が出せないですがとりあえずはこのまま。
（サンプル：sample2_string_and_shape.cppほか）

サウンドですが、ちょうど3.22cから3.22eのタイミングでiOSの実装（OpenAL→iOS独自）が変わり、
残されている旧実装をつかう形にしたのでもしかしたら将来的に動かなくなるかもしれません。
ちなみに外部ファイルを現在のディレクトリからの相対パスで指定してるので実行パスに注意してください。
うまくexeからの相対で指定できるといいのですが・・・
（サンプル：sample5_sound.cpp、音量注意）

画像の描写は特にほとんど何もいじった覚えがないくらいでした。
（サンプル：sample6_graph.cpp）

![s6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51482/181bc2b7-4bc8-4624-2af9-9d72de1a7458.png)

入力デバイスの対応はコントローラやタッチ対応デバイスが用意できてないのでマウスとキーボードのみです。
マウスは左右中ボタンとホイール上下左右に対応してます。
いわゆるボタン4以降は対応しません。（内部的にはホイールで使われている）
キーボードは一応フルキーボードに対応しているはずですが、
・Scroll Lockは反応しません。（Windowsでも反応しなかった）
・テンキーはNumlockに依存せず常にNUMPAD0〜9を返すようになっています。
あとイベント処理の都合でAlt+Tabとかで抜けるとAltが押しっぱなしになる挙動があります。
Altに限らず、ボタンを押したままウィンドウフォーカスをずらすと
リリースイベントが取得できず押しっぱなしになります。（直したい）
フォーカスを戻してもういちどそのキーを押すと戻ります。
（サンプル：sample8_input.cpp）

ほか、使える機能はsamples以下を参考にしてみてください。
3Dとかマスク処理とかほとんど試してませんが使えるかもしれません。

# 感想

GLESの汎用性が強すぎてDXライブラリの「DX」部分が弱く感じました。
あとコードを見てて思ったのはユーザ側のリンクの手間を省くためだと思うのですが、
依存ライブラリのコードを直接取り込んでいるため管理が大変そうでした。
（ライセンス文つくるのにも時間かかったし、合ってる？）

# 今後の課題

~~日本語の表示~~→([11](https://github.com/dragoon2014/dxlib-for-linux/blob/f71f336d/samples/sample11_change_font.cpp))は最低でも行いたいですね。
一度Windows環境でフリーフォントをDFT化すればおそらく使えるかと思います。
（Freetypeとかでガッツリ実装すればttf直接呼んで任意サイズのフォントで描写はできるでしょうが）
あとは~~サイズ変更~~→([09](https://github.com/dragoon2014/dxlib-for-linux/blob/f71f336d/samples/sample09_window.cpp))等ウィンドウ関連関数が弱いのでそこも強化したいです。

2022/07/16追記:あとdnd([10](https://github.com/dragoon2014/dxlib-for-linux/blob/f71f336d/samples/sample10_dnd.cpp))実装したので、気が向いたらまとめる