OpenSiv3Dで作ったアプリをWeb版に対応させた際にやったこと

[OpenSiv3D](https://siv3d.github.io/ja-jp/) で製作している Windows 向けのアプリケーションを Web ブラウザで動かしてみたくなり、[OpenSiv3D for Web](https://siv3d.kamenokosoft.com/) を使用して wasm 化をしてみました。

その結果、割とすんなり Windows / Web の両対応ができましたが、いくつかの注意点もありましたので、要点をまとめてみました。

ちなみに、私が制作しているアプリはゲームボーイエミュレータなのですが、下記のリポジトリで Web 版に対応させたバージョンを v1.4.2 として公開しています。何かの参考になればと思います。

https://github.com/voidproc/dmge

https://github.com/voidproc/dmge_web

## 開発環境

- Windows 11
- Visual Studio 2022
- OpenSiv3D v0.6.11
- OpenSiv3D for Web v0.6.6

## 公式ドキュメント

注意事項はほぼこちらに記載されています。

https://zenn.dev/reputeless/books/siv3d-documentation/viewer/web

https://siv3d.kamenokosoft.com/docs/ja/

## 環境設定

ドキュメントに沿って必要なソフトウェアをインストールします。

https://siv3d.kamenokosoft.com/docs/ja/download/web-vs/

## 既存のソリューション (.sln) にWeb版のプロジェクトを追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35599/7c08f3a3-7cb0-7b56-75dc-36327130bf30.png)

## 既存のソースファイル、ヘッダファイルをプロジェクトに追加

ファイルのコピーなどはせず、既存のファイルをそのまま Web 版のプロジェクトに追加しました。

## インクルードファイルについて

もともとは `stdafx.h` からプリコンパイル済みヘッダーを作成し、それを「必ず使用されるインクルードファイル」(/FI) に指定しており、各ソースファイルでは　`#include "stdafx.h"` の記述を省略していました。

ですが Emscripten での同様の設定方法がわからなかったため、`#include "stdafx.h"` を省略せずに記述することにしました。

## 外部ファイルをバンドル

フォントやテクスチャなど、必要な外部ファイルを配置しているフォルダをここで指定します。

プロジェクトのプロパティ → Emscripten リンカ → 入力 →「プリロードされるリソースファイル」

例えばプロジェクトフォルダ直下の `fonts` フォルダにフォントファイルを配置している場合、上記のプロパティに `$(ProjectDir)\fonts@/fonts` と追記すれば、`@` 以降のパスでファイルにアクセスすることができるようになり、下記のように使用できます。
```
Font font{ 24, U"/fonts/フォント.ttf" };
```

- [Web 固有の注意点 - OpenSiv3D for Web docs](https://siv3d.kamenokosoft.com/docs/ja/reference/web-specific-notes/#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)

## ASYNCIFY_ADD の設定

ドキュメントのとおりに `ASYNCIFY_ADD` に関数名を設定します。設定はリンカオプション → コマンドライン → 「追加のオプション」 から。

- [Asyncify を使う上での制約 - OpenSiv3D for Web docs](https://siv3d.kamenokosoft.com/docs/ja/reference/web-specific-notes/#asyncify-%E3%82%92%E4%BD%BF%E3%81%86%E4%B8%8A%E3%81%A7%E3%81%AE%E5%88%B6%E7%B4%84)

これをしないと次のようなエラーになりました:
```
Aborted(RuntimeError: null function or function signature mismatch)
``` 


## ソースコードを編集

### プラットフォームごとに処理を切り替える

`SIV3D_PLATFORM(x)` マクロが利用できます。

例:
```cpp
#if SIV3D_PLATFORM(WINDOWS)
  //Windows版での処理
  //...
#elif SIV3D_PLATFORM(WEB)
  //Web版での処理
  //...
#endif
```

### タッチ・スワイプのみの操作への対応

ブラウザで動作するアプリでは、スマホなどのマウス・キーボードのない環境を考慮する必要があります。

例えば、私のアプリでは ESCキー or 右クリックでメニュー表示をしていましたが、タッチ（左クリック）長押しでも表示できるようにしました。また、上下キー or ホイールでスクロール処理をしていた部分は、スワイプ（左ドラッグ）でも可能としました。

タッチ長押し検出の例:
```cpp
if (MouseL.pressedDuration() > 0.5s)
{
  // タッチ長押し時の処理
  ...
}
```

スワイプ処理の例:
```cpp
Optinal<Vec2> swipeBasePos;

//...

if (MouseL.down())
{
  // スワイプ開始
  swipeBasePos = Cursor::PosF();
}

//...

if (swipeBasePos)
{
  // スワイプ量：何かスクロール処理などに使う
  const auto swipeAmount = Cursor::PosF() - *swipeBasePos;

  //...

  // スワイプ終了
  if (MouseL.up())
  {
    swipeBasePos = none;
  }
}
```

また、ゲームアプリなどで、キーボード or ゲームパッドで操作するようなものをちゃんとスマホ対応する場合は、仮想ゲームパッドのようなインターフェースを配置する必要があると思います。（私はできていません）


## 出力ファイルのファイルサイズ削減

最終的な出力ファイルのうち .wasm ファイル、.data ファイルは、標準の状態ではファイルサイズがとても大きくなるので、GitHub Pages やレンタルサーバで公開するのであればドキュメントに従ってファイルサイズの削減をした方がよいです。

- [出力ファイルサイズの削減 - OpenSiv3D for Web docs](https://siv3d.kamenokosoft.com/docs/ja/publishing/publishing/#3-%E5%87%BA%E5%8A%9B%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B5%E3%82%A4%E3%82%BA%E3%81%AE%E5%89%8A%E6%B8%9B)
- [チュートリアル 41 | アプリの公開 - Siv3D リファレンス](https://zenn.dev/reputeless/books/siv3d-documentation/viewer/tutorial-release#41.9-%E5%90%8C%E6%A2%B1%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E7%84%A1%E3%81%84%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB)

### 不要なファイルをバンドルしない

次のファイルを削除できます。

- `example` フォルダ内の使っていないファイル
- `resources/engine` フォルダ内の使っていないファイル
  - フォントは最低限 `min` フォルダのみ残しておけばよい？

### 不要なライブラリをリンクしない

リンカオプション → 入力 → 「追加の依存ファイル」 を編集して不要なライブラリを削除

### バンドルするアセットのファイルサイズを削る

- サイズの大きい日本語フォントファイルを使用している場合はサブセット化するなど

## 今後の課題

- Web 版のコンパイルに時間がかかるので、プリコンパイル済みヘッダーを作成したい