UNPKG

phaser4-rex-plugins

Version:
1,641 lines (1,622 loc) 580 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.rexlive2dplugin = factory()); })(this, (function () { 'use strict'; const MainVersionNumber = 4; const SubVersionNumber = 0; var IsChecked = false; var CheckP3Version = function (minVersion) { if (IsChecked) { return; } if (minVersion === undefined) { minVersion = SubVersionNumber; } var version = Phaser.VERSION.split('.'); var mainVersion = parseInt(version[0]); if (mainVersion === MainVersionNumber) { var subVersion = parseInt(version[1]); if (subVersion < minVersion) { console.error(`Minimum supported version : ${mainVersion}.${subVersion}`); } } else { console.error(`Can't supported version : ${mainVersion}`); } IsChecked = true; }; CheckP3Version(); const Extern = Phaser.GameObjects.Extern; class Live2dGameObjectBase extends Extern { } const Components = Phaser.GameObjects.Components; Phaser.Class.mixin(Live2dGameObjectBase, [ Components.AlphaSingle, Components.ComputedSize, Components.GetBounds, ] ); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * ベクター型(可変配列型) */ class csmVector { /** * 引数付きコンストラクタ * @param iniitalCapacity 初期化後のキャパシティ。データサイズは_capacity * sizeof(T) * @param zeroClear trueなら初期化時に確保した領域を0で埋める */ constructor(initialCapacity = 0) { if (initialCapacity < 1) { this._ptr = []; this._capacity = 0; this._size = 0; } else { this._ptr = new Array(initialCapacity); this._capacity = initialCapacity; this._size = 0; } } /** * インデックスで指定した要素を返す */ at(index) { return this._ptr[index]; } /** * 要素をセット * @param index 要素をセットするインデックス * @param value セットする要素 */ set(index, value) { this._ptr[index] = value; } /** * コンテナを取得する */ get(offset = 0) { const ret = new Array(); for (let i = offset; i < this._size; i++) { ret.push(this._ptr[i]); } return ret; } /** * pushBack処理、コンテナに新たな要素を追加する * @param value PushBack処理で追加する値 */ pushBack(value) { if (this._size >= this._capacity) { this.prepareCapacity(this._capacity == 0 ? csmVector.s_defaultSize : this._capacity * 2); } this._ptr[this._size++] = value; } /** * コンテナの全要素を解放する */ clear() { this._ptr.length = 0; this._size = 0; } /** * コンテナの要素数を返す * @return コンテナの要素数 */ getSize() { return this._size; } /** * コンテナの全要素に対して代入処理を行う * @param newSize 代入処理後のサイズ * @param value 要素に代入する値 */ assign(newSize, value) { const curSize = this._size; if (curSize < newSize) { this.prepareCapacity(newSize); // capacity更新 } for (let i = 0; i < newSize; i++) { this._ptr[i] = value; } this._size = newSize; } /** * サイズ変更 */ resize(newSize, value = null) { this.updateSize(newSize, value, true); } /** * サイズ変更 */ updateSize(newSize, value = null, callPlacementNew = true) { const curSize = this._size; if (curSize < newSize) { this.prepareCapacity(newSize); // capacity更新 if (callPlacementNew) { for (let i = this._size; i < newSize; i++) { if (typeof value == 'function') { // new this._ptr[i] = JSON.parse(JSON.stringify(new value())); } // プリミティブ型なので値渡し else { this._ptr[i] = value; } } } else { for (let i = this._size; i < newSize; i++) { this._ptr[i] = value; } } } else { // newSize <= this._size //--- const sub = this._size - newSize; this._ptr.splice(this._size - sub, sub); // 不要なので破棄する } this._size = newSize; } /** * コンテナにコンテナ要素を挿入する * @param position 挿入する位置 * @param begin 挿入するコンテナの開始位置 * @param end 挿入するコンテナの終端位置 */ insert(position, begin, end) { let dstSi = position._index; const srcSi = begin._index; const srcEi = end._index; const addCount = srcEi - srcSi; this.prepareCapacity(this._size + addCount); // 挿入用の既存データをシフトして隙間を作る const addSize = this._size - dstSi; if (addSize > 0) { for (let i = 0; i < addSize; i++) { this._ptr.splice(dstSi + i, 0, null); } } for (let i = srcSi; i < srcEi; i++, dstSi++) { this._ptr[dstSi] = begin._vector._ptr[i]; } this._size = this._size + addCount; } /** * コンテナからインデックスで指定した要素を削除する * @param index インデックス値 * @return true 削除実行 * @return false 削除範囲外 */ remove(index) { if (index < 0 || this._size <= index) { return false; // 削除範囲外 } this._ptr.splice(index, 1); --this._size; return true; } /** * コンテナから要素を削除して他の要素をシフトする * @param ite 削除する要素 */ erase(ite) { const index = ite._index; if (index < 0 || this._size <= index) { return ite; // 削除範囲外 } // 削除 this._ptr.splice(index, 1); --this._size; const ite2 = new iterator$1(this, index); // 終了 return ite2; } /** * コンテナのキャパシティを確保する * @param newSize 新たなキャパシティ。引数の値が現在のサイズ未満の場合は何もしない. */ prepareCapacity(newSize) { if (newSize > this._capacity) { if (this._capacity == 0) { this._ptr = new Array(newSize); this._capacity = newSize; } else { this._ptr.length = newSize; this._capacity = newSize; } } } /** * コンテナの先頭要素を返す */ begin() { const ite = this._size == 0 ? this.end() : new iterator$1(this, 0); return ite; } /** * コンテナの終端要素を返す */ end() { const ite = new iterator$1(this, this._size); return ite; } getOffset(offset) { const newVector = new csmVector(); newVector._ptr = this.get(offset); newVector._size = this.get(offset).length; newVector._capacity = this.get(offset).length; return newVector; } } csmVector.s_defaultSize = 10; // コンテナ初期化のデフォルトサイズ let iterator$1 = class iterator { /** * コンストラクタ */ constructor(v, index) { this._vector = v != undefined ? v : null; this._index = index != undefined ? index : 0; } /** * 代入 */ set(ite) { this._index = ite._index; this._vector = ite._vector; return this; } /** * 前置き++演算 */ preIncrement() { ++this._index; return this; } /** * 前置き--演算 */ preDecrement() { --this._index; return this; } /** * 後置き++演算子 */ increment() { const iteold = new iterator(this._vector, this._index++); // 古い値を保存 return iteold; } /** * 後置き--演算子 */ decrement() { const iteold = new iterator(this._vector, this._index--); // 古い値を保存 return iteold; } /** * ptr */ ptr() { return this._vector._ptr[this._index]; } /** * =演算子のオーバーロード */ substitution(ite) { this._index = ite._index; this._vector = ite._vector; return this; } /** * !=演算子のオーバーロード */ notEqual(ite) { return this._index != ite._index || this._vector != ite._vector; } }; // eslint-disable-next-line @typescript-eslint/no-namespace var Live2DCubismFramework$B; (function (Live2DCubismFramework) { Live2DCubismFramework.csmVector = csmVector; Live2DCubismFramework.iterator = iterator$1; })(Live2DCubismFramework$B || (Live2DCubismFramework$B = {})); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * 文字列クラス。 */ class csmString { /** * 文字列を後方に追加する * * @param c 追加する文字列 * @return 更新された文字列 */ append(c, length) { this.s += length !== undefined ? c.substr(0, length) : c; return this; } /** * 文字サイズを拡張して文字を埋める * @param length 拡張する文字数 * @param v 埋める文字 * @return 更新された文字列 */ expansion(length, v) { for (let i = 0; i < length; i++) { this.append(v); } return this; } /** * 文字列の長さをバイト数で取得する */ getBytes() { return encodeURIComponent(this.s).replace(/%../g, 'x').length; } /** * 文字列の長さを返す */ getLength() { return this.s.length; } /** * 文字列比較 < * @param s 比較する文字列 * @return true: 比較する文字列より小さい * @return false: 比較する文字列より大きい */ isLess(s) { return this.s < s.s; } /** * 文字列比較 > * @param s 比較する文字列 * @return true: 比較する文字列より大きい * @return false: 比較する文字列より小さい */ isGreat(s) { return this.s > s.s; } /** * 文字列比較 == * @param s 比較する文字列 * @return true: 比較する文字列と等しい * @return false: 比較する文字列と異なる */ isEqual(s) { return this.s == s; } /** * 文字列が空かどうか * @return true: 空の文字列 * @return false: 値が設定されている */ isEmpty() { return this.s.length == 0; } /** * 引数付きコンストラクタ */ constructor(s) { this.s = s; } } // eslint-disable-next-line @typescript-eslint/no-namespace var Live2DCubismFramework$A; (function (Live2DCubismFramework) { Live2DCubismFramework.csmString = csmString; })(Live2DCubismFramework$A || (Live2DCubismFramework$A = {})); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * パラメータ名・パーツ名・Drawable名を保持 * * パラメータ名・パーツ名・Drawable名を保持するクラス。 */ class CubismId { /** * ID名を取得する */ getString() { return this._id; } /** * コンストラクタ */ constructor(id) { if (typeof id === 'string') { this._id = new csmString(id); return; } this._id = id; } /** * idを比較 * @param c 比較するid * @return 同じならばtrue,異なっていればfalseを返す */ isEqual(c) { if (typeof c === 'string') { return this._id.isEqual(c); } else if (c instanceof csmString) { return this._id.isEqual(c.s); } else if (c instanceof CubismId) { return this._id.isEqual(c._id.s); } return false; } /** * idを比較 * @param c 比較するid * @return 同じならばtrue,異なっていればfalseを返す */ isNotEqual(c) { if (typeof c == 'string') { return !this._id.isEqual(c); } else if (c instanceof csmString) { return !this._id.isEqual(c.s); } else if (c instanceof CubismId) { return !this._id.isEqual(c._id.s); } return false; } } // eslint-disable-next-line @typescript-eslint/no-namespace var Live2DCubismFramework$z; (function (Live2DCubismFramework) { Live2DCubismFramework.CubismId = CubismId; })(Live2DCubismFramework$z || (Live2DCubismFramework$z = {})); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * ID名の管理 * * ID名を管理する。 */ class CubismIdManager { /** * コンストラクタ */ constructor() { this._ids = new csmVector(); } /** * デストラクタ相当の処理 */ release() { for (let i = 0; i < this._ids.getSize(); ++i) { this._ids.set(i, void 0); } this._ids = null; } /** * ID名をリストから登録 * * @param ids ID名リスト * @param count IDの個数 */ registerIds(ids) { for (let i = 0; i < ids.length; i++) { this.registerId(ids[i]); } } /** * ID名を登録 * * @param id ID名 */ registerId(id) { let result = null; if ('string' == typeof id) { if ((result = this.findId(id)) != null) { return result; } result = new CubismId(id); this._ids.pushBack(result); } else { return this.registerId(id.s); } return result; } /** * ID名からIDを取得する * * @param id ID名 */ getId(id) { return this.registerId(id); } /** * ID名からIDの確認 * * @return true 存在する * @return false 存在しない */ isExist(id) { if ('string' == typeof id) { return this.findId(id) != null; } return this.isExist(id.s); } /** * ID名からIDを検索する。 * * @param id ID名 * @return 登録されているID。なければNULL。 */ findId(id) { for (let i = 0; i < this._ids.getSize(); ++i) { if (this._ids.at(i).getString().isEqual(id)) { return this._ids.at(i); } } return null; } } // eslint-disable-next-line @typescript-eslint/no-namespace var Live2DCubismFramework$y; (function (Live2DCubismFramework) { Live2DCubismFramework.CubismIdManager = CubismIdManager; })(Live2DCubismFramework$y || (Live2DCubismFramework$y = {})); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * 4x4の行列 * * 4x4行列の便利クラス。 */ class CubismMatrix44 { /** * コンストラクタ */ constructor() { this._tr = new Float32Array(16); // 4 * 4のサイズ this.loadIdentity(); } /** * 受け取った2つの行列の乗算を行う。 * * @param a 行列a * @param b 行列b * @return 乗算結果の行列 */ static multiply(a, b, dst) { const c = new Float32Array([ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ]); const n = 4; for (let i = 0; i < n; ++i) { for (let j = 0; j < n; ++j) { for (let k = 0; k < n; ++k) { c[j + i * 4] += a[k + i * 4] * b[j + k * 4]; } } } for (let i = 0; i < 16; ++i) { dst[i] = c[i]; } } /** * 単位行列に初期化する */ loadIdentity() { const c = new Float32Array([ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ]); this.setMatrix(c); } /** * 行列を設定 * * @param tr 16個の浮動小数点数で表される4x4の行列 */ setMatrix(tr) { for (let i = 0; i < 16; ++i) { this._tr[i] = tr[i]; } } /** * 行列を浮動小数点数の配列で取得 * * @return 16個の浮動小数点数で表される4x4の行列 */ getArray() { return this._tr; } /** * X軸の拡大率を取得 * @return X軸の拡大率 */ getScaleX() { return this._tr[0]; } /** * Y軸の拡大率を取得する * * @return Y軸の拡大率 */ getScaleY() { return this._tr[5]; } /** * X軸の移動量を取得 * @return X軸の移動量 */ getTranslateX() { return this._tr[12]; } /** * Y軸の移動量を取得 * @return Y軸の移動量 */ getTranslateY() { return this._tr[13]; } /** * X軸の値を現在の行列で計算 * * @param src X軸の値 * @return 現在の行列で計算されたX軸の値 */ transformX(src) { return this._tr[0] * src + this._tr[12]; } /** * Y軸の値を現在の行列で計算 * * @param src Y軸の値 * @return 現在の行列で計算されたY軸の値 */ transformY(src) { return this._tr[5] * src + this._tr[13]; } /** * X軸の値を現在の行列で逆計算 */ invertTransformX(src) { return (src - this._tr[12]) / this._tr[0]; } /** * Y軸の値を現在の行列で逆計算 */ invertTransformY(src) { return (src - this._tr[13]) / this._tr[5]; } /** * 現在の行列の位置を起点にして移動 * * 現在の行列の位置を起点にして相対的に移動する。 * * @param x X軸の移動量 * @param y Y軸の移動量 */ translateRelative(x, y) { const tr1 = new Float32Array([ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, x, y, 0.0, 1.0, ]); CubismMatrix44.multiply(tr1, this._tr, this._tr); } /** * 現在の行列の位置を移動 * * 現在の行列の位置を指定した位置へ移動する * * @param x X軸の移動量 * @param y y軸の移動量 */ translate(x, y) { this._tr[12] = x; this._tr[13] = y; } /** * 現在の行列のX軸の位置を指定した位置へ移動する * * @param x X軸の移動量 */ translateX(x) { this._tr[12] = x; } /** * 現在の行列のY軸の位置を指定した位置へ移動する * * @param y Y軸の移動量 */ translateY(y) { this._tr[13] = y; } /** * 現在の行列の拡大率を相対的に設定する * * @param x X軸の拡大率 * @param y Y軸の拡大率 */ scaleRelative(x, y) { const tr1 = new Float32Array([ x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ]); CubismMatrix44.multiply(tr1, this._tr, this._tr); } /** * 現在の行列の拡大率を指定した倍率に設定する * * @param x X軸の拡大率 * @param y Y軸の拡大率 */ scale(x, y) { this._tr[0] = x; this._tr[5] = y; } /** * 現在の行列に行列を乗算 * * @param m 行列 */ multiplyByMatrix(m) { CubismMatrix44.multiply(m.getArray(), this._tr, this._tr); } /** * オブジェクトのコピーを生成する */ clone() { const cloneMatrix = new CubismMatrix44(); for (let i = 0; i < this._tr.length; i++) { cloneMatrix._tr[i] = this._tr[i]; } return cloneMatrix; } } // eslint-disable-next-line @typescript-eslint/no-namespace var Live2DCubismFramework$x; (function (Live2DCubismFramework) { Live2DCubismFramework.CubismMatrix44 = CubismMatrix44; })(Live2DCubismFramework$x || (Live2DCubismFramework$x = {})); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * モデル描画を処理するレンダラ * * サブクラスに環境依存の描画命令を記述する。 */ class CubismRenderer { /** * レンダラのインスタンスを生成して取得する * * @return レンダラのインスタンス */ static create() { return null; } /** * レンダラのインスタンスを解放する */ static delete(renderer) { } /** * レンダラの初期化処理を実行する * 引数に渡したモデルからレンダラの初期化処理に必要な情報を取り出すことができる * @param model モデルのインスタンス */ initialize(model) { this._model = model; } /** * モデルを描画する */ drawModel() { if (this.getModel() == null) return; this.saveProfile(); this.doDrawModel(); this.restoreProfile(); } /** * Model-View-Projection 行列をセットする * 配列は複製されるので、元の配列は外で破棄して良い * @param matrix44 Model-View-Projection 行列 */ setMvpMatrix(matrix44) { this._mvpMatrix4x4.setMatrix(matrix44.getArray()); } /** * Model-View-Projection 行列を取得する * @return Model-View-Projection 行列 */ getMvpMatrix() { return this._mvpMatrix4x4; } /** * モデルの色をセットする * 各色0.0~1.0の間で指定する(1.0が標準の状態) * @param red 赤チャンネルの値 * @param green 緑チャンネルの値 * @param blue 青チャンネルの値 * @param alpha αチャンネルの値 */ setModelColor(red, green, blue, alpha) { if (red < 0.0) { red = 0.0; } else if (red > 1.0) { red = 1.0; } if (green < 0.0) { green = 0.0; } else if (green > 1.0) { green = 1.0; } if (blue < 0.0) { blue = 0.0; } else if (blue > 1.0) { blue = 1.0; } if (alpha < 0.0) { alpha = 0.0; } else if (alpha > 1.0) { alpha = 1.0; } this._modelColor.R = red; this._modelColor.G = green; this._modelColor.B = blue; this._modelColor.A = alpha; } /** * モデルの色を取得する * 各色0.0~1.0の間で指定する(1.0が標準の状態) * * @return RGBAのカラー情報 */ getModelColor() { return JSON.parse(JSON.stringify(this._modelColor)); } /** * 乗算済みαの有効・無効をセットする * 有効にするならtrue、無効にするならfalseをセットする */ setIsPremultipliedAlpha(enable) { this._isPremultipliedAlpha = enable; } /** * 乗算済みαの有効・無効を取得する * @return true 乗算済みのα有効 * @return false 乗算済みのα無効 */ isPremultipliedAlpha() { return this._isPremultipliedAlpha; } /** * カリング(片面描画)の有効・無効をセットする。 * 有効にするならtrue、無効にするならfalseをセットする */ setIsCulling(culling) { this._isCulling = culling; } /** * カリング(片面描画)の有効・無効を取得する。 * @return true カリング有効 * @return false カリング無効 */ isCulling() { return this._isCulling; } /** * テクスチャの異方性フィルタリングのパラメータをセットする * パラメータ値の影響度はレンダラの実装に依存する * @param n パラメータの値 */ setAnisotropy(n) { this._anisotropy = n; } /** * テクスチャの異方性フィルタリングのパラメータをセットする * @return 異方性フィルタリングのパラメータ */ getAnisotropy() { return this._anisotropy; } /** * レンダリングするモデルを取得する * @return レンダリングするモデル */ getModel() { return this._model; } /** * マスク描画の方式を変更する。 * falseの場合、マスクを1枚のテクスチャに分割してレンダリングする(デフォルト) * 高速だが、マスク個数の上限が36に限定され、質も荒くなる * trueの場合、パーツ描画の前にその都度必要なマスクを描き直す * レンダリング品質は高いが描画処理負荷は増す * @param high 高精細マスクに切り替えるか? */ useHighPrecisionMask(high) { this._useHighPrecisionMask = high; } /** * マスクの描画方式を取得する * @return true 高精細方式 * @return false デフォルト */ isUsingHighPrecisionMask() { return this._useHighPrecisionMask; } /** * コンストラクタ */ constructor() { this._isCulling = false; this._isPremultipliedAlpha = false; this._anisotropy = 0.0; this._model = null; this._modelColor = new CubismTextureColor(); this._useHighPrecisionMask = false; // 単位行列に初期化 this._mvpMatrix4x4 = new CubismMatrix44(); this._mvpMatrix4x4.loadIdentity(); } } var CubismBlendMode; (function (CubismBlendMode) { CubismBlendMode[CubismBlendMode["CubismBlendMode_Normal"] = 0] = "CubismBlendMode_Normal"; CubismBlendMode[CubismBlendMode["CubismBlendMode_Additive"] = 1] = "CubismBlendMode_Additive"; CubismBlendMode[CubismBlendMode["CubismBlendMode_Multiplicative"] = 2] = "CubismBlendMode_Multiplicative"; })(CubismBlendMode || (CubismBlendMode = {})); /** * テクスチャの色をRGBAで扱うためのクラス */ class CubismTextureColor { /** * コンストラクタ */ constructor(r = 1.0, g = 1.0, b = 1.0, a = 1.0) { this.R = r; this.G = g; this.B = b; this.A = a; } } // eslint-disable-next-line @typescript-eslint/no-namespace var Live2DCubismFramework$w; (function (Live2DCubismFramework) { Live2DCubismFramework.CubismBlendMode = CubismBlendMode; Live2DCubismFramework.CubismRenderer = CubismRenderer; Live2DCubismFramework.CubismTextureColor = CubismTextureColor; })(Live2DCubismFramework$w || (Live2DCubismFramework$w = {})); /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ /** * CubismJsonで実装されているJsonパーサを使用せず、 * TypeScript標準のJsonパーサなどを使用し出力された結果を * Cubism SDKで定義されているJSONエレメントの要素に * 置き換える処理をするクラス。 */ class CubismJsonExtension { static parseJsonObject(obj, map) { Object.keys(obj).forEach((key) => { if (typeof obj[key] == 'boolean') { const convValue = Boolean(obj[key]); map.put(key, new JsonBoolean(convValue)); } else if (typeof obj[key] == 'string') { const convValue = String(obj[key]); map.put(key, new JsonString(convValue)); } else if (typeof obj[key] == 'number') { const convValue = Number(obj[key]); map.put(key, new JsonFloat(convValue)); } else if (obj[key] instanceof Array) { map.put(key, CubismJsonExtension.parseJsonArray(obj[key])); } else if (obj[key] instanceof Object) { map.put(key, CubismJsonExtension.parseJsonObject(obj[key], new JsonMap())); } else if (obj[key] == null) { map.put(key, new JsonNullvalue()); } else { // どれにも当てはまらない場合でも処理する map.put(key, obj[key]); } }); return map; } static parseJsonArray(obj) { const arr = new JsonArray(); Object.keys(obj).forEach((key) => { const convKey = Number(key); if (typeof convKey == 'number') { if (typeof obj[key] == 'boolean') { const convValue = Boolean(obj[key]); arr.add(new JsonBoolean(convValue)); } else if (typeof obj[key] == 'string') { const convValue = String(obj[key]); arr.add(new JsonString(convValue)); } else if (typeof obj[key] == 'number') { const convValue = Number(obj[key]); arr.add(new JsonFloat(convValue)); } else if (obj[key] instanceof Array) { arr.add(this.parseJsonArray(obj[key])); } else if (obj[key] instanceof Object) { arr.add(this.parseJsonObject(obj[key], new JsonMap())); } else if (obj[key] == null) { arr.add(new JsonNullvalue()); } else { // どれにも当てはまらない場合でも処理する arr.add(obj[key]); } } else if (obj[key] instanceof Array) { arr.add(this.parseJsonArray(obj[key])); } else if (obj[key] instanceof Object) { arr.add(this.parseJsonObject(obj[key], new JsonMap())); } else if (obj[key] == null) { arr.add(new JsonNullvalue()); } else { const convValue = Array(obj[key]); // 配列ともObjectとも判定できなかった場合でも処理する for (let i = 0; i < convValue.length; i++) { arr.add(convValue[i]); } } }); return arr; } } /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ // StaticInitializeNotForClientCall()で初期化する const CSM_JSON_ERROR_TYPE_MISMATCH = 'Error: type mismatch'; const CSM_JSON_ERROR_INDEX_OF_BOUNDS = 'Error: index out of bounds'; /** * パースしたJSONエレメントの要素の基底クラス。 */ let Value$2 = class Value { /** * コンストラクタ */ constructor() { } /** * 要素を文字列型で返す(string) */ getRawString(defaultValue, indent) { return this.getString(defaultValue, indent); } /** * 要素を数値型で返す(number) */ toInt(defaultValue = 0) { return defaultValue; } /** * 要素を数値型で返す(number) */ toFloat(defaultValue = 0) { return defaultValue; } /** * 要素を真偽値で返す(boolean) */ toBoolean(defaultValue = false) { return defaultValue; } /** * サイズを返す */ getSize() { return 0; } /** * 要素を配列で返す(Value[]) */ getArray(defaultValue = null) { return defaultValue; } /** * 要素をコンテナで返す(array) */ getVector(defaultValue = new csmVector()) { return defaultValue; } /** * 要素をマップで返す(csmMap<csmString, Value>) */ getMap(defaultValue) { return defaultValue; } /** * 添字演算子[index] */ getValueByIndex(index) { return Value.errorValue.setErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH); } /** * 添字演算子[string | csmString] */ getValueByString(s) { return Value.nullValue.setErrorNotForClientCall(CSM_JSON_ERROR_TYPE_MISMATCH); } /** * マップのキー一覧をコンテナで返す * * @return マップのキーの一覧 */ getKeys() { return Value.s_dummyKeys; } /** * Valueの種類がエラー値ならtrue */ isError() { return false; } /** * Valueの種類がnullならtrue */ isNull() { return false; } /** * Valueの種類が真偽値ならtrue */ isBool() { return false; } /** * Valueの種類が数値型ならtrue */ isFloat() { return false; } /** * Valueの種類が文字列ならtrue */ isString() { return false; } /** * Valueの種類が配列ならtrue */ isArray() { return false; } /** * Valueの種類がマップ型ならtrue */ isMap() { return false; } equals(value) { return false; } /** * Valueの値が静的ならtrue、静的なら解放しない */ isStatic() { return false; } /** * Valueにエラー値をセットする */ setErrorNotForClientCall(errorStr) { return JsonError.errorValue; } /** * 初期化用メソッド */ static staticInitializeNotForClientCall() { JsonBoolean.trueValue = new JsonBoolean(true); JsonBoolean.falseValue = new JsonBoolean(false); Value.errorValue = new JsonError('ERROR', true); Value.nullValue = new JsonNullvalue(); Value.s_dummyKeys = new csmVector(); } /** * リリース用メソッド */ static staticReleaseNotForClientCall() { JsonBoolean.trueValue = null; JsonBoolean.falseValue = null; Value.errorValue = null; Value.nullValue = null; Value.s_dummyKeys = null; } }; /** * Ascii文字のみ対応した最小限の軽量JSONパーサ。 * 仕様はJSONのサブセットとなる。 * 設定ファイル(model3.json)などのロード用 * * [未対応項目] * ・日本語などの非ASCII文字 * ・eによる指数表現 */ class CubismJson { /** * コンストラクタ */ constructor(buffer, length) { this._parseCallback = CubismJsonExtension.parseJsonObject; // パース時に使う処理のコールバック関数 this._error = null; this._lineCount = 0; this._root = null; if (buffer != undefined) { this.parseBytes(buffer, length, this._parseCallback); } } /** * バイトデータから直接ロードしてパースする * * @param buffer バッファ * @param size バッファサイズ * @return CubismJsonクラスのインスタンス。失敗したらNULL */ static create(buffer, size) { const json = new CubismJson(); const succeeded = json.parseBytes(buffer, size, json._parseCallback); if (!succeeded) { CubismJson.delete(json); return null; } else { return json; } } /** * パースしたJSONオブジェクトの解放処理 * * @param instance CubismJsonクラスのインスタンス */ static delete(instance) { } /** * パースしたJSONのルート要素を返す */ getRoot() { return this._root; } /** * UnicodeのバイナリをStringに変換 * * @param buffer 変換するバイナリデータ * @return 変換後の文字列 */ static arrayBufferToString(buffer) { const uint8Array = new Uint8Array(buffer); let str = ''; for (let i = 0, len = uint8Array.length; i < len; ++i) { str += '%' + this.pad(uint8Array[i].toString(16)); } str = decodeURIComponent(str); return str; } /** * エンコード、パディング */ static pad(n) { return n.length < 2 ? '0' + n : n; } /** * JSONのパースを実行する * @param buffer パース対象のデータバイト * @param size データバイトのサイズ * return true : 成功 * return false: 失敗 */ parseBytes(buffer, size, parseCallback) { const endPos = new Array(1); // 参照渡しにするため配列 const decodeBuffer = CubismJson.arrayBufferToString(buffer); if (parseCallback == undefined) { this._root = this.parseValue(decodeBuffer, size, 0, endPos); } else { // TypeScript標準のJSONパーサを使う this._root = parseCallback(JSON.parse(decodeBuffer), new JsonMap()); } if (this._error) { let strbuf = '\0'; strbuf = 'Json parse error : @line ' + (this._lineCount + 1) + '\n'; this._root = new JsonString(strbuf); CubismLogInfo('{0}', this._root.getRawString()); return false; } else if (this._root == null) { this._root = new JsonError(new csmString(this._error), false); // rootは解放されるのでエラーオブジェクトを別途作成する return false; } return true; } /** * パース時のエラー値を返す */ getParseError() { return this._error; } /** * ルート要素の次の要素がファイルの終端だったらtrueを返す */ checkEndOfFile() { return this._root.getArray()[1].equals('EOF'); } /** * JSONエレメントからValue(float,String,Value*,Array,null,true,false)をパースする * エレメントの書式に応じて内部でParseString(), ParseObject(), ParseArray()を呼ぶ * * @param buffer JSONエレメントのバッファ * @param length パースする長さ * @param begin パースを開始する位置 * @param outEndPos パース終了時の位置 * @return パースから取得したValueオブジェクト */ parseValue(buffer, length, begin, outEndPos) { if (this._error) return null; let o = null; let i = begin; let f; for (; i < length; i++) { const c = buffer[i]; switch (c) { case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { const afterString = new Array(1); // 参照渡しにするため f = strtod(buffer.slice(i), afterString); outEndPos[0] = buffer.indexOf(afterString[0]); return new JsonFloat(f); } case '"': return new JsonString(this.parseString(buffer, length, i + 1, outEndPos)); // \"の次の文字から case '[': o = this.parseArray(buffer, length, i + 1, outEndPos); return o; case '{': o = this.parseObject(buffer, length, i + 1, outEndPos); return o; case 'n': // null以外にない if (i + 3 < length) { o = new JsonNullvalue(); // 解放できるようにする outEndPos[0] = i + 4; } else { this._error = 'parse null'; } return o; case 't': // true以外にない if (i + 3 < length) { o = JsonBoolean.trueValue; outEndPos[0] = i + 4; } else { this._error = 'parse true'; } return o; case 'f': // false以外にない if (i + 4 < length) { o = JsonBoolean.falseValue; outEndPos[0] = i + 5; } else { this._error = "illegal ',' position"; } return o; case ',': // Array separator this._error = "illegal ',' position"; return null; case ']': // 不正な}だがスキップする。配列の最後に不要な , があると思われる outEndPos[0] = i; // 同じ文字を再処理 return null; case '\n': this._lineCount++; } } this._error = 'illegal end of value'; return null; } /** * 次の「"」までの文字列をパースする。 * * @param string -> パース対象の文字列 * @param length -> パースする長さ * @param begin -> パースを開始する位置 * @param outEndPos -> パース終了時の位置 * @return パースした文F字列要素 */ parseString(string, length, begin, outEndPos) { if (this._error) return null; let i = begin; let c, c2; const ret = new csmString(''); let bufStart = begin; // sbufに登録されていない文字の開始位置 for (; i < length; i++) { c = string[i]; switch (c) { case '"': { // 終端の”、エスケープ文字は別に処理されるのでここに来ない outEndPos[0] = i + 1; // ”の次の文字 ret.append(string.slice(bufStart), i - bufStart); // 前の文字までを登録する return ret.s; } case '//': { // エスケープの場合 i++; // 2文字をセットで扱う if (i - 1 > bufStart) { ret.append(string.slice(bufStart), i - bufStart); // 前の文字までを登録する } bufStart = i + 1; // エスケープ(2文字)の次の文字から if (i < length) { c2 = string[i]; switch (c2) { case '\\': ret.expansion(1, '\\'); break; case '"': ret.expansion(1, '"'); break; case '/': ret.expansion(1, '/'); break; case 'b': ret.expansion(1, '\b'); break; case 'f': ret.expansion(1, '\f'); break; case 'n': ret.expansion(1, '\n'); break; case 'r': ret.expansion(1, '\r'); break; case 't': ret.expansion(1, '\t'); break; case 'u': this._error = 'parse string/unicord escape not supported'; break; } } else { this._error = 'parse string/escape error'; } } } } this._error = 'parse string/illegal end'; return null; } /** * JSONのオブジェクトエレメントをパースしてValueオブジェクトを返す * * @param buffer JSONエレメントのバッファ * @param length パースする長さ * @param begin パースを開始する位置 * @param outEndPos パース終了時の位置 * @return パースから取得したValueオブジェクト */ parseObject(buffer, length, begin, outEndPos) { if (this._error) return null; const ret = new JsonMap(); // Key: Value let key = ''; let i = begin; let c = ''; const localRetEndPos2 = Array(1); let ok = false; // , が続く限りループ for (; i < length; i++) { FOR_LOOP: for (; i < length; i++) { c = buffer[i]; switch (c) { case '"': key = this.parseString(buffer, length, i + 1, localRetEndPos2); if (this._error) { return null; } i = localRetEndPos2[0]; ok = true; break FOR_LOOP; //-- loopから出る case '}': // 閉じカッコ outEndPos[0] = i + 1; return ret; // 空 case ':': this._error = "illegal ':' position"; break; case '\n': this._lineCount++;