2575 lines
111 KiB
JavaScript
2575 lines
111 KiB
JavaScript
/*:
|
||
* @plugindesc
|
||
* @author 奏ねこま(おとぶきねこま)
|
||
* @url http://makonet.sakura.ne.jp/rpg_tkool
|
||
* @target MZ
|
||
*
|
||
* @param json file
|
||
* @type string[]
|
||
* @default []
|
||
* @desc Live2Dファイル(*.model3.json)
|
||
*
|
||
* @param disable auto loading
|
||
* @type boolean
|
||
* @default false
|
||
* @desc Live2Dの自動読み込みを無効にする
|
||
*
|
||
* @param Speed Load Live2D Model
|
||
* @type string[]
|
||
* @default []
|
||
* @desc ロードを優先するモデルの指定
|
||
*
|
||
* @help
|
||
*/
|
||
'use strict';
|
||
let Load_TextureArr = [];
|
||
class _Load_Texture {
|
||
constructor(_MdlName) {
|
||
this._MdlName = _MdlName;
|
||
this._TextureCnt = 0;
|
||
}
|
||
}
|
||
class _SeParam {
|
||
constructor(_SeName) {
|
||
this._SeName = _SeName;
|
||
this._OnFlg = false;
|
||
}
|
||
}
|
||
class _VoiceParams {
|
||
constructor(_VoiceChara, _VoiceName) {
|
||
this._VoiceChara = _VoiceChara;
|
||
this._VoiceName = _VoiceName;
|
||
this._OnFlg = false;
|
||
}
|
||
}
|
||
class _CmnEvParam {
|
||
constructor(_CmnEvNo) {
|
||
this._CmnEvNo = _CmnEvNo;
|
||
this._OnFlg = false;
|
||
}
|
||
}
|
||
let Live2D_JsonKeep = (p => ({
|
||
'json file': eval(p['json file']),
|
||
'live2d data': {}
|
||
}))(PluginManager.parameters('JsScript190Set'));
|
||
let $p = (p => ({
|
||
'json file': eval(p['json file']),
|
||
'Speed Load Live2D Model': eval(p['Speed Load Live2D Model']),
|
||
'live2d data': {}
|
||
}))(PluginManager.parameters('JsScript190Set'));
|
||
let mainLoadMdlSetting = [];
|
||
let subLoadMdlSetting = [];
|
||
function addModelsToLoader(loader, modelSettings) {
|
||
for (let file of modelSettings) {
|
||
let fileName = file._MdlName + "/" + file._MdlName;
|
||
let name = fileName.replace(/\.(?:json|model3.json)$/i, '');
|
||
loader.add(name, `img/live2d/${name}.model3.json`);
|
||
}
|
||
}
|
||
function addModels(modelSettings) {
|
||
for (let file of modelSettings) {
|
||
let fileName = file._MdlName + "/" + file._MdlName;
|
||
let name = fileName.replace(/\.(?:json|model3.json)$/i, '');
|
||
$p['live2d data'][name] = false;
|
||
Live2D_JsonKeep['live2d data'][name] = null;
|
||
}
|
||
}
|
||
function handleLoaderCompletion(loader, modelSettings, callback) {
|
||
loader.load((loader, resources) => {
|
||
for (let name in $p['live2d data']) {
|
||
if (resources[name] == undefined) continue;
|
||
$p['live2d data'][name] = resources[name].live2dData;
|
||
Live2D_JsonKeep['live2d data'][name] = resources[name].live2dData;
|
||
}
|
||
callback();
|
||
});
|
||
}
|
||
let Live2DSubCounter = 0;
|
||
let Live2DSubLoading = false;
|
||
let Live2D_NUpdateSc = Game_Interpreter.prototype.NUpdateSc;
|
||
Game_Interpreter.prototype.NUpdateSc = function () {
|
||
Live2D_NUpdateSc.call(this);
|
||
if (Live2DFirstLoadCompFlg) {
|
||
if (Live2DSubCounter < subLoadMdlSetting.length && !Live2DSubLoading) {
|
||
let loader2 = new (PIXI.Loader || PIXI.loaders.Loader)();
|
||
let subArr = [];
|
||
let exitCnt = 0;
|
||
for (let i = Live2DSubCounter; i < subLoadMdlSetting.length; i++) {
|
||
subArr.push(subLoadMdlSetting[i]);
|
||
exitCnt++;
|
||
Live2DSubCounter++;
|
||
if (exitCnt >= 5) break;
|
||
}
|
||
Live2DSubLoading = true;
|
||
addModelsToLoader(loader2, subArr);
|
||
handleLoaderCompletion(loader2, subArr, () => {
|
||
Live2DSubLoading = false;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
let Live2DFirstLoadCompFlg = false;
|
||
!function () {
|
||
function load() {
|
||
modelSetting = [];
|
||
for (let i = 0; i < $Live2dSettingData.modelSetting.length; i++) {
|
||
let setData = $Live2dSettingData.modelSetting[i];
|
||
modelSetting.push(
|
||
new _L2dDtlSet(setData.MdlFile , setData.ViewName , setData.FirstLoadFlg ,
|
||
setData.ZureX , setData.ZureY , setData.VoiceDirName)
|
||
);
|
||
}
|
||
console.log("PictureLive2DLoad開始!!!");
|
||
let speedLoadModels = $p['Speed Load Live2D Model'];
|
||
for (let i = 0; i < modelSetting.length; i++) {
|
||
let mainFlg = false;
|
||
for (let j = 0; j < speedLoadModels.length; j++) {
|
||
if (modelSetting[i]._MdlName == speedLoadModels[j]) {
|
||
mainFlg = true;
|
||
break;
|
||
}
|
||
}
|
||
if (mainFlg) mainLoadMdlSetting.push(modelSetting[i]);
|
||
else subLoadMdlSetting.push(modelSetting[i]);
|
||
}
|
||
addModels(mainLoadMdlSetting);
|
||
addModels(subLoadMdlSetting);
|
||
console.log("Live2D:1次ロード開始");
|
||
let loader = new (PIXI.Loader || PIXI.loaders.Loader)();
|
||
addModelsToLoader(loader, mainLoadMdlSetting);
|
||
handleLoaderCompletion(loader, mainLoadMdlSetting, () => {
|
||
Live2DFirstLoadCompFlg = true;
|
||
console.log("Live2D:2次ロード開始");
|
||
});
|
||
}
|
||
if (!window.Live2DCubismCore) {
|
||
let js = null;
|
||
for (let element of document.getElementsByTagName('script')) {
|
||
if (element.src.match('live2dcubismcore.min.js')) {
|
||
js = element;
|
||
}
|
||
}
|
||
if (!js) {
|
||
js = document.createElement('script');
|
||
js.type = 'text/javascript';
|
||
js.src = 'js/libs/live2dcubismcore.min.js';
|
||
document.body.appendChild(js);
|
||
}
|
||
js.addEventListener('load', load);
|
||
} else {
|
||
load();
|
||
}
|
||
class MosaicFilter extends PIXI.Filter {
|
||
constructor(size = 10, _XZure = 0, _YZure = 0) {
|
||
let vertex = '' +
|
||
'attribute vec2 aVertexPosition;' +
|
||
'attribute vec2 aTextureCoord;' +
|
||
'uniform mat3 projectionMatrix;' +
|
||
'varying vec2 vTextureCoord;' +
|
||
'void main(void){' +
|
||
'gl_Position=vec4((projectionMatrix*vec3(aVertexPosition,1.0)).xy,0.0,1.0);' +
|
||
'vTextureCoord=aTextureCoord;' +
|
||
'}';
|
||
let fragment = '' +
|
||
'precision mediump float;' +
|
||
'varying vec2 vTextureCoord;' +
|
||
'uniform vec2 size;' +
|
||
'uniform vec2 zure;' +
|
||
'uniform sampler2D uSampler;' +
|
||
'uniform vec4 filterArea;' +
|
||
'vec2 mapCoord(vec2 coord){' +
|
||
'coord*=filterArea.xy;' +
|
||
'coord+=filterArea.zw;' +
|
||
'return coord;' +
|
||
'}' +
|
||
'vec2 unmapCoord(vec2 coord){' +
|
||
'coord-=filterArea.zw;' +
|
||
'coord/=filterArea.xy;' +
|
||
'return coord;' +
|
||
'}' +
|
||
'vec2 pixelate(vec2 coord, vec2 size){' +
|
||
'coord+=zure;' +
|
||
'return floor(coord / size) * size;' +
|
||
'}' +
|
||
'void main(void){' +
|
||
'vec2 coord=mapCoord(vTextureCoord);' +
|
||
'coord=pixelate(coord, size);' +
|
||
'coord=unmapCoord(coord);' +
|
||
'gl_FragColor=texture2D(uSampler, coord);' +
|
||
'}';
|
||
super(vertex, fragment);
|
||
this.uniforms.size = [size, size];
|
||
this.uniforms.zure = [_XZure, _YZure];
|
||
}
|
||
}
|
||
function convars(obj) {
|
||
if (typeof obj == 'string') {
|
||
let _obj = obj.replace(/\\v\[(\d+)\]/gi, (match, p1) => {
|
||
return $gameVariables.value(Number(p1));
|
||
});
|
||
obj = _obj != obj ? convars(_obj) : _obj;
|
||
} else if (obj instanceof Array) {
|
||
obj = obj.map(value => convars(value));
|
||
} else if (typeof obj == 'object') {
|
||
obj = {...obj};
|
||
for (let key in obj) {
|
||
obj[key] = convars(obj[key]);
|
||
}
|
||
}
|
||
return obj;
|
||
}
|
||
class Game_Live2D {
|
||
constructor() {
|
||
this.init();
|
||
}
|
||
static live2dData() {
|
||
return $p['live2d data'];
|
||
}
|
||
static fullName(name = '') {
|
||
for (let key in this.live2dData()) {
|
||
if (key.match(`(?:^|/)${name}$`)) {
|
||
return key;
|
||
}
|
||
}
|
||
return '';
|
||
}
|
||
get model() {
|
||
return this._model;
|
||
}
|
||
get track() {
|
||
return this._track;
|
||
}
|
||
get timeScale() {
|
||
return this._timeScale;
|
||
}
|
||
get weight() {
|
||
return this._weight;
|
||
}
|
||
get mix() {
|
||
return this._mix;
|
||
}
|
||
get color() {
|
||
return this._color;
|
||
}
|
||
get mosaic() {
|
||
return this._mosaic;
|
||
}
|
||
get offset() {
|
||
return this._offset;
|
||
}
|
||
get scale() {
|
||
return this._scale;
|
||
}
|
||
get visible() {
|
||
return this._visible;
|
||
}
|
||
init() {
|
||
this._model = '';
|
||
this._track = {};
|
||
this._timeScale = 1;
|
||
this._weight = [];
|
||
this._mix = {};
|
||
this._color = {};
|
||
this._mosaic = {};
|
||
this._offset = {x: 0, y: 0};
|
||
this._scale = {x: 1, y: 1};
|
||
this._visible = true;
|
||
this._IdleMtn = "";
|
||
this._TgtAlpha = 0;
|
||
this._TgtAlphaCng = 0;
|
||
this._TgtAlphaFlame = 0;
|
||
this._expression = [];
|
||
for (let i = 0; i <= 10 - 1; i++) {
|
||
this._expression.push("");
|
||
}
|
||
}
|
||
get expression() {
|
||
return this._expression;
|
||
}
|
||
setModel(name = '') {
|
||
name = convars(name);
|
||
this.init();
|
||
this._name = name;
|
||
this._model = `${name}_${Date.now()}`;
|
||
return this;
|
||
}
|
||
setAnimation(id, animations, ...args) {
|
||
[id, animations, args] = convars([id, animations, args]);
|
||
this._track = {...this._track};
|
||
let list, order, continuance, interrupt;
|
||
if (typeof animations == 'string') {
|
||
list = [animations];
|
||
order = 'sequential';
|
||
continuance = args[0] || 'continue';
|
||
interrupt = typeof args[1] == 'boolean' ? args[1] : args[1] == 'true';
|
||
} else {
|
||
list = animations;
|
||
order = args[0] || 'sequential';
|
||
continuance = args[1] || 'continue';
|
||
interrupt = typeof args[2] == 'boolean' ? args[2] : args[2] == 'true';
|
||
}
|
||
this._track[id] = {list: [], order: order, continuance: continuance, interrupt: interrupt};
|
||
list.forEach(animation => {
|
||
let [name, options] = `${animation}/`.replace(/ +/, '').split(/\//);
|
||
let times = 1;
|
||
let timeScale = 1;
|
||
let weight = 1;
|
||
for (let option of options.replace(/ +/, '').split(/,/)) {
|
||
if (option.match(/^times=(\d+)$/i)) {
|
||
times = Number(RegExp.$1);
|
||
}
|
||
if (option.match(/^timeScale=(\d+\.?\d*)$/i)) {
|
||
timeScale = Number(RegExp.$1);
|
||
}
|
||
if (option.match(/^weight=(\d+\.?\d*)$/i)) {
|
||
weight = Number(RegExp.$1);
|
||
}
|
||
}
|
||
this._track[id].list.push({name: name, times: times, timeScale: timeScale, weight: weight});
|
||
});
|
||
return this;
|
||
}
|
||
setExpression(id, expStr) {
|
||
this._expression[id] = expStr;
|
||
}
|
||
setTimeScale(value) {
|
||
value = convars(value);
|
||
this._timeScale = Number(value);
|
||
return this;
|
||
}
|
||
setWeight(id, value) {
|
||
[id, value] = convars([id, value]);
|
||
this._weight = this._weight.slice();
|
||
this._weight[id] = Number(value);
|
||
return this;
|
||
}
|
||
setMix(...args) {
|
||
args = convars(args);
|
||
this._mix = {...this._mix};
|
||
let from, to, duration;
|
||
if (args.length == 1) {
|
||
from = '/default';
|
||
to = '';
|
||
duration = Number(args[0]);
|
||
} else {
|
||
from = args[0];
|
||
to = args[1];
|
||
duration = args.length > 2 ? Number(args[2]) : null;
|
||
}
|
||
if (duration !== null) {
|
||
this._mix[`${from}/${to}`] = duration;
|
||
} else {
|
||
delete this._mix[`${from}/${to}`];
|
||
}
|
||
return this;
|
||
}
|
||
setColor(...args) {
|
||
args = convars(args);
|
||
this._color = {...this._color};
|
||
let id, r, g, b, a;
|
||
if (args.length == 3) {
|
||
id = '/default/';
|
||
r = Number(args[0]);
|
||
g = Number(args[1]);
|
||
b = Number(args[2]);
|
||
if (this._color[id] == undefined) {
|
||
a = 1;
|
||
} else {
|
||
a = this._color[id][3];
|
||
}
|
||
} else if (args.length == 4) {
|
||
id = '/default/';
|
||
r = Number(args[0]);
|
||
g = Number(args[1]);
|
||
b = Number(args[2]);
|
||
a = Number(args[3]);
|
||
} else {
|
||
id = args[0];
|
||
r = Number(args[1]);
|
||
g = Number(args[2]);
|
||
b = Number(args[3]);
|
||
a = Number(args[4]);
|
||
}
|
||
if (r != 1 || g != 1 || b != 1 || a != 1) {
|
||
this._color[id] = [r, g, b, a];
|
||
} else {
|
||
this._color[id] = [r, g, b, a];
|
||
}
|
||
return this;
|
||
}
|
||
setMosaic(...args) {
|
||
args = convars(args);
|
||
this._mosaic = {...this._mosaic};
|
||
let id, size;
|
||
if (args.length == 1) {
|
||
id = '/default/';
|
||
size = Number(args[0]);
|
||
} else {
|
||
id = args[0];
|
||
size = Number(args[1]);
|
||
}
|
||
if (size > 1) {
|
||
this._mosaic[id] = size;
|
||
} else {
|
||
delete this._mosaic[id];
|
||
}
|
||
return this;
|
||
}
|
||
setOffset(x, y) {
|
||
[x, y] = convars([x, y]);
|
||
this._offset = {x: Number(x), y: Number(y)};
|
||
return this;
|
||
}
|
||
setScale(x, y) {
|
||
[x, y] = convars([x, y]);
|
||
this._scale = {x: Number(x), y: Number(y)};
|
||
return this;
|
||
}
|
||
setVisible(visible) {
|
||
this._visible = !!convars(visible);
|
||
return this;
|
||
}
|
||
setParams(_prmId, _value) {
|
||
let _ckid = this._model;
|
||
let _AddFlg = true;
|
||
for (let i = 0; i <= L2D_SetParams_Arr.length - 1; i++) {
|
||
if (L2D_SetParams_Arr[i]._modelId == _ckid) {
|
||
_AddFlg = false;
|
||
let _ckNo = L2D_SetParams_Arr[i]._ids.indexOf(_prmId);
|
||
if (_ckNo != -1) {
|
||
L2D_SetParams_Arr[i]._values[_ckNo] = _value;
|
||
} else {
|
||
L2D_SetParams_Arr[i]._ids.push(_prmId);
|
||
L2D_SetParams_Arr[i]._values.push(_value);
|
||
}
|
||
}
|
||
}
|
||
if (_AddFlg) {
|
||
let _SetVar = new L2D_SetParams();
|
||
_SetVar._modelId = _ckid;
|
||
_SetVar._ids = [_prmId];
|
||
_SetVar._values = [_value];
|
||
L2D_SetParams_Arr.push(_SetVar);
|
||
}
|
||
return this;
|
||
}
|
||
delParams(_prmId) {
|
||
let _ckid = this._model;
|
||
let _AddFlg = true;
|
||
for (let i = 0; i <= L2D_DelParams_Arr.length - 1; i++) {
|
||
if (L2D_DelParams_Arr[i]._modelId == _ckid) {
|
||
_AddFlg = false;
|
||
let _ckNo = L2D_DelParams_Arr[i]._ids.indexOf(_prmId);
|
||
if (_ckNo == -1) {
|
||
L2D_DelParams_Arr[i]._ids.push(_prmId);
|
||
}
|
||
}
|
||
}
|
||
if (_AddFlg) {
|
||
let _SetVar = new L2D_SetParams();
|
||
_SetVar._modelId = _ckid;
|
||
_SetVar._ids = [_prmId];
|
||
L2D_DelParams_Arr.push(_SetVar);
|
||
}
|
||
return this;
|
||
}
|
||
}
|
||
window.Game_Live2D = Game_Live2D;
|
||
class Sprite_Live2D extends Sprite {
|
||
constructor(...args) {
|
||
super();
|
||
this._pictureId = typeof args[0] == 'number' ? args[0] : 0;
|
||
this._live2d = args[0] instanceof Game_Live2D ? args[0] : null;
|
||
this._isRestore = false;
|
||
this.init();
|
||
}
|
||
init() {
|
||
this.removeChild(this._data);
|
||
this._data = null;
|
||
this._model = '';
|
||
this._track = {};
|
||
this._timeScale = 1;
|
||
this._weight = [];
|
||
this._mix = {};
|
||
this._color = {};
|
||
this._mosaic = {};
|
||
this._offset = null;
|
||
this._scale = null;
|
||
this._mdlAlpha = 1;
|
||
this.blnk_flg = false;
|
||
this.blnk_flame = 100 + Math.floor(Math.random() * 300);
|
||
this.blnk_LClosePrm = 0;
|
||
this.blnk_LOpenPrm = 0;
|
||
this.blnk_LBaseOpenPrm = 0;
|
||
this.blnk_LIdNo = -1;
|
||
this.blnk_RClosePrm = 0;
|
||
this.blnk_ROpenPrm = 0;
|
||
this.blnk_RBaseOpenPrm = 0;
|
||
this.blnk_RIdNo = -1;
|
||
}
|
||
live2d() {
|
||
if (this._live2d) {
|
||
return this._live2d;
|
||
}
|
||
return null;
|
||
}
|
||
update() {
|
||
if (!isFinite(this._updateTime) || this._updateTime < 0) {
|
||
this._updateTime = 0;
|
||
}
|
||
let live2d = this.live2d();
|
||
this.updateModel(live2d);
|
||
let ckData = this._data;
|
||
if (!ckData || !ckData._model || !ckData._model.parameters || !ckData._model.parameters.ids) return;
|
||
if (this._data) {
|
||
this.updateColor(live2d);
|
||
if (this.parent._mdlAlpha == undefined) this.parent._mdlAlpha = 1;
|
||
if (!this.parent._mdlAlpha < 0.00001) {
|
||
this.updateMosaic(live2d);
|
||
this.updateOffset(live2d);
|
||
this.updateScale(live2d);
|
||
this.updateVisible(live2d);
|
||
if (!this._isRestore) {
|
||
this.updateTimeScale(live2d);
|
||
this.updateWeight(live2d);
|
||
this.updateMix(live2d);
|
||
this.updateAnimation(live2d);
|
||
this.snapshot(live2d);
|
||
} else {
|
||
this.restore(live2d);
|
||
}
|
||
}
|
||
}
|
||
super.update();
|
||
}
|
||
updateModel(live2d) {
|
||
if (live2d) {
|
||
if (live2d.model != this._model) {
|
||
let _ckdata = Game_Live2D.live2dData()[Game_Live2D.fullName(live2d._name)];
|
||
if (_ckdata == null) {
|
||
throw new Error("Live2D_Err:モデル「" + live2d._name + "」が存在しない");
|
||
}
|
||
if (_ckdata == false) {
|
||
console.log("Json 読込中:" + live2d._name);
|
||
return;
|
||
}
|
||
if (_ckdata.Textures.indexOf(null) != -1) {
|
||
console.log("Err_updateModel:TextLoad_Wait:" + live2d._name);
|
||
return;
|
||
}
|
||
this.init();
|
||
this._name = live2d._name; //nupu:Sprite_Live2Dに_name(モデル名)追加
|
||
this._model = live2d.model;
|
||
let model = this._model.replace(/_\d+$/, '');
|
||
if (model) {
|
||
let data = Game_Live2D.live2dData()[Game_Live2D.fullName(model)];
|
||
data.name = live2d._name;
|
||
this._data = new PIXI.Live2D(data);
|
||
this._data.animation.addListener('start', this.onStart.bind(this));
|
||
if (data.Expressions != null) {
|
||
for (let i = 0; i <= data.Expressions.length - 1; i++) {
|
||
this._data.animation._expression.push(data.Expressions[i])
|
||
}
|
||
}
|
||
this.addChild(this._data);
|
||
if (live2d.snapshot) {
|
||
this._isRestore = true;
|
||
}
|
||
let _ckModel = this._data._model;
|
||
if (!_ckModel || !_ckModel.parameters || !_ckModel.parameters.ids) return;
|
||
let _ckids = _ckModel.parameters.ids;
|
||
if (_ckids.indexOf("eyeOpenL") != -1) {
|
||
this.blnk_flg = true;
|
||
let _LeyeId = _ckids.indexOf("eyeOpenL");
|
||
this.blnk_LIdNo = _LeyeId;
|
||
if (_ckModel.parameters.keyValues[_LeyeId].length > 0) {
|
||
let _ckLength = _ckModel.parameters.keyValues[_LeyeId].length;
|
||
this.blnk_LOpenPrm = _ckModel.parameters.keyValues[_LeyeId][0];
|
||
this.blnk_LClosePrm = _ckModel.parameters.keyValues[_LeyeId][_ckLength - 1];
|
||
this.blnk_LBaseOpenPrm = this.blnk_LOpenPrm;
|
||
}
|
||
}
|
||
if (_ckids.indexOf("eyeOpenR") != -1) {
|
||
this.blnk_flg = true;
|
||
let _ReyeId = _ckids.indexOf("eyeOpenR");
|
||
this.blnk_RIdNo = _ReyeId;
|
||
if (_ckModel.parameters.keyValues[_ReyeId].length > 0) {
|
||
let _ckLength = _ckModel.parameters.keyValues[_ReyeId].length;
|
||
this.blnk_ROpenPrm = _ckModel.parameters.keyValues[_ReyeId][0];
|
||
this.blnk_RClosePrm = _ckModel.parameters.keyValues[_ReyeId][_ckLength - 1];
|
||
this.blnk_RBaseOpenPrm = this.blnk_ROpenPrm;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else if (this._model) {
|
||
this.init();
|
||
}
|
||
}
|
||
updateTimeScale(live2d) {
|
||
if (live2d.timeScale == this._timeScale) return;
|
||
this._timeScale = live2d.timeScale;
|
||
this._data.animation.setTimeScale(this._timeScale);
|
||
}
|
||
updateWeight(live2d) {
|
||
if (live2d.weight == this._weight) return;
|
||
this._weight = live2d.weight;
|
||
try {
|
||
this._weight.forEach((value, index) => {
|
||
this._data.animation.setWeight(index, value);
|
||
});
|
||
} catch (e) {
|
||
}
|
||
}
|
||
updateMix(live2d) {
|
||
if (live2d.mix == this._mix) return;
|
||
for (let key in live2d.mix) {
|
||
if (live2d.mix[key] != this._mix[key]) {
|
||
let time = live2d.mix[key];
|
||
if (key == '/default/') {
|
||
this._data.animation.setDefaultMix(time);
|
||
} else {
|
||
let [from, to] = key.split('/');
|
||
this._data.animation.setMix(from, to, time);
|
||
}
|
||
}
|
||
}
|
||
for (let key in this._mix) {
|
||
if (key in live2d.mix == false) {
|
||
if (key == '/default/') {
|
||
this._data.animation.setDefaultMix(0);
|
||
} else {
|
||
let [from, to] = key.split('/');
|
||
this._data.animation.setMix(from, to, 0);
|
||
}
|
||
}
|
||
}
|
||
this._mix = live2d.mix;
|
||
}
|
||
updateColor(live2d) {
|
||
let _ckArr = live2d.color["/default/"];
|
||
if (_ckArr == undefined) {
|
||
if (this._color["/default/"] != undefined) {
|
||
live2d.color["/default/"] = this._color["/default/"];
|
||
_ckArr = live2d.color["/default/"];
|
||
} else {
|
||
live2d.color["/default/"] = [1, 1, 1, 1];
|
||
_ckArr = live2d.color["/default/"];
|
||
}
|
||
}
|
||
if (live2d._TgtAlphaFlame > 0) {
|
||
try {
|
||
let _baseAlpha = live2d.color["/default/"][3];
|
||
_baseAlpha += live2d._TgtAlphaCng;
|
||
live2d._TgtAlphaFlame--;
|
||
if (_baseAlpha < 0) {
|
||
_baseAlpha = 0;
|
||
live2d._TgtAlphaFlame = 0;
|
||
}
|
||
if (live2d._TgtAlphaFlame == 0) _baseAlpha = live2d._TgtAlpha;
|
||
live2d.setColor(_ckArr[0], _ckArr[1], _ckArr[2], _baseAlpha);
|
||
} catch (e) {
|
||
}
|
||
}
|
||
if (live2d.color == this._color) return;
|
||
for (let id in live2d.color) {
|
||
if (live2d.color[id] != this._color[id]) {
|
||
let color = live2d.color[id];
|
||
let filter = new PIXI.filters.ColorMatrixFilter();
|
||
filter.matrix = [
|
||
color[0], 0, 0, 0, 0,
|
||
0, color[1], 0, 0, 0,
|
||
0, 0, color[2], 0, 0,
|
||
0, 0, 0, color[3], 0
|
||
];
|
||
let target = (id == '/default/') ? this._data : this.getArtMesh(id);
|
||
let filters = (target.filters || []).filter(filter => {
|
||
return filter instanceof PIXI.filters.ColorMatrixFilter == false;
|
||
});
|
||
filters.push(filter);
|
||
target.filters = filters;
|
||
}
|
||
if (id == '/default/') {
|
||
this._mdlAlpha = live2d.color[id][3];
|
||
}
|
||
}
|
||
for (let id in this._color) {
|
||
if (id in live2d.color == false) {
|
||
let target = (id == '/default/') ? this._data : this.getArtMesh(id);
|
||
let filters = (target.filters || []).filter(filter => {
|
||
return filter instanceof PIXI.filters.ColorMatrixFilter == false;
|
||
});
|
||
target.filters = filters.length > 0 ? filters : null;
|
||
}
|
||
}
|
||
this._color = live2d.color;
|
||
}
|
||
updateMosaic(live2d) {
|
||
if (live2d.mosaic == this._mosaic) return;
|
||
for (let id in live2d.mosaic) {
|
||
if (live2d.mosaic[id] != this._mosaic[id]) {
|
||
let size = live2d.mosaic[id];
|
||
let _MosData = L2D_MosaicGet(live2d._name, id);
|
||
let _XZure = -_MosData._ZureX;
|
||
let _YZure = -_MosData._ZureY;
|
||
let filter = new MosaicFilter(size, _XZure, _YZure);
|
||
let target = (id == '/default/') ? this._data : this.getArtMesh(id);
|
||
let filters = (target.filters || []).filter(filter => {
|
||
return filter instanceof MosaicFilter == false;
|
||
});
|
||
filters.push(filter);
|
||
target.filters = filters;
|
||
}
|
||
}
|
||
for (let id in this._mosaic) {
|
||
if (id in live2d.mosaic == false) {
|
||
let target = (id == '/default/') ? this._data : this.getArtMesh(id);
|
||
let filters = (target.filters || []).filter(filter => {
|
||
return filter instanceof MosaicFilter == false;
|
||
});
|
||
target.filters = filters.length > 0 ? filters : null;
|
||
}
|
||
}
|
||
this._mosaic = live2d.mosaic;
|
||
}
|
||
updateOffset(live2d) {
|
||
if (live2d.offset == this._offset) return;
|
||
this._offset = live2d.offset;
|
||
this.x = this._offset.x;
|
||
this.y = this._offset.y;
|
||
}
|
||
updateScale(live2d) {
|
||
this.children.some(_CkLive2D => {
|
||
if (_CkLive2D.constructor.name === "Live2D") {
|
||
if (_CkLive2D.mask != live2d._SetMask) {
|
||
_CkLive2D.mask = live2d._SetMask;
|
||
}
|
||
}
|
||
});
|
||
if (live2d.scale == this._scale) return;
|
||
this._scale = live2d.scale;
|
||
this.scale.x = this._scale.x;
|
||
this.scale.y = this._scale.y;
|
||
}
|
||
updateVisible(live2d) {
|
||
this.visible = live2d.visible;
|
||
}
|
||
updateAnimation(live2d) {
|
||
for (let i = 0; i <= live2d._expression.length - 1; i++) {
|
||
if (live2d._expression[i] != "") {
|
||
this._data.setExpression(i, live2d._expression[i], live2d);
|
||
live2d._expression[i] = "";
|
||
}
|
||
}
|
||
if (live2d.TrackCkSkipFlg == undefined) live2d.TrackCkSkipFlg = false;
|
||
if (!live2d.TrackCkSkipFlg) {
|
||
if (live2d.track == this._track) return;
|
||
}
|
||
for (let id in live2d.track) {
|
||
if (live2d.track[id] != this._track[id] || live2d.TrackCkSkipFlg) {
|
||
let track = live2d.track[id];
|
||
let list = [];
|
||
let loop = track.continuance != 'none';
|
||
for (let animation of track.list) {
|
||
for (let j = 0; j < animation.times; j++) {
|
||
list.push(animation);
|
||
}
|
||
}
|
||
if (track.order == 'shuffle') {
|
||
let _list = [...list];
|
||
list = [];
|
||
while (_list.length > 0) {
|
||
let index = Math.floor(Math.random() * _list.length);
|
||
list.push(_list.splice(index, 1)[0]);
|
||
}
|
||
} else if (track.order == 'random') {
|
||
let index = Math.floor(Math.random() * list.length);
|
||
list = [list[index]];
|
||
}
|
||
list.forEach((animation, index) => {
|
||
let entry;
|
||
if ((index == 0 && track.interrupt) || live2d.TrackCkSkipFlg) {
|
||
entry = this._data.animation.setAnimation(Number(id), animation.name, loop);
|
||
} else {
|
||
entry = this._data.animation.addAnimation(Number(id), animation.name, loop);
|
||
}
|
||
entry.timeScale = animation.timeScale;
|
||
entry.weight = animation.weight;
|
||
});
|
||
}
|
||
}
|
||
this._track = live2d.track;
|
||
live2d.TrackCkSkipFlg = false;
|
||
}
|
||
getArtMesh(id) {
|
||
let index = this._data.model.drawables.ids.indexOf(id);
|
||
return this._data._meshes[index];
|
||
}
|
||
onStart(trackInfo) {
|
||
if (trackInfo.track.entries.length == 1) {
|
||
let live2d = this.live2d();
|
||
let index = trackInfo.index;
|
||
if (live2d && live2d.track[index]) {
|
||
if (live2d.track[index] == this._track[index]) {
|
||
if (this._track[index].continuance == 'reset') {
|
||
live2d.track[index].interrupt = false;
|
||
this._track = {...this._track};
|
||
this._track[index] = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
onEnd(trackInfo) {
|
||
}
|
||
snapshot(live2d) {
|
||
live2d.snapshot = this._data.snapshot();
|
||
}
|
||
restore(live2d) {
|
||
this._data.restore(live2d.snapshot);
|
||
this._timeScale = live2d.timeScale;
|
||
this._weight = live2d.weight;
|
||
this._mix = live2d.mix;
|
||
this._track = live2d.track;
|
||
this._isRestore = false;
|
||
}
|
||
}
|
||
window.Sprite_Live2D = Sprite_Live2D;
|
||
// Game_Screen.prototype.live2d = function(id) {
|
||
// let picture = this.picture(id);
|
||
// if(picture == null) return null;
|
||
// if (!picture._live2d) {
|
||
// picture._live2d = new Game_Live2D();
|
||
// Game_Picture.prototype.initialize = function() {
|
||
// __initialize.apply(this, arguments);
|
||
// })(Game_Picture.prototype.initialize);
|
||
// Game_Picture.prototype.erase = function() {
|
||
// __erase.apply(this, arguments);
|
||
// })(Game_Picture.prototype.erase);
|
||
// Sprite_Picture.prototype.initialize = function(pictureId) {
|
||
// __initialize.apply(this, arguments);
|
||
// this.addChild(new Sprite_Live2D(pictureId))
|
||
// })(Sprite_Picture.prototype.initialize);
|
||
}();
|
||
let SetSpriteLive2D = function (_No, _MdlName, _x, _y, _mx, _my) {
|
||
console.log("SetSpriteLive2D::" + _MdlName);
|
||
_x = typeof _x !== 'undefined' ? _x : 0;
|
||
_y = typeof _y !== 'undefined' ? _y : 0;
|
||
_mx = typeof _mx !== 'undefined' ? _mx : 100;
|
||
_my = typeof _my !== 'undefined' ? _my : 100;
|
||
let _N_Sprite = SelSprite(_No);
|
||
DelSprite(_No);
|
||
let _INNo = _GetSpriteInNo(_No);
|
||
let _SetSprite = _NSprite(_No, "", "", _x, _y, 255, _mx, _my);
|
||
_SetSprite._live2d = new Game_Live2D();
|
||
_SetSprite._live2d.setModel(_MdlName);
|
||
let _Set_SpriteLive2D = new Sprite_Live2D(_No);
|
||
_Set_SpriteLive2D._live2d = _SetSprite._live2d;
|
||
_SetSprite.addChild(_Set_SpriteLive2D);
|
||
for (let i = 0; i <= L2D_MosaicDataArr.length - 1; i++) {
|
||
if (L2D_MosaicDataArr[i]._Model == _MdlName) {
|
||
_SetSprite._live2d.setMosaic(L2D_MosaicDataArr[i]._ArtMesh, L2D_MosaicDataArr[i]._MosPx);
|
||
}
|
||
}
|
||
_N_Sprite.addChildAt(_SetSprite, _INNo);
|
||
ViewSpriteArr_Add(_No);
|
||
DebugSpriteNo(_No, "SetSpriteLive2D");
|
||
}
|
||
!function () {
|
||
class MultiplyScreenFilter extends PIXI.Filter {
|
||
constructor(multiplyColor, screenColor) {
|
||
let fragment = 'varying vec2 vTextureCoord;uniform sampler2D uSampler;uniform vec3 multiplyColor;uniform vec3 screenColor;void main(void){vec4 color=texture2D(uSampler, vTextureCoord);color.rgb*=multiplyColor;color.rgb=color.rgb+screenColor*color.a-color.rgb*screenColor;gl_FragColor=color;}';
|
||
super(null, fragment);
|
||
this.uniforms.multiplyColor = multiplyColor;
|
||
this.uniforms.screenColor = screenColor;
|
||
}
|
||
get enabled() {
|
||
return this.uniforms.multiplyColor.some(value => value != 1)
|
||
|| this.uniforms.screenColor.some(value => value != 0);
|
||
}
|
||
set enabled(value) { }
|
||
}
|
||
if (!PIXI.SimpleMesh) {
|
||
PIXI.SimpleMesh = class extends PIXI.mesh.Mesh {
|
||
constructor(texture, vertices, uvs, indices, drawMode) {
|
||
super(texture, vertices, uvs, indices, drawMode);
|
||
this.state = {};
|
||
this.shader = {};
|
||
this.texture.baseTexture.resource = {
|
||
source: this.texture.baseTexture.source
|
||
};
|
||
Object.defineProperty(this.state, 'blendMode', {
|
||
set: value => this.blendMode = value
|
||
});
|
||
}
|
||
}
|
||
}
|
||
if (!PIXI.filters.VoidFilter) {
|
||
PIXI.filters.VoidFilter = PIXI.filters.AlphaFilter;
|
||
}
|
||
class Mesh extends PIXI.SimpleMesh {
|
||
constructor(texture, vertices, uvs, indices, drawMode) {
|
||
super(texture, vertices, uvs, indices, drawMode);
|
||
this.uvs = this.uvs || this.uvBuffer.data;
|
||
this.indices = this.indices || this.geometry.indexBuffer.data;
|
||
this.orderIndex = 0;
|
||
}
|
||
_render(renderer) {
|
||
if (!this.state.culling) {
|
||
super._render(renderer);
|
||
return;
|
||
}
|
||
let gl = renderer.gl;
|
||
gl.frontFace(gl.getParameter(gl.FRAMEBUFFER_BINDING) ? gl.CW : gl.CCW);
|
||
super._render(renderer);
|
||
gl.frontFace(gl.CCW);
|
||
}
|
||
_renderWebGL(renderer) {
|
||
if (!this.state.culling) {
|
||
super._renderWebGL(renderer);
|
||
return;
|
||
}
|
||
let gl = renderer.gl;
|
||
gl.enable(gl.CULL_FACE);
|
||
gl.frontFace(gl.getParameter(gl.FRAMEBUFFER_BINDING) ? gl.CW : gl.CCW);
|
||
super._renderWebGL(renderer);
|
||
gl.frontFace(gl.CCW);
|
||
gl.disable(gl.CULL_FACE);
|
||
}
|
||
}
|
||
class CopyMesh extends Mesh {
|
||
constructor(mesh) {
|
||
super(mesh.texture, mesh.vertices, mesh.uvs, mesh.indices, mesh.drawMode);
|
||
this.state = mesh.state;
|
||
this.shader = mesh.shader;
|
||
this._mesh = mesh;
|
||
}
|
||
update() {
|
||
this.vertices = this._mesh.vertices;
|
||
}
|
||
}
|
||
class MaskMesh extends CopyMesh {
|
||
constructor(mesh) {
|
||
super(mesh);
|
||
this.maskTexture = null;
|
||
this.texturePool = {};
|
||
this.orderIndex = -Infinity;
|
||
this.setup();
|
||
}
|
||
setup() {
|
||
this.maskTexture = new PIXI.Texture(new PIXI.BaseTexture());
|
||
this.maskTexture.baseTexture.valid = true;
|
||
let filter = new PIXI.filters.VoidFilter();
|
||
filter.apply = this.apply.bind(this);
|
||
this.filters = [filter, new PIXI.filters.VoidFilter()];
|
||
}
|
||
render(renderer) {
|
||
let pool = renderer.filter.texturePool.texturePool;
|
||
renderer.filter.texturePool.texturePool = this.texturePool;
|
||
super.render(renderer);
|
||
renderer.filter.texturePool.texturePool = pool;
|
||
}
|
||
renderWebGL(renderer) {
|
||
let pool = renderer.filterManager.pool;
|
||
renderer.filterManager.pool = this.texturePool;
|
||
super.renderWebGL(renderer);
|
||
renderer.filterManager.pool = pool;
|
||
}
|
||
apply(filterManager, input, output, clear, currentState) {
|
||
let gl = filterManager.renderer.gl;
|
||
let uid = filterManager.renderer.CONTEXT_UID;
|
||
let frame = {}, size = {};
|
||
let texture;
|
||
if (input.filterFrame) {
|
||
frame.x = input.filterFrame.x;
|
||
frame.y = input.filterFrame.y;
|
||
frame.width = input.filterFrame.width;
|
||
frame.height = input.filterFrame.height;
|
||
size.width = input.width;
|
||
size.height = input.height;
|
||
texture = input.baseTexture._glTextures[uid].texture;
|
||
} else {
|
||
frame.x = input.sourceFrame.x;
|
||
frame.y = input.sourceFrame.y;
|
||
frame.width = input.sourceFrame.width;
|
||
frame.height = input.sourceFrame.height;
|
||
size.width = input.size.width;
|
||
size.height = input.size.height;
|
||
texture = input.texture.texture;
|
||
}
|
||
this.maskTexture.baseTexture._glTextures[uid] = {dirtyId: 0, texture: texture};
|
||
this.maskTexture.maskInfo = { frame: frame, size: size };
|
||
}
|
||
update() {
|
||
super.update();
|
||
this.children.forEach(child => child.update());
|
||
}
|
||
}
|
||
class MeshMaskFilter extends PIXI.Filter {
|
||
constructor(mask, invert) {
|
||
let vertexSrc = 'attribute vec2 aVertexPosition;attribute vec2 aTextureCoord;uniform mat3 projectionMatrix;uniform mat3 otherMatrix;uniform vec2 offset;varying vec2 vMaskCoord;varying vec2 vTextureCoord;void main(void){gl_Position=vec4((projectionMatrix*vec3(aVertexPosition,1.)).xy,0.,1.);vTextureCoord=aTextureCoord;vMaskCoord=(otherMatrix*vec3(aTextureCoord,1.)).xy+offset;}';
|
||
let fragmentSrc = 'precision mediump float;varying vec2 vMaskCoord;varying vec2 vTextureCoord;uniform sampler2D uSampler;uniform sampler2D mask;uniform vec2 size;uniform float invert;void main(void){float clip=step(3.5,step(0.,vMaskCoord.x)+step(0.,vMaskCoord.y)+step(vMaskCoord.x,size.x)+step(vMaskCoord.y,size.y));vec4 original=texture2D(uSampler,vTextureCoord);vec4 masky=texture2D(mask,vMaskCoord);gl_FragColor=original*abs(1.*invert-masky.a*clip);}';
|
||
super(vertexSrc, fragmentSrc);
|
||
this._mask = mask;
|
||
this.uniforms.invert = invert ? 1 : 0;
|
||
}
|
||
apply(filterManager, input, output, clear, currentState) {
|
||
let texture = this._mask.maskTexture;
|
||
let inputRect = {};
|
||
if (input.filterFrame) {
|
||
inputRect.x = input.filterFrame.x;
|
||
inputRect.y = input.filterFrame.y;
|
||
inputRect.width = input.width;
|
||
inputRect.height = input.height;
|
||
} else {
|
||
inputRect.x = input.sourceFrame.x;
|
||
inputRect.y = input.sourceFrame.y;
|
||
inputRect.width = input.size.width;
|
||
inputRect.height = input.size.height;
|
||
}
|
||
let maskInfo = texture.maskInfo;
|
||
this.uniforms.otherMatrix = new PIXI.Matrix(inputRect.width / maskInfo.size.width, 0, 0, inputRect.height / maskInfo.size.height, 0, 0);
|
||
this.uniforms.offset = [(inputRect.x - maskInfo.frame.x) / maskInfo.size.width, (inputRect.y - maskInfo.frame.y) / maskInfo.size.height];
|
||
this.uniforms.mask = texture;
|
||
this.uniforms.size = [maskInfo.frame.width / maskInfo.size.width, maskInfo.frame.height / maskInfo.size.height];
|
||
filterManager.applyFilter(this, input, output, clear);
|
||
}
|
||
}
|
||
class Vector2 {
|
||
constructor(x, y) {
|
||
this.x = x || 0;
|
||
this.y = y || 0;
|
||
}
|
||
add(vector2) {
|
||
return new Vector2(this.x + vector2.x, this.y + vector2.y);
|
||
}
|
||
substract(vector2) {
|
||
return new Vector2(this.x - vector2.x, this.y - vector2.y);
|
||
}
|
||
multiplyScalar(scalar) {
|
||
return new Vector2(this.x * scalar, this.y * scalar);
|
||
}
|
||
normalize() {
|
||
let length = Math.pow(this.x * this.x + this.y * this.y, 0.5);
|
||
this.x /= length;
|
||
this.y /= length;
|
||
return this;
|
||
}
|
||
}
|
||
class Physics {
|
||
constructor(physics, parameters) {
|
||
this._settings = {};
|
||
this._parameters = parameters;
|
||
this.init(physics);
|
||
}
|
||
get settings() {
|
||
return this._settings;
|
||
}
|
||
init(physics) {
|
||
if (!physics || !physics.Meta || !physics.PhysicsSettings) {
|
||
this._settings = this._settings || {};
|
||
return;
|
||
}
|
||
const parameters = this._parameters || {};
|
||
const ids = Array.isArray(parameters.ids) ? parameters.ids : [];
|
||
const dictionary = (physics.Meta && Array.isArray(physics.Meta.PhysicsDictionary))
|
||
? physics.Meta.PhysicsDictionary
|
||
: [];
|
||
let settings = [];
|
||
try {
|
||
settings = JSON.parse(
|
||
JSON.stringify(physics.PhysicsSettings).replace(
|
||
/"[^"]+(?=":)/g,
|
||
m => '"' + m[1].toLowerCase() + m.slice(2)
|
||
)
|
||
);
|
||
if (!Array.isArray(settings)) settings = [];
|
||
} catch (e) {
|
||
settings = [];
|
||
}
|
||
this._settings = this._settings || {};
|
||
for (let setting of settings) {
|
||
if (!setting) continue;
|
||
const id = setting.id;
|
||
delete setting.id;
|
||
const dictItem = dictionary.find(item => item && item.Id == id);
|
||
setting.name = (dictItem || { Name: '' }).Name;
|
||
const inputs = Array.isArray(setting.input) ? setting.input : [];
|
||
for (let input of inputs) {
|
||
if (!input || !input.source) continue;
|
||
const srcId = input.source.id;
|
||
input.source.index = ids.indexOf(srcId);
|
||
}
|
||
const outputs = Array.isArray(setting.output) ? setting.output : [];
|
||
for (let output of outputs) {
|
||
if (!output || !output.destination) continue;
|
||
const dstId = output.destination.id;
|
||
output.destination.index = ids.indexOf(dstId);
|
||
}
|
||
const vertices = Array.isArray(setting.vertices) ? setting.vertices : [];
|
||
for (let vertex of vertices) {
|
||
if (!vertex || !vertex.position) continue;
|
||
vertex.position = new Vector2(vertex.position.x, vertex.position.y);
|
||
vertex.lastGravity = new Vector2(0, 1);
|
||
vertex.velocity = new Vector2();
|
||
}
|
||
if (id == null) continue;
|
||
this._settings[id] = setting;
|
||
}
|
||
// let settings = JSON.parse(JSON.stringify(physics.PhysicsSettings).replace(/"[^"]+(?=":)/g, m => '"' + m[1].toLowerCase() + m.slice(2)));
|
||
// for (let setting of settings) {
|
||
// setting.name = (dictionary.find(item => item.Id == id) || {Name: ''}).Name;
|
||
// for (let input of setting.input) {
|
||
// input.source.index = parameters.ids.indexOf(input.source.id);
|
||
// for (let output of setting.output) {
|
||
// output.destination.index = parameters.ids.indexOf(output.destination.id);
|
||
// for (let vertex of setting.vertices) {
|
||
// vertex.position = new Vector2(vertex.position.x, vertex.position.y);
|
||
// vertex.lastGravity = new Vector2(0, 1);
|
||
// vertex.velocity = new Vector2();
|
||
}
|
||
apply(delta) {
|
||
let values = this._parameters.values;
|
||
let minimumValues = this._parameters.minimumValues;
|
||
let maximumValues = this._parameters.maximumValues;
|
||
let defaultValues = this._parameters.defaultValues;
|
||
for (let id in this._settings) {
|
||
let setting = this._settings[id];
|
||
let vertices = setting.vertices;
|
||
let normalization = setting.normalization;
|
||
let translation = {x: 0, y: 0};
|
||
let angle = 0;
|
||
for (let input of setting.input) {
|
||
let index = input.source.index;
|
||
let type = input.type;
|
||
let value = this.normalize(
|
||
values[index], minimumValues[index], maximumValues[index], defaultValues[index],
|
||
type == 'Angle' ? normalization.angle : normalization.position, input.reflect
|
||
);
|
||
value *= input.weight / 100;
|
||
switch (type) {
|
||
case 'X':
|
||
translation.x += value;
|
||
break;
|
||
case 'Y':
|
||
translation.y += value;
|
||
break;
|
||
case 'Angle':
|
||
angle += value;
|
||
break;
|
||
}
|
||
}
|
||
angle = -angle / 180 * Math.PI;
|
||
translation = {
|
||
x: translation.x * Math.cos(angle) - translation.y * Math.sin(angle) ,
|
||
y: translation.x * Math.sin(angle) + translation.y * Math.cos(angle)
|
||
};
|
||
this.updateVertices(vertices, translation, -angle, normalization.position.maximum * 0.001, delta);
|
||
for (let output of setting.output) {
|
||
let index = output.destination.index;
|
||
let vertexIndex = output.vertexIndex;
|
||
if (vertexIndex < 1 || vertexIndex >= vertices.length) {
|
||
continue;
|
||
}
|
||
translation = {
|
||
x: vertices[vertexIndex].position.x - vertices[vertexIndex - 1].position.x,
|
||
y: vertices[vertexIndex].position.y - vertices[vertexIndex - 1].position.y
|
||
};
|
||
let gravity = vertexIndex > 1 ? vertices[vertexIndex - 1].position.substract(vertices[vertexIndex - 2].position) : new Vector2(0, 1);
|
||
let value = this.directionToRadian(gravity, translation);
|
||
let outValues = values.slice(index);
|
||
this.updateValues(outValues, minimumValues[index], maximumValues[index], value * output.scale, output.weight);
|
||
for (let i = index, j = 0; i < values.length; i++, j++) {
|
||
values[i] = outValues[j];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
normalize(value, minimumValue, maximumValue, defaultValue, normalization, reflect) {
|
||
let result = 0;
|
||
value = Math.min(Math.max(value, minimumValue), maximumValue) - defaultValue;
|
||
if (value != 0) {
|
||
let p = (value > 0 ? maximumValue : minimumValue) - defaultValue;
|
||
if (p != 0) {
|
||
let n = (value > 0 ? normalization.maximum : normalization.minimum) - normalization.default;
|
||
result = value * n / p + normalization.default;
|
||
}
|
||
} else {
|
||
result = normalization.default;
|
||
}
|
||
return reflect ? result : -result;
|
||
}
|
||
updateVertices(vertices, translation, angle, shreshold, delta) {
|
||
let gravity = new Vector2(Math.sin(angle), Math.cos(angle)).normalize();
|
||
vertices[0].position = new Vector2(translation.x, translation.y);
|
||
for (let i = 1; i < vertices.length; ++i) {
|
||
let delay = vertices[i].delay * delta * 30;
|
||
let velocity = vertices[i].velocity.multiplyScalar(delay);
|
||
let force = gravity.multiplyScalar(vertices[i].acceleration * delay * delay);
|
||
let direction = vertices[i].position.substract(vertices[i - 1].position);
|
||
let radian = this.directionToRadian(vertices[i].lastGravity, gravity) / 5;
|
||
direction = new Vector2(
|
||
Math.cos(radian) * direction.x - direction.y * Math.sin(radian),
|
||
Math.sin(radian) * direction.x + direction.y * Math.cos(radian)
|
||
);
|
||
let lastPosition = new Vector2(vertices[i].position.x, vertices[i].position.y);
|
||
vertices[i].position = vertices[i - 1].position.add(direction).add(velocity).add(force);
|
||
direction = vertices[i].position.substract(vertices[i - 1].position).normalize();
|
||
vertices[i].position = vertices[i - 1].position.add(direction.multiplyScalar(vertices[i].radius));
|
||
if (Math.abs(vertices[i].position.x) < shreshold) {
|
||
vertices[i].position.x = 0;
|
||
}
|
||
if (delay != 0) {
|
||
vertices[i].velocity = vertices[i].position.substract(lastPosition).multiplyScalar(vertices[i].mobility / delay);
|
||
}
|
||
vertices[i].lastGravity = new Vector2(gravity.x, gravity.y);
|
||
}
|
||
}
|
||
updateValues(values, minimum, maximum, value, weight) {
|
||
value = Math.min(Math.max(value, minimum), maximum);
|
||
weight /= 100;
|
||
if (weight >= 1) {
|
||
values[0] = value;
|
||
} else {
|
||
values[0] = values[0] * (1 - weight) + value * weight;
|
||
}
|
||
}
|
||
directionToRadian(from, to) {
|
||
let q1 = Math.atan2(to.y, to.x);
|
||
let q2 = Math.atan2(from.y, from.x);
|
||
let ret = q1 - q2;
|
||
while (ret < -Math.PI) {
|
||
ret += Math.PI * 2;
|
||
}
|
||
while (ret > Math.PI) {
|
||
ret -= Math.PI * 2;
|
||
}
|
||
return ret;
|
||
}
|
||
}
|
||
class Curve {
|
||
constructor(curve, beziersRestricted = false) {
|
||
this._beziersRestricted = beziersRestricted;
|
||
this._target = '';
|
||
this._id = '';
|
||
this._segments = [];
|
||
this._points = [];
|
||
this.create(curve);
|
||
}
|
||
get target() {
|
||
return this._target;
|
||
}
|
||
get id() {
|
||
return this._id;
|
||
}
|
||
create(curve) {
|
||
this._target = curve.Target;
|
||
this._id = curve.Id;
|
||
this._fadeInTime = curve.FadeInTime;
|
||
this._fadeOutTime = curve.FadeOutTime;
|
||
this._segments = [];
|
||
this._points = [];
|
||
let basePoint = 0;
|
||
let endPoint = 0;
|
||
for (let i = 0; i < curve.Segments.length; i++) {
|
||
let evaluate = null;
|
||
if (i > 0) {
|
||
let type = curve.Segments[i];
|
||
basePoint = endPoint;
|
||
this._points.push({time: curve.Segments[i + 1], value: curve.Segments[i + 2]});
|
||
if (type == 1) {
|
||
this._points.push({time: curve.Segments[i + 3], value: curve.Segments[i + 4]});
|
||
this._points.push({time: curve.Segments[i + 5], value: curve.Segments[i + 6]});
|
||
endPoint = basePoint + 3;
|
||
evaluate = this.bezier;
|
||
i += 6;
|
||
} else {
|
||
endPoint = basePoint + 1;
|
||
evaluate = type == 0 ? this.linear
|
||
: type == 2 ? this.stepped
|
||
: type == 3 ? this.inverseStepped
|
||
: null;
|
||
i += 2;
|
||
}
|
||
} else {
|
||
this._points.push({time: curve.Segments[0], value: curve.Segments[1]});
|
||
i++;
|
||
}
|
||
this._segments.push({basePoint: basePoint, endPoint: endPoint, evaluate: evaluate});
|
||
}
|
||
}
|
||
value(time) {
|
||
let segments = this._segments;
|
||
let points = this._points;
|
||
for (let i = 0; i < segments.length; i++) {
|
||
if (points[segments[i].endPoint].time > time) {
|
||
let basePoint = segments[i].basePoint;
|
||
let endPoint = segments[i].endPoint;
|
||
let evaluate = segments[i].evaluate;
|
||
if (evaluate) {
|
||
return evaluate.call(this, points.slice(basePoint, endPoint + 1), time);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return points.slice(-1)[0].value;
|
||
}
|
||
lerp(a, b, t) {
|
||
let time = a.time + (b.time - a.time) * t;
|
||
let value = a.value + (b.value - a.value) * t;
|
||
return {time: time, value: value};
|
||
}
|
||
linear(points, time) {
|
||
let t = (time - points[0].time) / (points[1].time - points[0].time);
|
||
return points[0].value + (points[1].value - points[0].value) * Math.max(t, 0);
|
||
}
|
||
bezier(points, time) {
|
||
if (!this._beziersRestricted) {
|
||
return this.cardano(points, time);
|
||
}
|
||
let t = Math.max((time - points[0].time) / (points[3].time - points[0].time), 0);
|
||
let p0 = this.lerp(points[0], points[1], t);
|
||
let p1 = this.lerp(points[1], points[2], t);
|
||
let p2 = this.lerp(points[2], points[3], t);
|
||
let p3 = this.lerp(p0, p1, t);
|
||
let p4 = this.lerp(p1, p2, t);
|
||
return this.lerp(p3, p4, t).value;
|
||
}
|
||
cardano(points, time) {
|
||
let t0 = points[0].time;
|
||
let t1 = points[1].time;
|
||
let t2 = points[2].time;
|
||
let t3 = points[3].time;
|
||
let t4 = t3 + 3.0 * (t1 - t2) - t0;
|
||
let t5 = 3.0 * (t0 + t2) - 6.0 * t1;
|
||
let t6 = 3.0 * (t1 - t0);
|
||
let t7 = t0 - time;
|
||
let t = this.cardanoAlgorithm(t4, t5, t6, t7);
|
||
let p0 = this.lerp(points[0], points[1], t);
|
||
let p1 = this.lerp(points[1], points[2], t);
|
||
let p2 = this.lerp(points[2], points[3], t);
|
||
let p3 = this.lerp(p0, p1, t);
|
||
let p4 = this.lerp(p1, p2, t);
|
||
return this.lerp(p3, p4, t).value;
|
||
}
|
||
stepped(points) {
|
||
return points[0].value;
|
||
}
|
||
inverseStepped(points) {
|
||
return points[1].value;
|
||
}
|
||
range(value, min, max) {
|
||
return Math.min(Math.max(value, min), max);
|
||
}
|
||
cbrt(x) {
|
||
if (x == 0) {
|
||
return x;
|
||
}
|
||
var cx = x;
|
||
var isNegativeNumber = cx < 0;
|
||
if (isNegativeNumber) {
|
||
cx = -cx;
|
||
}
|
||
var ret;
|
||
if (cx == Infinity) {
|
||
ret = Infinity;
|
||
} else {
|
||
ret = Math.exp(Math.log(cx) / 3);
|
||
ret = (cx / (ret * ret) + 2 * ret) / 3;
|
||
}
|
||
return isNegativeNumber ? -ret : ret;
|
||
}
|
||
quadratic(a, b, c) {
|
||
if (Math.abs(a) < 0.00001) {
|
||
if (Math.abs(b) < 0.00001) {
|
||
return -c;
|
||
}
|
||
return -c / b;
|
||
}
|
||
return -(b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
|
||
}
|
||
cardanoAlgorithm(a, b, c, d) {
|
||
if (Math.sqrt(a) < 0.00001) {
|
||
return this.range(this.quadratic(b, c, d), 0, 1);
|
||
}
|
||
let ba = b / a;
|
||
let ca = c / a;
|
||
let da = d / a;
|
||
let p = (3 * ca - ba * ba) / 3;
|
||
let p3 = p / 3;
|
||
let q = (2 * ba * ba * ba - 9 * ba * ca + 27 * da) / 27;
|
||
let q2 = q / 2;
|
||
let discriminant = q2 * q2 + p3 * p3 * p3;
|
||
if (discriminant < 0) {
|
||
let mp3 = -p / 3;
|
||
let mp33 = mp3 * mp3 * mp3;
|
||
let r = Math.sqrt(mp33);
|
||
let t = -q / (2 * r);
|
||
let cosphi = this.range(t, -1, 1);
|
||
let phi = Math.acos(cosphi);
|
||
let crtr = this.cbrt(r);
|
||
let t1 = 2 * crtr;
|
||
let root1_1 = t1 * Math.cos(phi / 3) - ba / 3;
|
||
if (Math.abs(root1_1 - 0.5) < 0.51) {
|
||
return this.range(root1_1, 0, 1);
|
||
}
|
||
let root2 = t1 * Math.cos((phi + 2 * Math.PI) / 3) - ba / 3;
|
||
if (Math.abs(root2 - 0.5) < 0.51) {
|
||
return this.range(root2, 0, 1);
|
||
}
|
||
let root3 = t1 * Math.cos((phi + 4 * Math.PI) / 3) - ba / 3;
|
||
return this.range(root3, 0, 1);
|
||
} else if (discriminant == 0) {
|
||
let u1_1;
|
||
if (q2 < 0) {
|
||
u1_1 = this.cbrt(-q2);
|
||
} else {
|
||
u1_1 = -this.cbrt(q2);
|
||
}
|
||
let root1_2 = 2 * u1_1 - ba / 3;
|
||
if (Math.abs(root1_2 - 0.5) < 0.51) {
|
||
return this.range(root1_2, 0, 1);
|
||
}
|
||
let root2 = -u1_1 - ba / 3;
|
||
return this.range(root2, 0, 1);
|
||
}
|
||
let sd = Math.sqrt(discriminant);
|
||
let u1 = this.cbrt(sd - q2);
|
||
let v1 = this.cbrt(sd + q2);
|
||
let root1 = u1 - v1 - ba / 3;
|
||
return this.range(root1, 0, 1);
|
||
}
|
||
}
|
||
class Motion {
|
||
constructor(motion) {
|
||
if (motion) {
|
||
let meta = motion.Data.Meta;
|
||
this._duration = meta.Duration;
|
||
this._loop = meta.Loop;
|
||
this._beziersRestricted = meta.AreBeziersRestricted;
|
||
this._group = motion.Group;
|
||
this._name = motion.Name;
|
||
this._baseName = motion.BaseName;
|
||
this._fadeInTime = motion.FadeInTime;
|
||
this._fadeOutTime = motion.FadeOutTime;
|
||
this._sound = motion.Sound;
|
||
this._curves = [];
|
||
this.createCurve(motion.Data.Curves, this._beziersRestricted);
|
||
} else {
|
||
this._duration = 0;
|
||
this._loop = false;
|
||
this._beziersRestricted = false;
|
||
this._group = '';
|
||
this._name = '';
|
||
this._baseName = '';
|
||
this._fadeInTime = 0;
|
||
this._fadeOutTime = 0;
|
||
this._sound = '';
|
||
this._curves = [];
|
||
}
|
||
}
|
||
get duration() {
|
||
return this._duration;
|
||
}
|
||
get group() {
|
||
return this._group;
|
||
};
|
||
get name() {
|
||
return this._name;
|
||
};
|
||
get baseName() {
|
||
return this._baseName;
|
||
}
|
||
get sound() {
|
||
return this._sound;
|
||
}
|
||
createCurve(curves, beziersRestricted) {
|
||
this._curves = curves.map(curve => new Curve(curve, beziersRestricted));
|
||
}
|
||
fadeWeight(value) {
|
||
return 0.5 - 0.5 * Math.cos(value * Math.PI);
|
||
}
|
||
values(time) {
|
||
let remain = Math.max(this._duration - time, 0);
|
||
let values = {};
|
||
for (let curve of this._curves) {
|
||
let fadeInTime = curve._fadeInTime != null ? curve._fadeInTime : this._fadeInTime;
|
||
let fadeOutTime = curve._fadeOutTime != null ? curve._fadeOutTime : this._fadeOutTime;
|
||
let fadeInWeight = time < fadeInTime ? this.fadeWeight(time / fadeInTime) : 1;
|
||
let fadeOutWeight = remain < fadeOutTime ? this.fadeWeight(remain / fadeOutTime) : 1;
|
||
let target = curve.target;
|
||
let id = curve.id;
|
||
let value = curve.value(time);
|
||
let weight = fadeInWeight * fadeOutWeight;
|
||
values[target] = values[target] || {};
|
||
values[target][id] = {value: value, weight: weight};
|
||
}
|
||
return values;
|
||
}
|
||
}
|
||
class Entry {
|
||
constructor(motion, elapsed = 0) {
|
||
this._motion = motion;
|
||
this._elapsed = elapsed;
|
||
this.loop = false;
|
||
this.timeScale = 1;
|
||
this.weight = 1;
|
||
this.mixTime = 0;
|
||
this.endTime = 0;
|
||
}
|
||
get name() { return this._motion.name; }
|
||
get duration() { return this.endTime || this._motion.duration; }
|
||
get elapsed() { return this._elapsed; }
|
||
get remain() { return this.duration - this._elapsed; }
|
||
get sound() { return this._motion.sound; }
|
||
values(delta) {
|
||
this._elapsed += (delta * this.timeScale);
|
||
if (this.loop) {
|
||
this._elapsed %= this.duration;
|
||
}
|
||
let values = this._motion.values(this._elapsed);
|
||
for (let target in values) {
|
||
for (let id in values[target]) {
|
||
values[target][id].weight *= this.weight;
|
||
}
|
||
}
|
||
return values;
|
||
}
|
||
}
|
||
class Track {
|
||
constructor(active = false, mixing = false) {
|
||
this._entries = [];
|
||
this._active = active;
|
||
this._mixing = mixing;
|
||
this._history = [];
|
||
this.weight = 1;
|
||
}
|
||
get entries() { return this._entries; }
|
||
get active() { return this._active; }
|
||
get mixing() { return this._mixing; }
|
||
get history() { return this._history.shift(); }
|
||
add(entry) {
|
||
let last = this.entry(-1);
|
||
if (last) {
|
||
last.loop = false;
|
||
if (last.endTime > 0) {
|
||
last.endTime += entry.mixTime;
|
||
}
|
||
}
|
||
this._entries.push(entry);
|
||
}
|
||
entry(index) {
|
||
return this._entries.slice(index)[0];
|
||
}
|
||
mix(values, next_values, rate) {
|
||
let r0 = 1 - rate;
|
||
let r1 = rate;
|
||
for (let target in next_values) {
|
||
for (let id in next_values[target]) {
|
||
let value, weight;
|
||
if (values[target] && values[target][id]) {
|
||
let v0 = values[target][id];
|
||
let v1 = next_values[target][id];
|
||
value = v0.value * r0 + v1.value * r1;
|
||
weight = v0.weight * r0 + v1.weight * r1;
|
||
} else {
|
||
let v = next_values[target][id];
|
||
value = v.value;
|
||
weight = v.weight * r1;
|
||
}
|
||
values[target] = values[target] || {};
|
||
values[target][id] = { value: value, weight: weight };
|
||
}
|
||
}
|
||
for (let target in values) {
|
||
for (let id in values[target]) {
|
||
if (!next_values[target] || !next_values[target][id]) {
|
||
values[target][id].weight *= r0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
suspend() {
|
||
if (!this.active) {
|
||
return;
|
||
}
|
||
let entry = this._entries[0];
|
||
entry.endTime = entry.elapsed;
|
||
entry.loop = false;
|
||
this._entries.splice(1);
|
||
}
|
||
values(delta) {
|
||
try {
|
||
let entry = this._entries[0];
|
||
let next_entry = this._entries[1];
|
||
if (!entry) {
|
||
return null;
|
||
}
|
||
if (!this._active) {
|
||
delta = 0;
|
||
this._history.push({ start: entry });
|
||
}
|
||
let _remain = entry.remain;
|
||
let mixTime = next_entry ? next_entry.mixTime : 0;
|
||
let values = entry.values(delta);
|
||
let remain = entry.remain;
|
||
if (remain > 0) {
|
||
if (mixTime >= remain) {
|
||
delta = Math.min(mixTime - remain, _remain - remain);
|
||
let next_values = next_entry.values(delta);
|
||
let rate = (mixTime - remain) / mixTime;
|
||
this.mix(values, next_values, rate);
|
||
if (!this._mixing) {
|
||
this._history.push({ start: next_entry });
|
||
this._mixing = true;
|
||
}
|
||
}
|
||
} else {
|
||
this._entries.shift();
|
||
this._history.push({ end: entry });
|
||
if (next_entry) {
|
||
delta = -remain / entry.timeScale;
|
||
values = next_entry.values(delta);
|
||
if (!this._mixing) {
|
||
this._history.push({ start: next_entry });
|
||
}
|
||
}
|
||
this._mixing = false;
|
||
}
|
||
this._active = remain > 0 || !!next_entry;
|
||
return values;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
class Animation {
|
||
constructor(motions, parameters, parts) {
|
||
this._motions = [];
|
||
this._parameters = parameters;
|
||
this._parts = parts;
|
||
this._tracks = [];
|
||
this._timeScale = 1;
|
||
this._mixTime = {};
|
||
this._listeners = {};
|
||
this._expression = [];
|
||
this.createMotion(motions);
|
||
}
|
||
get motions() {
|
||
return this._motions;
|
||
}
|
||
get tracks() {
|
||
return this._tracks;
|
||
}
|
||
get timeScale() {
|
||
return this._timeScale;
|
||
}
|
||
get mixTime() {
|
||
return this._mixTime;
|
||
}
|
||
createMotion(motions) {
|
||
this._motions = motions.map(motion => new Motion(motion));
|
||
}
|
||
track(index) {
|
||
if (!this._tracks[index]) {
|
||
this._tracks[index] = new Track();
|
||
}
|
||
return this._tracks[index];
|
||
}
|
||
setAnimation(index, name, loop) {
|
||
let track = this._tracks[index];
|
||
if (track) {
|
||
track.suspend();
|
||
}
|
||
return this.addAnimation(index, name, loop);
|
||
}
|
||
addAnimation(index, name, loop) {
|
||
let motion = this._motions.find(motion => [motion.name, motion.baseName].includes(name));
|
||
let entry = new Entry(motion);
|
||
let track = this.track(index);
|
||
let last = track.entry(-1);
|
||
if (last) {
|
||
let key = `${last.name},${name}`;
|
||
entry.mixTime = this._mixTime[key] || this._mixTime.default || 0;
|
||
}
|
||
entry.loop = loop;
|
||
track.add(entry);
|
||
return entry;
|
||
}
|
||
clearAnimation(index, mixTime = 0) {
|
||
let track = this._tracks[index];
|
||
if (!track) {
|
||
return;
|
||
}
|
||
track.suspend();
|
||
let entry = new Entry(new Motion());
|
||
entry.mixTime = mixTime;
|
||
track.add(entry);
|
||
}
|
||
setTimeScale(scale) {
|
||
this._timeScale = scale;
|
||
}
|
||
setWeight(index, value) {
|
||
this.track(index).weight = value;
|
||
}
|
||
setMix(from, to, time) {
|
||
if (time > 0) {
|
||
this._mixTime[`${from},${to}`] = time;
|
||
} else {
|
||
delete this._mixTime[`${from},${to}`];
|
||
}
|
||
}
|
||
setDefaultMix(time) {
|
||
if (time > 0) {
|
||
this._mixTime.default = time;
|
||
} else {
|
||
delete this._mixTime.default;
|
||
}
|
||
}
|
||
addListener(event, callback) {
|
||
this._listeners[event] = this._listeners[event] || [];
|
||
this._listeners[event].push(callback);
|
||
}
|
||
removeListener(event, callback) {
|
||
if (this._listeners[event]) {
|
||
let index = this._listeners[event].indexOf(callback);
|
||
if (index >= 0) {
|
||
this._listeners[event].splice(index, 1);
|
||
}
|
||
}
|
||
}
|
||
callListener(event, index, track, entry) {
|
||
if (this._listeners[event]) {
|
||
let trackInfo = { index: index, track: track, entry: entry };
|
||
this._listeners[event].forEach(callback => callback(trackInfo));
|
||
}
|
||
}
|
||
apply(delta) {
|
||
delta *= this._timeScale;
|
||
let parameters = this._parameters;
|
||
if (!parameters || !parameters.ids) return;
|
||
let parts = this._parts;
|
||
for (let track of this._tracks) {
|
||
if (track == null) continue;
|
||
let values = track.values(delta);
|
||
if (!values) {
|
||
continue;
|
||
}
|
||
for (let target in values) {
|
||
for (let id in values[target]) {
|
||
let p = values[target][id];
|
||
let value = p.value;
|
||
let weight = p.weight * track.weight;
|
||
if (target == 'Parameter') {
|
||
let index = parameters.ids.indexOf(id);
|
||
let _value = parameters.values[index];
|
||
parameters.values[index] = _value * (1 - weight) + value * weight;
|
||
} else if (target == 'PartOpacity') {
|
||
let index = parts.ids.indexOf(id);
|
||
let _value = parts.opacities[index];
|
||
parts.opacities[index] = _value * (1 - weight) + value * weight;
|
||
}
|
||
}
|
||
}
|
||
let index = this._tracks.indexOf(track);
|
||
for (let history; history = track.history;) {
|
||
let event = history.start ? 'start' : 'end';
|
||
let entry = history.start || history.end;
|
||
this.callListener(event, index, track, entry);
|
||
if (event == 'end' && track.entries.length > 0) {
|
||
let _entry = track.entries[0];
|
||
try {
|
||
if(_entry._motion._name.indexOf("wait") == -1 && _entry._motion._name.indexOf("Wait")) {
|
||
Motion_EyeSetting(this.parent.parent._name, _entry._motion._name);
|
||
} else {
|
||
console.log("waitモーションは瞬き設定をさせない");
|
||
}
|
||
} catch (e) {
|
||
console.log("モーション設定失敗");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
class Live2D extends PIXI.Container {
|
||
constructor(live2dData) {
|
||
super();
|
||
this._data = live2dData;
|
||
this._model = new Live2DCubismCore.Model(this._data.Moc);
|
||
this._meshes = [];
|
||
this._masks = {};
|
||
this._physics = null;
|
||
this._animation = null;
|
||
this._updateTime = 0;
|
||
this.createMesh();
|
||
this.createMask();
|
||
this.createAnimation();
|
||
this.createPhysics();
|
||
this._exp_tracks = [];
|
||
this._exp_SetTracks = [];
|
||
this._SEParams = [];
|
||
this._VoiceParams = [];
|
||
for (let i = 0; i <= seSetting.length - 1; i++) {
|
||
if (seSetting[i]._MdlName == this._data.name) {
|
||
if (seSetting[i]._VoiceFol == "") {
|
||
this._SEParams.push(new _SeParam(seSetting[i]._SeName));
|
||
} else {
|
||
this._VoiceParams.push(
|
||
new _VoiceParams(seSetting[i]._VoiceFol, seSetting[i]._SeName)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
this._CmnParams = [];
|
||
(function () {
|
||
var self = this;
|
||
var maxAttempts = 10;
|
||
var intervalMs = 100;
|
||
var attempt = 0;
|
||
function hasModelParamsIds() {
|
||
return !!(self._model && self._model.parameters && Array.isArray(self._model.parameters.ids));
|
||
}
|
||
function waitForModelLoaded() {
|
||
if (hasModelParamsIds() || attempt >= maxAttempts) {
|
||
onReadyOrGiveUp();
|
||
return;
|
||
}
|
||
attempt++;
|
||
console.log("モデルロード待機処理...:" + attempt);
|
||
setTimeout(waitForModelLoaded, intervalMs);
|
||
}
|
||
function onReadyOrGiveUp() {
|
||
if (!hasModelParamsIds()) {
|
||
console.log("モデルロードの失敗");
|
||
return;
|
||
}
|
||
var ids = self._model.parameters.ids;
|
||
for (var i = 0; i < ids.length; i++) {
|
||
var id = ids[i];
|
||
if (id.indexOf("CmnEv_") !== -1) {
|
||
var cmnNo = id.replace("CmnEv_", "");
|
||
self._CmnParams.push(new _CmnEvParam(Number(cmnNo)));
|
||
}
|
||
}
|
||
if ($gameSystem.L2D_SetParams_Arr === undefined) $gameSystem.L2D_SetParams_Arr = [];
|
||
for (var a = 0; a < $gameSystem.L2D_SetParams_Arr.length; a++) {
|
||
var item = $gameSystem.L2D_SetParams_Arr[a];
|
||
if (item._modelId == self._data.name) {
|
||
for (var j = 0; j < item._ids.length; j++) {
|
||
var ckId = item._ids[j];
|
||
var setIndex = ids.indexOf(ckId);
|
||
if (setIndex !== -1) {
|
||
self._model.parameters.values[setIndex] = item._values[j];
|
||
} else {
|
||
item._ids.splice(j, 1);
|
||
item._values.splice(j, 1);
|
||
j--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
waitForModelLoaded();
|
||
}).call(this);
|
||
// if (!this._model?.parameters?.ids) return;
|
||
// for (let i = 0; i <= this._model.parameters.ids.length - 1; i++) {
|
||
// if (this._model.parameters.ids[i].indexOf("CmnEv_") != -1) {
|
||
// let _SetCmnNo = this._model.parameters.ids[i].replace("CmnEv_", "");
|
||
// this._CmnParams.push(new _CmnEvParam(Number(_SetCmnNo)));
|
||
// if ($gameSystem.L2D_SetParams_Arr == undefined) $gameSystem.L2D_SetParams_Arr = [];
|
||
// for (let i = 0; i <= $gameSystem.L2D_SetParams_Arr.length - 1; i++) {
|
||
// if ($gameSystem.L2D_SetParams_Arr[i]._modelId == this._data.name) {
|
||
// for (let j = 0; j <= $gameSystem.L2D_SetParams_Arr[i]._ids.length - 1; j++) {
|
||
// let _nSetNo = this._model.parameters.ids.indexOf(_CkId);
|
||
// if (_nSetNo != -1) {
|
||
// $gameSystem.L2D_SetParams_Arr[i]._ids.splice(j, 1);
|
||
// $gameSystem.L2D_SetParams_Arr[i]._values.splice(j, 1);
|
||
}
|
||
get model() {
|
||
return this._model;
|
||
}
|
||
get animation() {
|
||
return this._animation;
|
||
}
|
||
createMesh() {
|
||
if (this._meshes && this._meshes.length) return;
|
||
if (!this._model || !this._model.drawables) {
|
||
this._createMeshRetries = (this._createMeshRetries || 0) + 1;
|
||
if (this._createMeshRetries <= 6) {
|
||
const delay = Math.min(200 * Math.pow(2, this._createMeshRetries - 1), 2000);
|
||
console.warn(`Live2D.createMesh: drawables undefined for model ${this._data && this._data.name}, retry #${this._createMeshRetries} in ${delay}ms`);
|
||
setTimeout(() => {
|
||
if (this._data) this.createMesh();
|
||
}, delay);
|
||
} else {
|
||
console.error(`Live2D.createMesh: drawables still undefined after retries for ${this._data && this._data.name}`);
|
||
}
|
||
return;
|
||
}
|
||
if (!this._model || !this._model.drawables) {
|
||
console.warn(`Live2D.createMesh: drawables is undefined for model ${this._data && this._data.name}`);
|
||
return;
|
||
}
|
||
let drawables = this._model.drawables;
|
||
if (drawables.count != undefined) {
|
||
for (let i = 0; i < drawables.count; i++) {
|
||
let textureIndex = drawables.textureIndices[i];
|
||
let texture = this._data.Textures[textureIndex];
|
||
let vertices = this.localVertices(drawables.vertexPositions[i]);
|
||
let uvs = new Float32Array(drawables.vertexUvs[i]);
|
||
let indices = new Uint16Array(drawables.indices[i]);
|
||
for (let j = 0; j < drawables.vertexCounts[i]; j++) {
|
||
uvs[j * 2 + 1] = 1 - uvs[j * 2 + 1];
|
||
}
|
||
let mesh = new Mesh(texture, vertices, uvs, indices, PIXI.DRAW_MODES.TRIANGLES);
|
||
mesh.alpha = drawables.opacities[i];
|
||
mesh.visible = drawables.dynamicFlags[i] & 0x1;
|
||
mesh.blendMode = drawables.constantFlags[i] & 0x3;
|
||
mesh.state.culling = !(drawables.constantFlags[i] & 0x4);
|
||
mesh.orderIndex = drawables.renderOrders[i];
|
||
if (mesh.state.culling) {
|
||
mesh.shader.batchable = false;
|
||
}
|
||
mesh.filters = [new MultiplyScreenFilter(
|
||
drawables.multiplyColors.slice(i * 4, i * 4 + 3),
|
||
drawables.screenColors.slice(i * 4, i * 4 + 3)
|
||
)];
|
||
this._meshes.push(mesh);
|
||
this.addChild(mesh);
|
||
}
|
||
}
|
||
this.sortMesh();
|
||
}
|
||
createMask() {
|
||
if (!this._model || !this._model.drawables) {
|
||
this._createMaskRetries = (this._createMaskRetries || 0) + 1;
|
||
if (this._createMaskRetries <= 6) {
|
||
const delay = Math.min(200 * Math.pow(2, this._createMaskRetries - 1), 2000);
|
||
console.warn(
|
||
`Live2D.createMask: drawables undefined for model ${this._data && this._data.name}, retry #${this._createMaskRetries} in ${delay}ms`
|
||
);
|
||
setTimeout(() => {
|
||
if (this._data) this.createMask();
|
||
}, delay);
|
||
} else {
|
||
console.error(
|
||
`Live2D.createMask: drawables still undefined after retries for ${this._data && this._data.name}`
|
||
);
|
||
}
|
||
return;
|
||
}
|
||
if (!this._model || !this._model.drawables) {
|
||
console.warn(`Live2D.createMask: drawables is undefined for model ${this._data && this._data.name}`);
|
||
return;
|
||
}
|
||
let drawables = this._model.drawables;
|
||
if (drawables.count != undefined) {
|
||
for (let i = 0; i < drawables.count; i++) {
|
||
let mesh = this._meshes[i];
|
||
let invert = !!(drawables.constantFlags[i] & 0x8);
|
||
let masks = [...drawables.masks[i]].sort();
|
||
if (masks.length > 0) {
|
||
let mask = this._masks[masks];
|
||
if (!mask) {
|
||
mask = new MaskMesh(this._meshes[masks[0]]);
|
||
this.addChildAt(mask, 0);
|
||
this._masks[masks] = mask;
|
||
for (let j = 1; j < masks.length; j++) {
|
||
mask.addChild(new CopyMesh(this._meshes[masks[j]]));
|
||
}
|
||
}
|
||
let filters = mesh.filters || [];
|
||
filters.push(new MeshMaskFilter(mask, invert));
|
||
if (mesh.blendMode > 0) {
|
||
let filter = new PIXI.Filter();
|
||
filter.blendMode = mesh.blendMode;
|
||
mesh.blendMode = 0;
|
||
filters.push(filter);
|
||
}
|
||
mesh.filters = filters;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
createPhysics() {
|
||
if (this._data.Physics) {
|
||
this._physics = new Physics(this._data.Physics, this._model.parameters);
|
||
}
|
||
}
|
||
createAnimation() {
|
||
if (this._data.Motions) {
|
||
let motions = [];
|
||
let parameters = this._model.parameters;
|
||
let parts = this._model.parts;
|
||
for (let name in this._data.Motions) {
|
||
motions.push(...this._data.Motions[name]);
|
||
}
|
||
this._animation = new Animation(motions, parameters, parts);
|
||
this._animation.parent = this;
|
||
}
|
||
}
|
||
sortMesh() {
|
||
this.children.sort((a, b) => a.orderIndex - b.orderIndex);
|
||
}
|
||
localVertices(vertices, container) {
|
||
let canvasinfo = this._model.canvasinfo;
|
||
let cox = canvasinfo.CanvasOriginX;
|
||
let coy = canvasinfo.CanvasOriginY;
|
||
let ppu = canvasinfo.PixelsPerUnit;
|
||
let result = container || new Float32Array(vertices.length);
|
||
for (let i = 0; i < vertices.length; i++) {
|
||
result[i] = i % 2 ? coy - vertices[i] * ppu : vertices[i] * ppu + cox;
|
||
}
|
||
return result;
|
||
}
|
||
setExpression(index, name) {
|
||
for (let i = this._exp_tracks.length; i <= index; i++) {
|
||
this._exp_tracks.push(null);
|
||
}
|
||
for (let i = 0; i <= this._data.Expressions.length - 1; i++) {
|
||
if (this._data.Expressions[i].Name == name) {
|
||
this._exp_tracks[index] = this._data.Expressions[i];
|
||
let _LSetFlg = false;
|
||
var _RSetFlg = false;
|
||
this._data.Expressions[i].Parameters.forEach(_Prm => {
|
||
if (_Prm.Id == "eyeOpenL") {
|
||
this.parent.blnk_LOpenPrm = _Prm.Value;
|
||
_LSetFlg = true;
|
||
}
|
||
if (_Prm.Id == "eyeOpenR") {
|
||
this.parent.blnk_ROpenPrm = _Prm.Value;
|
||
_RSetFlg = true;
|
||
}
|
||
});
|
||
if (!_LSetFlg) this.parent.blnk_LOpenPrm = this.parent.blnk_LBaseOpenPrm;
|
||
if (!_RSetFlg) this.parent.blnk_ROpenPrm = this.parent.blnk_RBaseOpenPrm;
|
||
}
|
||
}
|
||
}
|
||
delExpression(index) {
|
||
for (var i = this._exp_tracks.length; i <= index; i++) {
|
||
this._exp_tracks.push(null);
|
||
}
|
||
this._exp_tracks[index] = null;
|
||
}
|
||
update() {
|
||
if (this.parent._mdlAlpha == undefined) this.parent._mdlAlpha = 1;
|
||
if (this.parent._mdlAlpha < 0.00001) {
|
||
return;
|
||
}
|
||
//★Live2Dのビューワーと見え方を合わせる為、時刻制御(performance.now())では無く、フレーム制御に変更
|
||
let time = 0;
|
||
switch (L2D_Mode) {
|
||
case L2D_PFSMode.Nomal:
|
||
time = performance.now() / 1000;
|
||
break;
|
||
case L2D_PFSMode.FPS30:
|
||
time = this._updateTime + (1 / 60);
|
||
break;
|
||
case L2D_PFSMode.FPS60:
|
||
time = this._updateTime + (1 / 30);
|
||
break;
|
||
}
|
||
if (this._updateTime === 0) {
|
||
this._updateTime = time;
|
||
return;
|
||
}
|
||
let delta = time - this._updateTime;
|
||
if (!isFinite(delta) || delta <= 0 || delta > 1) {
|
||
delta = 1 / 60;
|
||
}
|
||
if (L2D_Mode == L2D_PFSMode.FPS30) {
|
||
this._fps30Counter = (this._fps30Counter || 0) + 1;
|
||
if (this._fps30Counter % 2 !== 0) {
|
||
delta = 0;
|
||
}
|
||
}
|
||
this.applyAnimation(delta);
|
||
this.applyPhysics(delta);
|
||
this._model.drawables.resetDynamicFlags();
|
||
this._model.update();
|
||
for (let etrack of this._exp_SetTracks) {
|
||
if (etrack == null) continue;
|
||
for (let i = 0; i <= etrack.Parameters.length - 1; i++) {
|
||
let _EditMode = etrack.Parameters[i].Blend;
|
||
let _id = etrack.Parameters[i].Id;
|
||
let _Setvalue = etrack.Parameters[i].Value;
|
||
switch (_EditMode) {
|
||
case "Add":
|
||
let index = this._model.parameters.ids.indexOf(_id);
|
||
let _value = this._model.parameters.values[index];
|
||
this._model.parameters.values[index] = _value - _Setvalue;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
this._exp_SetTracks = [];
|
||
for (let etrack of this._exp_tracks) {
|
||
if (etrack == null) continue;
|
||
for (let i = 0; i <= etrack.Parameters.length - 1; i++) {
|
||
let _EditMode = etrack.Parameters[i].Blend;
|
||
let _id = etrack.Parameters[i].Id;
|
||
let _Setvalue = etrack.Parameters[i].Value;
|
||
switch (_EditMode) {
|
||
case "Add":
|
||
let index = this._model.parameters.ids.indexOf(_id);
|
||
let _value = this._model.parameters.values[index];
|
||
this._model.parameters.values[index] = _value + _Setvalue;
|
||
break;
|
||
}
|
||
}
|
||
this._exp_SetTracks.push(etrack);
|
||
}
|
||
if ($gameSwitches.value(DownFpsSwt)) {
|
||
if (this.donwUpdateFlame == 0) {
|
||
this.updateMesh();
|
||
this.updateMask();
|
||
this.donwUpdateFlame = 1;
|
||
} else {
|
||
if (this.donwUpdateFlame == undefined) this.donwUpdateFlame = 5;
|
||
this.donwUpdateFlame--;
|
||
}
|
||
} else {
|
||
this.updateMesh();
|
||
this.updateMask();
|
||
}
|
||
this._updateTime = time;
|
||
if (this.NSet_ids == undefined) this.NSet_ids = [];
|
||
if (this.NSet_values == undefined) this.NSet_values = [];
|
||
for (let i = 0; i <= L2D_DelParams_Arr.length - 1; i++) {
|
||
if (L2D_DelParams_Arr[i]._modelId == this.parent._model) {
|
||
for (let j = 0; j <= L2D_DelParams_Arr[i]._ids.length - 1; j++) {
|
||
let _nSetNo = this.NSet_ids.indexOf(L2D_DelParams_Arr[i]._ids[j]);
|
||
if (_nSetNo != -1) {
|
||
this.NSet_ids.splice(_nSetNo, 1);
|
||
this.NSet_values.splice(_nSetNo, 1);
|
||
}
|
||
}
|
||
L2D_DelParams_Arr.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
for (let i = 0; i <= L2D_SetParams_Arr.length - 1; i++) {
|
||
if (L2D_SetParams_Arr[i]._modelId == this.parent._model) {
|
||
for (let j = 0; j <= L2D_SetParams_Arr[i]._ids.length - 1; j++) {
|
||
let _nSetNo = this.NSet_ids.indexOf(L2D_SetParams_Arr[i]._ids[j]);
|
||
if (_nSetNo != -1) {
|
||
this.NSet_values[_nSetNo] = L2D_SetParams_Arr[i]._values[j];
|
||
} else {
|
||
this.NSet_ids.push(L2D_SetParams_Arr[i]._ids[j]);
|
||
this.NSet_values.push(L2D_SetParams_Arr[i]._values[j]);
|
||
}
|
||
}
|
||
L2D_SetParams_Arr.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
for (let i = 0; i <= this.NSet_ids.length - 1; i++) {
|
||
let _nSetNo = this._model.parameters.ids.indexOf(this.NSet_ids[i]);
|
||
if (_nSetNo != -1) {
|
||
this._model.parameters.values[_nSetNo] = this.NSet_values[i];
|
||
} else {
|
||
this.NSet_ids.splice(i, 1);
|
||
this.NSet_values.splice(i, 1);
|
||
i--;
|
||
}
|
||
}
|
||
if ($gameSystem.L2D_SetParams_Arr == undefined) $gameSystem.L2D_SetParams_Arr = [];
|
||
for (let i = 0; i <= $gameSystem.L2D_SetParams_Arr.length - 1; i++) {
|
||
if ($gameSystem.L2D_SetParams_Arr[i]._modelId == this.parent._name) {
|
||
for (let j = 0; j <= $gameSystem.L2D_SetParams_Arr[i]._ids.length - 1; j++) {
|
||
let _CkId = $gameSystem.L2D_SetParams_Arr[i]._ids[j];
|
||
let _nSetNo = this._model.parameters.ids.indexOf(_CkId);
|
||
if (_nSetNo != -1) {
|
||
this._model.parameters.values[_nSetNo] = $gameSystem.L2D_SetParams_Arr[i]._values[j];
|
||
} else {
|
||
$gameSystem.L2D_SetParams_Arr[i]._ids.splice(j, 1);
|
||
$gameSystem.L2D_SetParams_Arr[i]._values.splice(j, 1);
|
||
j--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (L2D_SetParamsOne_Arr == undefined) L2D_SetParamsOne_Arr = [];
|
||
for (let i = 0; i <= L2D_SetParamsOne_Arr.length - 1; i++) {
|
||
if (L2D_SetParamsOne_Arr[i]._modelId == this.parent._name) {
|
||
for (let j = 0; j <= L2D_SetParamsOne_Arr[i]._ids.length - 1; j++) {
|
||
let _CkId = L2D_SetParamsOne_Arr[i]._ids[j];
|
||
let _nSetNo = this._model.parameters.ids.indexOf(_CkId);
|
||
if (_nSetNo != -1) {
|
||
this._model.parameters.values[_nSetNo] = L2D_SetParamsOne_Arr[i]._values[j];
|
||
L2D_SetParamsOne_Arr.splice(i, 1);
|
||
i--;
|
||
if (i == -1) break;
|
||
} else {
|
||
L2D_SetParamsOne_Arr[i]._ids.splice(j, 1);
|
||
L2D_SetParamsOne_Arr[i]._values.splice(j, 1);
|
||
j--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
const _bCloseFlame = 5;
|
||
const _bOpenFlame = 10;
|
||
if (this.parent.blnk_flg) {
|
||
this.parent.blnk_flame--;
|
||
var _CngParaL = this.parent.blnk_LOpenPrm;
|
||
var _CngParaR = this.parent.blnk_ROpenPrm;
|
||
if (this.parent.blnk_flame < 0) {
|
||
let WariMabL = this.parent.blnk_LClosePrm - this.parent.blnk_LOpenPrm;
|
||
let WariMabR = this.parent.blnk_RClosePrm - this.parent.blnk_ROpenPrm;
|
||
if (this.parent.blnk_LOpenPrm > this.parent.blnk_LClosePrm) this.parent.blnk_LClosePrm = this.parent.blnk_LOpenPrm;
|
||
if (this.parent.blnk_ROpenPrm > this.parent.blnk_RClosePrm) this.parent.blnk_RClosePrm = this.parent.blnk_ROpenPrm;
|
||
if (this.parent.blnk_flame >= -_bCloseFlame) {
|
||
let _Var = (-this.parent.blnk_flame);
|
||
_CngParaL = this.parent.blnk_LOpenPrm + (WariMabL * (_Var / 5));
|
||
_CngParaR = this.parent.blnk_ROpenPrm + (WariMabR * (_Var / 5));
|
||
} else if (this.parent.blnk_flame >= -(_bCloseFlame + _bOpenFlame)) {
|
||
let _Var = (-this.parent.blnk_flame) - _bCloseFlame;
|
||
_CngParaL = this.parent.blnk_LClosePrm - (WariMabL * (_Var / _bOpenFlame));
|
||
_CngParaR = this.parent.blnk_RClosePrm - (WariMabR * (_Var / _bOpenFlame));
|
||
} else if (this.parent.blnk_flame >= -16) {
|
||
if (Math.random() > 0.5 && !this.blink_dflg) {
|
||
this.parent.blnk_flame = 0;
|
||
this.blink_dflg = true;
|
||
} else {
|
||
this.parent.blnk_flame = Math.floor(Math.random() * 300 + 50);
|
||
this.blink_dflg = false;
|
||
}
|
||
}
|
||
}
|
||
if (this.parent.blnk_LIdNo != -1) {
|
||
this._model.parameters.values[this.parent.blnk_LIdNo] = _CngParaL;
|
||
}
|
||
if (this.parent.blnk_RIdNo != -1) {
|
||
this._model.parameters.values[this.parent.blnk_RIdNo] = _CngParaR;
|
||
}
|
||
}
|
||
for (let i = 0; i <= this._SEParams.length - 1; i++) {
|
||
let _idNo = this._model.parameters.ids.indexOf(this._SEParams[i]._SeName);
|
||
if (_idNo == -1) {
|
||
this._SEParams.splice(i, 1);
|
||
i--;
|
||
continue;
|
||
}
|
||
let _ckVar = this._model.parameters.values[_idNo];
|
||
if (!this._SEParams[i]._OnFlg) {
|
||
if (_ckVar >= 28) {
|
||
this._SEParams[i]._OnFlg = true;
|
||
L2D_SePlayEvArr.push(this._SEParams[i]._SeName)
|
||
}
|
||
} else {
|
||
if (_ckVar < 28) {
|
||
this._SEParams[i]._OnFlg = false;
|
||
}
|
||
}
|
||
}
|
||
for (let i = 0; i <= this._VoiceParams.length - 1; i++) {
|
||
let _idNo = this._model.parameters.ids.indexOf(this._VoiceParams[i]._VoiceName);
|
||
if (_idNo == -1) {
|
||
this._VoiceParams.splice(i, 1);
|
||
i--;
|
||
continue;
|
||
}
|
||
let _ckVar = this._model.parameters.values[_idNo];
|
||
if (!this._VoiceParams[i]._OnFlg) {
|
||
if (_ckVar >= 28) {
|
||
this._VoiceParams[i]._OnFlg = true;
|
||
L2D_VoicePlayEvArr.push(
|
||
[this._VoiceParams[i]._VoiceChara, this._VoiceParams[i]._VoiceName]
|
||
);
|
||
}
|
||
} else {
|
||
if (_ckVar < 28) {
|
||
this._VoiceParams[i]._OnFlg = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
updateMesh() {
|
||
let drawables = this._model.drawables;
|
||
let vertices = drawables.vertexPositions;
|
||
let opacities = drawables.opacities;
|
||
let renderOrders = drawables.renderOrders;
|
||
let dynamicFlags = drawables.dynamicFlags;
|
||
let needsSort = false;
|
||
this._meshes.forEach((mesh, index) => {
|
||
mesh.visible = !!(dynamicFlags[index] & 0x1);
|
||
mesh.alpha = opacities[index];
|
||
mesh.orderIndex = renderOrders[index];
|
||
if (dynamicFlags[index] & 0x10) {
|
||
needsSort = true;
|
||
}
|
||
if (dynamicFlags[index] & 0x20) {
|
||
this.localVertices(vertices[index], mesh.vertices);
|
||
}
|
||
if (mesh.visible) {
|
||
let uniforms = mesh.filters.find(filter => filter instanceof MultiplyScreenFilter).uniforms;
|
||
uniforms.multiplyColor = drawables.multiplyColors.slice(index * 4, index * 4 + 3);
|
||
uniforms.screenColor = drawables.screenColors.slice(index * 4, index * 4 + 3);
|
||
}
|
||
});
|
||
if (needsSort) {
|
||
this.sortMesh();
|
||
}
|
||
}
|
||
updateMask() {
|
||
for (let key in this._masks) {
|
||
this._masks[key].update();
|
||
}
|
||
}
|
||
applyPhysics(delta) {
|
||
if (this._physics) {
|
||
this._physics.apply(delta);
|
||
}
|
||
}
|
||
applyAnimation(delta) {
|
||
if (this._animation) {
|
||
this._animation.apply(delta);
|
||
}
|
||
}
|
||
snapshot() {
|
||
if (!this._animation) {
|
||
return null;
|
||
}
|
||
let parameters = {
|
||
ids: [...this._model.parameters.ids],
|
||
values: [...this._model.parameters.values]
|
||
};
|
||
let parts = {
|
||
ids: [...this._model.parts.ids],
|
||
opacities: [...this._model.parts.opacities]
|
||
};
|
||
let animation = {
|
||
tracks: [],
|
||
timeScale: this._animation.timeScale,
|
||
mixTime: {}
|
||
};
|
||
for (let key in this._animation.mixTime) {
|
||
animation.mixTime[key] = this._animation.mixTime[key];
|
||
}
|
||
this._animation.tracks.forEach((track, index) => {
|
||
let entries = [];
|
||
animation.tracks[index] = {
|
||
entries: entries,
|
||
active: track.active,
|
||
mixing: track.mixing,
|
||
weight: track.weight
|
||
};
|
||
try {
|
||
track.entries.forEach(entry => {
|
||
entries.push({
|
||
name: entry.name,
|
||
elapsed: entry.elapsed,
|
||
loop: entry.loop,
|
||
timeScale: entry.timeScale,
|
||
weight: entry.weight,
|
||
mixTime: entry.mixTime,
|
||
endTime: entry.endTime
|
||
});
|
||
});
|
||
} catch (e) {
|
||
console.log("Live2D::TrackEntryErr");
|
||
}
|
||
});
|
||
let physics = {};
|
||
if (this._physics != null) {
|
||
for (let key in this._physics.settings) {
|
||
physics[key] = [];
|
||
for (let vertex of this._physics.settings[key].vertices) {
|
||
physics[key].push({
|
||
position: {...vertex.position},
|
||
lastGravity: {...vertex.lastGravity},
|
||
velocity: {...vertex.velocity}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
return {
|
||
parameters: parameters,
|
||
parts: parts,
|
||
animation: animation,
|
||
physics: physics
|
||
};
|
||
}
|
||
restore(snapshot) {
|
||
if (!snapshot) {
|
||
return;
|
||
}
|
||
let parameters = snapshot.parameters;
|
||
let parts = snapshot.parts;
|
||
let animation = snapshot.animation;
|
||
let physics = snapshot.physics;
|
||
parameters.ids.forEach((id, index) => {
|
||
let _index = this._model.parameters.ids.indexOf(id);
|
||
if (_index >= 0) {
|
||
this._model.parameters.values[_index] = parameters.values[index];
|
||
}
|
||
});
|
||
parts.ids.forEach((id, index) => {
|
||
let _index = this._model.parts.ids.indexOf(id);
|
||
if (_index >= 0) {
|
||
this._model.parts.opacities[_index] = parts.opacities[index];
|
||
}
|
||
});
|
||
this._animation.setTimeScale(animation.timeScale);
|
||
for (let key in animation.mixTime) {
|
||
if (key == 'default') {
|
||
this._animation.setDefaultMix(animation.mixTime[key]);
|
||
} else {
|
||
let [from, to] = key.split(/,(?=[^,]+$)/);
|
||
this._animation.setMix(from, to, animation.mixTime[key]);
|
||
}
|
||
}
|
||
let motions = this._animation.motions;
|
||
this._animation.tracks.splice(0);
|
||
animation.tracks.forEach((trackData, index) => {
|
||
let track = new Track(trackData.active, trackData.mixing);
|
||
track.weight = trackData.weight;
|
||
for (let entryData of trackData.entries) {
|
||
let motion = entryData.name ? motions.find(motion => motion.name == entryData.name) : new Motion();
|
||
let entry = new Entry(motion, entryData.elapsed);
|
||
entry.loop = entryData.loop;
|
||
entry.timeScale = entryData.timeScale;
|
||
entry.weight = entryData.weight;
|
||
entry.mixTime = entryData.mixTime;
|
||
entry.endTime = entryData.endTime;
|
||
track.entries.push(entry);
|
||
}
|
||
this._animation.tracks[index] = track;
|
||
});
|
||
if (this._physics && physics) {
|
||
for (let key in physics) {
|
||
if (key in this._physics.settings) {
|
||
let vertices = this._physics.settings[key].vertices;
|
||
physics[key].forEach((vertex, index) => {
|
||
if (vertices[index]) {
|
||
Object.assign(vertices[index].position, vertex.position);
|
||
Object.assign(vertices[index].lastGravity, vertex.lastGravity);
|
||
Object.assign(vertices[index].velocity, vertex.velocity);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
Live2D.Mesh = Mesh;
|
||
Live2D.CopyMesh = CopyMesh;
|
||
Live2D.MaskMesh = MaskMesh;
|
||
Live2D.MeshMaskFilter = MeshMaskFilter;
|
||
Live2D.Vector2 = Vector2;
|
||
Live2D.Physics = Physics;
|
||
Live2D.Curve = Curve;
|
||
Live2D.Motion = Motion;
|
||
Live2D.Entry = Entry;
|
||
Live2D.Track = Track;
|
||
Live2D.Animation = Animation;
|
||
PIXI.Live2D = Live2D;
|
||
let Model3Parser = (function () {
|
||
let LoaderResource = PIXI.LoaderResource || PIXI.loaders.Resource;
|
||
LoaderResource.setExtensionXhrType('moc3', LoaderResource.XHR_RESPONSE_TYPE.BUFFER);
|
||
function isJson(resource) {
|
||
return resource.type == LoaderResource.TYPE.JSON;
|
||
}
|
||
function Model3Parser() {
|
||
return Model3Parser.use;
|
||
}
|
||
Model3Parser.use = function (resource, next) {
|
||
if (!isJson(resource) || !resource.data.FileReferences) {
|
||
return next();
|
||
}
|
||
let _loadFileName = resource.data.FileReferences.Moc.replace(".moc3", "");
|
||
Load_TextureArr.push(new _Load_Texture(_loadFileName));
|
||
let data = resource.data;
|
||
let fileReferences = resource.data.FileReferences;
|
||
let baseUrl = resource.url.replace(/[^/]+$/, '');
|
||
let loadOption = {parentResource: resource};
|
||
let live2dData = {
|
||
Version: data.Version,
|
||
Moc: null,
|
||
Textures: [],
|
||
Physics: null,
|
||
Pose: null,
|
||
UserData: null,
|
||
Motions: null,
|
||
Expressions: null,
|
||
Groups: data.Groups,
|
||
HitAreas: data.HitAreas
|
||
};
|
||
for (let index in fileReferences) {
|
||
if (index == 'Moc') {
|
||
let url = baseUrl + fileReferences.Moc;
|
||
this.add(`${resource.name}/Moc`, url, loadOption, function (resource) {
|
||
live2dData.Moc = new Live2DCubismCore.Moc(resource.data);
|
||
next();
|
||
});
|
||
} else if (index == 'Textures') {
|
||
for (let i = 0; i < fileReferences.Textures.length; i++) {
|
||
let url = baseUrl + fileReferences.Textures[i];
|
||
if (live2dData.Texture_url == undefined) live2dData.Texture_url = [];
|
||
live2dData.Texture_url.push(url)
|
||
live2dData.Textures.push(null);
|
||
this.add(`${resource.name}/Texture_${i}`, url, loadOption, function (resource) {
|
||
var _setIndex = live2dData.Texture_url.indexOf(resource.url);
|
||
live2dData.Textures[_setIndex] = resource.texture;
|
||
next();
|
||
});
|
||
Load_TextureArr[Load_TextureArr.length - 1]._TextureCnt++;
|
||
}
|
||
} else if (['Physics', 'Pose', 'UserData'].includes(index)) {
|
||
if (fileReferences[index] != null) {
|
||
let url = baseUrl + fileReferences[index];
|
||
this.add(`${resource.name}/${index}`, url, loadOption, function (resource) {
|
||
live2dData[index] = resource.data;
|
||
next();
|
||
});
|
||
}
|
||
} else if (index == 'Motions') {
|
||
live2dData.Motions = {};
|
||
for (let group in fileReferences.Motions) {
|
||
live2dData.Motions[group] = [];
|
||
let motion = fileReferences.Motions[group];
|
||
for (let i = 0; i < motion.length; i++) {
|
||
live2dData.Motions[group][i] = {
|
||
FadeInTime: motion[i].FadeInTime,
|
||
FadeOutTime: motion[i].FadeOutTime
|
||
};
|
||
let url = baseUrl + motion[i].File;
|
||
this.add(`${resource.name}/Motion/${group}_${i}`, url, loadOption, function (resource) {
|
||
live2dData.Motions[group][i].Group = group;
|
||
live2dData.Motions[group][i].Name = motion[i].File.replace("motions/", "").replace(".motion3.json", "");
|
||
//live2dData.Motions[group][i].Name = motion[i].Name || group + String(i + 1).padStart(2, '0');
|
||
live2dData.Motions[group][i].Data = resource.data;
|
||
next();
|
||
});
|
||
}
|
||
}
|
||
} else if (index == "Expressions") {
|
||
live2dData.Expressions = fileReferences.Expressions;
|
||
for (let i = 0; i < live2dData.Expressions.length; i++) {
|
||
live2dData.Expressions[i].Parameters = [];
|
||
let url = baseUrl + live2dData.Expressions[i].File;
|
||
let ename = live2dData.Expressions[i].Name;
|
||
this.add(`${resource.name}/Expression/${ename}`, url, loadOption, function (resource) {
|
||
live2dData.Expressions.forEach(_EXP => {
|
||
var _ckStrArr = resource.name.split('/');
|
||
if (_EXP.Name == _ckStrArr[_ckStrArr.length - 1]) _EXP.Parameters = resource.data.Parameters;
|
||
});
|
||
next();
|
||
});
|
||
}
|
||
}
|
||
}
|
||
resource.live2dData = live2dData;
|
||
next();
|
||
};
|
||
return Model3Parser;
|
||
})();
|
||
if (PIXI.Loader) {
|
||
PIXI.Loader.registerPlugin(Model3Parser);
|
||
} else {
|
||
PIXI.loaders.Loader.addPixiMiddleware(Model3Parser);
|
||
}
|
||
}();
|