Upgrade to Pro — share decks privately, control downloads, hide ads and more …

伺か on Browser

Narazaka
October 05, 2016

伺か on Browser

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

Narazaka

October 05, 2016
Tweet

More Decks by Narazaka

Other Decks in Programming

Transcript

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

    View full-size slide

  2. 自己紹介
    佐藤隆人
    (
    な ら ざ か
    奈良阪
    )
    Twitter: @narazaka
    Github: @Narazaka
    npm: @narazaka
    CPAN: NARAZAKA
    ドリコム
    2015
    新卒
    (2
    年目
    )
    サー
    バー
    サイド
    Ruby
    書いてます
    Perl / JavaScript / Ruby / C#
    あたりが好き
    その他
    :
    伺か
    /
    漫画読み描き
    / OP
    アニメ愛好家
    /

    View full-size slide


  3. 注意 1
    から
    10
    まで趣味の話です
    プロダクションレベルの知見ではありません。
    試行錯誤の途中なのでアドバイスなどいただけると幸いです。

    View full-size slide

  4. 近年やってる趣味

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  7. かわいい

    View full-size slide

  8. かわいい

    View full-size slide

  9. 懐かしい

    View full-size slide

  10. 懐かしい

    View full-size slide

  11. なんかすごい

    View full-size slide

  12. キャラクター
    表現プラットフォー

    16
    年目の現在もたくさんのキャラの更新がある

    View full-size slide

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

    View full-size slide


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

    View full-size slide

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

    View full-size slide


  16. 伺か
    on Browser
    イカガカ」
    プロジェクト
    コー

    https://github.com/Ikagaka
    デモ
    http://ikagaka.github.io/Ikagaka.demo/

    View full-size slide

  17. ブラウザに載せるにあたって……
    うかがか
    伺か はどういうプログラム?

    View full-size slide

  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)
    がいくつか存在

    View full-size slide

  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!"
    }

    View full-size slide

  20. _
    人人人人人人人_
    > Emscripten
     <
     ̄Y^Y^Y^Y^Y^Y

    View full-size slide

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

    View full-size slide

  22. Makefile
    もフラグ追加と
    g++ ‑> em++
    rem emsdk1.25.0 on Windows
    emcmdprompt.bat
    D:
    cd kawari
    make

    View full-size slide

  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

    View full-size slide

  24. _
    人人人人人人人_
    > Emscripten
     <
     ̄Y^Y^Y^Y^Y^Y




    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. 1.
    落ちるキャラデー
    タがある
    (
    解決
    )
    em++
    のデフォルトでは最大メモリサイズが固定値だった。
    メモリが足りなくなったら自動的に拡張してくれる
    ‐s ALLOW_MEMORY_GROWTH=1
    をつけてコンパイル。
    (
    実行速度遅くなるよという警告が出る
    )

    View full-size slide

  29. 2.
    複数キャラをたちあげたい
    同じ人格
    DLL.js
    を色々
    なキャラデー
    タに適用したい。
    しかし→Emscripten
    はスクリプトをロー
    ドした時点で、
    グロー

    ルの Module
    とかに色々
    入れてそのまま単一インスタンスとして実
    行してしまう。

    View full-size slide

  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);

    View full-size slide

  31. 3.
    ファイルシステムの取り扱い
    ユー
    ザー
    が投げる任意のキャラデー

    (
    ファイルサイズ無制
    限の
    ZIP)
    を展開して
    FS
    に配置し、
    中に入っているスクリプト
    を動かしたい。
    DLL

    FS
    に書き込むセー
    ブファイル等を保持したい。
    追加の前提
    ブラウザではロー
    カルのファイルシステムは読めない。
    Worker

    IndexedDB
    にアクセスできないブラウザ
    (IE)
    がある。

    View full-size slide

  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
    の扱いも大して変わらない
    めちゃくちゃ泥臭いので何かいい方法ないでしょうかね……

    View full-size slide

  33. 3.
    ファイルシステムの取り扱い
    (
    願い
    )
    Worker
    で使える
    IndexedDB
    の同期版
    API
    復活しないかなあ
    mount
    みたいに
    FS
    の一部だけロー
    ドできないかなあ
    IE
    がサポー
    ト切れますように
    (

    )

    View full-size slide

  34. 4. Shift̲JIS
    文字列を渡す
    人格用言語
    DLL

    2000
    年代初頭製なので
    SJIS
    前提
    ユー
    ザー
    から投げられるキャラデー
    タのソー
    スも
    SJIS

    互換性のため文字コー
    ド変換かましたコンパイルはしたくない。
    Emscripten
    デフォルトの
    Pointer̲stringify

    intArrayFromString

    Unicode
    前提なのか正しく動かなかった。

    View full-size slide

  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);

    View full-size slide

  36. 4. Shift̲JIS
    文字列を渡す
    (
    解決
    )
    詳しくは
    https://github.com/Narazaka/nativeshiori

    実際のコー

    View full-size slide

  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)
    呼びたい

    View full-size slide

  38. 5.
    人格用言語
    DLL
    から別の
    DLL
    を呼ぶ
    (
    未解決
    )
    https://github.com/kripken/emscripten/wiki/Linking
    2015
    年から対応された模様?

    イカガカ初期開発時の
    2014
    年当時はうやむやだった)
    素人が「
    ホー
    ムペー
    ジ」
    に気軽における程度に簡単な対応にした
    いが、
    まだよく調べていません。

    View full-size slide

  39. (
    要件によっては
    )
    コンパイル後の対処が大変
    今回の要件
    =
    デスクトップアプリとの互換動作
    1.
    全部
    C++
    ではなく、JavaScript
    で書かれたメインルー
    チンに任
    意個数のコンポー
    ネント
    DLL
    を連携させて動作させる。
    2.
    任意のスクリプトを言語ランタイムに食わせてデスクトップ
    と互換の動作・
    ファイル操作をする。
    3.
    入出力は
    SJIS

    4. DLL
    から別の任意
    DLL
    を呼ぶ
    (
    未解決
    )

    めぼしい知見がなかったので全部無理矢理解決

    View full-size slide

  40. 知見はまだまだ足りない
    エミュレー
    ター
    で動かしているようなものなので
    C++

    JavaScript
    単体と異なった事情が出てくる。

    全部
    C++
    で書いてそのまま実行する」
    以外のシナリオ例が
    あまりない。

    View full-size slide

  41. まとめ
    ブラウザでデスクトップマスコット「
    伺か」
    を動かしてみた
    DLL
    があったので
    Emscripten

    JS
    にした
    要求仕様に沿って
    DLL
    を扱うにあたって、
    複数起動、
    ファイル
    システム、
    文字コー
    ド、
    動的リンクの問題があった
    この様な
    (
    ニッチな
    )
    需要にみあう知見は
    (
    当然
    )
    充実していない

    View full-size slide

  42. [PR]
    イカガカ開発チー
    ムドリコムはエンジニアを
    募集しています!

    View full-size slide