伺か on Browser

58ab8900254150820e685da7cd0d4d9f?s=47 Narazaka
October 05, 2016

伺か on Browser

デスクトップマスコットをブラウザ移植してみた
利用者視点のEmscriptenとその周辺

58ab8900254150820e685da7cd0d4d9f?s=128

Narazaka

October 05, 2016
Tweet

Transcript

  1. うかがか 伺か on Browser デスクトップマスコットをブラウザ移植してみた 利用者視点の Emscripten とその周辺

  2. 自己紹介 佐藤隆人 ( な ら ざ か 奈良阪 ) Twitter:

    @narazaka Github: @Narazaka npm: @narazaka CPAN: NARAZAKA ドリコム 2015 新卒 (2 年目 ) サー バー サイド Ruby 書いてます Perl / JavaScript / Ruby / C# あたりが好き その他 : 伺か / 漫画読み描き / OP アニメ愛好家 / 鉄
  3. ※ 注意 1 から 10 まで趣味の話です プロダクションレベルの知見ではありません。 試行錯誤の途中なのでアドバイスなどいただけると幸いです。

  4. 近年やってる趣味

  5. うかがか 伺か 2000 年頃に一部で流行ったデスクトップマスコット

  6. デスクトップマスコットのなかま? たち ポストペット ペルソナウェア デスクトップのメイドさん いもうとデスクトップ まいんど・ ふぉ~ かす お座りマルチ

  7. かわいい

  8. かわいい

  9. 懐かしい

  10. 懐かしい

  11. なんかすごい

  12. キャラクター 表現プラットフォー ム 16 年目の現在もたくさんのキャラの更新がある

  13. しかし…… 世はスマホ全盛

  14. 「 キャラクター の居場所 デスクトップ」 の消滅

  15. …… スマホでも使いたい ブラウザにのせて動かせないか?

  16. 「 伺か on Browser イカガカ」 プロジェクト コー ド https://github.com/Ikagaka デモ

    http://ikagaka.github.io/Ikagaka.demo/
  17. ブラウザに載せるにあたって…… うかがか 伺か はどういうプログラム?

  18. うかがか 伺か (materia.exe) キャラクター デー タを差し替えられる デスクトップマスコットランタイム → クロー ズドソー

    スなので JavaScript で新規開発 キャラクター の人格は任意の Windows 用アンマネー ジド DLL をそ のまま動作させる仕様 ( めっちゃ自由 ) extern "C" ̲̲declspec(dllexport) BOOL ̲̲cdecl load(HGLOBAL h, long len); extern "C" ̲̲declspec(dllexport) BOOL ̲̲cdecl unload(); extern "C" ̲̲declspec(dllexport) HGLOBAL ̲̲cdecl request(HGLOBAL h, long *len); →OSS の C++ 製人格 ( 台本 ) 記述用言語 DLL(.so) がいくつか存在
  19. 各人格記述用言語 DLL (with Hello, World!) shiori.dll ( 華和梨 8) /

    shiori.dll ( 華和梨 7) System.Callback.OnGET: Hello, World! satori.dll ( 里々) * Hello, World! yaya.dll (YAYA) / aya5.dll ( 文 5) request { "Hello World!" }
  20. _ 人人人人人人人_ > Emscripten  <  ̄Y^Y^Y^Y^Y^Y  ̄

  21. Linux で依存なくコンパイルできる C++ だった ( 一部 boost はずした ) 既存のコー

    ドほぼ変更なし
  22. Makefile もフラグ追加と g++ ‑> em++ rem emsdk1.25.0 on Windows emcmdprompt.bat

    D: cd kawari make
  23. 各人格記述用言語 DLL 割とすんなり変換できた shiori.dll ( 華和梨 8) ‑> kawari.js shiori.dll

    ( 華和梨 7) ‑> kawari7.js satori.dll ( 里々) ‑> libsatori.js yaya.dll (YAYA) ‑> yaya.js aya5.dll ( 文 5) ‑> aya5.js
  24. _ 人人人人人人人_ > Emscripten  <  ̄Y^Y^Y^Y^Y^Y  ̄ ‑ 完 ‑

  25. ! ここからが問題 ! ~Emscripten とその周辺~

  26. 今回の最重要要件 = 互換動作 キャラデー タの変更なしに デスクトップと同じ挙動を保証したい キャラデー タは創作畑の人たちが作っていて、 形式変換などが望めるものではない

  27. 1. 落ちるキャラデー タがある メモリ関係のエラー で落ちる 任意のキャラデー タを突っ込んで動作させたい……。

  28. 1. 落ちるキャラデー タがある ( 解決 ) em++ のデフォルトでは最大メモリサイズが固定値だった。 メモリが足りなくなったら自動的に拡張してくれる ‐s

    ALLOW_MEMORY_GROWTH=1 をつけてコンパイル。 ( 実行速度遅くなるよという警告が出る )
  29. 2. 複数キャラをたちあげたい 同じ人格 DLL.js を色々 なキャラデー タに適用したい。 しかし→Emscripten はスクリプトをロー ドした時点で、

    グロー バ ルの Module とかに色々 入れてそのまま単一インスタンスとして実 行してしまう。
  30. 2. 複数キャラをたちあげたい ( 解決 ) 関数で囲って new する ‐‐pre‐js em‐pre.js

    ‐‐post‐js em‐post.js ( どう見ても正攻法ではない気がする…… → 現在は Worker に隔離 ) var Kawari = function(){ // em‐pre.js (****Emscriptenでコンパイルされたコード...****) this['Module'] = Module; this['FS'] = FS; this['PATH'] = PATH; this['ERRNO_CODES'] = ERRNO_CODES; this['NODEFS'] = NODEFS; this['IDBFS'] = IDBFS; this['WORKERFS'] = WORKERFS; }; // em‐post.js var kawari = new Kawari(); console.log(kawari.ERRNO_CODES);
  31. 3. ファイルシステムの取り扱い ユー ザー が投げる任意のキャラデー タ ( ファイルサイズ無制 限の ZIP)

    を展開して FS に配置し、 中に入っているスクリプト を動かしたい。 DLL が FS に書き込むセー ブファイル等を保持したい。 追加の前提 ブラウザではロー カルのファイルシステムは読めない。 Worker で IndexedDB にアクセスできないブラウザ (IE) がある。
  32. 3. ファイルシステムの取り扱い ( 解決 ) npm install browserfs 1. ZIP

    を展開し (FS API をエミュレー トする )BrowserFS で IndexedDB に保存して保持 2. (IndexedDB は非同期 API しかないので同期 API を使う )Emscripten FS にメモリロー ドしてから DLL 実行 3. 実行終了後に FS の中身を IndexedDB に書き戻す 数 MB の ZIP 複数扱う時点で IndexedDB 以外容量足りません Emscripten 付属の IndexedDB の扱いも大して変わらない めちゃくちゃ泥臭いので何かいい方法ないでしょうかね……
  33. 3. ファイルシステムの取り扱い ( 願い ) Worker で使える IndexedDB の同期版 API

    復活しないかなあ mount みたいに FS の一部だけロー ドできないかなあ IE がサポー ト切れますように ( ♪ )
  34. 4. Shift̲JIS 文字列を渡す 人格用言語 DLL が 2000 年代初頭製なので SJIS 前提

    ユー ザー から投げられるキャラデー タのソー スも SJIS 。 互換性のため文字コー ド変換かましたコンパイルはしたくない。 Emscripten デフォルトの Pointer̲stringify や intArrayFromString は Unicode 前提なのか正しく動かなかった。
  35. 4. Shift̲JIS 文字列を渡す ( 解決 ) npm install encoding‐japanese var

    _request = Module.cwrap( // DLLのrequest()関数 'request', 'number', ['number', 'number']); var requestStr = "こんにちは"; // intArrayFromStringではダメだった var unicodeReq = Encoding.stringToCode(requestStr); var sjisReq = Encoding.convert(unicodeReq, 'SJIS', 'UNICODE'); var req = allocString(sjisReq); // 文字列メモリ確保 var len = allocLong(req.size); // 文字列長メモリ確保 var resPtr = _request(req.ptr, len.ptr); // request()! var resHeap = new Uint8Array( // 応答文字列のヒープの参照 Module.HEAPU8.buffer, resPtr, len.heap[0]); // intArrayToStringはOK var sjisResStr = Module.intArrayToString(resHeap); Module._free(len.ptr); Module._free(resPtr); // freeする var sjisRes = Encoding.stringToCode(sjisResStr); var unicodeRes = Encoding.convert(sjisRes, 'UNICODE', 'SJIS'); var response = Encoding.codeToString(unicodeRes);
  36. 4. Shift̲JIS 文字列を渡す ( 解決 ) 詳しくは https://github.com/Narazaka/nativeshiori ↓ 実際のコー

  37. 5. 人格用言語 DLL から別の DLL を呼ぶ 機能の少ない人格用言語 DLL から別の DLL

    を呼んで機能を補 完する SAORI というインター フェー ス規格が流通している extern "C" ̲̲declspec(dllexport) HGLOBAL ̲̲cdecl request(HGLOBAL h, long *len); extern "C" ̲̲declspec(dllexport) BOOL ̲̲cdecl load(HGLOBAL h, long len); extern "C" ̲̲declspec(dllexport) BOOL ̲̲cdecl unload(); 任意の DLL(.so) 呼びたい
  38. 5. 人格用言語 DLL から別の DLL を呼ぶ ( 未解決 ) https://github.com/kripken/emscripten/wiki/Linking

    2015 年から対応された模様? ( イカガカ初期開発時の 2014 年当時はうやむやだった) 素人が「 ホー ムペー ジ」 に気軽における程度に簡単な対応にした いが、 まだよく調べていません。
  39. ( 要件によっては ) コンパイル後の対処が大変 今回の要件 = デスクトップアプリとの互換動作 1. 全部 C++

    ではなく、JavaScript で書かれたメインルー チンに任 意個数のコンポー ネント DLL を連携させて動作させる。 2. 任意のスクリプトを言語ランタイムに食わせてデスクトップ と互換の動作・ ファイル操作をする。 3. 入出力は SJIS 。 4. DLL から別の任意 DLL を呼ぶ ( 未解決 ) 。 めぼしい知見がなかったので全部無理矢理解決
  40. 知見はまだまだ足りない エミュレー ター で動かしているようなものなので C++ や JavaScript 単体と異なった事情が出てくる。 「 全部

    C++ で書いてそのまま実行する」 以外のシナリオ例が あまりない。
  41. まとめ ブラウザでデスクトップマスコット「 伺か」 を動かしてみた DLL があったので Emscripten で JS にした

    要求仕様に沿って DLL を扱うにあたって、 複数起動、 ファイル システム、 文字コー ド、 動的リンクの問題があった この様な ( ニッチな ) 需要にみあう知見は ( 当然 ) 充実していない
  42. [PR] イカガカ開発チー ムドリコムはエンジニアを 募集しています!