rust
Emscripten
SDL2
WebAssembly

rust-sdl2を用いてwasmを生成する際の音楽ファイル関連のtips

tl;dr;

  • emscripten-portsのsdl2の問題で音楽ファイルを読み込ませられない
  • Music::from_static_bytesなどを用いてWebAssembly(wasm)に予め読み込ませておけば動く
  • C、C++バインディングのrustのライブラリを使う場合、emscriptenを使わざるをえないと思われる

はじめに

 mac上の環境をぶっ壊したのでdocker上に再構築する羽目になっているr-chaser53です。正直ほとんど進捗できなかったのでrust-sdl2を使ったアプリをwasmに変換した際のtipsを書こうと思います(※1)。

無理やり音楽ファイルを読み込ませる

 rust-sdl2で任意のpathの音楽ファイルを読み込ませたい場合、以下のようになります。

sdl2::mixer::Music::from_file(path).unwrap();

 本来ならば変数pathからメタデータを生成しSDL.rwopsというオブジェクトに格納するようなのですが、肝心のSDL.rwopsオブジェクトは[null]と最初に宣言した時のままです。値が代入されてません(※2)。そのまま実行するとnullのrwopsオブジェクトのfilenameを参照しようとして処理が進みません。以下のようなハックで動かすこともできたのですが、正直微妙なところです。そもそもファイルを読み込ませること自体に問題があるのかと思いましたが、マップを読み込ませる処理自体は問題なく動いています。おそらくそちらに問題はないでしょう。

Module['preRun'] = function () {
  FS.createPreloadedFile(
    '/',
    'filepath',
    '/filepath',
    true, false);
  SDL.rwops = [{ filename: 'filepath'}];
}

予め読み込ませてみる

rust-sdl2は以下のようにコンパイル時に音楽データを取り込んでしまうmethodも提供しています。

sdl2::mixer::Music::from_static_bytes(include_bytes!("filepath"));

 こちらは問題なく読み込んでくれるようです。コンパイル後にファイルが指定できないですし、音楽ファイルの分だけファイルが大きくなってしまうのも芳しくありません。しかし複数の音楽ファイルを読み込ませた場合、上のハックではとてもメンテできそうにありません。諦めてこちらを使うのが妥当なのではないでしょうか。

emscriptenとrustとc, c++バインディング

 進捗駄目です。レポジトリはこれです。
packman.gif
 「Rustでパックマン風のゲームを作ってみた」のgifと比べると分かりますが円じゃなくて矩形になってます。理由としてはsdl2-gfxという円などを描画してくれるライブラリをemscriptenがサポートしてくれていないためです。cやc++のライブラリを使用したrustのアプリからwasmを作成する際に、対象のcやc++のライブラリがあるかemscripten portsを参照しますが、今回使用したいsdl2-gfxがないのです。自力でsdl2-gfxをwasm上で動かせるように色々調べてはいますが、必要な知識が多くいつまでかかるやらという状況です。この辺については「Rustからwasmを生成してみた話」あたりを見てくださると嬉しいです。
 選択肢の1つとしてemscriptenを使わない「wasm32-unknown-unknown」も考えたのですが、cやc++のバインディングを考慮してくれないようでした(※3)。開発を行う上でcやc++の資産を使いたいケースは少なくないと思われます。若干emscriptenから逃げたい気持ちもあるのですが、現状wasmを作成しようとする限りemscriptenからは逃げられないのかなというのが個人の感想です。

備考

※1 2017/12/17 rust-sdl2 version 0.31 現在
※2 ソースを追ってみると「throw 'Mix_QuerySpec: TODO'」とか書いていて「そっか…」てなります
※3 調査不足で設定や書き方次第では「wasm32-unknown-unknown」でもc、c++バインディングのwasmを生成できてほしいと正直思っています