6035 lines
230 KiB
JavaScript
Executable File
6035 lines
230 KiB
JavaScript
Executable File
var __pow = Math.pow;
|
|
var __async = (__this, __arguments, generator) => {
|
|
return new Promise((resolve, reject) => {
|
|
var fulfilled = (value) => {
|
|
try {
|
|
step(generator.next(value));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
};
|
|
var rejected = (value) => {
|
|
try {
|
|
step(generator.throw(value));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
};
|
|
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
});
|
|
};
|
|
(function(global, factory) {
|
|
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@pixi/utils"), require("@pixi/math"), require("@pixi/core"), require("@pixi/display")) : typeof define === "function" && define.amd ? define(["exports", "@pixi/utils", "@pixi/math", "@pixi/core", "@pixi/display"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory((global.PIXI = global.PIXI || {}, global.PIXI.live2d = global.PIXI.live2d || {}), global.PIXI.utils, global.PIXI, global.PIXI, global.PIXI));
|
|
})(this, function(exports2, utils, math, core, display) {
|
|
"use strict";
|
|
const LOGICAL_WIDTH = 2;
|
|
const LOGICAL_HEIGHT = 2;
|
|
var CubismConfig;
|
|
((CubismConfig2) => {
|
|
CubismConfig2.supportMoreMaskDivisions = true;
|
|
CubismConfig2.setOpacityFromMotion = false;
|
|
})(CubismConfig || (CubismConfig = {}));
|
|
exports2.config = void 0;
|
|
((config2) => {
|
|
config2.LOG_LEVEL_VERBOSE = 0;
|
|
config2.LOG_LEVEL_WARNING = 1;
|
|
config2.LOG_LEVEL_ERROR = 2;
|
|
config2.LOG_LEVEL_NONE = 999;
|
|
config2.logLevel = config2.LOG_LEVEL_WARNING;
|
|
config2.sound = true;
|
|
config2.motionSync = true;
|
|
config2.motionFadingDuration = 500;
|
|
config2.idleMotionFadingDuration = 2e3;
|
|
config2.expressionFadingDuration = 500;
|
|
config2.preserveExpressionOnMotion = true;
|
|
config2.cubism4 = CubismConfig;
|
|
})(exports2.config || (exports2.config = {}));
|
|
const VERSION = "0.4.0";
|
|
const logger = {
|
|
log(tag, ...messages) {
|
|
if (exports2.config.logLevel <= exports2.config.LOG_LEVEL_VERBOSE) {
|
|
console.log(`[${tag}]`, ...messages);
|
|
}
|
|
},
|
|
warn(tag, ...messages) {
|
|
if (exports2.config.logLevel <= exports2.config.LOG_LEVEL_WARNING) {
|
|
console.warn(`[${tag}]`, ...messages);
|
|
}
|
|
},
|
|
error(tag, ...messages) {
|
|
if (exports2.config.logLevel <= exports2.config.LOG_LEVEL_ERROR) {
|
|
console.error(`[${tag}]`, ...messages);
|
|
}
|
|
}
|
|
};
|
|
function clamp(num, lower, upper) {
|
|
return num < lower ? lower : num > upper ? upper : num;
|
|
}
|
|
function rand(min, max) {
|
|
return Math.random() * (max - min) + min;
|
|
}
|
|
function copyProperty(type, from, to, fromKey, toKey) {
|
|
const value = from[fromKey];
|
|
if (value !== null && typeof value === type) {
|
|
to[toKey] = value;
|
|
}
|
|
}
|
|
function copyArray(type, from, to, fromKey, toKey) {
|
|
const array = from[fromKey];
|
|
if (Array.isArray(array)) {
|
|
to[toKey] = array.filter((item) => item !== null && typeof item === type);
|
|
}
|
|
}
|
|
function applyMixins(derivedCtor, baseCtors) {
|
|
baseCtors.forEach((baseCtor) => {
|
|
Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
|
|
if (name !== "constructor") {
|
|
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function folderName(url) {
|
|
let lastSlashIndex = url.lastIndexOf("/");
|
|
if (lastSlashIndex != -1) {
|
|
url = url.slice(0, lastSlashIndex);
|
|
}
|
|
lastSlashIndex = url.lastIndexOf("/");
|
|
if (lastSlashIndex !== -1) {
|
|
url = url.slice(lastSlashIndex + 1);
|
|
}
|
|
return url;
|
|
}
|
|
function remove(array, item) {
|
|
const index = array.indexOf(item);
|
|
if (index !== -1) {
|
|
array.splice(index, 1);
|
|
}
|
|
}
|
|
class ExpressionManager extends utils.EventEmitter {
|
|
constructor(settings, options) {
|
|
super();
|
|
this.expressions = [];
|
|
this.reserveExpressionIndex = -1;
|
|
this.destroyed = false;
|
|
this.settings = settings;
|
|
this.tag = `ExpressionManager(${settings.name})`;
|
|
}
|
|
init() {
|
|
this.defaultExpression = this.createExpression({}, void 0);
|
|
this.currentExpression = this.defaultExpression;
|
|
this.stopAllExpressions();
|
|
}
|
|
loadExpression(index) {
|
|
return __async(this, null, function* () {
|
|
if (!this.definitions[index]) {
|
|
logger.warn(this.tag, `Undefined expression at [${index}]`);
|
|
return void 0;
|
|
}
|
|
if (this.expressions[index] === null) {
|
|
logger.warn(this.tag, `Cannot set expression at [${index}] because it's already failed in loading.`);
|
|
return void 0;
|
|
}
|
|
if (this.expressions[index]) {
|
|
return this.expressions[index];
|
|
}
|
|
const expression = yield this._loadExpression(index);
|
|
this.expressions[index] = expression;
|
|
return expression;
|
|
});
|
|
}
|
|
_loadExpression(index) {
|
|
throw new Error("Not implemented.");
|
|
}
|
|
setRandomExpression() {
|
|
return __async(this, null, function* () {
|
|
if (this.definitions.length) {
|
|
const availableIndices = [];
|
|
for (let i = 0; i < this.definitions.length; i++) {
|
|
if (this.expressions[i] !== null && this.expressions[i] !== this.currentExpression && i !== this.reserveExpressionIndex) {
|
|
availableIndices.push(i);
|
|
}
|
|
}
|
|
if (availableIndices.length) {
|
|
const index = Math.floor(Math.random() * availableIndices.length);
|
|
return this.setExpression(index);
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
resetExpression() {
|
|
this._setExpression(this.defaultExpression);
|
|
}
|
|
restoreExpression() {
|
|
this._setExpression(this.currentExpression);
|
|
}
|
|
setExpression(index) {
|
|
return __async(this, null, function* () {
|
|
if (typeof index !== "number") {
|
|
index = this.getExpressionIndex(index);
|
|
}
|
|
if (!(index > -1 && index < this.definitions.length)) {
|
|
return false;
|
|
}
|
|
if (index === this.expressions.indexOf(this.currentExpression)) {
|
|
return false;
|
|
}
|
|
this.reserveExpressionIndex = index;
|
|
const expression = yield this.loadExpression(index);
|
|
if (!expression || this.reserveExpressionIndex !== index) {
|
|
return false;
|
|
}
|
|
this.reserveExpressionIndex = -1;
|
|
this.currentExpression = expression;
|
|
this._setExpression(expression);
|
|
return true;
|
|
});
|
|
}
|
|
update(model, now) {
|
|
if (!this.isFinished()) {
|
|
return this.updateParameters(model, now);
|
|
}
|
|
return false;
|
|
}
|
|
destroy() {
|
|
this.destroyed = true;
|
|
this.emit("destroy");
|
|
const self2 = this;
|
|
self2.definitions = void 0;
|
|
self2.expressions = void 0;
|
|
}
|
|
}
|
|
const EPSILON = 0.01;
|
|
const MAX_SPEED = 40 / 7.5;
|
|
const ACCELERATION_TIME = 1 / (0.15 * 1e3);
|
|
class FocusController {
|
|
constructor() {
|
|
this.targetX = 0;
|
|
this.targetY = 0;
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.vx = 0;
|
|
this.vy = 0;
|
|
}
|
|
focus(x, y, instant = false) {
|
|
this.targetX = clamp(x, -1, 1);
|
|
this.targetY = clamp(y, -1, 1);
|
|
if (instant) {
|
|
this.x = this.targetX;
|
|
this.y = this.targetY;
|
|
}
|
|
}
|
|
update(dt) {
|
|
const dx = this.targetX - this.x;
|
|
const dy = this.targetY - this.y;
|
|
if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON)
|
|
return;
|
|
const d = Math.sqrt(__pow(dx, 2) + __pow(dy, 2));
|
|
const maxSpeed = MAX_SPEED / (1e3 / dt);
|
|
let ax = maxSpeed * (dx / d) - this.vx;
|
|
let ay = maxSpeed * (dy / d) - this.vy;
|
|
const a = Math.sqrt(__pow(ax, 2) + __pow(ay, 2));
|
|
const maxA = maxSpeed * ACCELERATION_TIME * dt;
|
|
if (a > maxA) {
|
|
ax *= maxA / a;
|
|
ay *= maxA / a;
|
|
}
|
|
this.vx += ax;
|
|
this.vy += ay;
|
|
const v = Math.sqrt(__pow(this.vx, 2) + __pow(this.vy, 2));
|
|
const maxV = 0.5 * (Math.sqrt(__pow(maxA, 2) + 8 * maxA * d) - maxA);
|
|
if (v > maxV) {
|
|
this.vx *= maxV / v;
|
|
this.vy *= maxV / v;
|
|
}
|
|
this.x += this.vx;
|
|
this.y += this.vy;
|
|
}
|
|
}
|
|
class ModelSettings {
|
|
constructor(json) {
|
|
this.json = json;
|
|
let url2 = json.url;
|
|
if (typeof url2 !== "string") {
|
|
throw new TypeError("The `url` field in settings JSON must be defined as a string.");
|
|
}
|
|
this.url = url2;
|
|
this.name = folderName(this.url);
|
|
}
|
|
resolveURL(path) {
|
|
return utils.url.resolve(this.url, path);
|
|
}
|
|
replaceFiles(replacer) {
|
|
this.moc = replacer(this.moc, "moc");
|
|
if (this.pose !== void 0) {
|
|
this.pose = replacer(this.pose, "pose");
|
|
}
|
|
if (this.physics !== void 0) {
|
|
this.physics = replacer(this.physics, "physics");
|
|
}
|
|
for (let i = 0; i < this.textures.length; i++) {
|
|
this.textures[i] = replacer(this.textures[i], `textures[${i}]`);
|
|
}
|
|
}
|
|
getDefinedFiles() {
|
|
const files = [];
|
|
this.replaceFiles((file) => {
|
|
files.push(file);
|
|
return file;
|
|
});
|
|
return files;
|
|
}
|
|
validateFiles(files) {
|
|
const assertFileExists = (expectedFile, shouldThrow) => {
|
|
const actualPath = this.resolveURL(expectedFile);
|
|
if (!files.includes(actualPath)) {
|
|
if (shouldThrow) {
|
|
throw new Error(`File "${expectedFile}" is defined in settings, but doesn't exist in given files`);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
const essentialFiles = [this.moc, ...this.textures];
|
|
essentialFiles.forEach((texture) => assertFileExists(texture, true));
|
|
const definedFiles = this.getDefinedFiles();
|
|
return definedFiles.filter((file) => assertFileExists(file, false));
|
|
}
|
|
}
|
|
var MotionPriority = /* @__PURE__ */ ((MotionPriority2) => {
|
|
MotionPriority2[MotionPriority2["NONE"] = 0] = "NONE";
|
|
MotionPriority2[MotionPriority2["IDLE"] = 1] = "IDLE";
|
|
MotionPriority2[MotionPriority2["NORMAL"] = 2] = "NORMAL";
|
|
MotionPriority2[MotionPriority2["FORCE"] = 3] = "FORCE";
|
|
return MotionPriority2;
|
|
})(MotionPriority || {});
|
|
class MotionState {
|
|
constructor() {
|
|
this.debug = false;
|
|
this.currentPriority = 0;
|
|
this.reservePriority = 0;
|
|
}
|
|
reserve(group, index, priority) {
|
|
if (priority <= 0) {
|
|
logger.log(this.tag, `Cannot start a motion with MotionPriority.NONE.`);
|
|
return false;
|
|
}
|
|
if (group === this.currentGroup && index === this.currentIndex) {
|
|
logger.log(this.tag, `Motion is already playing.`, this.dump(group, index));
|
|
return false;
|
|
}
|
|
if (group === this.reservedGroup && index === this.reservedIndex || group === this.reservedIdleGroup && index === this.reservedIdleIndex) {
|
|
logger.log(this.tag, `Motion is already reserved.`, this.dump(group, index));
|
|
return false;
|
|
}
|
|
if (priority === 1) {
|
|
if (this.currentPriority !== 0) {
|
|
logger.log(this.tag, `Cannot start idle motion because another motion is playing.`, this.dump(group, index));
|
|
return false;
|
|
}
|
|
if (this.reservedIdleGroup !== void 0) {
|
|
logger.log(this.tag, `Cannot start idle motion because another idle motion has reserved.`, this.dump(group, index));
|
|
return false;
|
|
}
|
|
this.setReservedIdle(group, index);
|
|
} else {
|
|
if (priority < 3) {
|
|
if (priority <= this.currentPriority) {
|
|
logger.log(this.tag, "Cannot start motion because another motion is playing as an equivalent or higher priority.", this.dump(group, index));
|
|
return false;
|
|
}
|
|
if (priority <= this.reservePriority) {
|
|
logger.log(this.tag, "Cannot start motion because another motion has reserved as an equivalent or higher priority.", this.dump(group, index));
|
|
return false;
|
|
}
|
|
}
|
|
this.setReserved(group, index, priority);
|
|
}
|
|
return true;
|
|
}
|
|
start(motion, group, index, priority) {
|
|
if (priority === 1) {
|
|
this.setReservedIdle(void 0, void 0);
|
|
if (this.currentPriority !== 0) {
|
|
logger.log(this.tag, "Cannot start idle motion because another motion is playing.", this.dump(group, index));
|
|
return false;
|
|
}
|
|
} else {
|
|
if (group !== this.reservedGroup || index !== this.reservedIndex) {
|
|
logger.log(this.tag, "Cannot start motion because another motion has taken the place.", this.dump(group, index));
|
|
return false;
|
|
}
|
|
this.setReserved(void 0, void 0, 0);
|
|
}
|
|
if (!motion) {
|
|
return false;
|
|
}
|
|
this.setCurrent(group, index, priority);
|
|
return true;
|
|
}
|
|
complete() {
|
|
this.setCurrent(void 0, void 0, 0);
|
|
}
|
|
setCurrent(group, index, priority) {
|
|
this.currentPriority = priority;
|
|
this.currentGroup = group;
|
|
this.currentIndex = index;
|
|
}
|
|
setReserved(group, index, priority) {
|
|
this.reservePriority = priority;
|
|
this.reservedGroup = group;
|
|
this.reservedIndex = index;
|
|
}
|
|
setReservedIdle(group, index) {
|
|
this.reservedIdleGroup = group;
|
|
this.reservedIdleIndex = index;
|
|
}
|
|
isActive(group, index) {
|
|
return group === this.currentGroup && index === this.currentIndex || group === this.reservedGroup && index === this.reservedIndex || group === this.reservedIdleGroup && index === this.reservedIdleIndex;
|
|
}
|
|
reset() {
|
|
this.setCurrent(void 0, void 0, 0);
|
|
this.setReserved(void 0, void 0, 0);
|
|
this.setReservedIdle(void 0, void 0);
|
|
}
|
|
shouldRequestIdleMotion() {
|
|
return this.currentGroup === void 0 && this.reservedIdleGroup === void 0;
|
|
}
|
|
shouldOverrideExpression() {
|
|
return !exports2.config.preserveExpressionOnMotion && this.currentPriority > 1;
|
|
}
|
|
dump(requestedGroup, requestedIndex) {
|
|
if (this.debug) {
|
|
const keys = [
|
|
"currentPriority",
|
|
"reservePriority",
|
|
"currentGroup",
|
|
"currentIndex",
|
|
"reservedGroup",
|
|
"reservedIndex",
|
|
"reservedIdleGroup",
|
|
"reservedIdleIndex"
|
|
];
|
|
return `
|
|
<Requested> group = "${requestedGroup}", index = ${requestedIndex}
|
|
` + keys.map((key) => "[" + key + "] " + this[key]).join("\n");
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
const TAG$2 = "SoundManager";
|
|
const VOLUME = 0.5;
|
|
class SoundManager {
|
|
static get volume() {
|
|
return this._volume;
|
|
}
|
|
static set volume(value) {
|
|
this._volume = (value > 1 ? 1 : value < 0 ? 0 : value) || 0;
|
|
this.audios.forEach((audio) => audio.volume = this._volume);
|
|
}
|
|
static add(file, onFinish, onError) {
|
|
const audio = new Audio(file);
|
|
audio.volume = this._volume;
|
|
audio.preload = "auto";
|
|
audio.addEventListener("ended", () => {
|
|
this.dispose(audio);
|
|
onFinish == null ? void 0 : onFinish();
|
|
});
|
|
audio.addEventListener("error", (e) => {
|
|
this.dispose(audio);
|
|
logger.warn(TAG$2, `Error occurred on "${file}"`, e.error);
|
|
onError == null ? void 0 : onError(e.error);
|
|
});
|
|
this.audios.push(audio);
|
|
return audio;
|
|
}
|
|
static play(audio) {
|
|
return new Promise((resolve, reject) => {
|
|
var _a;
|
|
(_a = audio.play()) == null ? void 0 : _a.catch((e) => {
|
|
audio.dispatchEvent(new ErrorEvent("error", { error: e }));
|
|
reject(e);
|
|
});
|
|
if (audio.readyState === audio.HAVE_ENOUGH_DATA) {
|
|
resolve();
|
|
} else {
|
|
audio.addEventListener("canplaythrough", resolve);
|
|
}
|
|
});
|
|
}
|
|
static dispose(audio) {
|
|
audio.pause();
|
|
audio.removeAttribute("src");
|
|
remove(this.audios, audio);
|
|
}
|
|
static destroy() {
|
|
for (let i = this.audios.length - 1; i >= 0; i--) {
|
|
this.dispose(this.audios[i]);
|
|
}
|
|
}
|
|
}
|
|
SoundManager.audios = [];
|
|
SoundManager._volume = VOLUME;
|
|
var MotionPreloadStrategy = /* @__PURE__ */ ((MotionPreloadStrategy2) => {
|
|
MotionPreloadStrategy2["ALL"] = "ALL";
|
|
MotionPreloadStrategy2["IDLE"] = "IDLE";
|
|
MotionPreloadStrategy2["NONE"] = "NONE";
|
|
return MotionPreloadStrategy2;
|
|
})(MotionPreloadStrategy || {});
|
|
class MotionManager extends utils.EventEmitter {
|
|
constructor(settings, options) {
|
|
super();
|
|
this.motionGroups = {};
|
|
this.state = new MotionState();
|
|
this.playing = false;
|
|
this.destroyed = false;
|
|
this.settings = settings;
|
|
this.tag = `MotionManager(${settings.name})`;
|
|
this.state.tag = this.tag;
|
|
}
|
|
init(options) {
|
|
if (options == null ? void 0 : options.idleMotionGroup) {
|
|
this.groups.idle = options.idleMotionGroup;
|
|
}
|
|
this.setupMotions(options);
|
|
this.stopAllMotions();
|
|
}
|
|
setupMotions(options) {
|
|
for (const group of Object.keys(this.definitions)) {
|
|
this.motionGroups[group] = [];
|
|
}
|
|
let groups;
|
|
switch (options == null ? void 0 : options.motionPreload) {
|
|
case "NONE":
|
|
return;
|
|
case "ALL":
|
|
groups = Object.keys(this.definitions);
|
|
break;
|
|
case "IDLE":
|
|
default:
|
|
groups = [this.groups.idle];
|
|
break;
|
|
}
|
|
for (const group of groups) {
|
|
if (this.definitions[group]) {
|
|
for (let i = 0; i < this.definitions[group].length; i++) {
|
|
this.loadMotion(group, i).then();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
loadMotion(group, index) {
|
|
return __async(this, null, function* () {
|
|
var _a;
|
|
if (!((_a = this.definitions[group]) == null ? void 0 : _a[index])) {
|
|
logger.warn(this.tag, `Undefined motion at "${group}"[${index}]`);
|
|
return void 0;
|
|
}
|
|
if (this.motionGroups[group][index] === null) {
|
|
logger.warn(this.tag, `Cannot start motion at "${group}"[${index}] because it's already failed in loading.`);
|
|
return void 0;
|
|
}
|
|
if (this.motionGroups[group][index]) {
|
|
return this.motionGroups[group][index];
|
|
}
|
|
const motion = yield this._loadMotion(group, index);
|
|
if (this.destroyed) {
|
|
return;
|
|
}
|
|
this.motionGroups[group][index] = motion != null ? motion : null;
|
|
return motion;
|
|
});
|
|
}
|
|
_loadMotion(group, index) {
|
|
throw new Error("Not implemented.");
|
|
}
|
|
startMotion(_0, _1) {
|
|
return __async(this, arguments, function* (group, index, priority = MotionPriority.NORMAL) {
|
|
var _a;
|
|
if (!this.state.reserve(group, index, priority)) {
|
|
return false;
|
|
}
|
|
const definition = (_a = this.definitions[group]) == null ? void 0 : _a[index];
|
|
if (!definition) {
|
|
return false;
|
|
}
|
|
if (this.currentAudio) {
|
|
SoundManager.dispose(this.currentAudio);
|
|
}
|
|
let audio;
|
|
if (exports2.config.sound) {
|
|
const soundURL = this.getSoundFile(definition);
|
|
if (soundURL) {
|
|
try {
|
|
audio = SoundManager.add(this.settings.resolveURL(soundURL), () => this.currentAudio = void 0, () => this.currentAudio = void 0);
|
|
this.currentAudio = audio;
|
|
} catch (e) {
|
|
logger.warn(this.tag, "Failed to create audio", soundURL, e);
|
|
}
|
|
}
|
|
}
|
|
const motion = yield this.loadMotion(group, index);
|
|
if (audio) {
|
|
const readyToPlay = SoundManager.play(audio).catch((e) => logger.warn(this.tag, "Failed to play audio", audio.src, e));
|
|
if (exports2.config.motionSync) {
|
|
yield readyToPlay;
|
|
}
|
|
}
|
|
if (!this.state.start(motion, group, index, priority)) {
|
|
if (audio) {
|
|
SoundManager.dispose(audio);
|
|
this.currentAudio = void 0;
|
|
}
|
|
return false;
|
|
}
|
|
logger.log(this.tag, "Start motion:", this.getMotionName(definition));
|
|
this.emit("motionStart", group, index, audio);
|
|
if (this.state.shouldOverrideExpression()) {
|
|
this.expressionManager && this.expressionManager.resetExpression();
|
|
}
|
|
this.playing = true;
|
|
this._startMotion(motion);
|
|
return true;
|
|
});
|
|
}
|
|
startRandomMotion(group, priority) {
|
|
return __async(this, null, function* () {
|
|
const groupDefs = this.definitions[group];
|
|
if (groupDefs == null ? void 0 : groupDefs.length) {
|
|
const availableIndices = [];
|
|
for (let i = 0; i < groupDefs.length; i++) {
|
|
if (this.motionGroups[group][i] !== null && !this.state.isActive(group, i)) {
|
|
availableIndices.push(i);
|
|
}
|
|
}
|
|
if (availableIndices.length) {
|
|
const index = Math.floor(Math.random() * availableIndices.length);
|
|
return this.startMotion(group, availableIndices[index], priority);
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
stopAllMotions() {
|
|
this._stopAllMotions();
|
|
this.state.reset();
|
|
if (this.currentAudio) {
|
|
SoundManager.dispose(this.currentAudio);
|
|
this.currentAudio = void 0;
|
|
}
|
|
}
|
|
update(model, now) {
|
|
var _a;
|
|
if (this.isFinished()) {
|
|
if (this.playing) {
|
|
this.playing = false;
|
|
this.emit("motionFinish");
|
|
}
|
|
if (this.state.shouldOverrideExpression()) {
|
|
(_a = this.expressionManager) == null ? void 0 : _a.restoreExpression();
|
|
}
|
|
this.state.complete();
|
|
if (this.state.shouldRequestIdleMotion()) {
|
|
this.startRandomMotion(this.groups.idle, MotionPriority.IDLE);
|
|
}
|
|
}
|
|
return this.updateParameters(model, now);
|
|
}
|
|
destroy() {
|
|
var _a;
|
|
this.destroyed = true;
|
|
this.emit("destroy");
|
|
this.stopAllMotions();
|
|
(_a = this.expressionManager) == null ? void 0 : _a.destroy();
|
|
const self2 = this;
|
|
self2.definitions = void 0;
|
|
self2.motionGroups = void 0;
|
|
}
|
|
}
|
|
const tempBounds = { x: 0, y: 0, width: 0, height: 0 };
|
|
class InternalModel extends utils.EventEmitter {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.focusController = new FocusController();
|
|
this.originalWidth = 0;
|
|
this.originalHeight = 0;
|
|
this.width = 0;
|
|
this.height = 0;
|
|
this.localTransform = new math.Matrix();
|
|
this.drawingMatrix = new math.Matrix();
|
|
this.hitAreas = {};
|
|
this.textureFlipY = false;
|
|
this.viewport = [0, 0, 0, 0];
|
|
this.destroyed = false;
|
|
}
|
|
init() {
|
|
this.setupLayout();
|
|
this.setupHitAreas();
|
|
}
|
|
setupLayout() {
|
|
const self2 = this;
|
|
const size = this.getSize();
|
|
self2.originalWidth = size[0];
|
|
self2.originalHeight = size[1];
|
|
const layout = Object.assign({
|
|
width: LOGICAL_WIDTH,
|
|
height: LOGICAL_HEIGHT
|
|
}, this.getLayout());
|
|
this.localTransform.scale(layout.width / LOGICAL_WIDTH, layout.height / LOGICAL_HEIGHT);
|
|
self2.width = this.originalWidth * this.localTransform.a;
|
|
self2.height = this.originalHeight * this.localTransform.d;
|
|
const offsetX = layout.x !== void 0 && layout.x - layout.width / 2 || layout.centerX !== void 0 && layout.centerX || layout.left !== void 0 && layout.left - layout.width / 2 || layout.right !== void 0 && layout.right + layout.width / 2 || 0;
|
|
const offsetY = layout.y !== void 0 && layout.y - layout.height / 2 || layout.centerY !== void 0 && layout.centerY || layout.top !== void 0 && layout.top - layout.height / 2 || layout.bottom !== void 0 && layout.bottom + layout.height / 2 || 0;
|
|
this.localTransform.translate(this.width * offsetX, -this.height * offsetY);
|
|
}
|
|
setupHitAreas() {
|
|
const definitions = this.getHitAreaDefs().filter((hitArea) => hitArea.index >= 0);
|
|
for (const def of definitions) {
|
|
this.hitAreas[def.name] = def;
|
|
}
|
|
}
|
|
hitTest(x, y) {
|
|
return Object.keys(this.hitAreas).filter((hitAreaName) => this.isHit(hitAreaName, x, y));
|
|
}
|
|
isHit(hitAreaName, x, y) {
|
|
if (!this.hitAreas[hitAreaName]) {
|
|
return false;
|
|
}
|
|
const drawIndex = this.hitAreas[hitAreaName].index;
|
|
const bounds = this.getDrawableBounds(drawIndex, tempBounds);
|
|
return bounds.x <= x && x <= bounds.x + bounds.width && bounds.y <= y && y <= bounds.y + bounds.height;
|
|
}
|
|
getDrawableBounds(index, bounds) {
|
|
const vertices = this.getDrawableVertices(index);
|
|
let left = vertices[0];
|
|
let right = vertices[0];
|
|
let top = vertices[1];
|
|
let bottom = vertices[1];
|
|
for (let i = 0; i < vertices.length; i += 2) {
|
|
const vx = vertices[i];
|
|
const vy = vertices[i + 1];
|
|
left = Math.min(vx, left);
|
|
right = Math.max(vx, right);
|
|
top = Math.min(vy, top);
|
|
bottom = Math.max(vy, bottom);
|
|
}
|
|
bounds != null ? bounds : bounds = {};
|
|
bounds.x = left;
|
|
bounds.y = top;
|
|
bounds.width = right - left;
|
|
bounds.height = bottom - top;
|
|
return bounds;
|
|
}
|
|
updateTransform(transform) {
|
|
this.drawingMatrix.copyFrom(transform).append(this.localTransform);
|
|
}
|
|
update(dt, now) {
|
|
this.focusController.update(dt);
|
|
}
|
|
destroy() {
|
|
this.destroyed = true;
|
|
this.emit("destroy");
|
|
this.motionManager.destroy();
|
|
this.motionManager = void 0;
|
|
}
|
|
}
|
|
const TAG$1 = "XHRLoader";
|
|
class NetworkError extends Error {
|
|
constructor(message, url, status, aborted = false) {
|
|
super(message);
|
|
this.url = url;
|
|
this.status = status;
|
|
this.aborted = aborted;
|
|
}
|
|
}
|
|
const _XHRLoader = class {
|
|
static createXHR(target, url, type, onload, onerror) {
|
|
const xhr = new XMLHttpRequest();
|
|
_XHRLoader.allXhrSet.add(xhr);
|
|
if (target) {
|
|
let xhrSet = _XHRLoader.xhrMap.get(target);
|
|
if (!xhrSet) {
|
|
xhrSet = /* @__PURE__ */ new Set([xhr]);
|
|
_XHRLoader.xhrMap.set(target, xhrSet);
|
|
} else {
|
|
xhrSet.add(xhr);
|
|
}
|
|
if (!target.listeners("destroy").includes(_XHRLoader.cancelXHRs)) {
|
|
target.once("destroy", _XHRLoader.cancelXHRs);
|
|
}
|
|
}
|
|
xhr.open("GET", url);
|
|
xhr.responseType = type;
|
|
xhr.onload = () => {
|
|
if ((xhr.status === 200 || xhr.status === 0) && xhr.response) {
|
|
onload(xhr.response);
|
|
} else {
|
|
xhr.onerror();
|
|
}
|
|
};
|
|
xhr.onerror = () => {
|
|
logger.warn(TAG$1, `Failed to load resource as ${xhr.responseType} (Status ${xhr.status}): ${url}`);
|
|
onerror(new NetworkError("Network error.", url, xhr.status));
|
|
};
|
|
xhr.onabort = () => onerror(new NetworkError("Aborted.", url, xhr.status, true));
|
|
xhr.onloadend = () => {
|
|
var _a;
|
|
_XHRLoader.allXhrSet.delete(xhr);
|
|
if (target) {
|
|
(_a = _XHRLoader.xhrMap.get(target)) == null ? void 0 : _a.delete(xhr);
|
|
}
|
|
};
|
|
return xhr;
|
|
}
|
|
static cancelXHRs() {
|
|
var _a;
|
|
(_a = _XHRLoader.xhrMap.get(this)) == null ? void 0 : _a.forEach((xhr) => {
|
|
xhr.abort();
|
|
_XHRLoader.allXhrSet.delete(xhr);
|
|
});
|
|
_XHRLoader.xhrMap.delete(this);
|
|
}
|
|
static release() {
|
|
_XHRLoader.allXhrSet.forEach((xhr) => xhr.abort());
|
|
_XHRLoader.allXhrSet.clear();
|
|
_XHRLoader.xhrMap = /* @__PURE__ */ new WeakMap();
|
|
}
|
|
};
|
|
let XHRLoader = _XHRLoader;
|
|
XHRLoader.xhrMap = /* @__PURE__ */ new WeakMap();
|
|
XHRLoader.allXhrSet = /* @__PURE__ */ new Set();
|
|
XHRLoader.loader = (context, next) => {
|
|
return new Promise((resolve, reject) => {
|
|
const xhr = _XHRLoader.createXHR(context.target, context.settings ? context.settings.resolveURL(context.url) : context.url, context.type, (data) => {
|
|
context.result = data;
|
|
resolve();
|
|
}, reject);
|
|
xhr.send();
|
|
});
|
|
};
|
|
function runMiddlewares(middleware, context) {
|
|
let index = -1;
|
|
return dispatch(0);
|
|
function dispatch(i, err) {
|
|
if (err)
|
|
return Promise.reject(err);
|
|
if (i <= index)
|
|
return Promise.reject(new Error("next() called multiple times"));
|
|
index = i;
|
|
const fn = middleware[i];
|
|
if (!fn)
|
|
return Promise.resolve();
|
|
try {
|
|
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
|
|
} catch (err2) {
|
|
return Promise.reject(err2);
|
|
}
|
|
}
|
|
}
|
|
class Live2DLoader {
|
|
static load(context) {
|
|
return runMiddlewares(this.middlewares, context).then(() => context.result);
|
|
}
|
|
}
|
|
Live2DLoader.middlewares = [XHRLoader.loader];
|
|
function createTexture(url, options = {}) {
|
|
var _a;
|
|
const textureOptions = { resourceOptions: { crossorigin: options.crossOrigin } };
|
|
if (core.Texture.fromURL) {
|
|
return core.Texture.fromURL(url, textureOptions).catch((e) => {
|
|
if (e instanceof Error) {
|
|
throw e;
|
|
}
|
|
const err = new Error("Texture loading error");
|
|
err.event = e;
|
|
throw err;
|
|
});
|
|
}
|
|
textureOptions.resourceOptions.autoLoad = false;
|
|
const texture = core.Texture.from(url, textureOptions);
|
|
if (texture.baseTexture.valid) {
|
|
return Promise.resolve(texture);
|
|
}
|
|
const resource = texture.baseTexture.resource;
|
|
(_a = resource._live2d_load) != null ? _a : resource._live2d_load = new Promise((resolve, reject) => {
|
|
const errorHandler = (event) => {
|
|
resource.source.removeEventListener("error", errorHandler);
|
|
const err = new Error("Texture loading error");
|
|
err.event = event;
|
|
reject(err);
|
|
};
|
|
resource.source.addEventListener("error", errorHandler);
|
|
resource.load().then(() => resolve(texture)).catch(errorHandler);
|
|
});
|
|
return resource._live2d_load;
|
|
}
|
|
const TAG = "Live2DFactory";
|
|
const urlToJSON = (context, next) => __async(this, null, function* () {
|
|
if (typeof context.source === "string") {
|
|
const data = yield Live2DLoader.load({
|
|
url: context.source,
|
|
type: "json",
|
|
target: context.live2dModel
|
|
});
|
|
data.url = context.source;
|
|
context.source = data;
|
|
context.live2dModel.emit("settingsJSONLoaded", data);
|
|
}
|
|
return next();
|
|
});
|
|
const jsonToSettings = (context, next) => __async(this, null, function* () {
|
|
if (context.source instanceof ModelSettings) {
|
|
context.settings = context.source;
|
|
return next();
|
|
} else if (typeof context.source === "object") {
|
|
const runtime = Live2DFactory.findRuntime(context.source);
|
|
if (runtime) {
|
|
const settings = runtime.createModelSettings(context.source);
|
|
context.settings = settings;
|
|
context.live2dModel.emit("settingsLoaded", settings);
|
|
return next();
|
|
}
|
|
}
|
|
throw new TypeError("Unknown settings format.");
|
|
});
|
|
const waitUntilReady = (context, next) => {
|
|
if (context.settings) {
|
|
const runtime = Live2DFactory.findRuntime(context.settings);
|
|
if (runtime) {
|
|
return runtime.ready().then(next);
|
|
}
|
|
}
|
|
return next();
|
|
};
|
|
const setupOptionals = (context, next) => __async(this, null, function* () {
|
|
yield next();
|
|
const internalModel = context.internalModel;
|
|
if (internalModel) {
|
|
const settings = context.settings;
|
|
const runtime = Live2DFactory.findRuntime(settings);
|
|
if (runtime) {
|
|
const tasks = [];
|
|
if (settings.pose) {
|
|
tasks.push(Live2DLoader.load({
|
|
settings,
|
|
url: settings.pose,
|
|
type: "json",
|
|
target: internalModel
|
|
}).then((data) => {
|
|
internalModel.pose = runtime.createPose(internalModel.coreModel, data);
|
|
context.live2dModel.emit("poseLoaded", internalModel.pose);
|
|
}).catch((e) => {
|
|
context.live2dModel.emit("poseLoadError", e);
|
|
logger.warn(TAG, "Failed to load pose.", e);
|
|
}));
|
|
}
|
|
if (settings.physics) {
|
|
tasks.push(Live2DLoader.load({
|
|
settings,
|
|
url: settings.physics,
|
|
type: "json",
|
|
target: internalModel
|
|
}).then((data) => {
|
|
internalModel.physics = runtime.createPhysics(internalModel.coreModel, data);
|
|
context.live2dModel.emit("physicsLoaded", internalModel.physics);
|
|
}).catch((e) => {
|
|
context.live2dModel.emit("physicsLoadError", e);
|
|
logger.warn(TAG, "Failed to load physics.", e);
|
|
}));
|
|
}
|
|
if (tasks.length) {
|
|
yield Promise.all(tasks);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
const setupEssentials = (context, next) => __async(this, null, function* () {
|
|
if (context.settings) {
|
|
const live2DModel = context.live2dModel;
|
|
const textureLoadings = context.settings.textures.map((tex) => {
|
|
const url = context.settings.resolveURL(tex);
|
|
return createTexture(url, { crossOrigin: context.options.crossOrigin });
|
|
});
|
|
yield next();
|
|
if (context.internalModel) {
|
|
live2DModel.internalModel = context.internalModel;
|
|
live2DModel.emit("modelLoaded", context.internalModel);
|
|
} else {
|
|
throw new TypeError("Missing internal model.");
|
|
}
|
|
live2DModel.textures = yield Promise.all(textureLoadings);
|
|
live2DModel.emit("textureLoaded", live2DModel.textures);
|
|
} else {
|
|
throw new TypeError("Missing settings.");
|
|
}
|
|
});
|
|
const createInternalModel = (context, next) => __async(this, null, function* () {
|
|
const settings = context.settings;
|
|
if (settings instanceof ModelSettings) {
|
|
const runtime = Live2DFactory.findRuntime(settings);
|
|
if (!runtime) {
|
|
throw new TypeError("Unknown model settings.");
|
|
}
|
|
const modelData = yield Live2DLoader.load({
|
|
settings,
|
|
url: settings.moc,
|
|
type: "arraybuffer",
|
|
target: context.live2dModel
|
|
});
|
|
if (!runtime.isValidMoc(modelData)) {
|
|
throw new Error("Invalid moc data");
|
|
}
|
|
const coreModel = runtime.createCoreModel(modelData);
|
|
context.internalModel = runtime.createInternalModel(coreModel, settings, context.options);
|
|
return next();
|
|
}
|
|
throw new TypeError("Missing settings.");
|
|
});
|
|
const _Live2DFactory = class {
|
|
static registerRuntime(runtime) {
|
|
_Live2DFactory.runtimes.push(runtime);
|
|
_Live2DFactory.runtimes.sort((a, b) => b.version - a.version);
|
|
}
|
|
static findRuntime(source) {
|
|
for (const runtime of _Live2DFactory.runtimes) {
|
|
if (runtime.test(source)) {
|
|
return runtime;
|
|
}
|
|
}
|
|
}
|
|
static setupLive2DModel(live2dModel, source, options) {
|
|
return __async(this, null, function* () {
|
|
const textureLoaded = new Promise((resolve) => live2dModel.once("textureLoaded", resolve));
|
|
const modelLoaded = new Promise((resolve) => live2dModel.once("modelLoaded", resolve));
|
|
const readyEventEmitted = Promise.all([textureLoaded, modelLoaded]).then(() => live2dModel.emit("ready"));
|
|
yield runMiddlewares(_Live2DFactory.live2DModelMiddlewares, {
|
|
live2dModel,
|
|
source,
|
|
options: options || {}
|
|
});
|
|
yield readyEventEmitted;
|
|
live2dModel.emit("load");
|
|
});
|
|
}
|
|
static loadMotion(motionManager, group, index) {
|
|
var _a, _b;
|
|
const handleError = (e) => motionManager.emit("motionLoadError", group, index, e);
|
|
try {
|
|
const definition = (_a = motionManager.definitions[group]) == null ? void 0 : _a[index];
|
|
if (!definition) {
|
|
return Promise.resolve(void 0);
|
|
}
|
|
if (!motionManager.listeners("destroy").includes(_Live2DFactory.releaseTasks)) {
|
|
motionManager.once("destroy", _Live2DFactory.releaseTasks);
|
|
}
|
|
let tasks = _Live2DFactory.motionTasksMap.get(motionManager);
|
|
if (!tasks) {
|
|
tasks = {};
|
|
_Live2DFactory.motionTasksMap.set(motionManager, tasks);
|
|
}
|
|
let taskGroup = tasks[group];
|
|
if (!taskGroup) {
|
|
taskGroup = [];
|
|
tasks[group] = taskGroup;
|
|
}
|
|
const path = motionManager.getMotionFile(definition);
|
|
(_b = taskGroup[index]) != null ? _b : taskGroup[index] = Live2DLoader.load({
|
|
url: path,
|
|
settings: motionManager.settings,
|
|
type: motionManager.motionDataType,
|
|
target: motionManager
|
|
}).then((data) => {
|
|
var _a2;
|
|
const taskGroup2 = (_a2 = _Live2DFactory.motionTasksMap.get(motionManager)) == null ? void 0 : _a2[group];
|
|
if (taskGroup2) {
|
|
delete taskGroup2[index];
|
|
}
|
|
const motion = motionManager.createMotion(data, group, definition);
|
|
motionManager.emit("motionLoaded", group, index, motion);
|
|
return motion;
|
|
}).catch((e) => {
|
|
logger.warn(motionManager.tag, `Failed to load motion: ${path}
|
|
`, e);
|
|
handleError(e);
|
|
});
|
|
return taskGroup[index];
|
|
} catch (e) {
|
|
logger.warn(motionManager.tag, `Failed to load motion at "${group}"[${index}]
|
|
`, e);
|
|
handleError(e);
|
|
}
|
|
return Promise.resolve(void 0);
|
|
}
|
|
static loadExpression(expressionManager, index) {
|
|
var _a;
|
|
const handleError = (e) => expressionManager.emit("expressionLoadError", index, e);
|
|
try {
|
|
const definition = expressionManager.definitions[index];
|
|
if (!definition) {
|
|
return Promise.resolve(void 0);
|
|
}
|
|
if (!expressionManager.listeners("destroy").includes(_Live2DFactory.releaseTasks)) {
|
|
expressionManager.once("destroy", _Live2DFactory.releaseTasks);
|
|
}
|
|
let tasks = _Live2DFactory.expressionTasksMap.get(expressionManager);
|
|
if (!tasks) {
|
|
tasks = [];
|
|
_Live2DFactory.expressionTasksMap.set(expressionManager, tasks);
|
|
}
|
|
const path = expressionManager.getExpressionFile(definition);
|
|
(_a = tasks[index]) != null ? _a : tasks[index] = Live2DLoader.load({
|
|
url: path,
|
|
settings: expressionManager.settings,
|
|
type: "json",
|
|
target: expressionManager
|
|
}).then((data) => {
|
|
const tasks2 = _Live2DFactory.expressionTasksMap.get(expressionManager);
|
|
if (tasks2) {
|
|
delete tasks2[index];
|
|
}
|
|
const expression = expressionManager.createExpression(data, definition);
|
|
expressionManager.emit("expressionLoaded", index, expression);
|
|
return expression;
|
|
}).catch((e) => {
|
|
logger.warn(expressionManager.tag, `Failed to load expression: ${path}
|
|
`, e);
|
|
handleError(e);
|
|
});
|
|
return tasks[index];
|
|
} catch (e) {
|
|
logger.warn(expressionManager.tag, `Failed to load expression at [${index}]
|
|
`, e);
|
|
handleError(e);
|
|
}
|
|
return Promise.resolve(void 0);
|
|
}
|
|
static releaseTasks() {
|
|
if (this instanceof MotionManager) {
|
|
_Live2DFactory.motionTasksMap.delete(this);
|
|
} else {
|
|
_Live2DFactory.expressionTasksMap.delete(this);
|
|
}
|
|
}
|
|
};
|
|
let Live2DFactory = _Live2DFactory;
|
|
Live2DFactory.runtimes = [];
|
|
Live2DFactory.urlToJSON = urlToJSON;
|
|
Live2DFactory.jsonToSettings = jsonToSettings;
|
|
Live2DFactory.waitUntilReady = waitUntilReady;
|
|
Live2DFactory.setupOptionals = setupOptionals;
|
|
Live2DFactory.setupEssentials = setupEssentials;
|
|
Live2DFactory.createInternalModel = createInternalModel;
|
|
Live2DFactory.live2DModelMiddlewares = [
|
|
urlToJSON,
|
|
jsonToSettings,
|
|
waitUntilReady,
|
|
setupOptionals,
|
|
setupEssentials,
|
|
createInternalModel
|
|
];
|
|
Live2DFactory.motionTasksMap = /* @__PURE__ */ new WeakMap();
|
|
Live2DFactory.expressionTasksMap = /* @__PURE__ */ new WeakMap();
|
|
MotionManager.prototype["_loadMotion"] = function(group, index) {
|
|
return Live2DFactory.loadMotion(this, group, index);
|
|
};
|
|
ExpressionManager.prototype["_loadExpression"] = function(index) {
|
|
return Live2DFactory.loadExpression(this, index);
|
|
};
|
|
class InteractionMixin {
|
|
constructor() {
|
|
this._autoInteract = false;
|
|
}
|
|
get autoInteract() {
|
|
return this._autoInteract;
|
|
}
|
|
set autoInteract(autoInteract) {
|
|
if (autoInteract !== this._autoInteract) {
|
|
if (autoInteract) {
|
|
this.on("pointertap", onTap, this);
|
|
} else {
|
|
this.off("pointertap", onTap, this);
|
|
}
|
|
this._autoInteract = autoInteract;
|
|
}
|
|
}
|
|
registerInteraction(manager) {
|
|
if (manager !== this.interactionManager) {
|
|
this.unregisterInteraction();
|
|
if (this._autoInteract && manager) {
|
|
this.interactionManager = manager;
|
|
manager.on("pointermove", onPointerMove, this);
|
|
}
|
|
}
|
|
}
|
|
unregisterInteraction() {
|
|
var _a;
|
|
if (this.interactionManager) {
|
|
(_a = this.interactionManager) == null ? void 0 : _a.off("pointermove", onPointerMove, this);
|
|
this.interactionManager = void 0;
|
|
}
|
|
}
|
|
}
|
|
function onTap(event) {
|
|
this.tap(event.data.global.x, event.data.global.y);
|
|
}
|
|
function onPointerMove(event) {
|
|
this.focus(event.data.global.x, event.data.global.y);
|
|
}
|
|
class Live2DTransform extends math.Transform {
|
|
}
|
|
const tempPoint = new math.Point();
|
|
const tempMatrix$1 = new math.Matrix();
|
|
let tickerRef;
|
|
class Live2DModel extends display.Container {
|
|
constructor(options) {
|
|
super();
|
|
this.tag = "Live2DModel(uninitialized)";
|
|
this.textures = [];
|
|
this.transform = new Live2DTransform();
|
|
this.anchor = new math.ObservablePoint(this.onAnchorChange, this, 0, 0);
|
|
this.glContextID = -1;
|
|
this.elapsedTime = performance.now();
|
|
this.deltaTime = 0;
|
|
this._autoUpdate = false;
|
|
this.once("modelLoaded", () => this.init(options));
|
|
}
|
|
static from(source, options) {
|
|
const model = new this(options);
|
|
return Live2DFactory.setupLive2DModel(model, source, options).then(() => model);
|
|
}
|
|
static fromSync(source, options) {
|
|
const model = new this(options);
|
|
Live2DFactory.setupLive2DModel(model, source, options).then(options == null ? void 0 : options.onLoad).catch(options == null ? void 0 : options.onError);
|
|
return model;
|
|
}
|
|
static registerTicker(tickerClass) {
|
|
tickerRef = tickerClass;
|
|
}
|
|
get autoUpdate() {
|
|
return this._autoUpdate;
|
|
}
|
|
set autoUpdate(autoUpdate) {
|
|
var _a;
|
|
tickerRef || (tickerRef = (_a = window.PIXI) == null ? void 0 : _a.Ticker);
|
|
if (autoUpdate) {
|
|
if (!this._destroyed) {
|
|
if (tickerRef) {
|
|
tickerRef.shared.add(this.onTickerUpdate, this);
|
|
this._autoUpdate = true;
|
|
} else {
|
|
logger.warn(this.tag, "No Ticker registered, please call Live2DModel.registerTicker(Ticker).");
|
|
}
|
|
}
|
|
} else {
|
|
tickerRef == null ? void 0 : tickerRef.shared.remove(this.onTickerUpdate, this);
|
|
this._autoUpdate = false;
|
|
}
|
|
}
|
|
init(options) {
|
|
this.tag = `Live2DModel(${this.internalModel.settings.name})`;
|
|
const _options = Object.assign({
|
|
autoUpdate: true,
|
|
autoInteract: true
|
|
}, options);
|
|
if (_options.autoInteract) {
|
|
this.interactive = true;
|
|
}
|
|
this.autoInteract = _options.autoInteract;
|
|
this.autoUpdate = _options.autoUpdate;
|
|
}
|
|
onAnchorChange() {
|
|
this.pivot.set(this.anchor.x * this.internalModel.width, this.anchor.y * this.internalModel.height);
|
|
}
|
|
motion(group, index, priority) {
|
|
return index === void 0 ? this.internalModel.motionManager.startRandomMotion(group, priority) : this.internalModel.motionManager.startMotion(group, index, priority);
|
|
}
|
|
expression(id) {
|
|
if (this.internalModel.motionManager.expressionManager) {
|
|
return id === void 0 ? this.internalModel.motionManager.expressionManager.setRandomExpression() : this.internalModel.motionManager.expressionManager.setExpression(id);
|
|
}
|
|
return Promise.resolve(false);
|
|
}
|
|
focus(x, y, instant = false) {
|
|
tempPoint.x = x;
|
|
tempPoint.y = y;
|
|
this.toModelPosition(tempPoint, tempPoint, true);
|
|
let tx = tempPoint.x / this.internalModel.originalWidth * 2 - 1;
|
|
let ty = tempPoint.y / this.internalModel.originalHeight * 2 - 1;
|
|
let radian = Math.atan2(ty, tx);
|
|
this.internalModel.focusController.focus(Math.cos(radian), -Math.sin(radian), instant);
|
|
}
|
|
tap(x, y) {
|
|
const hitAreaNames = this.hitTest(x, y);
|
|
if (hitAreaNames.length) {
|
|
logger.log(this.tag, `Hit`, hitAreaNames);
|
|
this.emit("hit", hitAreaNames);
|
|
}
|
|
}
|
|
hitTest(x, y) {
|
|
tempPoint.x = x;
|
|
tempPoint.y = y;
|
|
this.toModelPosition(tempPoint, tempPoint);
|
|
return this.internalModel.hitTest(tempPoint.x, tempPoint.y);
|
|
}
|
|
toModelPosition(position, result = position.clone(), skipUpdate) {
|
|
if (!skipUpdate) {
|
|
this._recursivePostUpdateTransform();
|
|
if (!this.parent) {
|
|
this.parent = this._tempDisplayObjectParent;
|
|
this.displayObjectUpdateTransform();
|
|
this.parent = null;
|
|
} else {
|
|
this.displayObjectUpdateTransform();
|
|
}
|
|
}
|
|
this.transform.worldTransform.applyInverse(position, result);
|
|
this.internalModel.localTransform.applyInverse(result, result);
|
|
return result;
|
|
}
|
|
containsPoint(point) {
|
|
return this.getBounds(true).contains(point.x, point.y);
|
|
}
|
|
_calculateBounds() {
|
|
this._bounds.addFrame(this.transform, 0, 0, this.internalModel.width, this.internalModel.height);
|
|
}
|
|
onTickerUpdate() {
|
|
this.update(tickerRef.shared.deltaMS);
|
|
}
|
|
update(dt) {
|
|
this.deltaTime += dt;
|
|
this.elapsedTime += dt;
|
|
}
|
|
_render(renderer) {
|
|
this.registerInteraction(renderer.plugins.interaction);
|
|
renderer.batch.reset();
|
|
renderer.geometry.reset();
|
|
renderer.shader.reset();
|
|
renderer.state.reset();
|
|
let shouldUpdateTexture = false;
|
|
if (this.glContextID !== renderer.CONTEXT_UID) {
|
|
this.glContextID = renderer.CONTEXT_UID;
|
|
this.internalModel.updateWebGLContext(renderer.gl, this.glContextID);
|
|
shouldUpdateTexture = true;
|
|
}
|
|
for (let i = 0; i < this.textures.length; i++) {
|
|
const texture = this.textures[i];
|
|
if (!texture.valid) {
|
|
continue;
|
|
}
|
|
if (shouldUpdateTexture || !texture.baseTexture._glTextures[this.glContextID]) {
|
|
renderer.gl.pixelStorei(WebGLRenderingContext.UNPACK_FLIP_Y_WEBGL, this.internalModel.textureFlipY);
|
|
renderer.texture.bind(texture.baseTexture, 0);
|
|
}
|
|
this.internalModel.bindTexture(i, texture.baseTexture._glTextures[this.glContextID].texture);
|
|
texture.baseTexture.touched = renderer.textureGC.count;
|
|
}
|
|
const viewport = renderer.framebuffer.viewport;
|
|
this.internalModel.viewport = [viewport.x, viewport.y, viewport.width, viewport.height];
|
|
if (this.deltaTime) {
|
|
this.internalModel.update(this.deltaTime, this.elapsedTime);
|
|
this.deltaTime = 0;
|
|
}
|
|
const internalTransform = tempMatrix$1.copyFrom(renderer.globalUniforms.uniforms.projectionMatrix).append(this.worldTransform);
|
|
this.internalModel.updateTransform(internalTransform);
|
|
this.internalModel.draw(renderer.gl);
|
|
renderer.state.reset();
|
|
renderer.texture.reset();
|
|
}
|
|
destroy(options) {
|
|
this.emit("destroy");
|
|
this.autoUpdate = false;
|
|
this.unregisterInteraction();
|
|
if (options == null ? void 0 : options.texture) {
|
|
this.textures.forEach((texture) => texture.destroy(options.baseTexture));
|
|
}
|
|
this.internalModel.destroy();
|
|
super.destroy(options);
|
|
}
|
|
}
|
|
applyMixins(Live2DModel, [InteractionMixin]);
|
|
const _FileLoader = class {
|
|
static resolveURL(settingsURL, filePath) {
|
|
var _a;
|
|
const resolved = (_a = _FileLoader.filesMap[settingsURL]) == null ? void 0 : _a[filePath];
|
|
if (resolved === void 0) {
|
|
throw new Error("Cannot find this file from uploaded files: " + filePath);
|
|
}
|
|
return resolved;
|
|
}
|
|
static upload(files, settings) {
|
|
return __async(this, null, function* () {
|
|
const fileMap = {};
|
|
for (const definedFile of settings.getDefinedFiles()) {
|
|
const actualPath = decodeURI(utils.url.resolve(settings.url, definedFile));
|
|
const actualFile = files.find((file) => file.webkitRelativePath === actualPath);
|
|
if (actualFile) {
|
|
fileMap[definedFile] = URL.createObjectURL(actualFile);
|
|
}
|
|
}
|
|
_FileLoader.filesMap[settings._objectURL] = fileMap;
|
|
});
|
|
}
|
|
static createSettings(files) {
|
|
return __async(this, null, function* () {
|
|
const settingsFile = files.find((file) => file.name.endsWith("model.json") || file.name.endsWith("model3.json"));
|
|
if (!settingsFile) {
|
|
throw new TypeError("Settings file not found");
|
|
}
|
|
const settingsText = yield _FileLoader.readText(settingsFile);
|
|
const settingsJSON = JSON.parse(settingsText);
|
|
settingsJSON.url = settingsFile.webkitRelativePath;
|
|
const runtime = Live2DFactory.findRuntime(settingsJSON);
|
|
if (!runtime) {
|
|
throw new Error("Unknown settings JSON");
|
|
}
|
|
const settings = runtime.createModelSettings(settingsJSON);
|
|
settings._objectURL = URL.createObjectURL(settingsFile);
|
|
return settings;
|
|
});
|
|
}
|
|
static readText(file) {
|
|
return __async(this, null, function* () {
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => resolve(reader.result);
|
|
reader.onerror = reject;
|
|
reader.readAsText(file, "utf8");
|
|
});
|
|
});
|
|
}
|
|
};
|
|
let FileLoader = _FileLoader;
|
|
FileLoader.filesMap = {};
|
|
FileLoader.factory = (context, next) => __async(this, null, function* () {
|
|
if (Array.isArray(context.source) && context.source[0] instanceof File) {
|
|
const files = context.source;
|
|
let settings = files.settings;
|
|
if (!settings) {
|
|
settings = yield _FileLoader.createSettings(files);
|
|
} else if (!settings._objectURL) {
|
|
throw new Error('"_objectURL" must be specified in ModelSettings');
|
|
}
|
|
settings.validateFiles(files.map((file) => encodeURI(file.webkitRelativePath)));
|
|
yield _FileLoader.upload(files, settings);
|
|
settings.resolveURL = function(url) {
|
|
return _FileLoader.resolveURL(this._objectURL, url);
|
|
};
|
|
context.source = settings;
|
|
context.live2dModel.once("modelLoaded", (internalModel) => {
|
|
internalModel.once("destroy", function() {
|
|
const objectURL = this.settings._objectURL;
|
|
URL.revokeObjectURL(objectURL);
|
|
if (_FileLoader.filesMap[objectURL]) {
|
|
for (const resourceObjectURL of Object.values(_FileLoader.filesMap[objectURL])) {
|
|
URL.revokeObjectURL(resourceObjectURL);
|
|
}
|
|
}
|
|
delete _FileLoader.filesMap[objectURL];
|
|
});
|
|
});
|
|
}
|
|
return next();
|
|
});
|
|
Live2DFactory.live2DModelMiddlewares.unshift(FileLoader.factory);
|
|
const _ZipLoader = class {
|
|
static unzip(reader, settings) {
|
|
return __async(this, null, function* () {
|
|
const filePaths = yield _ZipLoader.getFilePaths(reader);
|
|
const requiredFilePaths = [];
|
|
for (const definedFile of settings.getDefinedFiles()) {
|
|
const actualPath = decodeURI(utils.url.resolve(settings.url, definedFile));
|
|
if (filePaths.includes(actualPath)) {
|
|
requiredFilePaths.push(actualPath);
|
|
}
|
|
}
|
|
const files = yield _ZipLoader.getFiles(reader, requiredFilePaths);
|
|
for (let i = 0; i < files.length; i++) {
|
|
const path = requiredFilePaths[i];
|
|
const file = files[i];
|
|
Object.defineProperty(file, "webkitRelativePath", {
|
|
value: path
|
|
});
|
|
}
|
|
return files;
|
|
});
|
|
}
|
|
static createSettings(reader) {
|
|
return __async(this, null, function* () {
|
|
const filePaths = yield _ZipLoader.getFilePaths(reader);
|
|
const settingsFilePath = filePaths.find((path) => path.endsWith("model.json") || path.endsWith("model3.json"));
|
|
if (!settingsFilePath) {
|
|
throw new Error("Settings file not found");
|
|
}
|
|
const settingsText = yield _ZipLoader.readText(reader, settingsFilePath);
|
|
if (!settingsText) {
|
|
throw new Error("Empty settings file: " + settingsFilePath);
|
|
}
|
|
const settingsJSON = JSON.parse(settingsText);
|
|
settingsJSON.url = settingsFilePath;
|
|
const runtime = Live2DFactory.findRuntime(settingsJSON);
|
|
if (!runtime) {
|
|
throw new Error("Unknown settings JSON");
|
|
}
|
|
return runtime.createModelSettings(settingsJSON);
|
|
});
|
|
}
|
|
static zipReader(data, url) {
|
|
return __async(this, null, function* () {
|
|
throw new Error("Not implemented");
|
|
});
|
|
}
|
|
static getFilePaths(reader) {
|
|
return __async(this, null, function* () {
|
|
throw new Error("Not implemented");
|
|
});
|
|
}
|
|
static getFiles(reader, paths) {
|
|
return __async(this, null, function* () {
|
|
throw new Error("Not implemented");
|
|
});
|
|
}
|
|
static readText(reader, path) {
|
|
return __async(this, null, function* () {
|
|
throw new Error("Not implemented");
|
|
});
|
|
}
|
|
static releaseReader(reader) {
|
|
}
|
|
};
|
|
let ZipLoader = _ZipLoader;
|
|
ZipLoader.ZIP_PROTOCOL = "zip://";
|
|
ZipLoader.uid = 0;
|
|
ZipLoader.factory = (context, next) => __async(this, null, function* () {
|
|
const source = context.source;
|
|
let sourceURL;
|
|
let zipBlob;
|
|
let settings;
|
|
if (typeof source === "string" && (source.endsWith(".zip") || source.startsWith(_ZipLoader.ZIP_PROTOCOL))) {
|
|
if (source.startsWith(_ZipLoader.ZIP_PROTOCOL)) {
|
|
sourceURL = source.slice(_ZipLoader.ZIP_PROTOCOL.length);
|
|
} else {
|
|
sourceURL = source;
|
|
}
|
|
zipBlob = yield Live2DLoader.load({
|
|
url: sourceURL,
|
|
type: "blob",
|
|
target: context.live2dModel
|
|
});
|
|
} else if (Array.isArray(source) && source.length === 1 && source[0] instanceof File && source[0].name.endsWith(".zip")) {
|
|
zipBlob = source[0];
|
|
sourceURL = URL.createObjectURL(zipBlob);
|
|
settings = source.settings;
|
|
}
|
|
if (zipBlob) {
|
|
if (!zipBlob.size) {
|
|
throw new Error("Empty zip file");
|
|
}
|
|
const reader = yield _ZipLoader.zipReader(zipBlob, sourceURL);
|
|
if (!settings) {
|
|
settings = yield _ZipLoader.createSettings(reader);
|
|
}
|
|
settings._objectURL = _ZipLoader.ZIP_PROTOCOL + _ZipLoader.uid + "/" + settings.url;
|
|
const files = yield _ZipLoader.unzip(reader, settings);
|
|
files.settings = settings;
|
|
context.source = files;
|
|
if (sourceURL.startsWith("blob:")) {
|
|
context.live2dModel.once("modelLoaded", (internalModel) => {
|
|
internalModel.once("destroy", function() {
|
|
URL.revokeObjectURL(sourceURL);
|
|
});
|
|
});
|
|
}
|
|
_ZipLoader.releaseReader(reader);
|
|
}
|
|
return next();
|
|
});
|
|
Live2DFactory.live2DModelMiddlewares.unshift(ZipLoader.factory);
|
|
if (!window.Live2D) {
|
|
throw new Error("Could not find Cubism 2 runtime. This plugin requires live2d.min.js to be loaded.");
|
|
}
|
|
const originalUpdateParam = Live2DMotion.prototype.updateParam;
|
|
Live2DMotion.prototype.updateParam = function(model, entry) {
|
|
originalUpdateParam.call(this, model, entry);
|
|
if (entry.isFinished() && this.onFinishHandler) {
|
|
this.onFinishHandler(this);
|
|
delete this.onFinishHandler;
|
|
}
|
|
};
|
|
class Live2DExpression extends AMotion {
|
|
constructor(json) {
|
|
super();
|
|
this.params = [];
|
|
this.setFadeIn(json.fade_in > 0 ? json.fade_in : exports2.config.expressionFadingDuration);
|
|
this.setFadeOut(json.fade_out > 0 ? json.fade_out : exports2.config.expressionFadingDuration);
|
|
if (Array.isArray(json.params)) {
|
|
json.params.forEach((param) => {
|
|
const calc = param.calc || "add";
|
|
if (calc === "add") {
|
|
const defaultValue = param.def || 0;
|
|
param.val -= defaultValue;
|
|
} else if (calc === "mult") {
|
|
const defaultValue = param.def || 1;
|
|
param.val /= defaultValue;
|
|
}
|
|
this.params.push({
|
|
calc,
|
|
val: param.val,
|
|
id: param.id
|
|
});
|
|
});
|
|
}
|
|
}
|
|
updateParamExe(model, time, weight, motionQueueEnt) {
|
|
this.params.forEach((param) => {
|
|
model.setParamFloat(param.id, param.val * weight);
|
|
});
|
|
}
|
|
}
|
|
class Cubism2ExpressionManager extends ExpressionManager {
|
|
constructor(settings, options) {
|
|
var _a;
|
|
super(settings, options);
|
|
this.queueManager = new MotionQueueManager();
|
|
this.definitions = (_a = this.settings.expressions) != null ? _a : [];
|
|
this.init();
|
|
}
|
|
isFinished() {
|
|
return this.queueManager.isFinished();
|
|
}
|
|
getExpressionIndex(name) {
|
|
return this.definitions.findIndex((def) => def.name === name);
|
|
}
|
|
getExpressionFile(definition) {
|
|
return definition.file;
|
|
}
|
|
createExpression(data, definition) {
|
|
return new Live2DExpression(data);
|
|
}
|
|
_setExpression(motion) {
|
|
return this.queueManager.startMotion(motion);
|
|
}
|
|
stopAllExpressions() {
|
|
this.queueManager.stopAllMotions();
|
|
}
|
|
updateParameters(model, dt) {
|
|
return this.queueManager.updateParam(model);
|
|
}
|
|
}
|
|
class Cubism2MotionManager extends MotionManager {
|
|
constructor(settings, options) {
|
|
super(settings, options);
|
|
this.groups = { idle: "idle" };
|
|
this.motionDataType = "arraybuffer";
|
|
this.queueManager = new MotionQueueManager();
|
|
this.definitions = this.settings.motions;
|
|
this.init(options);
|
|
}
|
|
init(options) {
|
|
super.init(options);
|
|
if (this.settings.expressions) {
|
|
this.expressionManager = new Cubism2ExpressionManager(this.settings, options);
|
|
}
|
|
}
|
|
isFinished() {
|
|
return this.queueManager.isFinished();
|
|
}
|
|
createMotion(data, group, definition) {
|
|
const motion = Live2DMotion.loadMotion(data);
|
|
const defaultFadingDuration = group === this.groups.idle ? exports2.config.idleMotionFadingDuration : exports2.config.motionFadingDuration;
|
|
motion.setFadeIn(definition.fade_in > 0 ? definition.fade_in : defaultFadingDuration);
|
|
motion.setFadeOut(definition.fade_out > 0 ? definition.fade_out : defaultFadingDuration);
|
|
return motion;
|
|
}
|
|
getMotionFile(definition) {
|
|
return definition.file;
|
|
}
|
|
getMotionName(definition) {
|
|
return definition.file;
|
|
}
|
|
getSoundFile(definition) {
|
|
return definition.sound;
|
|
}
|
|
_startMotion(motion, onFinish) {
|
|
motion.onFinishHandler = onFinish;
|
|
this.queueManager.stopAllMotions();
|
|
return this.queueManager.startMotion(motion);
|
|
}
|
|
_stopAllMotions() {
|
|
this.queueManager.stopAllMotions();
|
|
}
|
|
updateParameters(model, now) {
|
|
return this.queueManager.updateParam(model);
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.queueManager = void 0;
|
|
}
|
|
}
|
|
class Live2DEyeBlink {
|
|
constructor(coreModel) {
|
|
this.coreModel = coreModel;
|
|
this.blinkInterval = 4e3;
|
|
this.closingDuration = 100;
|
|
this.closedDuration = 50;
|
|
this.openingDuration = 150;
|
|
this.eyeState = 0;
|
|
this.eyeParamValue = 1;
|
|
this.closedTimer = 0;
|
|
this.nextBlinkTimeLeft = this.blinkInterval;
|
|
this.leftParam = coreModel.getParamIndex("PARAM_EYE_L_OPEN");
|
|
this.rightParam = coreModel.getParamIndex("PARAM_EYE_R_OPEN");
|
|
}
|
|
setEyeParams(value) {
|
|
this.eyeParamValue = clamp(value, 0, 1);
|
|
this.coreModel.setParamFloat(this.leftParam, this.eyeParamValue);
|
|
this.coreModel.setParamFloat(this.rightParam, this.eyeParamValue);
|
|
}
|
|
update(dt) {
|
|
switch (this.eyeState) {
|
|
case 0:
|
|
this.nextBlinkTimeLeft -= dt;
|
|
if (this.nextBlinkTimeLeft < 0) {
|
|
this.eyeState = 1;
|
|
this.nextBlinkTimeLeft = this.blinkInterval + this.closingDuration + this.closedDuration + this.openingDuration + rand(0, 2e3);
|
|
}
|
|
break;
|
|
case 1:
|
|
this.setEyeParams(this.eyeParamValue + dt / this.closingDuration);
|
|
if (this.eyeParamValue <= 0) {
|
|
this.eyeState = 2;
|
|
this.closedTimer = 0;
|
|
}
|
|
break;
|
|
case 2:
|
|
this.closedTimer += dt;
|
|
if (this.closedTimer >= this.closedDuration) {
|
|
this.eyeState = 3;
|
|
}
|
|
break;
|
|
case 3:
|
|
this.setEyeParams(this.eyeParamValue + dt / this.openingDuration);
|
|
if (this.eyeParamValue >= 1) {
|
|
this.eyeState = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const tempMatrixArray = new Float32Array([
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1
|
|
]);
|
|
class Cubism2InternalModel extends InternalModel {
|
|
constructor(coreModel, settings, options) {
|
|
super();
|
|
this.textureFlipY = true;
|
|
this.drawDataCount = 0;
|
|
this.disableCulling = false;
|
|
this.coreModel = coreModel;
|
|
this.settings = settings;
|
|
this.motionManager = new Cubism2MotionManager(settings, options);
|
|
this.eyeBlink = new Live2DEyeBlink(coreModel);
|
|
this.eyeballXParamIndex = coreModel.getParamIndex("PARAM_EYE_BALL_X");
|
|
this.eyeballYParamIndex = coreModel.getParamIndex("PARAM_EYE_BALL_Y");
|
|
this.angleXParamIndex = coreModel.getParamIndex("PARAM_ANGLE_X");
|
|
this.angleYParamIndex = coreModel.getParamIndex("PARAM_ANGLE_Y");
|
|
this.angleZParamIndex = coreModel.getParamIndex("PARAM_ANGLE_Z");
|
|
this.bodyAngleXParamIndex = coreModel.getParamIndex("PARAM_BODY_ANGLE_X");
|
|
this.breathParamIndex = coreModel.getParamIndex("PARAM_BREATH");
|
|
this.init();
|
|
}
|
|
init() {
|
|
super.init();
|
|
if (this.settings.initParams) {
|
|
this.settings.initParams.forEach(({ id, value }) => this.coreModel.setParamFloat(id, value));
|
|
}
|
|
if (this.settings.initOpacities) {
|
|
this.settings.initOpacities.forEach(({ id, value }) => this.coreModel.setPartsOpacity(id, value));
|
|
}
|
|
this.coreModel.saveParam();
|
|
const arr = this.coreModel.getModelContext()._$aS;
|
|
if (arr == null ? void 0 : arr.length) {
|
|
this.drawDataCount = arr.length;
|
|
}
|
|
let culling = this.coreModel.drawParamWebGL.culling;
|
|
Object.defineProperty(this.coreModel.drawParamWebGL, "culling", {
|
|
set: (v) => culling = v,
|
|
get: () => this.disableCulling ? false : culling
|
|
});
|
|
const clipManager = this.coreModel.getModelContext().clipManager;
|
|
const originalSetupClip = clipManager.setupClip;
|
|
clipManager.setupClip = (modelContext, drawParam) => {
|
|
originalSetupClip.call(clipManager, modelContext, drawParam);
|
|
drawParam.gl.viewport(...this.viewport);
|
|
};
|
|
}
|
|
getSize() {
|
|
return [this.coreModel.getCanvasWidth(), this.coreModel.getCanvasHeight()];
|
|
}
|
|
getLayout() {
|
|
const layout = {};
|
|
if (this.settings.layout) {
|
|
for (const key of Object.keys(this.settings.layout)) {
|
|
let commonKey = key;
|
|
if (key === "center_x") {
|
|
commonKey = "centerX";
|
|
} else if (key === "center_y") {
|
|
commonKey = "centerY";
|
|
}
|
|
layout[commonKey] = this.settings.layout[key];
|
|
}
|
|
}
|
|
return layout;
|
|
}
|
|
updateWebGLContext(gl, glContextID) {
|
|
const drawParamWebGL = this.coreModel.drawParamWebGL;
|
|
drawParamWebGL.firstDraw = true;
|
|
drawParamWebGL.setGL(gl);
|
|
drawParamWebGL.glno = glContextID;
|
|
for (const prop in drawParamWebGL) {
|
|
if (drawParamWebGL.hasOwnProperty(prop) && drawParamWebGL[prop] instanceof WebGLBuffer) {
|
|
drawParamWebGL[prop] = null;
|
|
}
|
|
}
|
|
const clipManager = this.coreModel.getModelContext().clipManager;
|
|
clipManager.curFrameNo = glContextID;
|
|
const framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
|
|
clipManager.getMaskRenderTexture();
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
}
|
|
bindTexture(index, texture) {
|
|
this.coreModel.setTexture(index, texture);
|
|
}
|
|
getHitAreaDefs() {
|
|
var _a;
|
|
return ((_a = this.settings.hitAreas) == null ? void 0 : _a.map((hitArea) => ({
|
|
id: hitArea.id,
|
|
name: hitArea.name,
|
|
index: this.coreModel.getDrawDataIndex(hitArea.id)
|
|
}))) || [];
|
|
}
|
|
getDrawableIDs() {
|
|
const modelContext = this.coreModel.getModelContext();
|
|
const ids = [];
|
|
for (let i = 0; i < this.drawDataCount; i++) {
|
|
const drawData = modelContext.getDrawData(i);
|
|
if (drawData) {
|
|
ids.push(drawData.getDrawDataID().id);
|
|
}
|
|
}
|
|
return ids;
|
|
}
|
|
getDrawableIndex(id) {
|
|
return this.coreModel.getDrawDataIndex(id);
|
|
}
|
|
getDrawableVertices(drawIndex) {
|
|
if (typeof drawIndex === "string") {
|
|
drawIndex = this.coreModel.getDrawDataIndex(drawIndex);
|
|
if (drawIndex === -1)
|
|
throw new TypeError("Unable to find drawable ID: " + drawIndex);
|
|
}
|
|
return this.coreModel.getTransformedPoints(drawIndex).slice();
|
|
}
|
|
update(dt, now) {
|
|
var _a, _b, _c, _d;
|
|
super.update(dt, now);
|
|
const model = this.coreModel;
|
|
this.emit("beforeMotionUpdate");
|
|
const motionUpdated = this.motionManager.update(this.coreModel, now);
|
|
this.emit("afterMotionUpdate");
|
|
model.saveParam();
|
|
(_a = this.motionManager.expressionManager) == null ? void 0 : _a.update(model, now);
|
|
if (!motionUpdated) {
|
|
(_b = this.eyeBlink) == null ? void 0 : _b.update(dt);
|
|
}
|
|
this.updateFocus();
|
|
this.updateNaturalMovements(dt, now);
|
|
(_c = this.physics) == null ? void 0 : _c.update(now);
|
|
(_d = this.pose) == null ? void 0 : _d.update(dt);
|
|
this.emit("beforeModelUpdate");
|
|
model.update();
|
|
model.loadParam();
|
|
}
|
|
updateFocus() {
|
|
this.coreModel.addToParamFloat(this.eyeballXParamIndex, this.focusController.x);
|
|
this.coreModel.addToParamFloat(this.eyeballYParamIndex, this.focusController.y);
|
|
this.coreModel.addToParamFloat(this.angleXParamIndex, this.focusController.x * 30);
|
|
this.coreModel.addToParamFloat(this.angleYParamIndex, this.focusController.y * 30);
|
|
this.coreModel.addToParamFloat(this.angleZParamIndex, this.focusController.x * this.focusController.y * -30);
|
|
this.coreModel.addToParamFloat(this.bodyAngleXParamIndex, this.focusController.x * 10);
|
|
}
|
|
updateNaturalMovements(dt, now) {
|
|
const t = now / 1e3 * 2 * Math.PI;
|
|
this.coreModel.addToParamFloat(this.angleXParamIndex, 15 * Math.sin(t / 6.5345) * 0.5);
|
|
this.coreModel.addToParamFloat(this.angleYParamIndex, 8 * Math.sin(t / 3.5345) * 0.5);
|
|
this.coreModel.addToParamFloat(this.angleZParamIndex, 10 * Math.sin(t / 5.5345) * 0.5);
|
|
this.coreModel.addToParamFloat(this.bodyAngleXParamIndex, 4 * Math.sin(t / 15.5345) * 0.5);
|
|
this.coreModel.setParamFloat(this.breathParamIndex, 0.5 + 0.5 * Math.sin(t / 3.2345));
|
|
}
|
|
draw(gl) {
|
|
const disableCulling = this.disableCulling;
|
|
if (gl.getParameter(gl.FRAMEBUFFER_BINDING)) {
|
|
this.disableCulling = true;
|
|
}
|
|
const matrix = this.drawingMatrix;
|
|
tempMatrixArray[0] = matrix.a;
|
|
tempMatrixArray[1] = matrix.b;
|
|
tempMatrixArray[4] = matrix.c;
|
|
tempMatrixArray[5] = matrix.d;
|
|
tempMatrixArray[12] = matrix.tx;
|
|
tempMatrixArray[13] = matrix.ty;
|
|
this.coreModel.setMatrix(tempMatrixArray);
|
|
this.coreModel.draw();
|
|
this.disableCulling = disableCulling;
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.coreModel = void 0;
|
|
}
|
|
}
|
|
class Cubism2ModelSettings extends ModelSettings {
|
|
constructor(json) {
|
|
super(json);
|
|
this.motions = {};
|
|
if (!Cubism2ModelSettings.isValidJSON(json)) {
|
|
throw new TypeError("Invalid JSON.");
|
|
}
|
|
this.moc = json.model;
|
|
copyArray("string", json, this, "textures", "textures");
|
|
this.copy(json);
|
|
}
|
|
static isValidJSON(json) {
|
|
var _a;
|
|
return !!json && typeof json.model === "string" && ((_a = json.textures) == null ? void 0 : _a.length) > 0 && json.textures.every((item) => typeof item === "string");
|
|
}
|
|
copy(json) {
|
|
copyProperty("string", json, this, "name", "name");
|
|
copyProperty("string", json, this, "pose", "pose");
|
|
copyProperty("string", json, this, "physics", "physics");
|
|
copyProperty("object", json, this, "layout", "layout");
|
|
copyProperty("object", json, this, "motions", "motions");
|
|
copyArray("object", json, this, "hit_areas", "hitAreas");
|
|
copyArray("object", json, this, "expressions", "expressions");
|
|
copyArray("object", json, this, "init_params", "initParams");
|
|
copyArray("object", json, this, "init_opacities", "initOpacities");
|
|
}
|
|
replaceFiles(replace) {
|
|
super.replaceFiles(replace);
|
|
for (const [group, motions] of Object.entries(this.motions)) {
|
|
for (let i = 0; i < motions.length; i++) {
|
|
motions[i].file = replace(motions[i].file, `motions.${group}[${i}].file`);
|
|
if (motions[i].sound !== void 0) {
|
|
motions[i].sound = replace(motions[i].sound, `motions.${group}[${i}].sound`);
|
|
}
|
|
}
|
|
}
|
|
if (this.expressions) {
|
|
for (let i = 0; i < this.expressions.length; i++) {
|
|
this.expressions[i].file = replace(this.expressions[i].file, `expressions[${i}].file`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const SRC_TYPE_MAP = {
|
|
x: PhysicsHair.Src.SRC_TO_X,
|
|
y: PhysicsHair.Src.SRC_TO_Y,
|
|
angle: PhysicsHair.Src.SRC_TO_G_ANGLE
|
|
};
|
|
const TARGET_TYPE_MAP = {
|
|
x: PhysicsHair.Src.SRC_TO_X,
|
|
y: PhysicsHair.Src.SRC_TO_Y,
|
|
angle: PhysicsHair.Src.SRC_TO_G_ANGLE
|
|
};
|
|
class Live2DPhysics {
|
|
constructor(coreModel, json) {
|
|
this.coreModel = coreModel;
|
|
this.physicsHairs = [];
|
|
if (json.physics_hair) {
|
|
this.physicsHairs = json.physics_hair.map((definition) => {
|
|
const physicsHair = new PhysicsHair();
|
|
physicsHair.setup(definition.setup.length, definition.setup.regist, definition.setup.mass);
|
|
definition.src.forEach(({ id, ptype, scale, weight }) => {
|
|
const type = SRC_TYPE_MAP[ptype];
|
|
if (type) {
|
|
physicsHair.addSrcParam(type, id, scale, weight);
|
|
}
|
|
});
|
|
definition.targets.forEach(({ id, ptype, scale, weight }) => {
|
|
const type = TARGET_TYPE_MAP[ptype];
|
|
if (type) {
|
|
physicsHair.addTargetParam(type, id, scale, weight);
|
|
}
|
|
});
|
|
return physicsHair;
|
|
});
|
|
}
|
|
}
|
|
update(elapsed) {
|
|
this.physicsHairs.forEach((physicsHair) => physicsHair.update(this.coreModel, elapsed));
|
|
}
|
|
}
|
|
class Live2DPartsParam {
|
|
constructor(id) {
|
|
this.id = id;
|
|
this.paramIndex = -1;
|
|
this.partsIndex = -1;
|
|
this.link = [];
|
|
}
|
|
initIndex(model) {
|
|
this.paramIndex = model.getParamIndex("VISIBLE:" + this.id);
|
|
this.partsIndex = model.getPartsDataIndex(PartsDataID.getID(this.id));
|
|
model.setParamFloat(this.paramIndex, 1);
|
|
}
|
|
}
|
|
class Live2DPose {
|
|
constructor(coreModel, json) {
|
|
this.coreModel = coreModel;
|
|
this.opacityAnimDuration = 500;
|
|
this.partsGroups = [];
|
|
if (json.parts_visible) {
|
|
this.partsGroups = json.parts_visible.map(({ group }) => group.map(({ id, link }) => {
|
|
const parts = new Live2DPartsParam(id);
|
|
if (link) {
|
|
parts.link = link.map((l) => new Live2DPartsParam(l));
|
|
}
|
|
return parts;
|
|
}));
|
|
this.init();
|
|
}
|
|
}
|
|
init() {
|
|
this.partsGroups.forEach((group) => {
|
|
group.forEach((parts) => {
|
|
parts.initIndex(this.coreModel);
|
|
if (parts.paramIndex >= 0) {
|
|
const visible = this.coreModel.getParamFloat(parts.paramIndex) !== 0;
|
|
this.coreModel.setPartsOpacity(parts.partsIndex, visible ? 1 : 0);
|
|
this.coreModel.setParamFloat(parts.paramIndex, visible ? 1 : 0);
|
|
if (parts.link.length > 0) {
|
|
parts.link.forEach((p) => p.initIndex(this.coreModel));
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
normalizePartsOpacityGroup(partsGroup, dt) {
|
|
const model = this.coreModel;
|
|
const phi = 0.5;
|
|
const maxBackOpacity = 0.15;
|
|
let visibleOpacity = 1;
|
|
let visibleIndex = partsGroup.findIndex(({ paramIndex, partsIndex }) => partsIndex >= 0 && model.getParamFloat(paramIndex) !== 0);
|
|
if (visibleIndex >= 0) {
|
|
const originalOpacity = model.getPartsOpacity(partsGroup[visibleIndex].partsIndex);
|
|
visibleOpacity = clamp(originalOpacity + dt / this.opacityAnimDuration, 0, 1);
|
|
} else {
|
|
visibleIndex = 0;
|
|
visibleOpacity = 1;
|
|
}
|
|
partsGroup.forEach(({ partsIndex }, index) => {
|
|
if (partsIndex >= 0) {
|
|
if (visibleIndex == index) {
|
|
model.setPartsOpacity(partsIndex, visibleOpacity);
|
|
} else {
|
|
let opacity = model.getPartsOpacity(partsIndex);
|
|
let a1;
|
|
if (visibleOpacity < phi) {
|
|
a1 = visibleOpacity * (phi - 1) / phi + 1;
|
|
} else {
|
|
a1 = (1 - visibleOpacity) * phi / (1 - phi);
|
|
}
|
|
let backOp = (1 - a1) * (1 - visibleOpacity);
|
|
if (backOp > maxBackOpacity) {
|
|
a1 = 1 - maxBackOpacity / (1 - visibleOpacity);
|
|
}
|
|
if (opacity > a1) {
|
|
opacity = a1;
|
|
}
|
|
model.setPartsOpacity(partsIndex, opacity);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
copyOpacity(partsGroup) {
|
|
const model = this.coreModel;
|
|
partsGroup.forEach(({ partsIndex, link }) => {
|
|
if (partsIndex >= 0 && link) {
|
|
const opacity = model.getPartsOpacity(partsIndex);
|
|
link.forEach(({ partsIndex: partsIndex2 }) => {
|
|
if (partsIndex2 >= 0) {
|
|
model.setPartsOpacity(partsIndex2, opacity);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
update(dt) {
|
|
this.partsGroups.forEach((partGroup) => {
|
|
this.normalizePartsOpacityGroup(partGroup, dt);
|
|
this.copyOpacity(partGroup);
|
|
});
|
|
}
|
|
}
|
|
Live2DFactory.registerRuntime({
|
|
version: 2,
|
|
test(source) {
|
|
return source instanceof Cubism2ModelSettings || Cubism2ModelSettings.isValidJSON(source);
|
|
},
|
|
ready() {
|
|
return Promise.resolve();
|
|
},
|
|
isValidMoc(modelData) {
|
|
if (modelData.byteLength < 3) {
|
|
return false;
|
|
}
|
|
const view = new Int8Array(modelData, 0, 3);
|
|
return String.fromCharCode(...view) === "moc";
|
|
},
|
|
createModelSettings(json) {
|
|
return new Cubism2ModelSettings(json);
|
|
},
|
|
createCoreModel(data) {
|
|
const model = Live2DModelWebGL.loadModel(data);
|
|
const error = Live2D.getError();
|
|
if (error)
|
|
throw error;
|
|
return model;
|
|
},
|
|
createInternalModel(coreModel, settings, options) {
|
|
return new Cubism2InternalModel(coreModel, settings, options);
|
|
},
|
|
createPose(coreModel, data) {
|
|
return new Live2DPose(coreModel, data);
|
|
},
|
|
createPhysics(coreModel, data) {
|
|
return new Live2DPhysics(coreModel, data);
|
|
}
|
|
});
|
|
if (!window.Live2DCubismCore) {
|
|
throw new Error("Could not find Cubism 4 runtime. This plugin requires live2dcubismcore.js to be loaded.");
|
|
}
|
|
class CubismVector2 {
|
|
constructor(x, y) {
|
|
this.x = x || 0;
|
|
this.y = y || 0;
|
|
}
|
|
add(vector2) {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this.x + vector2.x;
|
|
ret.y = this.y + vector2.y;
|
|
return ret;
|
|
}
|
|
substract(vector2) {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this.x - vector2.x;
|
|
ret.y = this.y - vector2.y;
|
|
return ret;
|
|
}
|
|
multiply(vector2) {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this.x * vector2.x;
|
|
ret.y = this.y * vector2.y;
|
|
return ret;
|
|
}
|
|
multiplyByScaler(scalar) {
|
|
return this.multiply(new CubismVector2(scalar, scalar));
|
|
}
|
|
division(vector2) {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this.x / vector2.x;
|
|
ret.y = this.y / vector2.y;
|
|
return ret;
|
|
}
|
|
divisionByScalar(scalar) {
|
|
return this.division(new CubismVector2(scalar, scalar));
|
|
}
|
|
getLength() {
|
|
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
}
|
|
getDistanceWith(a) {
|
|
return Math.sqrt((this.x - a.x) * (this.x - a.x) + (this.y - a.y) * (this.y - a.y));
|
|
}
|
|
dot(a) {
|
|
return this.x * a.x + this.y * a.y;
|
|
}
|
|
normalize() {
|
|
const length = Math.pow(this.x * this.x + this.y * this.y, 0.5);
|
|
this.x = this.x / length;
|
|
this.y = this.y / length;
|
|
}
|
|
isEqual(rhs) {
|
|
return this.x == rhs.x && this.y == rhs.y;
|
|
}
|
|
isNotEqual(rhs) {
|
|
return !this.isEqual(rhs);
|
|
}
|
|
}
|
|
const _CubismMath = class {
|
|
static range(value, min, max) {
|
|
if (value < min) {
|
|
value = min;
|
|
} else if (value > max) {
|
|
value = max;
|
|
}
|
|
return value;
|
|
}
|
|
static sin(x) {
|
|
return Math.sin(x);
|
|
}
|
|
static cos(x) {
|
|
return Math.cos(x);
|
|
}
|
|
static abs(x) {
|
|
return Math.abs(x);
|
|
}
|
|
static sqrt(x) {
|
|
return Math.sqrt(x);
|
|
}
|
|
static cbrt(x) {
|
|
if (x === 0) {
|
|
return x;
|
|
}
|
|
let cx = x;
|
|
const isNegativeNumber = cx < 0;
|
|
if (isNegativeNumber) {
|
|
cx = -cx;
|
|
}
|
|
let 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;
|
|
}
|
|
static getEasingSine(value) {
|
|
if (value < 0) {
|
|
return 0;
|
|
} else if (value > 1) {
|
|
return 1;
|
|
}
|
|
return 0.5 - 0.5 * this.cos(value * Math.PI);
|
|
}
|
|
static max(left, right) {
|
|
return left > right ? left : right;
|
|
}
|
|
static min(left, right) {
|
|
return left > right ? right : left;
|
|
}
|
|
static degreesToRadian(degrees) {
|
|
return degrees / 180 * Math.PI;
|
|
}
|
|
static radianToDegrees(radian) {
|
|
return radian * 180 / Math.PI;
|
|
}
|
|
static directionToRadian(from, to) {
|
|
const q1 = Math.atan2(to.y, to.x);
|
|
const 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;
|
|
}
|
|
static directionToDegrees(from, to) {
|
|
const radian = this.directionToRadian(from, to);
|
|
let degree = this.radianToDegrees(radian);
|
|
if (to.x - from.x > 0) {
|
|
degree = -degree;
|
|
}
|
|
return degree;
|
|
}
|
|
static radianToDirection(totalAngle) {
|
|
const ret = new CubismVector2();
|
|
ret.x = this.sin(totalAngle);
|
|
ret.y = this.cos(totalAngle);
|
|
return ret;
|
|
}
|
|
static quadraticEquation(a, b, c) {
|
|
if (this.abs(a) < _CubismMath.Epsilon) {
|
|
if (this.abs(b) < _CubismMath.Epsilon) {
|
|
return -c;
|
|
}
|
|
return -c / b;
|
|
}
|
|
return -(b + this.sqrt(b * b - 4 * a * c)) / (2 * a);
|
|
}
|
|
static cardanoAlgorithmForBezier(a, b, c, d) {
|
|
if (this.sqrt(a) < _CubismMath.Epsilon) {
|
|
return this.range(this.quadraticEquation(b, c, d), 0, 1);
|
|
}
|
|
const ba = b / a;
|
|
const ca = c / a;
|
|
const da = d / a;
|
|
const p = (3 * ca - ba * ba) / 3;
|
|
const p3 = p / 3;
|
|
const q = (2 * ba * ba * ba - 9 * ba * ca + 27 * da) / 27;
|
|
const q2 = q / 2;
|
|
const discriminant = q2 * q2 + p3 * p3 * p3;
|
|
const center = 0.5;
|
|
const threshold = center + 0.01;
|
|
if (discriminant < 0) {
|
|
const mp3 = -p / 3;
|
|
const mp33 = mp3 * mp3 * mp3;
|
|
const r = this.sqrt(mp33);
|
|
const t = -q / (2 * r);
|
|
const cosphi = this.range(t, -1, 1);
|
|
const phi = Math.acos(cosphi);
|
|
const crtr = this.cbrt(r);
|
|
const t1 = 2 * crtr;
|
|
const root12 = t1 * this.cos(phi / 3) - ba / 3;
|
|
if (this.abs(root12 - center) < threshold) {
|
|
return this.range(root12, 0, 1);
|
|
}
|
|
const root2 = t1 * this.cos((phi + 2 * Math.PI) / 3) - ba / 3;
|
|
if (this.abs(root2 - center) < threshold) {
|
|
return this.range(root2, 0, 1);
|
|
}
|
|
const root3 = t1 * this.cos((phi + 4 * Math.PI) / 3) - ba / 3;
|
|
return this.range(root3, 0, 1);
|
|
}
|
|
if (discriminant == 0) {
|
|
let u12;
|
|
if (q2 < 0) {
|
|
u12 = this.cbrt(-q2);
|
|
} else {
|
|
u12 = -this.cbrt(q2);
|
|
}
|
|
const root12 = 2 * u12 - ba / 3;
|
|
if (this.abs(root12 - center) < threshold) {
|
|
return this.range(root12, 0, 1);
|
|
}
|
|
const root2 = -u12 - ba / 3;
|
|
return this.range(root2, 0, 1);
|
|
}
|
|
const sd = this.sqrt(discriminant);
|
|
const u1 = this.cbrt(sd - q2);
|
|
const v1 = this.cbrt(sd + q2);
|
|
const root1 = u1 - v1 - ba / 3;
|
|
return this.range(root1, 0, 1);
|
|
}
|
|
constructor() {
|
|
}
|
|
};
|
|
let CubismMath = _CubismMath;
|
|
CubismMath.Epsilon = 1e-5;
|
|
class CubismMatrix44 {
|
|
constructor() {
|
|
this._tr = new Float32Array(16);
|
|
this.loadIdentity();
|
|
}
|
|
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
|
|
]);
|
|
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,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1
|
|
]);
|
|
this.setMatrix(c);
|
|
}
|
|
setMatrix(tr) {
|
|
for (let i = 0; i < 16; ++i) {
|
|
this._tr[i] = tr[i];
|
|
}
|
|
}
|
|
getArray() {
|
|
return this._tr;
|
|
}
|
|
getScaleX() {
|
|
return this._tr[0];
|
|
}
|
|
getScaleY() {
|
|
return this._tr[5];
|
|
}
|
|
getTranslateX() {
|
|
return this._tr[12];
|
|
}
|
|
getTranslateY() {
|
|
return this._tr[13];
|
|
}
|
|
transformX(src) {
|
|
return this._tr[0] * src + this._tr[12];
|
|
}
|
|
transformY(src) {
|
|
return this._tr[5] * src + this._tr[13];
|
|
}
|
|
invertTransformX(src) {
|
|
return (src - this._tr[12]) / this._tr[0];
|
|
}
|
|
invertTransformY(src) {
|
|
return (src - this._tr[13]) / this._tr[5];
|
|
}
|
|
translateRelative(x, y) {
|
|
const tr1 = new Float32Array([
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
x,
|
|
y,
|
|
0,
|
|
1
|
|
]);
|
|
CubismMatrix44.multiply(tr1, this._tr, this._tr);
|
|
}
|
|
translate(x, y) {
|
|
this._tr[12] = x;
|
|
this._tr[13] = y;
|
|
}
|
|
translateX(x) {
|
|
this._tr[12] = x;
|
|
}
|
|
translateY(y) {
|
|
this._tr[13] = y;
|
|
}
|
|
scaleRelative(x, y) {
|
|
const tr1 = new Float32Array([
|
|
x,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
y,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1
|
|
]);
|
|
CubismMatrix44.multiply(tr1, this._tr, this._tr);
|
|
}
|
|
scale(x, y) {
|
|
this._tr[0] = x;
|
|
this._tr[5] = y;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
class CubismRenderer {
|
|
initialize(model) {
|
|
this._model = model;
|
|
}
|
|
drawModel() {
|
|
if (this.getModel() == null)
|
|
return;
|
|
this.doDrawModel();
|
|
}
|
|
setMvpMatrix(matrix44) {
|
|
this._mvpMatrix4x4.setMatrix(matrix44.getArray());
|
|
}
|
|
getMvpMatrix() {
|
|
return this._mvpMatrix4x4;
|
|
}
|
|
setModelColor(red, green, blue, alpha) {
|
|
if (red < 0) {
|
|
red = 0;
|
|
} else if (red > 1) {
|
|
red = 1;
|
|
}
|
|
if (green < 0) {
|
|
green = 0;
|
|
} else if (green > 1) {
|
|
green = 1;
|
|
}
|
|
if (blue < 0) {
|
|
blue = 0;
|
|
} else if (blue > 1) {
|
|
blue = 1;
|
|
}
|
|
if (alpha < 0) {
|
|
alpha = 0;
|
|
} else if (alpha > 1) {
|
|
alpha = 1;
|
|
}
|
|
this._modelColor.R = red;
|
|
this._modelColor.G = green;
|
|
this._modelColor.B = blue;
|
|
this._modelColor.A = alpha;
|
|
}
|
|
getModelColor() {
|
|
return Object.assign({}, this._modelColor);
|
|
}
|
|
setIsPremultipliedAlpha(enable) {
|
|
this._isPremultipliedAlpha = enable;
|
|
}
|
|
isPremultipliedAlpha() {
|
|
return this._isPremultipliedAlpha;
|
|
}
|
|
setIsCulling(culling) {
|
|
this._isCulling = culling;
|
|
}
|
|
isCulling() {
|
|
return this._isCulling;
|
|
}
|
|
setAnisotropy(n) {
|
|
this._anisortopy = n;
|
|
}
|
|
getAnisotropy() {
|
|
return this._anisortopy;
|
|
}
|
|
getModel() {
|
|
return this._model;
|
|
}
|
|
constructor() {
|
|
this._isCulling = false;
|
|
this._isPremultipliedAlpha = false;
|
|
this._anisortopy = 0;
|
|
this._modelColor = new CubismTextureColor();
|
|
this._mvpMatrix4x4 = new CubismMatrix44();
|
|
this._mvpMatrix4x4.loadIdentity();
|
|
}
|
|
}
|
|
var CubismBlendMode = /* @__PURE__ */ ((CubismBlendMode2) => {
|
|
CubismBlendMode2[CubismBlendMode2["CubismBlendMode_Normal"] = 0] = "CubismBlendMode_Normal";
|
|
CubismBlendMode2[CubismBlendMode2["CubismBlendMode_Additive"] = 1] = "CubismBlendMode_Additive";
|
|
CubismBlendMode2[CubismBlendMode2["CubismBlendMode_Multiplicative"] = 2] = "CubismBlendMode_Multiplicative";
|
|
return CubismBlendMode2;
|
|
})(CubismBlendMode || {});
|
|
class CubismTextureColor {
|
|
constructor() {
|
|
this.R = 1;
|
|
this.G = 1;
|
|
this.B = 1;
|
|
this.A = 1;
|
|
}
|
|
}
|
|
let s_isStarted = false;
|
|
let s_isInitialized = false;
|
|
let s_option = void 0;
|
|
const Constant = {
|
|
vertexOffset: 0,
|
|
vertexStep: 2
|
|
};
|
|
class CubismFramework {
|
|
static startUp(option) {
|
|
if (s_isStarted) {
|
|
CubismLogInfo("CubismFramework.startUp() is already done.");
|
|
return s_isStarted;
|
|
}
|
|
if (Live2DCubismCore._isStarted) {
|
|
s_isStarted = true;
|
|
return true;
|
|
}
|
|
Live2DCubismCore._isStarted = true;
|
|
s_option = option;
|
|
if (s_option) {
|
|
Live2DCubismCore.Logging.csmSetLogFunction(s_option.logFunction);
|
|
}
|
|
s_isStarted = true;
|
|
if (s_isStarted) {
|
|
const version = Live2DCubismCore.Version.csmGetVersion();
|
|
const major = (version & 4278190080) >> 24;
|
|
const minor = (version & 16711680) >> 16;
|
|
const patch = version & 65535;
|
|
const versionNumber = version;
|
|
CubismLogInfo(`Live2D Cubism Core version: {0}.{1}.{2} ({3})`, ("00" + major).slice(-2), ("00" + minor).slice(-2), ("0000" + patch).slice(-4), versionNumber);
|
|
}
|
|
CubismLogInfo("CubismFramework.startUp() is complete.");
|
|
return s_isStarted;
|
|
}
|
|
static cleanUp() {
|
|
s_isStarted = false;
|
|
s_isInitialized = false;
|
|
s_option = void 0;
|
|
}
|
|
static initialize() {
|
|
if (!s_isStarted) {
|
|
CubismLogWarning("CubismFramework is not started.");
|
|
return;
|
|
}
|
|
if (s_isInitialized) {
|
|
CubismLogWarning("CubismFramework.initialize() skipped, already initialized.");
|
|
return;
|
|
}
|
|
s_isInitialized = true;
|
|
CubismLogInfo("CubismFramework.initialize() is complete.");
|
|
}
|
|
static dispose() {
|
|
if (!s_isStarted) {
|
|
CubismLogWarning("CubismFramework is not started.");
|
|
return;
|
|
}
|
|
if (!s_isInitialized) {
|
|
CubismLogWarning("CubismFramework.dispose() skipped, not initialized.");
|
|
return;
|
|
}
|
|
CubismRenderer.staticRelease();
|
|
s_isInitialized = false;
|
|
CubismLogInfo("CubismFramework.dispose() is complete.");
|
|
}
|
|
static isStarted() {
|
|
return s_isStarted;
|
|
}
|
|
static isInitialized() {
|
|
return s_isInitialized;
|
|
}
|
|
static coreLogFunction(message) {
|
|
if (!Live2DCubismCore.Logging.csmGetLogFunction()) {
|
|
return;
|
|
}
|
|
Live2DCubismCore.Logging.csmGetLogFunction()(message);
|
|
}
|
|
static getLoggingLevel() {
|
|
if (s_option != null) {
|
|
return s_option.loggingLevel;
|
|
}
|
|
return LogLevel.LogLevel_Off;
|
|
}
|
|
constructor() {
|
|
}
|
|
}
|
|
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
LogLevel2[LogLevel2["LogLevel_Verbose"] = 0] = "LogLevel_Verbose";
|
|
LogLevel2[LogLevel2["LogLevel_Debug"] = 1] = "LogLevel_Debug";
|
|
LogLevel2[LogLevel2["LogLevel_Info"] = 2] = "LogLevel_Info";
|
|
LogLevel2[LogLevel2["LogLevel_Warning"] = 3] = "LogLevel_Warning";
|
|
LogLevel2[LogLevel2["LogLevel_Error"] = 4] = "LogLevel_Error";
|
|
LogLevel2[LogLevel2["LogLevel_Off"] = 5] = "LogLevel_Off";
|
|
return LogLevel2;
|
|
})(LogLevel || {});
|
|
const CSM_ASSERT = () => {
|
|
};
|
|
function CubismLogDebug(fmt, ...args) {
|
|
CubismDebug.print(LogLevel.LogLevel_Debug, "[CSM][D]" + fmt + "\n", args);
|
|
}
|
|
function CubismLogInfo(fmt, ...args) {
|
|
CubismDebug.print(LogLevel.LogLevel_Info, "[CSM][I]" + fmt + "\n", args);
|
|
}
|
|
function CubismLogWarning(fmt, ...args) {
|
|
CubismDebug.print(LogLevel.LogLevel_Warning, "[CSM][W]" + fmt + "\n", args);
|
|
}
|
|
function CubismLogError(fmt, ...args) {
|
|
CubismDebug.print(LogLevel.LogLevel_Error, "[CSM][E]" + fmt + "\n", args);
|
|
}
|
|
class CubismDebug {
|
|
static print(logLevel, format, args) {
|
|
if (logLevel < CubismFramework.getLoggingLevel()) {
|
|
return;
|
|
}
|
|
const logPrint = CubismFramework.coreLogFunction;
|
|
if (!logPrint)
|
|
return;
|
|
const buffer = format.replace(/{(\d+)}/g, (m, k) => {
|
|
return args[k];
|
|
});
|
|
logPrint(buffer);
|
|
}
|
|
static dumpBytes(logLevel, data, length) {
|
|
for (let i = 0; i < length; i++) {
|
|
if (i % 16 == 0 && i > 0)
|
|
this.print(logLevel, "\n");
|
|
else if (i % 8 == 0 && i > 0)
|
|
this.print(logLevel, " ");
|
|
this.print(logLevel, "{0} ", [data[i] & 255]);
|
|
}
|
|
this.print(logLevel, "\n");
|
|
}
|
|
constructor() {
|
|
}
|
|
}
|
|
class ACubismMotion {
|
|
constructor() {
|
|
this._fadeInSeconds = -1;
|
|
this._fadeOutSeconds = -1;
|
|
this._weight = 1;
|
|
this._offsetSeconds = 0;
|
|
this._firedEventValues = [];
|
|
}
|
|
release() {
|
|
this._weight = 0;
|
|
}
|
|
updateParameters(model, motionQueueEntry, userTimeSeconds) {
|
|
if (!motionQueueEntry.isAvailable() || motionQueueEntry.isFinished()) {
|
|
return;
|
|
}
|
|
if (!motionQueueEntry.isStarted()) {
|
|
motionQueueEntry.setIsStarted(true);
|
|
motionQueueEntry.setStartTime(userTimeSeconds - this._offsetSeconds);
|
|
motionQueueEntry.setFadeInStartTime(userTimeSeconds);
|
|
const duration = this.getDuration();
|
|
if (motionQueueEntry.getEndTime() < 0) {
|
|
motionQueueEntry.setEndTime(duration <= 0 ? -1 : motionQueueEntry.getStartTime() + duration);
|
|
}
|
|
}
|
|
let fadeWeight = this._weight;
|
|
const fadeIn = this._fadeInSeconds == 0 ? 1 : CubismMath.getEasingSine((userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / this._fadeInSeconds);
|
|
const fadeOut = this._fadeOutSeconds == 0 || motionQueueEntry.getEndTime() < 0 ? 1 : CubismMath.getEasingSine((motionQueueEntry.getEndTime() - userTimeSeconds) / this._fadeOutSeconds);
|
|
fadeWeight = fadeWeight * fadeIn * fadeOut;
|
|
motionQueueEntry.setState(userTimeSeconds, fadeWeight);
|
|
this.doUpdateParameters(model, userTimeSeconds, fadeWeight, motionQueueEntry);
|
|
if (motionQueueEntry.getEndTime() > 0 && motionQueueEntry.getEndTime() < userTimeSeconds) {
|
|
motionQueueEntry.setIsFinished(true);
|
|
}
|
|
}
|
|
setFadeInTime(fadeInSeconds) {
|
|
this._fadeInSeconds = fadeInSeconds;
|
|
}
|
|
setFadeOutTime(fadeOutSeconds) {
|
|
this._fadeOutSeconds = fadeOutSeconds;
|
|
}
|
|
getFadeOutTime() {
|
|
return this._fadeOutSeconds;
|
|
}
|
|
getFadeInTime() {
|
|
return this._fadeInSeconds;
|
|
}
|
|
setWeight(weight) {
|
|
this._weight = weight;
|
|
}
|
|
getWeight() {
|
|
return this._weight;
|
|
}
|
|
getDuration() {
|
|
return -1;
|
|
}
|
|
getLoopDuration() {
|
|
return -1;
|
|
}
|
|
setOffsetTime(offsetSeconds) {
|
|
this._offsetSeconds = offsetSeconds;
|
|
}
|
|
getFiredEvent(beforeCheckTimeSeconds, motionTimeSeconds) {
|
|
return this._firedEventValues;
|
|
}
|
|
setFinishedMotionHandler(onFinishedMotionHandler) {
|
|
this._onFinishedMotion = onFinishedMotionHandler;
|
|
}
|
|
getFinishedMotionHandler() {
|
|
return this._onFinishedMotion;
|
|
}
|
|
}
|
|
const DefaultFadeTime = 1;
|
|
class CubismExpressionMotion extends ACubismMotion {
|
|
constructor() {
|
|
super();
|
|
this._parameters = [];
|
|
}
|
|
static create(json) {
|
|
const expression = new CubismExpressionMotion();
|
|
const fadeInTime = json.FadeInTime;
|
|
const fadeOutTime = json.FadeOutTime;
|
|
expression.setFadeInTime(fadeInTime !== void 0 ? fadeInTime : DefaultFadeTime);
|
|
expression.setFadeOutTime(fadeOutTime !== void 0 ? fadeOutTime : DefaultFadeTime);
|
|
const parameters = json.Parameters || [];
|
|
for (let i = 0; i < parameters.length; ++i) {
|
|
const param = parameters[i];
|
|
const parameterId = param.Id;
|
|
const value = param.Value;
|
|
let blendType;
|
|
switch (param.Blend) {
|
|
case "Multiply":
|
|
blendType = ExpressionBlendType.ExpressionBlendType_Multiply;
|
|
break;
|
|
case "Overwrite":
|
|
blendType = ExpressionBlendType.ExpressionBlendType_Overwrite;
|
|
break;
|
|
case "Add":
|
|
default:
|
|
blendType = ExpressionBlendType.ExpressionBlendType_Add;
|
|
break;
|
|
}
|
|
const item = {
|
|
parameterId,
|
|
blendType,
|
|
value
|
|
};
|
|
expression._parameters.push(item);
|
|
}
|
|
return expression;
|
|
}
|
|
doUpdateParameters(model, userTimeSeconds, weight, motionQueueEntry) {
|
|
for (let i = 0; i < this._parameters.length; ++i) {
|
|
const parameter = this._parameters[i];
|
|
switch (parameter.blendType) {
|
|
case ExpressionBlendType.ExpressionBlendType_Add: {
|
|
model.addParameterValueById(parameter.parameterId, parameter.value, weight);
|
|
break;
|
|
}
|
|
case ExpressionBlendType.ExpressionBlendType_Multiply: {
|
|
model.multiplyParameterValueById(parameter.parameterId, parameter.value, weight);
|
|
break;
|
|
}
|
|
case ExpressionBlendType.ExpressionBlendType_Overwrite: {
|
|
model.setParameterValueById(parameter.parameterId, parameter.value, weight);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var ExpressionBlendType = /* @__PURE__ */ ((ExpressionBlendType2) => {
|
|
ExpressionBlendType2[ExpressionBlendType2["ExpressionBlendType_Add"] = 0] = "ExpressionBlendType_Add";
|
|
ExpressionBlendType2[ExpressionBlendType2["ExpressionBlendType_Multiply"] = 1] = "ExpressionBlendType_Multiply";
|
|
ExpressionBlendType2[ExpressionBlendType2["ExpressionBlendType_Overwrite"] = 2] = "ExpressionBlendType_Overwrite";
|
|
return ExpressionBlendType2;
|
|
})(ExpressionBlendType || {});
|
|
class CubismMotionQueueEntry {
|
|
constructor() {
|
|
this._autoDelete = false;
|
|
this._available = true;
|
|
this._finished = false;
|
|
this._started = false;
|
|
this._startTimeSeconds = -1;
|
|
this._fadeInStartTimeSeconds = 0;
|
|
this._endTimeSeconds = -1;
|
|
this._stateTimeSeconds = 0;
|
|
this._stateWeight = 0;
|
|
this._lastEventCheckSeconds = 0;
|
|
this._motionQueueEntryHandle = this;
|
|
this._fadeOutSeconds = 0;
|
|
this._isTriggeredFadeOut = false;
|
|
}
|
|
release() {
|
|
if (this._autoDelete && this._motion) {
|
|
this._motion.release();
|
|
}
|
|
}
|
|
setFadeOut(fadeOutSeconds) {
|
|
this._fadeOutSeconds = fadeOutSeconds;
|
|
this._isTriggeredFadeOut = true;
|
|
}
|
|
startFadeOut(fadeOutSeconds, userTimeSeconds) {
|
|
const newEndTimeSeconds = userTimeSeconds + fadeOutSeconds;
|
|
this._isTriggeredFadeOut = true;
|
|
if (this._endTimeSeconds < 0 || newEndTimeSeconds < this._endTimeSeconds) {
|
|
this._endTimeSeconds = newEndTimeSeconds;
|
|
}
|
|
}
|
|
isFinished() {
|
|
return this._finished;
|
|
}
|
|
isStarted() {
|
|
return this._started;
|
|
}
|
|
getStartTime() {
|
|
return this._startTimeSeconds;
|
|
}
|
|
getFadeInStartTime() {
|
|
return this._fadeInStartTimeSeconds;
|
|
}
|
|
getEndTime() {
|
|
return this._endTimeSeconds;
|
|
}
|
|
setStartTime(startTime) {
|
|
this._startTimeSeconds = startTime;
|
|
}
|
|
setFadeInStartTime(startTime) {
|
|
this._fadeInStartTimeSeconds = startTime;
|
|
}
|
|
setEndTime(endTime) {
|
|
this._endTimeSeconds = endTime;
|
|
}
|
|
setIsFinished(f) {
|
|
this._finished = f;
|
|
}
|
|
setIsStarted(f) {
|
|
this._started = f;
|
|
}
|
|
isAvailable() {
|
|
return this._available;
|
|
}
|
|
setIsAvailable(v) {
|
|
this._available = v;
|
|
}
|
|
setState(timeSeconds, weight) {
|
|
this._stateTimeSeconds = timeSeconds;
|
|
this._stateWeight = weight;
|
|
}
|
|
getStateTime() {
|
|
return this._stateTimeSeconds;
|
|
}
|
|
getStateWeight() {
|
|
return this._stateWeight;
|
|
}
|
|
getLastCheckEventSeconds() {
|
|
return this._lastEventCheckSeconds;
|
|
}
|
|
setLastCheckEventSeconds(checkSeconds) {
|
|
this._lastEventCheckSeconds = checkSeconds;
|
|
}
|
|
isTriggeredFadeOut() {
|
|
return this._isTriggeredFadeOut;
|
|
}
|
|
getFadeOutSeconds() {
|
|
return this._fadeOutSeconds;
|
|
}
|
|
}
|
|
class CubismMotionQueueManager {
|
|
constructor() {
|
|
this._userTimeSeconds = 0;
|
|
this._eventCustomData = null;
|
|
this._motions = [];
|
|
}
|
|
release() {
|
|
for (let i = 0; i < this._motions.length; ++i) {
|
|
if (this._motions[i]) {
|
|
this._motions[i].release();
|
|
}
|
|
}
|
|
this._motions = void 0;
|
|
}
|
|
startMotion(motion, autoDelete, userTimeSeconds) {
|
|
if (motion == null) {
|
|
return InvalidMotionQueueEntryHandleValue;
|
|
}
|
|
let motionQueueEntry;
|
|
for (let i = 0; i < this._motions.length; ++i) {
|
|
motionQueueEntry = this._motions[i];
|
|
if (motionQueueEntry == null) {
|
|
continue;
|
|
}
|
|
motionQueueEntry.setFadeOut(motionQueueEntry._motion.getFadeOutTime());
|
|
}
|
|
motionQueueEntry = new CubismMotionQueueEntry();
|
|
motionQueueEntry._autoDelete = autoDelete;
|
|
motionQueueEntry._motion = motion;
|
|
this._motions.push(motionQueueEntry);
|
|
return motionQueueEntry._motionQueueEntryHandle;
|
|
}
|
|
isFinished() {
|
|
let i = 0;
|
|
while (i < this._motions.length) {
|
|
const motionQueueEntry = this._motions[i];
|
|
if (motionQueueEntry == null) {
|
|
this._motions.splice(i, 1);
|
|
continue;
|
|
}
|
|
const motion = motionQueueEntry._motion;
|
|
if (motion == null) {
|
|
motionQueueEntry.release();
|
|
this._motions.splice(i, 1);
|
|
continue;
|
|
}
|
|
if (!motionQueueEntry.isFinished()) {
|
|
return false;
|
|
}
|
|
i++;
|
|
}
|
|
return true;
|
|
}
|
|
isFinishedByHandle(motionQueueEntryNumber) {
|
|
for (let i = 0; i < this._motions.length; i++) {
|
|
const motionQueueEntry = this._motions[i];
|
|
if (motionQueueEntry == null) {
|
|
continue;
|
|
}
|
|
if (motionQueueEntry._motionQueueEntryHandle == motionQueueEntryNumber && !motionQueueEntry.isFinished()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
stopAllMotions() {
|
|
for (let i = 0; i < this._motions.length; i++) {
|
|
const motionQueueEntry = this._motions[i];
|
|
if (motionQueueEntry != null) {
|
|
motionQueueEntry.release();
|
|
}
|
|
}
|
|
this._motions = [];
|
|
}
|
|
getCubismMotionQueueEntry(motionQueueEntryNumber) {
|
|
return this._motions.find((entry) => entry != null && entry._motionQueueEntryHandle == motionQueueEntryNumber);
|
|
}
|
|
setEventCallback(callback, customData = null) {
|
|
this._eventCallBack = callback;
|
|
this._eventCustomData = customData;
|
|
}
|
|
doUpdateMotion(model, userTimeSeconds) {
|
|
let updated = false;
|
|
let i = 0;
|
|
while (i < this._motions.length) {
|
|
const motionQueueEntry = this._motions[i];
|
|
if (motionQueueEntry == null) {
|
|
this._motions.splice(i, 1);
|
|
continue;
|
|
}
|
|
const motion = motionQueueEntry._motion;
|
|
if (motion == null) {
|
|
motionQueueEntry.release();
|
|
this._motions.splice(i, 1);
|
|
continue;
|
|
}
|
|
motion.updateParameters(model, motionQueueEntry, userTimeSeconds);
|
|
updated = true;
|
|
const firedList = motion.getFiredEvent(motionQueueEntry.getLastCheckEventSeconds() - motionQueueEntry.getStartTime(), userTimeSeconds - motionQueueEntry.getStartTime());
|
|
for (let i2 = 0; i2 < firedList.length; ++i2) {
|
|
this._eventCallBack(this, firedList[i2], this._eventCustomData);
|
|
}
|
|
motionQueueEntry.setLastCheckEventSeconds(userTimeSeconds);
|
|
if (motionQueueEntry.isFinished()) {
|
|
motionQueueEntry.release();
|
|
this._motions.splice(i, 1);
|
|
} else {
|
|
if (motionQueueEntry.isTriggeredFadeOut()) {
|
|
motionQueueEntry.startFadeOut(motionQueueEntry.getFadeOutSeconds(), userTimeSeconds);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return updated;
|
|
}
|
|
}
|
|
const InvalidMotionQueueEntryHandleValue = -1;
|
|
class Cubism4ExpressionManager extends ExpressionManager {
|
|
constructor(settings, options) {
|
|
var _a;
|
|
super(settings, options);
|
|
this.queueManager = new CubismMotionQueueManager();
|
|
this.definitions = (_a = settings.expressions) != null ? _a : [];
|
|
this.init();
|
|
}
|
|
isFinished() {
|
|
return this.queueManager.isFinished();
|
|
}
|
|
getExpressionIndex(name) {
|
|
return this.definitions.findIndex((def) => def.Name === name);
|
|
}
|
|
getExpressionFile(definition) {
|
|
return definition.File;
|
|
}
|
|
createExpression(data, definition) {
|
|
return CubismExpressionMotion.create(data);
|
|
}
|
|
_setExpression(motion) {
|
|
return this.queueManager.startMotion(motion, false, performance.now());
|
|
}
|
|
stopAllExpressions() {
|
|
this.queueManager.stopAllMotions();
|
|
}
|
|
updateParameters(model, now) {
|
|
return this.queueManager.doUpdateMotion(model, now);
|
|
}
|
|
}
|
|
class CubismModelSettingsJson {
|
|
constructor(json) {
|
|
this.groups = json.Groups;
|
|
this.hitAreas = json.HitAreas;
|
|
this.layout = json.Layout;
|
|
this.moc = json.FileReferences.Moc;
|
|
this.expressions = json.FileReferences.Expressions;
|
|
this.motions = json.FileReferences.Motions;
|
|
this.textures = json.FileReferences.Textures;
|
|
this.physics = json.FileReferences.Physics;
|
|
this.pose = json.FileReferences.Pose;
|
|
}
|
|
getEyeBlinkParameters() {
|
|
var _a, _b;
|
|
return (_b = (_a = this.groups) == null ? void 0 : _a.find((group) => group.Name === "EyeBlink")) == null ? void 0 : _b.Ids;
|
|
}
|
|
getLipSyncParameters() {
|
|
var _a, _b;
|
|
return (_b = (_a = this.groups) == null ? void 0 : _a.find((group) => group.Name === "LipSync")) == null ? void 0 : _b.Ids;
|
|
}
|
|
}
|
|
class Cubism4ModelSettings extends ModelSettings {
|
|
constructor(json) {
|
|
super(json);
|
|
if (!Cubism4ModelSettings.isValidJSON(json)) {
|
|
throw new TypeError("Invalid JSON.");
|
|
}
|
|
Object.assign(this, new CubismModelSettingsJson(json));
|
|
}
|
|
static isValidJSON(json) {
|
|
var _a;
|
|
return !!(json == null ? void 0 : json.FileReferences) && typeof json.FileReferences.Moc === "string" && ((_a = json.FileReferences.Textures) == null ? void 0 : _a.length) > 0 && json.FileReferences.Textures.every((item) => typeof item === "string");
|
|
}
|
|
replaceFiles(replace) {
|
|
super.replaceFiles(replace);
|
|
if (this.motions) {
|
|
for (const [group, motions] of Object.entries(this.motions)) {
|
|
for (let i = 0; i < motions.length; i++) {
|
|
motions[i].File = replace(motions[i].File, `motions.${group}[${i}].File`);
|
|
if (motions[i].Sound !== void 0) {
|
|
motions[i].Sound = replace(motions[i].Sound, `motions.${group}[${i}].Sound`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (this.expressions) {
|
|
for (let i = 0; i < this.expressions.length; i++) {
|
|
this.expressions[i].File = replace(this.expressions[i].File, `expressions[${i}].File`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
applyMixins(Cubism4ModelSettings, [CubismModelSettingsJson]);
|
|
var CubismMotionCurveTarget = /* @__PURE__ */ ((CubismMotionCurveTarget2) => {
|
|
CubismMotionCurveTarget2[CubismMotionCurveTarget2["CubismMotionCurveTarget_Model"] = 0] = "CubismMotionCurveTarget_Model";
|
|
CubismMotionCurveTarget2[CubismMotionCurveTarget2["CubismMotionCurveTarget_Parameter"] = 1] = "CubismMotionCurveTarget_Parameter";
|
|
CubismMotionCurveTarget2[CubismMotionCurveTarget2["CubismMotionCurveTarget_PartOpacity"] = 2] = "CubismMotionCurveTarget_PartOpacity";
|
|
return CubismMotionCurveTarget2;
|
|
})(CubismMotionCurveTarget || {});
|
|
var CubismMotionSegmentType = /* @__PURE__ */ ((CubismMotionSegmentType2) => {
|
|
CubismMotionSegmentType2[CubismMotionSegmentType2["CubismMotionSegmentType_Linear"] = 0] = "CubismMotionSegmentType_Linear";
|
|
CubismMotionSegmentType2[CubismMotionSegmentType2["CubismMotionSegmentType_Bezier"] = 1] = "CubismMotionSegmentType_Bezier";
|
|
CubismMotionSegmentType2[CubismMotionSegmentType2["CubismMotionSegmentType_Stepped"] = 2] = "CubismMotionSegmentType_Stepped";
|
|
CubismMotionSegmentType2[CubismMotionSegmentType2["CubismMotionSegmentType_InverseStepped"] = 3] = "CubismMotionSegmentType_InverseStepped";
|
|
return CubismMotionSegmentType2;
|
|
})(CubismMotionSegmentType || {});
|
|
class CubismMotionPoint {
|
|
constructor(time = 0, value = 0) {
|
|
this.time = time;
|
|
this.value = value;
|
|
}
|
|
}
|
|
class CubismMotionSegment {
|
|
constructor() {
|
|
this.basePointIndex = 0;
|
|
this.segmentType = 0;
|
|
}
|
|
}
|
|
class CubismMotionCurve {
|
|
constructor() {
|
|
this.id = "";
|
|
this.type = 0;
|
|
this.segmentCount = 0;
|
|
this.baseSegmentIndex = 0;
|
|
this.fadeInTime = 0;
|
|
this.fadeOutTime = 0;
|
|
}
|
|
}
|
|
class CubismMotionEvent {
|
|
constructor() {
|
|
this.fireTime = 0;
|
|
this.value = "";
|
|
}
|
|
}
|
|
class CubismMotionData {
|
|
constructor() {
|
|
this.duration = 0;
|
|
this.loop = false;
|
|
this.curveCount = 0;
|
|
this.eventCount = 0;
|
|
this.fps = 0;
|
|
this.curves = [];
|
|
this.segments = [];
|
|
this.points = [];
|
|
this.events = [];
|
|
}
|
|
}
|
|
class CubismMotionJson {
|
|
constructor(json) {
|
|
this._json = json;
|
|
}
|
|
release() {
|
|
this._json = void 0;
|
|
}
|
|
getMotionDuration() {
|
|
return this._json.Meta.Duration;
|
|
}
|
|
isMotionLoop() {
|
|
return this._json.Meta.Loop || false;
|
|
}
|
|
getEvaluationOptionFlag(flagType) {
|
|
if (EvaluationOptionFlag.EvaluationOptionFlag_AreBeziersRistricted == flagType) {
|
|
return !!this._json.Meta.AreBeziersRestricted;
|
|
}
|
|
return false;
|
|
}
|
|
getMotionCurveCount() {
|
|
return this._json.Meta.CurveCount;
|
|
}
|
|
getMotionFps() {
|
|
return this._json.Meta.Fps;
|
|
}
|
|
getMotionTotalSegmentCount() {
|
|
return this._json.Meta.TotalSegmentCount;
|
|
}
|
|
getMotionTotalPointCount() {
|
|
return this._json.Meta.TotalPointCount;
|
|
}
|
|
getMotionFadeInTime() {
|
|
return this._json.Meta.FadeInTime;
|
|
}
|
|
getMotionFadeOutTime() {
|
|
return this._json.Meta.FadeOutTime;
|
|
}
|
|
getMotionCurveTarget(curveIndex) {
|
|
return this._json.Curves[curveIndex].Target;
|
|
}
|
|
getMotionCurveId(curveIndex) {
|
|
return this._json.Curves[curveIndex].Id;
|
|
}
|
|
getMotionCurveFadeInTime(curveIndex) {
|
|
return this._json.Curves[curveIndex].FadeInTime;
|
|
}
|
|
getMotionCurveFadeOutTime(curveIndex) {
|
|
return this._json.Curves[curveIndex].FadeOutTime;
|
|
}
|
|
getMotionCurveSegmentCount(curveIndex) {
|
|
return this._json.Curves[curveIndex].Segments.length;
|
|
}
|
|
getMotionCurveSegment(curveIndex, segmentIndex) {
|
|
return this._json.Curves[curveIndex].Segments[segmentIndex];
|
|
}
|
|
getEventCount() {
|
|
return this._json.Meta.UserDataCount || 0;
|
|
}
|
|
getTotalEventValueSize() {
|
|
return this._json.Meta.TotalUserDataSize;
|
|
}
|
|
getEventTime(userDataIndex) {
|
|
return this._json.UserData[userDataIndex].Time;
|
|
}
|
|
getEventValue(userDataIndex) {
|
|
return this._json.UserData[userDataIndex].Value;
|
|
}
|
|
}
|
|
var EvaluationOptionFlag = /* @__PURE__ */ ((EvaluationOptionFlag2) => {
|
|
EvaluationOptionFlag2[EvaluationOptionFlag2["EvaluationOptionFlag_AreBeziersRistricted"] = 0] = "EvaluationOptionFlag_AreBeziersRistricted";
|
|
return EvaluationOptionFlag2;
|
|
})(EvaluationOptionFlag || {});
|
|
const EffectNameEyeBlink = "EyeBlink";
|
|
const EffectNameLipSync = "LipSync";
|
|
const TargetNameModel = "Model";
|
|
const TargetNameParameter = "Parameter";
|
|
const TargetNamePartOpacity = "PartOpacity";
|
|
const UseOldBeziersCurveMotion = false;
|
|
function lerpPoints(a, b, t) {
|
|
const result = new CubismMotionPoint();
|
|
result.time = a.time + (b.time - a.time) * t;
|
|
result.value = a.value + (b.value - a.value) * t;
|
|
return result;
|
|
}
|
|
function linearEvaluate(points, time) {
|
|
let t = (time - points[0].time) / (points[1].time - points[0].time);
|
|
if (t < 0) {
|
|
t = 0;
|
|
}
|
|
return points[0].value + (points[1].value - points[0].value) * t;
|
|
}
|
|
function bezierEvaluate(points, time) {
|
|
let t = (time - points[0].time) / (points[3].time - points[0].time);
|
|
if (t < 0) {
|
|
t = 0;
|
|
}
|
|
const p01 = lerpPoints(points[0], points[1], t);
|
|
const p12 = lerpPoints(points[1], points[2], t);
|
|
const p23 = lerpPoints(points[2], points[3], t);
|
|
const p012 = lerpPoints(p01, p12, t);
|
|
const p123 = lerpPoints(p12, p23, t);
|
|
return lerpPoints(p012, p123, t).value;
|
|
}
|
|
function bezierEvaluateCardanoInterpretation(points, time) {
|
|
const x = time;
|
|
const x1 = points[0].time;
|
|
const x2 = points[3].time;
|
|
const cx1 = points[1].time;
|
|
const cx2 = points[2].time;
|
|
const a = x2 - 3 * cx2 + 3 * cx1 - x1;
|
|
const b = 3 * cx2 - 6 * cx1 + 3 * x1;
|
|
const c = 3 * cx1 - 3 * x1;
|
|
const d = x1 - x;
|
|
const t = CubismMath.cardanoAlgorithmForBezier(a, b, c, d);
|
|
const p01 = lerpPoints(points[0], points[1], t);
|
|
const p12 = lerpPoints(points[1], points[2], t);
|
|
const p23 = lerpPoints(points[2], points[3], t);
|
|
const p012 = lerpPoints(p01, p12, t);
|
|
const p123 = lerpPoints(p12, p23, t);
|
|
return lerpPoints(p012, p123, t).value;
|
|
}
|
|
function steppedEvaluate(points, time) {
|
|
return points[0].value;
|
|
}
|
|
function inverseSteppedEvaluate(points, time) {
|
|
return points[1].value;
|
|
}
|
|
function evaluateCurve(motionData, index, time) {
|
|
const curve = motionData.curves[index];
|
|
let target = -1;
|
|
const totalSegmentCount = curve.baseSegmentIndex + curve.segmentCount;
|
|
let pointPosition = 0;
|
|
for (let i = curve.baseSegmentIndex; i < totalSegmentCount; ++i) {
|
|
pointPosition = motionData.segments[i].basePointIndex + (motionData.segments[i].segmentType == CubismMotionSegmentType.CubismMotionSegmentType_Bezier ? 3 : 1);
|
|
if (motionData.points[pointPosition].time > time) {
|
|
target = i;
|
|
break;
|
|
}
|
|
}
|
|
if (target == -1) {
|
|
return motionData.points[pointPosition].value;
|
|
}
|
|
const segment = motionData.segments[target];
|
|
return segment.evaluate(motionData.points.slice(segment.basePointIndex), time);
|
|
}
|
|
class CubismMotion extends ACubismMotion {
|
|
constructor() {
|
|
super();
|
|
this._eyeBlinkParameterIds = [];
|
|
this._lipSyncParameterIds = [];
|
|
this._sourceFrameRate = 30;
|
|
this._loopDurationSeconds = -1;
|
|
this._isLoop = false;
|
|
this._isLoopFadeIn = true;
|
|
this._lastWeight = 0;
|
|
}
|
|
static create(json, onFinishedMotionHandler) {
|
|
const ret = new CubismMotion();
|
|
ret.parse(json);
|
|
ret._sourceFrameRate = ret._motionData.fps;
|
|
ret._loopDurationSeconds = ret._motionData.duration;
|
|
ret._onFinishedMotion = onFinishedMotionHandler;
|
|
return ret;
|
|
}
|
|
doUpdateParameters(model, userTimeSeconds, fadeWeight, motionQueueEntry) {
|
|
if (this._modelCurveIdEyeBlink == null) {
|
|
this._modelCurveIdEyeBlink = EffectNameEyeBlink;
|
|
}
|
|
if (this._modelCurveIdLipSync == null) {
|
|
this._modelCurveIdLipSync = EffectNameLipSync;
|
|
}
|
|
let timeOffsetSeconds = userTimeSeconds - motionQueueEntry.getStartTime();
|
|
if (timeOffsetSeconds < 0) {
|
|
timeOffsetSeconds = 0;
|
|
}
|
|
let lipSyncValue = Number.MAX_VALUE;
|
|
let eyeBlinkValue = Number.MAX_VALUE;
|
|
const MaxTargetSize = 64;
|
|
let lipSyncFlags = 0;
|
|
let eyeBlinkFlags = 0;
|
|
if (this._eyeBlinkParameterIds.length > MaxTargetSize) {
|
|
CubismLogDebug("too many eye blink targets : {0}", this._eyeBlinkParameterIds.length);
|
|
}
|
|
if (this._lipSyncParameterIds.length > MaxTargetSize) {
|
|
CubismLogDebug("too many lip sync targets : {0}", this._lipSyncParameterIds.length);
|
|
}
|
|
const tmpFadeIn = this._fadeInSeconds <= 0 ? 1 : CubismMath.getEasingSine((userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / this._fadeInSeconds);
|
|
const tmpFadeOut = this._fadeOutSeconds <= 0 || motionQueueEntry.getEndTime() < 0 ? 1 : CubismMath.getEasingSine((motionQueueEntry.getEndTime() - userTimeSeconds) / this._fadeOutSeconds);
|
|
let value;
|
|
let c, parameterIndex;
|
|
let time = timeOffsetSeconds;
|
|
if (this._isLoop) {
|
|
while (time > this._motionData.duration) {
|
|
time -= this._motionData.duration;
|
|
}
|
|
}
|
|
const curves = this._motionData.curves;
|
|
for (c = 0; c < this._motionData.curveCount && curves[c].type == CubismMotionCurveTarget.CubismMotionCurveTarget_Model; ++c) {
|
|
value = evaluateCurve(this._motionData, c, time);
|
|
if (curves[c].id == this._modelCurveIdEyeBlink) {
|
|
eyeBlinkValue = value;
|
|
} else if (curves[c].id == this._modelCurveIdLipSync) {
|
|
lipSyncValue = value;
|
|
}
|
|
}
|
|
for (; c < this._motionData.curveCount && curves[c].type == CubismMotionCurveTarget.CubismMotionCurveTarget_Parameter; ++c) {
|
|
parameterIndex = model.getParameterIndex(curves[c].id);
|
|
if (parameterIndex == -1) {
|
|
continue;
|
|
}
|
|
const sourceValue = model.getParameterValueByIndex(parameterIndex);
|
|
value = evaluateCurve(this._motionData, c, time);
|
|
if (eyeBlinkValue != Number.MAX_VALUE) {
|
|
for (let i = 0; i < this._eyeBlinkParameterIds.length && i < MaxTargetSize; ++i) {
|
|
if (this._eyeBlinkParameterIds[i] == curves[c].id) {
|
|
value *= eyeBlinkValue;
|
|
eyeBlinkFlags |= 1 << i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (lipSyncValue != Number.MAX_VALUE) {
|
|
for (let i = 0; i < this._lipSyncParameterIds.length && i < MaxTargetSize; ++i) {
|
|
if (this._lipSyncParameterIds[i] == curves[c].id) {
|
|
value += lipSyncValue;
|
|
lipSyncFlags |= 1 << i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
let v;
|
|
if (curves[c].fadeInTime < 0 && curves[c].fadeOutTime < 0) {
|
|
v = sourceValue + (value - sourceValue) * fadeWeight;
|
|
} else {
|
|
let fin;
|
|
let fout;
|
|
if (curves[c].fadeInTime < 0) {
|
|
fin = tmpFadeIn;
|
|
} else {
|
|
fin = curves[c].fadeInTime == 0 ? 1 : CubismMath.getEasingSine((userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / curves[c].fadeInTime);
|
|
}
|
|
if (curves[c].fadeOutTime < 0) {
|
|
fout = tmpFadeOut;
|
|
} else {
|
|
fout = curves[c].fadeOutTime == 0 || motionQueueEntry.getEndTime() < 0 ? 1 : CubismMath.getEasingSine((motionQueueEntry.getEndTime() - userTimeSeconds) / curves[c].fadeOutTime);
|
|
}
|
|
const paramWeight = this._weight * fin * fout;
|
|
v = sourceValue + (value - sourceValue) * paramWeight;
|
|
}
|
|
// model.setParameterValueByIndex(parameterIndex, v, 1);
|
|
if (parameterIndex != model.getParameterIndex("ParamMouthOpenY") && parameterIndex != model.getParameterIndex("ParamMouthForm") && parameterIndex != model.getParameterIndex("Part01Mouth001")) {
|
|
model.setParameterValueByIndex(parameterIndex, v, 1);
|
|
// console.log(value)
|
|
}
|
|
}
|
|
{
|
|
if (eyeBlinkValue != Number.MAX_VALUE) {
|
|
for (let i = 0; i < this._eyeBlinkParameterIds.length && i < MaxTargetSize; ++i) {
|
|
const sourceValue = model.getParameterValueById(this._eyeBlinkParameterIds[i]);
|
|
if (eyeBlinkFlags >> i & 1) {
|
|
continue;
|
|
}
|
|
const v = sourceValue + (eyeBlinkValue - sourceValue) * fadeWeight;
|
|
model.setParameterValueById(this._eyeBlinkParameterIds[i], v);
|
|
}
|
|
}
|
|
if (lipSyncValue != Number.MAX_VALUE) {
|
|
for (let i = 0; i < this._lipSyncParameterIds.length && i < MaxTargetSize; ++i) {
|
|
const sourceValue = model.getParameterValueById(this._lipSyncParameterIds[i]);
|
|
if (lipSyncFlags >> i & 1) {
|
|
continue;
|
|
}
|
|
const v = sourceValue + (lipSyncValue - sourceValue) * fadeWeight;
|
|
model.setParameterValueById(this._lipSyncParameterIds[i], v);
|
|
}
|
|
}
|
|
}
|
|
for (; c < this._motionData.curveCount && curves[c].type == CubismMotionCurveTarget.CubismMotionCurveTarget_PartOpacity; ++c) {
|
|
value = evaluateCurve(this._motionData, c, time);
|
|
if (CubismConfig.setOpacityFromMotion) {
|
|
model.setPartOpacityById(curves[c].id, value);
|
|
} else {
|
|
parameterIndex = model.getParameterIndex(curves[c].id);
|
|
if (parameterIndex == -1) {
|
|
continue;
|
|
}
|
|
model.setParameterValueByIndex(parameterIndex, value);
|
|
}
|
|
}
|
|
if (timeOffsetSeconds >= this._motionData.duration) {
|
|
if (this._isLoop) {
|
|
motionQueueEntry.setStartTime(userTimeSeconds);
|
|
if (this._isLoopFadeIn) {
|
|
motionQueueEntry.setFadeInStartTime(userTimeSeconds);
|
|
}
|
|
} else {
|
|
if (this._onFinishedMotion) {
|
|
this._onFinishedMotion(this);
|
|
}
|
|
motionQueueEntry.setIsFinished(true);
|
|
}
|
|
}
|
|
this._lastWeight = fadeWeight;
|
|
}
|
|
setIsLoop(loop) {
|
|
this._isLoop = loop;
|
|
}
|
|
isLoop() {
|
|
return this._isLoop;
|
|
}
|
|
setIsLoopFadeIn(loopFadeIn) {
|
|
this._isLoopFadeIn = loopFadeIn;
|
|
}
|
|
isLoopFadeIn() {
|
|
return this._isLoopFadeIn;
|
|
}
|
|
getDuration() {
|
|
return this._isLoop ? -1 : this._loopDurationSeconds;
|
|
}
|
|
getLoopDuration() {
|
|
return this._loopDurationSeconds;
|
|
}
|
|
setParameterFadeInTime(parameterId, value) {
|
|
const curves = this._motionData.curves;
|
|
for (let i = 0; i < this._motionData.curveCount; ++i) {
|
|
if (parameterId == curves[i].id) {
|
|
curves[i].fadeInTime = value;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
setParameterFadeOutTime(parameterId, value) {
|
|
const curves = this._motionData.curves;
|
|
for (let i = 0; i < this._motionData.curveCount; ++i) {
|
|
if (parameterId == curves[i].id) {
|
|
curves[i].fadeOutTime = value;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
getParameterFadeInTime(parameterId) {
|
|
const curves = this._motionData.curves;
|
|
for (let i = 0; i < this._motionData.curveCount; ++i) {
|
|
if (parameterId == curves[i].id) {
|
|
return curves[i].fadeInTime;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
getParameterFadeOutTime(parameterId) {
|
|
const curves = this._motionData.curves;
|
|
for (let i = 0; i < this._motionData.curveCount; ++i) {
|
|
if (parameterId == curves[i].id) {
|
|
return curves[i].fadeOutTime;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
setEffectIds(eyeBlinkParameterIds, lipSyncParameterIds) {
|
|
this._eyeBlinkParameterIds = eyeBlinkParameterIds;
|
|
this._lipSyncParameterIds = lipSyncParameterIds;
|
|
}
|
|
release() {
|
|
this._motionData = void 0;
|
|
}
|
|
parse(motionJson) {
|
|
this._motionData = new CubismMotionData();
|
|
let json = new CubismMotionJson(motionJson);
|
|
this._motionData.duration = json.getMotionDuration();
|
|
this._motionData.loop = json.isMotionLoop();
|
|
this._motionData.curveCount = json.getMotionCurveCount();
|
|
this._motionData.fps = json.getMotionFps();
|
|
this._motionData.eventCount = json.getEventCount();
|
|
const areBeziersRestructed = json.getEvaluationOptionFlag(EvaluationOptionFlag.EvaluationOptionFlag_AreBeziersRistricted);
|
|
const fadeInSeconds = json.getMotionFadeInTime();
|
|
const fadeOutSeconds = json.getMotionFadeOutTime();
|
|
if (fadeInSeconds !== void 0) {
|
|
this._fadeInSeconds = fadeInSeconds < 0 ? 1 : fadeInSeconds;
|
|
} else {
|
|
this._fadeInSeconds = 1;
|
|
}
|
|
if (fadeOutSeconds !== void 0) {
|
|
this._fadeOutSeconds = fadeOutSeconds < 0 ? 1 : fadeOutSeconds;
|
|
} else {
|
|
this._fadeOutSeconds = 1;
|
|
}
|
|
this._motionData.curves = Array.from({ length: this._motionData.curveCount }).map(() => new CubismMotionCurve());
|
|
this._motionData.segments = Array.from({ length: json.getMotionTotalSegmentCount() }).map(() => new CubismMotionSegment());
|
|
this._motionData.events = Array.from({ length: this._motionData.eventCount }).map(() => new CubismMotionEvent());
|
|
this._motionData.points = [];
|
|
let totalPointCount = 0;
|
|
let totalSegmentCount = 0;
|
|
for (let curveCount = 0; curveCount < this._motionData.curveCount; ++curveCount) {
|
|
const curve = this._motionData.curves[curveCount];
|
|
switch (json.getMotionCurveTarget(curveCount)) {
|
|
case TargetNameModel:
|
|
curve.type = CubismMotionCurveTarget.CubismMotionCurveTarget_Model;
|
|
break;
|
|
case TargetNameParameter:
|
|
curve.type = CubismMotionCurveTarget.CubismMotionCurveTarget_Parameter;
|
|
break;
|
|
case TargetNamePartOpacity:
|
|
curve.type = CubismMotionCurveTarget.CubismMotionCurveTarget_PartOpacity;
|
|
break;
|
|
default:
|
|
CubismLogWarning('Warning : Unable to get segment type from Curve! The number of "CurveCount" may be incorrect!');
|
|
}
|
|
curve.id = json.getMotionCurveId(curveCount);
|
|
curve.baseSegmentIndex = totalSegmentCount;
|
|
const fadeInTime = json.getMotionCurveFadeInTime(curveCount);
|
|
const fadeOutTime = json.getMotionCurveFadeOutTime(curveCount);
|
|
curve.fadeInTime = fadeInTime !== void 0 ? fadeInTime : -1;
|
|
curve.fadeOutTime = fadeOutTime !== void 0 ? fadeOutTime : -1;
|
|
for (let segmentPosition = 0; segmentPosition < json.getMotionCurveSegmentCount(curveCount); ) {
|
|
if (segmentPosition == 0) {
|
|
this._motionData.segments[totalSegmentCount].basePointIndex = totalPointCount;
|
|
this._motionData.points[totalPointCount] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition), json.getMotionCurveSegment(curveCount, segmentPosition + 1));
|
|
totalPointCount += 1;
|
|
segmentPosition += 2;
|
|
} else {
|
|
this._motionData.segments[totalSegmentCount].basePointIndex = totalPointCount - 1;
|
|
}
|
|
const segment = json.getMotionCurveSegment(curveCount, segmentPosition);
|
|
switch (segment) {
|
|
case CubismMotionSegmentType.CubismMotionSegmentType_Linear: {
|
|
this._motionData.segments[totalSegmentCount].segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Linear;
|
|
this._motionData.segments[totalSegmentCount].evaluate = linearEvaluate;
|
|
this._motionData.points[totalPointCount] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition + 1), json.getMotionCurveSegment(curveCount, segmentPosition + 2));
|
|
totalPointCount += 1;
|
|
segmentPosition += 3;
|
|
break;
|
|
}
|
|
case CubismMotionSegmentType.CubismMotionSegmentType_Bezier: {
|
|
this._motionData.segments[totalSegmentCount].segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Bezier;
|
|
if (areBeziersRestructed || UseOldBeziersCurveMotion) {
|
|
this._motionData.segments[totalSegmentCount].evaluate = bezierEvaluate;
|
|
} else {
|
|
this._motionData.segments[totalSegmentCount].evaluate = bezierEvaluateCardanoInterpretation;
|
|
}
|
|
this._motionData.points[totalPointCount] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition + 1), json.getMotionCurveSegment(curveCount, segmentPosition + 2));
|
|
this._motionData.points[totalPointCount + 1] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition + 3), json.getMotionCurveSegment(curveCount, segmentPosition + 4));
|
|
this._motionData.points[totalPointCount + 2] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition + 5), json.getMotionCurveSegment(curveCount, segmentPosition + 6));
|
|
totalPointCount += 3;
|
|
segmentPosition += 7;
|
|
break;
|
|
}
|
|
case CubismMotionSegmentType.CubismMotionSegmentType_Stepped: {
|
|
this._motionData.segments[totalSegmentCount].segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Stepped;
|
|
this._motionData.segments[totalSegmentCount].evaluate = steppedEvaluate;
|
|
this._motionData.points[totalPointCount] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition + 1), json.getMotionCurveSegment(curveCount, segmentPosition + 2));
|
|
totalPointCount += 1;
|
|
segmentPosition += 3;
|
|
break;
|
|
}
|
|
case CubismMotionSegmentType.CubismMotionSegmentType_InverseStepped: {
|
|
this._motionData.segments[totalSegmentCount].segmentType = CubismMotionSegmentType.CubismMotionSegmentType_InverseStepped;
|
|
this._motionData.segments[totalSegmentCount].evaluate = inverseSteppedEvaluate;
|
|
this._motionData.points[totalPointCount] = new CubismMotionPoint(json.getMotionCurveSegment(curveCount, segmentPosition + 1), json.getMotionCurveSegment(curveCount, segmentPosition + 2));
|
|
totalPointCount += 1;
|
|
segmentPosition += 3;
|
|
break;
|
|
}
|
|
}
|
|
++curve.segmentCount;
|
|
++totalSegmentCount;
|
|
}
|
|
this._motionData.curves.push(curve);
|
|
}
|
|
for (let userdatacount = 0; userdatacount < json.getEventCount(); ++userdatacount) {
|
|
this._motionData.events[userdatacount].fireTime = json.getEventTime(userdatacount);
|
|
this._motionData.events[userdatacount].value = json.getEventValue(userdatacount);
|
|
}
|
|
json.release();
|
|
}
|
|
getFiredEvent(beforeCheckTimeSeconds, motionTimeSeconds) {
|
|
this._firedEventValues.length = 0;
|
|
for (let u = 0; u < this._motionData.eventCount; ++u) {
|
|
if (this._motionData.events[u].fireTime > beforeCheckTimeSeconds && this._motionData.events[u].fireTime <= motionTimeSeconds) {
|
|
this._firedEventValues.push(this._motionData.events[u].value);
|
|
}
|
|
}
|
|
return this._firedEventValues;
|
|
}
|
|
}
|
|
class Cubism4MotionManager extends MotionManager {
|
|
constructor(settings, options) {
|
|
var _a;
|
|
super(settings, options);
|
|
this.groups = { idle: "Idle" };
|
|
this.motionDataType = "json";
|
|
this.queueManager = new CubismMotionQueueManager();
|
|
this.definitions = (_a = settings.motions) != null ? _a : {};
|
|
this.eyeBlinkIds = settings.getEyeBlinkParameters() || [];
|
|
this.lipSyncIds = settings.getLipSyncParameters() || [];
|
|
this.init(options);
|
|
}
|
|
init(options) {
|
|
super.init(options);
|
|
if (this.settings.expressions) {
|
|
this.expressionManager = new Cubism4ExpressionManager(this.settings, options);
|
|
}
|
|
this.queueManager.setEventCallback((caller, eventValue, customData) => {
|
|
this.emit("motion:" + eventValue);
|
|
});
|
|
}
|
|
isFinished() {
|
|
return this.queueManager.isFinished();
|
|
}
|
|
_startMotion(motion, onFinish) {
|
|
motion.setFinishedMotionHandler(onFinish);
|
|
this.queueManager.stopAllMotions();
|
|
return this.queueManager.startMotion(motion, false, performance.now());
|
|
}
|
|
_stopAllMotions() {
|
|
this.queueManager.stopAllMotions();
|
|
}
|
|
createMotion(data, group, definition) {
|
|
const motion = CubismMotion.create(data);
|
|
const json = new CubismMotionJson(data);
|
|
const defaultFadingDuration = (group === this.groups.idle ? exports2.config.idleMotionFadingDuration : exports2.config.motionFadingDuration) / 1e3;
|
|
if (json.getMotionFadeInTime() === void 0) {
|
|
motion.setFadeInTime(definition.FadeInTime > 0 ? definition.FadeInTime : defaultFadingDuration);
|
|
}
|
|
if (json.getMotionFadeOutTime() === void 0) {
|
|
motion.setFadeOutTime(definition.FadeOutTime > 0 ? definition.FadeOutTime : defaultFadingDuration);
|
|
}
|
|
motion.setEffectIds(this.eyeBlinkIds, this.lipSyncIds);
|
|
return motion;
|
|
}
|
|
getMotionFile(definition) {
|
|
return definition.File;
|
|
}
|
|
getMotionName(definition) {
|
|
return definition.File;
|
|
}
|
|
getSoundFile(definition) {
|
|
return definition.Sound;
|
|
}
|
|
updateParameters(model, now) {
|
|
return this.queueManager.doUpdateMotion(model, now);
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.queueManager.release();
|
|
this.queueManager = void 0;
|
|
}
|
|
}
|
|
const ParamAngleX = "ParamAngleX";
|
|
const ParamAngleY = "ParamAngleY";
|
|
const ParamAngleZ = "ParamAngleZ";
|
|
const ParamEyeBallX = "ParamEyeBallX";
|
|
const ParamEyeBallY = "ParamEyeBallY";
|
|
const ParamBodyAngleX = "ParamBodyAngleX";
|
|
const ParamBreath = "ParamBreath";
|
|
class CubismBreath {
|
|
constructor() {
|
|
this._breathParameters = [];
|
|
this._currentTime = 0;
|
|
}
|
|
static create() {
|
|
return new CubismBreath();
|
|
}
|
|
setParameters(breathParameters) {
|
|
this._breathParameters = breathParameters;
|
|
}
|
|
getParameters() {
|
|
return this._breathParameters;
|
|
}
|
|
updateParameters(model, deltaTimeSeconds) {
|
|
this._currentTime += deltaTimeSeconds;
|
|
const t = this._currentTime * 2 * 3.14159;
|
|
for (let i = 0; i < this._breathParameters.length; ++i) {
|
|
const data = this._breathParameters[i];
|
|
model.addParameterValueById(data.parameterId, data.offset + data.peak * Math.sin(t / data.cycle), data.weight);
|
|
}
|
|
}
|
|
}
|
|
class BreathParameterData {
|
|
constructor(parameterId, offset, peak, cycle, weight) {
|
|
this.parameterId = parameterId == void 0 ? void 0 : parameterId;
|
|
this.offset = offset == void 0 ? 0 : offset;
|
|
this.peak = peak == void 0 ? 0 : peak;
|
|
this.cycle = cycle == void 0 ? 0 : cycle;
|
|
this.weight = weight == void 0 ? 0 : weight;
|
|
}
|
|
}
|
|
const _CubismEyeBlink = class {
|
|
static create(modelSetting) {
|
|
return new _CubismEyeBlink(modelSetting);
|
|
}
|
|
setBlinkingInterval(blinkingInterval) {
|
|
this._blinkingIntervalSeconds = blinkingInterval;
|
|
}
|
|
setBlinkingSetting(closing, closed, opening) {
|
|
this._closingSeconds = closing;
|
|
this._closedSeconds = closed;
|
|
this._openingSeconds = opening;
|
|
}
|
|
setParameterIds(parameterIds) {
|
|
this._parameterIds = parameterIds;
|
|
}
|
|
getParameterIds() {
|
|
return this._parameterIds;
|
|
}
|
|
updateParameters(model, deltaTimeSeconds) {
|
|
this._userTimeSeconds += deltaTimeSeconds;
|
|
let parameterValue;
|
|
let t = 0;
|
|
switch (this._blinkingState) {
|
|
case EyeState.EyeState_Closing:
|
|
t = (this._userTimeSeconds - this._stateStartTimeSeconds) / this._closingSeconds;
|
|
if (t >= 1) {
|
|
t = 1;
|
|
this._blinkingState = EyeState.EyeState_Closed;
|
|
this._stateStartTimeSeconds = this._userTimeSeconds;
|
|
}
|
|
parameterValue = 1 - t;
|
|
break;
|
|
case EyeState.EyeState_Closed:
|
|
t = (this._userTimeSeconds - this._stateStartTimeSeconds) / this._closedSeconds;
|
|
if (t >= 1) {
|
|
this._blinkingState = EyeState.EyeState_Opening;
|
|
this._stateStartTimeSeconds = this._userTimeSeconds;
|
|
}
|
|
parameterValue = 0;
|
|
break;
|
|
case EyeState.EyeState_Opening:
|
|
t = (this._userTimeSeconds - this._stateStartTimeSeconds) / this._openingSeconds;
|
|
if (t >= 1) {
|
|
t = 1;
|
|
this._blinkingState = EyeState.EyeState_Interval;
|
|
this._nextBlinkingTime = this.determinNextBlinkingTiming();
|
|
}
|
|
parameterValue = t;
|
|
break;
|
|
case EyeState.EyeState_Interval:
|
|
if (this._nextBlinkingTime < this._userTimeSeconds) {
|
|
this._blinkingState = EyeState.EyeState_Closing;
|
|
this._stateStartTimeSeconds = this._userTimeSeconds;
|
|
}
|
|
parameterValue = 1;
|
|
break;
|
|
case EyeState.EyeState_First:
|
|
default:
|
|
this._blinkingState = EyeState.EyeState_Interval;
|
|
this._nextBlinkingTime = this.determinNextBlinkingTiming();
|
|
parameterValue = 1;
|
|
break;
|
|
}
|
|
if (!_CubismEyeBlink.CloseIfZero) {
|
|
parameterValue = -parameterValue;
|
|
}
|
|
for (let i = 0; i < this._parameterIds.length; ++i) {
|
|
model.setParameterValueById(this._parameterIds[i], parameterValue);
|
|
}
|
|
}
|
|
constructor(modelSetting) {
|
|
var _a, _b;
|
|
this._blinkingState = EyeState.EyeState_First;
|
|
this._nextBlinkingTime = 0;
|
|
this._stateStartTimeSeconds = 0;
|
|
this._blinkingIntervalSeconds = 4;
|
|
this._closingSeconds = 0.1;
|
|
this._closedSeconds = 0.05;
|
|
this._openingSeconds = 0.15;
|
|
this._userTimeSeconds = 0;
|
|
this._parameterIds = [];
|
|
if (modelSetting == null) {
|
|
return;
|
|
}
|
|
this._parameterIds = (_b = (_a = modelSetting.getEyeBlinkParameters()) == null ? void 0 : _a.slice()) != null ? _b : this._parameterIds;
|
|
}
|
|
determinNextBlinkingTiming() {
|
|
const r = Math.random();
|
|
return this._userTimeSeconds + r * (2 * this._blinkingIntervalSeconds - 1);
|
|
}
|
|
};
|
|
let CubismEyeBlink = _CubismEyeBlink;
|
|
CubismEyeBlink.CloseIfZero = true;
|
|
var EyeState = /* @__PURE__ */ ((EyeState2) => {
|
|
EyeState2[EyeState2["EyeState_First"] = 0] = "EyeState_First";
|
|
EyeState2[EyeState2["EyeState_Interval"] = 1] = "EyeState_Interval";
|
|
EyeState2[EyeState2["EyeState_Closing"] = 2] = "EyeState_Closing";
|
|
EyeState2[EyeState2["EyeState_Closed"] = 3] = "EyeState_Closed";
|
|
EyeState2[EyeState2["EyeState_Opening"] = 4] = "EyeState_Opening";
|
|
return EyeState2;
|
|
})(EyeState || {});
|
|
class csmRect {
|
|
constructor(x = 0, y = 0, w = 0, h = 0) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = w;
|
|
this.height = h;
|
|
}
|
|
getCenterX() {
|
|
return this.x + 0.5 * this.width;
|
|
}
|
|
getCenterY() {
|
|
return this.y + 0.5 * this.height;
|
|
}
|
|
getRight() {
|
|
return this.x + this.width;
|
|
}
|
|
getBottom() {
|
|
return this.y + this.height;
|
|
}
|
|
setRect(r) {
|
|
this.x = r.x;
|
|
this.y = r.y;
|
|
this.width = r.width;
|
|
this.height = r.height;
|
|
}
|
|
expand(w, h) {
|
|
this.x -= w;
|
|
this.y -= h;
|
|
this.width += w * 2;
|
|
this.height += h * 2;
|
|
}
|
|
}
|
|
const ColorChannelCount = 4;
|
|
const shaderCount = 10;
|
|
let s_instance;
|
|
let s_viewport;
|
|
let s_fbo;
|
|
class CubismClippingManager_WebGL {
|
|
getChannelFlagAsColor(channelNo) {
|
|
return this._channelColors[channelNo];
|
|
}
|
|
getMaskRenderTexture() {
|
|
let ret = 0;
|
|
if (this._maskTexture && this._maskTexture.texture != 0) {
|
|
this._maskTexture.frameNo = this._currentFrameNo;
|
|
ret = this._maskTexture.texture;
|
|
}
|
|
if (ret == 0) {
|
|
const size = this._clippingMaskBufferSize;
|
|
this._colorBuffer = this.gl.createTexture();
|
|
this.gl.bindTexture(this.gl.TEXTURE_2D, this._colorBuffer);
|
|
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, size, size, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null);
|
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
|
this.gl.bindTexture(this.gl.TEXTURE_2D, null);
|
|
ret = this.gl.createFramebuffer();
|
|
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, ret);
|
|
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._colorBuffer, 0);
|
|
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, s_fbo);
|
|
this._maskTexture = new CubismRenderTextureResource(this._currentFrameNo, ret);
|
|
}
|
|
return ret;
|
|
}
|
|
setGL(gl) {
|
|
this.gl = gl;
|
|
}
|
|
calcClippedDrawTotalBounds(model, clippingContext) {
|
|
let clippedDrawTotalMinX = Number.MAX_VALUE;
|
|
let clippedDrawTotalMinY = Number.MAX_VALUE;
|
|
let clippedDrawTotalMaxX = Number.MIN_VALUE;
|
|
let clippedDrawTotalMaxY = Number.MIN_VALUE;
|
|
const clippedDrawCount = clippingContext._clippedDrawableIndexList.length;
|
|
for (let clippedDrawableIndex = 0; clippedDrawableIndex < clippedDrawCount; clippedDrawableIndex++) {
|
|
const drawableIndex = clippingContext._clippedDrawableIndexList[clippedDrawableIndex];
|
|
const drawableVertexCount = model.getDrawableVertexCount(drawableIndex);
|
|
const drawableVertexes = model.getDrawableVertices(drawableIndex);
|
|
let minX = Number.MAX_VALUE;
|
|
let minY = Number.MAX_VALUE;
|
|
let maxX = Number.MIN_VALUE;
|
|
let maxY = Number.MIN_VALUE;
|
|
const loop = drawableVertexCount * Constant.vertexStep;
|
|
for (let pi = Constant.vertexOffset; pi < loop; pi += Constant.vertexStep) {
|
|
const x = drawableVertexes[pi];
|
|
const y = drawableVertexes[pi + 1];
|
|
if (x < minX) {
|
|
minX = x;
|
|
}
|
|
if (x > maxX) {
|
|
maxX = x;
|
|
}
|
|
if (y < minY) {
|
|
minY = y;
|
|
}
|
|
if (y > maxY) {
|
|
maxY = y;
|
|
}
|
|
}
|
|
if (minX == Number.MAX_VALUE) {
|
|
continue;
|
|
}
|
|
if (minX < clippedDrawTotalMinX) {
|
|
clippedDrawTotalMinX = minX;
|
|
}
|
|
if (minY < clippedDrawTotalMinY) {
|
|
clippedDrawTotalMinY = minY;
|
|
}
|
|
if (maxX > clippedDrawTotalMaxX) {
|
|
clippedDrawTotalMaxX = maxX;
|
|
}
|
|
if (maxY > clippedDrawTotalMaxY) {
|
|
clippedDrawTotalMaxY = maxY;
|
|
}
|
|
if (clippedDrawTotalMinX == Number.MAX_VALUE) {
|
|
clippingContext._allClippedDrawRect.x = 0;
|
|
clippingContext._allClippedDrawRect.y = 0;
|
|
clippingContext._allClippedDrawRect.width = 0;
|
|
clippingContext._allClippedDrawRect.height = 0;
|
|
clippingContext._isUsing = false;
|
|
} else {
|
|
clippingContext._isUsing = true;
|
|
const w = clippedDrawTotalMaxX - clippedDrawTotalMinX;
|
|
const h = clippedDrawTotalMaxY - clippedDrawTotalMinY;
|
|
clippingContext._allClippedDrawRect.x = clippedDrawTotalMinX;
|
|
clippingContext._allClippedDrawRect.y = clippedDrawTotalMinY;
|
|
clippingContext._allClippedDrawRect.width = w;
|
|
clippingContext._allClippedDrawRect.height = h;
|
|
}
|
|
}
|
|
}
|
|
constructor() {
|
|
this._maskRenderTexture = null;
|
|
this._colorBuffer = null;
|
|
this._currentFrameNo = 0;
|
|
this._clippingMaskBufferSize = 256;
|
|
this._clippingContextListForMask = [];
|
|
this._clippingContextListForDraw = [];
|
|
this._channelColors = [];
|
|
this._tmpBoundsOnModel = new csmRect();
|
|
this._tmpMatrix = new CubismMatrix44();
|
|
this._tmpMatrixForMask = new CubismMatrix44();
|
|
this._tmpMatrixForDraw = new CubismMatrix44();
|
|
let tmp = new CubismTextureColor();
|
|
tmp.R = 1;
|
|
tmp.G = 0;
|
|
tmp.B = 0;
|
|
tmp.A = 0;
|
|
this._channelColors.push(tmp);
|
|
tmp = new CubismTextureColor();
|
|
tmp.R = 0;
|
|
tmp.G = 1;
|
|
tmp.B = 0;
|
|
tmp.A = 0;
|
|
this._channelColors.push(tmp);
|
|
tmp = new CubismTextureColor();
|
|
tmp.R = 0;
|
|
tmp.G = 0;
|
|
tmp.B = 1;
|
|
tmp.A = 0;
|
|
this._channelColors.push(tmp);
|
|
tmp = new CubismTextureColor();
|
|
tmp.R = 0;
|
|
tmp.G = 0;
|
|
tmp.B = 0;
|
|
tmp.A = 1;
|
|
this._channelColors.push(tmp);
|
|
}
|
|
release() {
|
|
var _a, _b, _c;
|
|
const self2 = this;
|
|
for (let i = 0; i < this._clippingContextListForMask.length; i++) {
|
|
if (this._clippingContextListForMask[i]) {
|
|
(_a = this._clippingContextListForMask[i]) == null ? void 0 : _a.release();
|
|
}
|
|
}
|
|
self2._clippingContextListForMask = void 0;
|
|
self2._clippingContextListForDraw = void 0;
|
|
if (this._maskTexture) {
|
|
(_b = this.gl) == null ? void 0 : _b.deleteFramebuffer(this._maskTexture.texture);
|
|
self2._maskTexture = void 0;
|
|
}
|
|
self2._channelColors = void 0;
|
|
(_c = this.gl) == null ? void 0 : _c.deleteTexture(this._colorBuffer);
|
|
this._colorBuffer = null;
|
|
}
|
|
initialize(model, drawableCount, drawableMasks, drawableMaskCounts) {
|
|
for (let i = 0; i < drawableCount; i++) {
|
|
if (drawableMaskCounts[i] <= 0) {
|
|
this._clippingContextListForDraw.push(null);
|
|
continue;
|
|
}
|
|
let clippingContext = this.findSameClip(drawableMasks[i], drawableMaskCounts[i]);
|
|
if (clippingContext == null) {
|
|
clippingContext = new CubismClippingContext(this, drawableMasks[i], drawableMaskCounts[i]);
|
|
this._clippingContextListForMask.push(clippingContext);
|
|
}
|
|
clippingContext.addClippedDrawable(i);
|
|
this._clippingContextListForDraw.push(clippingContext);
|
|
}
|
|
}
|
|
setupClippingContext(model, renderer) {
|
|
this._currentFrameNo++;
|
|
let usingClipCount = 0;
|
|
for (let clipIndex = 0; clipIndex < this._clippingContextListForMask.length; clipIndex++) {
|
|
const cc = this._clippingContextListForMask[clipIndex];
|
|
this.calcClippedDrawTotalBounds(model, cc);
|
|
if (cc._isUsing) {
|
|
usingClipCount++;
|
|
}
|
|
}
|
|
if (usingClipCount > 0) {
|
|
this.gl.viewport(0, 0, this._clippingMaskBufferSize, this._clippingMaskBufferSize);
|
|
this._maskRenderTexture = this.getMaskRenderTexture();
|
|
renderer.getMvpMatrix();
|
|
renderer.preDraw();
|
|
this.setupLayoutBounds(usingClipCount);
|
|
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this._maskRenderTexture);
|
|
this.gl.clearColor(1, 1, 1, 1);
|
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
|
|
for (let clipIndex = 0; clipIndex < this._clippingContextListForMask.length; clipIndex++) {
|
|
const clipContext = this._clippingContextListForMask[clipIndex];
|
|
const allClipedDrawRect = clipContext._allClippedDrawRect;
|
|
const layoutBoundsOnTex01 = clipContext._layoutBounds;
|
|
const MARGIN = 0.05;
|
|
this._tmpBoundsOnModel.setRect(allClipedDrawRect);
|
|
this._tmpBoundsOnModel.expand(allClipedDrawRect.width * MARGIN, allClipedDrawRect.height * MARGIN);
|
|
const scaleX = layoutBoundsOnTex01.width / this._tmpBoundsOnModel.width;
|
|
const scaleY = layoutBoundsOnTex01.height / this._tmpBoundsOnModel.height;
|
|
{
|
|
this._tmpMatrix.loadIdentity();
|
|
{
|
|
this._tmpMatrix.translateRelative(-1, -1);
|
|
this._tmpMatrix.scaleRelative(2, 2);
|
|
}
|
|
{
|
|
this._tmpMatrix.translateRelative(layoutBoundsOnTex01.x, layoutBoundsOnTex01.y);
|
|
this._tmpMatrix.scaleRelative(scaleX, scaleY);
|
|
this._tmpMatrix.translateRelative(-this._tmpBoundsOnModel.x, -this._tmpBoundsOnModel.y);
|
|
}
|
|
this._tmpMatrixForMask.setMatrix(this._tmpMatrix.getArray());
|
|
}
|
|
{
|
|
this._tmpMatrix.loadIdentity();
|
|
{
|
|
this._tmpMatrix.translateRelative(layoutBoundsOnTex01.x, layoutBoundsOnTex01.y);
|
|
this._tmpMatrix.scaleRelative(scaleX, scaleY);
|
|
this._tmpMatrix.translateRelative(-this._tmpBoundsOnModel.x, -this._tmpBoundsOnModel.y);
|
|
}
|
|
this._tmpMatrixForDraw.setMatrix(this._tmpMatrix.getArray());
|
|
}
|
|
clipContext._matrixForMask.setMatrix(this._tmpMatrixForMask.getArray());
|
|
clipContext._matrixForDraw.setMatrix(this._tmpMatrixForDraw.getArray());
|
|
const clipDrawCount = clipContext._clippingIdCount;
|
|
for (let i = 0; i < clipDrawCount; i++) {
|
|
const clipDrawIndex = clipContext._clippingIdList[i];
|
|
if (!model.getDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex)) {
|
|
continue;
|
|
}
|
|
renderer.setIsCulling(model.getDrawableCulling(clipDrawIndex) != false);
|
|
renderer.setClippingContextBufferForMask(clipContext);
|
|
renderer.drawMesh(model.getDrawableTextureIndices(clipDrawIndex), model.getDrawableVertexIndexCount(clipDrawIndex), model.getDrawableVertexCount(clipDrawIndex), model.getDrawableVertexIndices(clipDrawIndex), model.getDrawableVertices(clipDrawIndex), model.getDrawableVertexUvs(clipDrawIndex), model.getDrawableOpacity(clipDrawIndex), CubismBlendMode.CubismBlendMode_Normal, false);
|
|
}
|
|
}
|
|
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, s_fbo);
|
|
renderer.setClippingContextBufferForMask(null);
|
|
this.gl.viewport(s_viewport[0], s_viewport[1], s_viewport[2], s_viewport[3]);
|
|
}
|
|
}
|
|
findSameClip(drawableMasks, drawableMaskCounts) {
|
|
for (let i = 0; i < this._clippingContextListForMask.length; i++) {
|
|
const clippingContext = this._clippingContextListForMask[i];
|
|
const count = clippingContext._clippingIdCount;
|
|
if (count != drawableMaskCounts) {
|
|
continue;
|
|
}
|
|
let sameCount = 0;
|
|
for (let j = 0; j < count; j++) {
|
|
const clipId = clippingContext._clippingIdList[j];
|
|
for (let k = 0; k < count; k++) {
|
|
if (drawableMasks[k] == clipId) {
|
|
sameCount++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (sameCount == count) {
|
|
return clippingContext;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
setupLayoutBounds(usingClipCount) {
|
|
let div = usingClipCount / ColorChannelCount;
|
|
let mod = usingClipCount % ColorChannelCount;
|
|
div = ~~div;
|
|
mod = ~~mod;
|
|
let curClipIndex = 0;
|
|
for (let channelNo = 0; channelNo < ColorChannelCount; channelNo++) {
|
|
const layoutCount = div + (channelNo < mod ? 1 : 0);
|
|
if (layoutCount == 0)
|
|
;
|
|
else if (layoutCount == 1) {
|
|
const clipContext = this._clippingContextListForMask[curClipIndex++];
|
|
clipContext._layoutChannelNo = channelNo;
|
|
clipContext._layoutBounds.x = 0;
|
|
clipContext._layoutBounds.y = 0;
|
|
clipContext._layoutBounds.width = 1;
|
|
clipContext._layoutBounds.height = 1;
|
|
} else if (layoutCount == 2) {
|
|
for (let i = 0; i < layoutCount; i++) {
|
|
let xpos = i % 2;
|
|
xpos = ~~xpos;
|
|
const cc = this._clippingContextListForMask[curClipIndex++];
|
|
cc._layoutChannelNo = channelNo;
|
|
cc._layoutBounds.x = xpos * 0.5;
|
|
cc._layoutBounds.y = 0;
|
|
cc._layoutBounds.width = 0.5;
|
|
cc._layoutBounds.height = 1;
|
|
}
|
|
} else if (layoutCount <= 4) {
|
|
for (let i = 0; i < layoutCount; i++) {
|
|
let xpos = i % 2;
|
|
let ypos = i / 2;
|
|
xpos = ~~xpos;
|
|
ypos = ~~ypos;
|
|
const cc = this._clippingContextListForMask[curClipIndex++];
|
|
cc._layoutChannelNo = channelNo;
|
|
cc._layoutBounds.x = xpos * 0.5;
|
|
cc._layoutBounds.y = ypos * 0.5;
|
|
cc._layoutBounds.width = 0.5;
|
|
cc._layoutBounds.height = 0.5;
|
|
}
|
|
} else if (layoutCount <= 9) {
|
|
for (let i = 0; i < layoutCount; i++) {
|
|
let xpos = i % 3;
|
|
let ypos = i / 3;
|
|
xpos = ~~xpos;
|
|
ypos = ~~ypos;
|
|
const cc = this._clippingContextListForMask[curClipIndex++];
|
|
cc._layoutChannelNo = channelNo;
|
|
cc._layoutBounds.x = xpos / 3;
|
|
cc._layoutBounds.y = ypos / 3;
|
|
cc._layoutBounds.width = 1 / 3;
|
|
cc._layoutBounds.height = 1 / 3;
|
|
}
|
|
} else if (CubismConfig.supportMoreMaskDivisions && layoutCount <= 16) {
|
|
for (let i = 0; i < layoutCount; i++) {
|
|
let xpos = i % 4;
|
|
let ypos = i / 4;
|
|
xpos = ~~xpos;
|
|
ypos = ~~ypos;
|
|
const cc = this._clippingContextListForMask[curClipIndex++];
|
|
cc._layoutChannelNo = channelNo;
|
|
cc._layoutBounds.x = xpos / 4;
|
|
cc._layoutBounds.y = ypos / 4;
|
|
cc._layoutBounds.width = 1 / 4;
|
|
cc._layoutBounds.height = 1 / 4;
|
|
}
|
|
} else {
|
|
CubismLogError("not supported mask count : {0}", layoutCount);
|
|
}
|
|
}
|
|
}
|
|
getColorBuffer() {
|
|
return this._colorBuffer;
|
|
}
|
|
getClippingContextListForDraw() {
|
|
return this._clippingContextListForDraw;
|
|
}
|
|
setClippingMaskBufferSize(size) {
|
|
this._clippingMaskBufferSize = size;
|
|
}
|
|
getClippingMaskBufferSize() {
|
|
return this._clippingMaskBufferSize;
|
|
}
|
|
}
|
|
class CubismRenderTextureResource {
|
|
constructor(frameNo, texture) {
|
|
this.frameNo = frameNo;
|
|
this.texture = texture;
|
|
}
|
|
}
|
|
class CubismClippingContext {
|
|
constructor(manager, clippingDrawableIndices, clipCount) {
|
|
this._isUsing = false;
|
|
this._owner = manager;
|
|
this._clippingIdList = clippingDrawableIndices;
|
|
this._clippingIdCount = clipCount;
|
|
this._allClippedDrawRect = new csmRect();
|
|
this._layoutBounds = new csmRect();
|
|
this._clippedDrawableIndexList = [];
|
|
this._matrixForMask = new CubismMatrix44();
|
|
this._matrixForDraw = new CubismMatrix44();
|
|
}
|
|
release() {
|
|
const self2 = this;
|
|
self2._layoutBounds = void 0;
|
|
self2._allClippedDrawRect = void 0;
|
|
self2._clippedDrawableIndexList = void 0;
|
|
}
|
|
addClippedDrawable(drawableIndex) {
|
|
this._clippedDrawableIndexList.push(drawableIndex);
|
|
}
|
|
getClippingManager() {
|
|
return this._owner;
|
|
}
|
|
setGl(gl) {
|
|
this._owner.setGL(gl);
|
|
}
|
|
}
|
|
class CubismShader_WebGL {
|
|
static getInstance() {
|
|
if (s_instance == null) {
|
|
s_instance = new CubismShader_WebGL();
|
|
return s_instance;
|
|
}
|
|
return s_instance;
|
|
}
|
|
static deleteInstance() {
|
|
if (s_instance) {
|
|
s_instance.release();
|
|
s_instance = void 0;
|
|
}
|
|
}
|
|
constructor() {
|
|
this._shaderSets = [];
|
|
}
|
|
release() {
|
|
this.releaseShaderProgram();
|
|
}
|
|
setupShaderProgram(renderer, textureId, vertexCount, vertexArray, indexArray, uvArray, bufferData, opacity, colorBlendMode, baseColor, isPremultipliedAlpha, matrix4x4, invertedMask) {
|
|
if (!isPremultipliedAlpha) {
|
|
CubismLogError("NoPremultipliedAlpha is not allowed");
|
|
}
|
|
if (this._shaderSets.length == 0) {
|
|
this.generateShaders();
|
|
}
|
|
let SRC_COLOR;
|
|
let DST_COLOR;
|
|
let SRC_ALPHA;
|
|
let DST_ALPHA;
|
|
const clippingContextBufferForMask = renderer.getClippingContextBufferForMask();
|
|
if (clippingContextBufferForMask != null) {
|
|
const shaderSet = this._shaderSets[ShaderNames.ShaderNames_SetupMask];
|
|
this.gl.useProgram(shaderSet.shaderProgram);
|
|
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
this.gl.bindTexture(this.gl.TEXTURE_2D, textureId);
|
|
this.gl.uniform1i(shaderSet.samplerTexture0Location, 0);
|
|
if (bufferData.vertex == null) {
|
|
bufferData.vertex = this.gl.createBuffer();
|
|
}
|
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.vertex);
|
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertexArray, this.gl.DYNAMIC_DRAW);
|
|
this.gl.enableVertexAttribArray(shaderSet.attributePositionLocation);
|
|
this.gl.vertexAttribPointer(shaderSet.attributePositionLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
if (bufferData.uv == null) {
|
|
bufferData.uv = this.gl.createBuffer();
|
|
}
|
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.uv);
|
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, uvArray, this.gl.DYNAMIC_DRAW);
|
|
this.gl.enableVertexAttribArray(shaderSet.attributeTexCoordLocation);
|
|
this.gl.vertexAttribPointer(shaderSet.attributeTexCoordLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
const channelNo = clippingContextBufferForMask._layoutChannelNo;
|
|
const colorChannel = clippingContextBufferForMask.getClippingManager().getChannelFlagAsColor(channelNo);
|
|
this.gl.uniform4f(shaderSet.uniformChannelFlagLocation, colorChannel.R, colorChannel.G, colorChannel.B, colorChannel.A);
|
|
this.gl.uniformMatrix4fv(shaderSet.uniformClipMatrixLocation, false, clippingContextBufferForMask._matrixForMask.getArray());
|
|
const rect = clippingContextBufferForMask._layoutBounds;
|
|
this.gl.uniform4f(shaderSet.uniformBaseColorLocation, rect.x * 2 - 1, rect.y * 2 - 1, rect.getRight() * 2 - 1, rect.getBottom() * 2 - 1);
|
|
SRC_COLOR = this.gl.ZERO;
|
|
DST_COLOR = this.gl.ONE_MINUS_SRC_COLOR;
|
|
SRC_ALPHA = this.gl.ZERO;
|
|
DST_ALPHA = this.gl.ONE_MINUS_SRC_ALPHA;
|
|
} else {
|
|
const clippingContextBufferForDraw = renderer.getClippingContextBufferForDraw();
|
|
const masked = clippingContextBufferForDraw != null;
|
|
const offset = masked ? invertedMask ? 2 : 1 : 0;
|
|
let shaderSet;
|
|
switch (colorBlendMode) {
|
|
case CubismBlendMode.CubismBlendMode_Normal:
|
|
default:
|
|
shaderSet = this._shaderSets[ShaderNames.ShaderNames_NormalPremultipliedAlpha + offset];
|
|
SRC_COLOR = this.gl.ONE;
|
|
DST_COLOR = this.gl.ONE_MINUS_SRC_ALPHA;
|
|
SRC_ALPHA = this.gl.ONE;
|
|
DST_ALPHA = this.gl.ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
case CubismBlendMode.CubismBlendMode_Additive:
|
|
shaderSet = this._shaderSets[ShaderNames.ShaderNames_AddPremultipliedAlpha + offset];
|
|
SRC_COLOR = this.gl.ONE;
|
|
DST_COLOR = this.gl.ONE;
|
|
SRC_ALPHA = this.gl.ZERO;
|
|
DST_ALPHA = this.gl.ONE;
|
|
break;
|
|
case CubismBlendMode.CubismBlendMode_Multiplicative:
|
|
shaderSet = this._shaderSets[ShaderNames.ShaderNames_MultPremultipliedAlpha + offset];
|
|
SRC_COLOR = this.gl.DST_COLOR;
|
|
DST_COLOR = this.gl.ONE_MINUS_SRC_ALPHA;
|
|
SRC_ALPHA = this.gl.ZERO;
|
|
DST_ALPHA = this.gl.ONE;
|
|
break;
|
|
}
|
|
this.gl.useProgram(shaderSet.shaderProgram);
|
|
if (bufferData.vertex == null) {
|
|
bufferData.vertex = this.gl.createBuffer();
|
|
}
|
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.vertex);
|
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertexArray, this.gl.DYNAMIC_DRAW);
|
|
this.gl.enableVertexAttribArray(shaderSet.attributePositionLocation);
|
|
this.gl.vertexAttribPointer(shaderSet.attributePositionLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
if (bufferData.uv == null) {
|
|
bufferData.uv = this.gl.createBuffer();
|
|
}
|
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.uv);
|
|
this.gl.bufferData(this.gl.ARRAY_BUFFER, uvArray, this.gl.DYNAMIC_DRAW);
|
|
this.gl.enableVertexAttribArray(shaderSet.attributeTexCoordLocation);
|
|
this.gl.vertexAttribPointer(shaderSet.attributeTexCoordLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
if (clippingContextBufferForDraw != null) {
|
|
this.gl.activeTexture(this.gl.TEXTURE1);
|
|
const tex = clippingContextBufferForDraw.getClippingManager().getColorBuffer();
|
|
this.gl.bindTexture(this.gl.TEXTURE_2D, tex);
|
|
this.gl.uniform1i(shaderSet.samplerTexture1Location, 1);
|
|
this.gl.uniformMatrix4fv(shaderSet.uniformClipMatrixLocation, false, clippingContextBufferForDraw._matrixForDraw.getArray());
|
|
const channelNo = clippingContextBufferForDraw._layoutChannelNo;
|
|
const colorChannel = clippingContextBufferForDraw.getClippingManager().getChannelFlagAsColor(channelNo);
|
|
this.gl.uniform4f(shaderSet.uniformChannelFlagLocation, colorChannel.R, colorChannel.G, colorChannel.B, colorChannel.A);
|
|
}
|
|
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
this.gl.bindTexture(this.gl.TEXTURE_2D, textureId);
|
|
this.gl.uniform1i(shaderSet.samplerTexture0Location, 0);
|
|
this.gl.uniformMatrix4fv(shaderSet.uniformMatrixLocation, false, matrix4x4.getArray());
|
|
this.gl.uniform4f(shaderSet.uniformBaseColorLocation, baseColor.R, baseColor.G, baseColor.B, baseColor.A);
|
|
}
|
|
if (bufferData.index == null) {
|
|
bufferData.index = this.gl.createBuffer();
|
|
}
|
|
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, bufferData.index);
|
|
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, indexArray, this.gl.DYNAMIC_DRAW);
|
|
this.gl.blendFuncSeparate(SRC_COLOR, DST_COLOR, SRC_ALPHA, DST_ALPHA);
|
|
}
|
|
releaseShaderProgram() {
|
|
for (let i = 0; i < this._shaderSets.length; i++) {
|
|
this.gl.deleteProgram(this._shaderSets[i].shaderProgram);
|
|
this._shaderSets[i].shaderProgram = 0;
|
|
}
|
|
this._shaderSets = [];
|
|
}
|
|
generateShaders() {
|
|
for (let i = 0; i < shaderCount; i++) {
|
|
this._shaderSets.push({});
|
|
}
|
|
this._shaderSets[0].shaderProgram = this.loadShaderProgram(vertexShaderSrcSetupMask, fragmentShaderSrcsetupMask);
|
|
this._shaderSets[1].shaderProgram = this.loadShaderProgram(vertexShaderSrc, fragmentShaderSrcPremultipliedAlpha);
|
|
this._shaderSets[2].shaderProgram = this.loadShaderProgram(vertexShaderSrcMasked, fragmentShaderSrcMaskPremultipliedAlpha);
|
|
this._shaderSets[3].shaderProgram = this.loadShaderProgram(vertexShaderSrcMasked, fragmentShaderSrcMaskInvertedPremultipliedAlpha);
|
|
this._shaderSets[4].shaderProgram = this._shaderSets[1].shaderProgram;
|
|
this._shaderSets[5].shaderProgram = this._shaderSets[2].shaderProgram;
|
|
this._shaderSets[6].shaderProgram = this._shaderSets[3].shaderProgram;
|
|
this._shaderSets[7].shaderProgram = this._shaderSets[1].shaderProgram;
|
|
this._shaderSets[8].shaderProgram = this._shaderSets[2].shaderProgram;
|
|
this._shaderSets[9].shaderProgram = this._shaderSets[3].shaderProgram;
|
|
this._shaderSets[0].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[0].shaderProgram, "a_position");
|
|
this._shaderSets[0].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[0].shaderProgram, "a_texCoord");
|
|
this._shaderSets[0].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[0].shaderProgram, "s_texture0");
|
|
this._shaderSets[0].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[0].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[0].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[0].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[0].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[0].shaderProgram, "u_baseColor");
|
|
this._shaderSets[1].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[1].shaderProgram, "a_position");
|
|
this._shaderSets[1].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[1].shaderProgram, "a_texCoord");
|
|
this._shaderSets[1].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[1].shaderProgram, "s_texture0");
|
|
this._shaderSets[1].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[1].shaderProgram, "u_matrix");
|
|
this._shaderSets[1].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[1].shaderProgram, "u_baseColor");
|
|
this._shaderSets[2].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[2].shaderProgram, "a_position");
|
|
this._shaderSets[2].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[2].shaderProgram, "a_texCoord");
|
|
this._shaderSets[2].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[2].shaderProgram, "s_texture0");
|
|
this._shaderSets[2].samplerTexture1Location = this.gl.getUniformLocation(this._shaderSets[2].shaderProgram, "s_texture1");
|
|
this._shaderSets[2].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[2].shaderProgram, "u_matrix");
|
|
this._shaderSets[2].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[2].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[2].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[2].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[2].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[2].shaderProgram, "u_baseColor");
|
|
this._shaderSets[3].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[3].shaderProgram, "a_position");
|
|
this._shaderSets[3].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[3].shaderProgram, "a_texCoord");
|
|
this._shaderSets[3].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[3].shaderProgram, "s_texture0");
|
|
this._shaderSets[3].samplerTexture1Location = this.gl.getUniformLocation(this._shaderSets[3].shaderProgram, "s_texture1");
|
|
this._shaderSets[3].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[3].shaderProgram, "u_matrix");
|
|
this._shaderSets[3].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[3].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[3].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[3].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[3].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[3].shaderProgram, "u_baseColor");
|
|
this._shaderSets[4].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[4].shaderProgram, "a_position");
|
|
this._shaderSets[4].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[4].shaderProgram, "a_texCoord");
|
|
this._shaderSets[4].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[4].shaderProgram, "s_texture0");
|
|
this._shaderSets[4].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[4].shaderProgram, "u_matrix");
|
|
this._shaderSets[4].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[4].shaderProgram, "u_baseColor");
|
|
this._shaderSets[5].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[5].shaderProgram, "a_position");
|
|
this._shaderSets[5].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[5].shaderProgram, "a_texCoord");
|
|
this._shaderSets[5].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[5].shaderProgram, "s_texture0");
|
|
this._shaderSets[5].samplerTexture1Location = this.gl.getUniformLocation(this._shaderSets[5].shaderProgram, "s_texture1");
|
|
this._shaderSets[5].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[5].shaderProgram, "u_matrix");
|
|
this._shaderSets[5].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[5].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[5].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[5].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[5].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[5].shaderProgram, "u_baseColor");
|
|
this._shaderSets[6].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[6].shaderProgram, "a_position");
|
|
this._shaderSets[6].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[6].shaderProgram, "a_texCoord");
|
|
this._shaderSets[6].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[6].shaderProgram, "s_texture0");
|
|
this._shaderSets[6].samplerTexture1Location = this.gl.getUniformLocation(this._shaderSets[6].shaderProgram, "s_texture1");
|
|
this._shaderSets[6].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[6].shaderProgram, "u_matrix");
|
|
this._shaderSets[6].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[6].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[6].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[6].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[6].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[6].shaderProgram, "u_baseColor");
|
|
this._shaderSets[7].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[7].shaderProgram, "a_position");
|
|
this._shaderSets[7].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[7].shaderProgram, "a_texCoord");
|
|
this._shaderSets[7].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[7].shaderProgram, "s_texture0");
|
|
this._shaderSets[7].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[7].shaderProgram, "u_matrix");
|
|
this._shaderSets[7].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[7].shaderProgram, "u_baseColor");
|
|
this._shaderSets[8].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[8].shaderProgram, "a_position");
|
|
this._shaderSets[8].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[8].shaderProgram, "a_texCoord");
|
|
this._shaderSets[8].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[8].shaderProgram, "s_texture0");
|
|
this._shaderSets[8].samplerTexture1Location = this.gl.getUniformLocation(this._shaderSets[8].shaderProgram, "s_texture1");
|
|
this._shaderSets[8].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[8].shaderProgram, "u_matrix");
|
|
this._shaderSets[8].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[8].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[8].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[8].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[8].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[8].shaderProgram, "u_baseColor");
|
|
this._shaderSets[9].attributePositionLocation = this.gl.getAttribLocation(this._shaderSets[9].shaderProgram, "a_position");
|
|
this._shaderSets[9].attributeTexCoordLocation = this.gl.getAttribLocation(this._shaderSets[9].shaderProgram, "a_texCoord");
|
|
this._shaderSets[9].samplerTexture0Location = this.gl.getUniformLocation(this._shaderSets[9].shaderProgram, "s_texture0");
|
|
this._shaderSets[9].samplerTexture1Location = this.gl.getUniformLocation(this._shaderSets[9].shaderProgram, "s_texture1");
|
|
this._shaderSets[9].uniformMatrixLocation = this.gl.getUniformLocation(this._shaderSets[9].shaderProgram, "u_matrix");
|
|
this._shaderSets[9].uniformClipMatrixLocation = this.gl.getUniformLocation(this._shaderSets[9].shaderProgram, "u_clipMatrix");
|
|
this._shaderSets[9].uniformChannelFlagLocation = this.gl.getUniformLocation(this._shaderSets[9].shaderProgram, "u_channelFlag");
|
|
this._shaderSets[9].uniformBaseColorLocation = this.gl.getUniformLocation(this._shaderSets[9].shaderProgram, "u_baseColor");
|
|
}
|
|
loadShaderProgram(vertexShaderSource, fragmentShaderSource) {
|
|
let shaderProgram = this.gl.createProgram();
|
|
let vertShader = this.compileShaderSource(this.gl.VERTEX_SHADER, vertexShaderSource);
|
|
if (!vertShader) {
|
|
CubismLogError("Vertex shader compile error!");
|
|
return 0;
|
|
}
|
|
let fragShader = this.compileShaderSource(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
if (!fragShader) {
|
|
CubismLogError("Vertex shader compile error!");
|
|
return 0;
|
|
}
|
|
this.gl.attachShader(shaderProgram, vertShader);
|
|
this.gl.attachShader(shaderProgram, fragShader);
|
|
this.gl.linkProgram(shaderProgram);
|
|
const linkStatus = this.gl.getProgramParameter(shaderProgram, this.gl.LINK_STATUS);
|
|
if (!linkStatus) {
|
|
CubismLogError("Failed to link program: {0}", shaderProgram);
|
|
this.gl.deleteShader(vertShader);
|
|
this.gl.deleteShader(fragShader);
|
|
if (shaderProgram) {
|
|
this.gl.deleteProgram(shaderProgram);
|
|
}
|
|
return 0;
|
|
}
|
|
this.gl.deleteShader(vertShader);
|
|
this.gl.deleteShader(fragShader);
|
|
return shaderProgram;
|
|
}
|
|
compileShaderSource(shaderType, shaderSource) {
|
|
const source = shaderSource;
|
|
const shader = this.gl.createShader(shaderType);
|
|
this.gl.shaderSource(shader, source);
|
|
this.gl.compileShader(shader);
|
|
if (!shader) {
|
|
const log = this.gl.getShaderInfoLog(shader);
|
|
CubismLogError("Shader compile log: {0} ", log);
|
|
}
|
|
const status = this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS);
|
|
if (!status) {
|
|
this.gl.deleteShader(shader);
|
|
return null;
|
|
}
|
|
return shader;
|
|
}
|
|
setGl(gl) {
|
|
this.gl = gl;
|
|
}
|
|
}
|
|
var ShaderNames = /* @__PURE__ */ ((ShaderNames2) => {
|
|
ShaderNames2[ShaderNames2["ShaderNames_SetupMask"] = 0] = "ShaderNames_SetupMask";
|
|
ShaderNames2[ShaderNames2["ShaderNames_NormalPremultipliedAlpha"] = 1] = "ShaderNames_NormalPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_NormalMaskedPremultipliedAlpha"] = 2] = "ShaderNames_NormalMaskedPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_NomralMaskedInvertedPremultipliedAlpha"] = 3] = "ShaderNames_NomralMaskedInvertedPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_AddPremultipliedAlpha"] = 4] = "ShaderNames_AddPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_AddMaskedPremultipliedAlpha"] = 5] = "ShaderNames_AddMaskedPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_AddMaskedPremultipliedAlphaInverted"] = 6] = "ShaderNames_AddMaskedPremultipliedAlphaInverted";
|
|
ShaderNames2[ShaderNames2["ShaderNames_MultPremultipliedAlpha"] = 7] = "ShaderNames_MultPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_MultMaskedPremultipliedAlpha"] = 8] = "ShaderNames_MultMaskedPremultipliedAlpha";
|
|
ShaderNames2[ShaderNames2["ShaderNames_MultMaskedPremultipliedAlphaInverted"] = 9] = "ShaderNames_MultMaskedPremultipliedAlphaInverted";
|
|
return ShaderNames2;
|
|
})(ShaderNames || {});
|
|
const vertexShaderSrcSetupMask = "attribute vec4 a_position;attribute vec2 a_texCoord;varying vec2 v_texCoord;varying vec4 v_myPos;uniform mat4 u_clipMatrix;void main(){ gl_Position = u_clipMatrix * a_position; v_myPos = u_clipMatrix * a_position; v_texCoord = a_texCoord; v_texCoord.y = 1.0 - v_texCoord.y;}";
|
|
const fragmentShaderSrcsetupMask = "precision mediump float;varying vec2 v_texCoord;varying vec4 v_myPos;uniform vec4 u_baseColor;uniform vec4 u_channelFlag;uniform sampler2D s_texture0;void main(){ float isInside = step(u_baseColor.x, v_myPos.x/v_myPos.w) * step(u_baseColor.y, v_myPos.y/v_myPos.w) * step(v_myPos.x/v_myPos.w, u_baseColor.z) * step(v_myPos.y/v_myPos.w, u_baseColor.w); gl_FragColor = u_channelFlag * texture2D(s_texture0, v_texCoord).a * isInside;}";
|
|
const vertexShaderSrc = "attribute vec4 a_position;attribute vec2 a_texCoord;varying vec2 v_texCoord;uniform mat4 u_matrix;void main(){ gl_Position = u_matrix * a_position; v_texCoord = a_texCoord; v_texCoord.y = 1.0 - v_texCoord.y;}";
|
|
const vertexShaderSrcMasked = "attribute vec4 a_position;attribute vec2 a_texCoord;varying vec2 v_texCoord;varying vec4 v_clipPos;uniform mat4 u_matrix;uniform mat4 u_clipMatrix;void main(){ gl_Position = u_matrix * a_position; v_clipPos = u_clipMatrix * a_position; v_texCoord = a_texCoord; v_texCoord.y = 1.0 - v_texCoord.y;}";
|
|
const fragmentShaderSrcPremultipliedAlpha = "precision mediump float;varying vec2 v_texCoord;uniform vec4 u_baseColor;uniform sampler2D s_texture0;void main(){ gl_FragColor = texture2D(s_texture0 , v_texCoord) * u_baseColor;}";
|
|
const fragmentShaderSrcMaskPremultipliedAlpha = "precision mediump float;varying vec2 v_texCoord;varying vec4 v_clipPos;uniform vec4 u_baseColor;uniform vec4 u_channelFlag;uniform sampler2D s_texture0;uniform sampler2D s_texture1;void main(){ vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor; vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag; float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a; col_formask = col_formask * maskVal; gl_FragColor = col_formask;}";
|
|
const fragmentShaderSrcMaskInvertedPremultipliedAlpha = "precision mediump float;varying vec2 v_texCoord;varying vec4 v_clipPos;uniform sampler2D s_texture0;uniform sampler2D s_texture1;uniform vec4 u_channelFlag;uniform vec4 u_baseColor;void main(){vec4 col_formask = texture2D(s_texture0, v_texCoord) * u_baseColor;vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;col_formask = col_formask * (1.0 - maskVal);gl_FragColor = col_formask;}";
|
|
class CubismRenderer_WebGL extends CubismRenderer {
|
|
constructor() {
|
|
super();
|
|
this._clippingContextBufferForMask = null;
|
|
this._clippingContextBufferForDraw = null;
|
|
this._clippingManager = new CubismClippingManager_WebGL();
|
|
this.firstDraw = true;
|
|
this._textures = {};
|
|
this._sortedDrawableIndexList = [];
|
|
this._bufferData = {
|
|
vertex: null,
|
|
uv: null,
|
|
index: null
|
|
};
|
|
}
|
|
initialize(model) {
|
|
if (model.isUsingMasking()) {
|
|
this._clippingManager = new CubismClippingManager_WebGL();
|
|
this._clippingManager.initialize(model, model.getDrawableCount(), model.getDrawableMasks(), model.getDrawableMaskCounts());
|
|
}
|
|
for (let i = model.getDrawableCount() - 1; i >= 0; i--) {
|
|
this._sortedDrawableIndexList[i] = 0;
|
|
}
|
|
super.initialize(model);
|
|
}
|
|
bindTexture(modelTextureNo, glTexture) {
|
|
this._textures[modelTextureNo] = glTexture;
|
|
}
|
|
getBindedTextures() {
|
|
return this._textures;
|
|
}
|
|
setClippingMaskBufferSize(size) {
|
|
this._clippingManager.release();
|
|
this._clippingManager = new CubismClippingManager_WebGL();
|
|
this._clippingManager.setClippingMaskBufferSize(size);
|
|
this._clippingManager.initialize(this.getModel(), this.getModel().getDrawableCount(), this.getModel().getDrawableMasks(), this.getModel().getDrawableMaskCounts());
|
|
}
|
|
getClippingMaskBufferSize() {
|
|
return this._clippingManager.getClippingMaskBufferSize();
|
|
}
|
|
release() {
|
|
var _a, _b, _c;
|
|
const self2 = this;
|
|
this._clippingManager.release();
|
|
self2._clippingManager = void 0;
|
|
(_a = this.gl) == null ? void 0 : _a.deleteBuffer(this._bufferData.vertex);
|
|
this._bufferData.vertex = null;
|
|
(_b = this.gl) == null ? void 0 : _b.deleteBuffer(this._bufferData.uv);
|
|
this._bufferData.uv = null;
|
|
(_c = this.gl) == null ? void 0 : _c.deleteBuffer(this._bufferData.index);
|
|
this._bufferData.index = null;
|
|
self2._bufferData = void 0;
|
|
self2._textures = void 0;
|
|
}
|
|
doDrawModel() {
|
|
this.preDraw();
|
|
if (this._clippingManager != null) {
|
|
this._clippingManager.setupClippingContext(this.getModel(), this);
|
|
}
|
|
const drawableCount = this.getModel().getDrawableCount();
|
|
const renderOrder = this.getModel().getDrawableRenderOrders();
|
|
for (let i = 0; i < drawableCount; ++i) {
|
|
const order = renderOrder[i];
|
|
this._sortedDrawableIndexList[order] = i;
|
|
}
|
|
for (let i = 0; i < drawableCount; ++i) {
|
|
const drawableIndex = this._sortedDrawableIndexList[i];
|
|
if (!this.getModel().getDrawableDynamicFlagIsVisible(drawableIndex)) {
|
|
continue;
|
|
}
|
|
this.setClippingContextBufferForDraw(this._clippingManager != null ? this._clippingManager.getClippingContextListForDraw()[drawableIndex] : null);
|
|
this.setIsCulling(this.getModel().getDrawableCulling(drawableIndex));
|
|
this.drawMesh(this.getModel().getDrawableTextureIndices(drawableIndex), this.getModel().getDrawableVertexIndexCount(drawableIndex), this.getModel().getDrawableVertexCount(drawableIndex), this.getModel().getDrawableVertexIndices(drawableIndex), this.getModel().getDrawableVertices(drawableIndex), this.getModel().getDrawableVertexUvs(drawableIndex), this.getModel().getDrawableOpacity(drawableIndex), this.getModel().getDrawableBlendMode(drawableIndex), this.getModel().getDrawableInvertedMaskBit(drawableIndex));
|
|
}
|
|
}
|
|
drawMesh(textureNo, indexCount, vertexCount, indexArray, vertexArray, uvArray, opacity, colorBlendMode, invertedMask) {
|
|
if (this.isCulling()) {
|
|
this.gl.enable(this.gl.CULL_FACE);
|
|
} else {
|
|
this.gl.disable(this.gl.CULL_FACE);
|
|
}
|
|
this.gl.frontFace(this.gl.CCW);
|
|
const modelColorRGBA = this.getModelColor();
|
|
if (this.getClippingContextBufferForMask() == null) {
|
|
modelColorRGBA.A *= opacity;
|
|
if (this.isPremultipliedAlpha()) {
|
|
modelColorRGBA.R *= modelColorRGBA.A;
|
|
modelColorRGBA.G *= modelColorRGBA.A;
|
|
modelColorRGBA.B *= modelColorRGBA.A;
|
|
}
|
|
}
|
|
let drawtexture = null;
|
|
if (this._textures[textureNo] != null) {
|
|
drawtexture = this._textures[textureNo];
|
|
}
|
|
CubismShader_WebGL.getInstance().setupShaderProgram(this, drawtexture, vertexCount, vertexArray, indexArray, uvArray, this._bufferData, opacity, colorBlendMode, modelColorRGBA, this.isPremultipliedAlpha(), this.getMvpMatrix(), invertedMask);
|
|
this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_SHORT, 0);
|
|
this.gl.useProgram(null);
|
|
this.setClippingContextBufferForDraw(null);
|
|
this.setClippingContextBufferForMask(null);
|
|
}
|
|
static doStaticRelease() {
|
|
CubismShader_WebGL.deleteInstance();
|
|
}
|
|
setRenderState(fbo, viewport) {
|
|
s_fbo = fbo;
|
|
s_viewport = viewport;
|
|
}
|
|
preDraw() {
|
|
if (this.firstDraw) {
|
|
this.firstDraw = false;
|
|
this._anisortopy = this.gl.getExtension("EXT_texture_filter_anisotropic") || this.gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic") || this.gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
|
|
}
|
|
this.gl.disable(this.gl.SCISSOR_TEST);
|
|
this.gl.disable(this.gl.STENCIL_TEST);
|
|
this.gl.disable(this.gl.DEPTH_TEST);
|
|
this.gl.frontFace(this.gl.CW);
|
|
this.gl.enable(this.gl.BLEND);
|
|
this.gl.colorMask(true, true, true, true);
|
|
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
|
|
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);
|
|
}
|
|
setClippingContextBufferForMask(clip) {
|
|
this._clippingContextBufferForMask = clip;
|
|
}
|
|
getClippingContextBufferForMask() {
|
|
return this._clippingContextBufferForMask;
|
|
}
|
|
setClippingContextBufferForDraw(clip) {
|
|
this._clippingContextBufferForDraw = clip;
|
|
}
|
|
getClippingContextBufferForDraw() {
|
|
return this._clippingContextBufferForDraw;
|
|
}
|
|
startUp(gl) {
|
|
this.gl = gl;
|
|
this._clippingManager.setGL(gl);
|
|
CubismShader_WebGL.getInstance().setGl(gl);
|
|
}
|
|
}
|
|
CubismRenderer.staticRelease = () => {
|
|
CubismRenderer_WebGL.doStaticRelease();
|
|
};
|
|
const tempMatrix = new CubismMatrix44();
|
|
class Cubism4InternalModel extends InternalModel {
|
|
constructor(coreModel, settings, options) {
|
|
super();
|
|
this.lipSync = true;
|
|
this.breath = CubismBreath.create();
|
|
this.renderer = new CubismRenderer_WebGL();
|
|
this.idParamAngleX = ParamAngleX;
|
|
this.idParamAngleY = ParamAngleY;
|
|
this.idParamAngleZ = ParamAngleZ;
|
|
this.idParamEyeBallX = ParamEyeBallX;
|
|
this.idParamEyeBallY = ParamEyeBallY;
|
|
this.idParamBodyAngleX = ParamBodyAngleX;
|
|
this.idParamBreath = ParamBreath;
|
|
this.pixelsPerUnit = 1;
|
|
this.centeringTransform = new math.Matrix();
|
|
this.coreModel = coreModel;
|
|
this.settings = settings;
|
|
this.motionManager = new Cubism4MotionManager(settings, options);
|
|
this.init();
|
|
}
|
|
init() {
|
|
var _a;
|
|
super.init();
|
|
if (((_a = this.settings.getEyeBlinkParameters()) == null ? void 0 : _a.length) > 0) {
|
|
this.eyeBlink = CubismEyeBlink.create(this.settings);
|
|
}
|
|
this.breath.setParameters([
|
|
new BreathParameterData(this.idParamAngleX, 0, 15, 6.5345, 0.5),
|
|
new BreathParameterData(this.idParamAngleY, 0, 8, 3.5345, 0.5),
|
|
new BreathParameterData(this.idParamAngleZ, 0, 10, 5.5345, 0.5),
|
|
new BreathParameterData(this.idParamBodyAngleX, 0, 4, 15.5345, 0.5),
|
|
new BreathParameterData(this.idParamBreath, 0, 0.5, 3.2345, 0.5)
|
|
]);
|
|
this.renderer.initialize(this.coreModel);
|
|
this.renderer.setIsPremultipliedAlpha(true);
|
|
}
|
|
getSize() {
|
|
return [this.coreModel.getModel().canvasinfo.CanvasWidth, this.coreModel.getModel().canvasinfo.CanvasHeight];
|
|
}
|
|
getLayout() {
|
|
const layout = {};
|
|
if (this.settings.layout) {
|
|
for (const key of Object.keys(this.settings.layout)) {
|
|
const commonKey = key.charAt(0).toLowerCase() + key.slice(1);
|
|
layout[commonKey] = this.settings.layout[key];
|
|
}
|
|
}
|
|
return layout;
|
|
}
|
|
setupLayout() {
|
|
super.setupLayout();
|
|
this.pixelsPerUnit = this.coreModel.getModel().canvasinfo.PixelsPerUnit;
|
|
this.centeringTransform.scale(this.pixelsPerUnit, this.pixelsPerUnit).translate(this.originalWidth / 2, this.originalHeight / 2);
|
|
}
|
|
updateWebGLContext(gl, glContextID) {
|
|
this.renderer.firstDraw = true;
|
|
this.renderer._bufferData = {
|
|
vertex: null,
|
|
uv: null,
|
|
index: null
|
|
};
|
|
this.renderer.startUp(gl);
|
|
this.renderer._clippingManager._currentFrameNo = glContextID;
|
|
this.renderer._clippingManager._maskTexture = void 0;
|
|
CubismShader_WebGL.getInstance()._shaderSets = [];
|
|
}
|
|
bindTexture(index, texture) {
|
|
this.renderer.bindTexture(index, texture);
|
|
}
|
|
getHitAreaDefs() {
|
|
var _a, _b;
|
|
return (_b = (_a = this.settings.hitAreas) == null ? void 0 : _a.map((hitArea) => ({
|
|
id: hitArea.Id,
|
|
name: hitArea.Name,
|
|
index: this.coreModel.getDrawableIndex(hitArea.Id)
|
|
}))) != null ? _b : [];
|
|
}
|
|
getDrawableIDs() {
|
|
return this.coreModel.getDrawableIds();
|
|
}
|
|
getDrawableIndex(id) {
|
|
return this.coreModel.getDrawableIndex(id);
|
|
}
|
|
getDrawableVertices(drawIndex) {
|
|
if (typeof drawIndex === "string") {
|
|
drawIndex = this.coreModel.getDrawableIndex(drawIndex);
|
|
if (drawIndex === -1)
|
|
throw new TypeError("Unable to find drawable ID: " + drawIndex);
|
|
}
|
|
const arr = this.coreModel.getDrawableVertices(drawIndex).slice();
|
|
for (let i = 0; i < arr.length; i += 2) {
|
|
arr[i] = arr[i] * this.pixelsPerUnit + this.originalWidth / 2;
|
|
arr[i + 1] = -arr[i + 1] * this.pixelsPerUnit + this.originalHeight / 2;
|
|
}
|
|
return arr;
|
|
}
|
|
updateTransform(transform) {
|
|
this.drawingMatrix.copyFrom(this.centeringTransform).prepend(this.localTransform).prepend(transform);
|
|
}
|
|
update(dt, now) {
|
|
var _a, _b, _c, _d;
|
|
super.update(dt, now);
|
|
dt /= 1e3;
|
|
now /= 1e3;
|
|
const model = this.coreModel;
|
|
this.emit("beforeMotionUpdate");
|
|
const motionUpdated = this.motionManager.update(this.coreModel, now);
|
|
this.emit("afterMotionUpdate");
|
|
model.saveParameters();
|
|
(_a = this.motionManager.expressionManager) == null ? void 0 : _a.update(model, now);
|
|
if (!motionUpdated) {
|
|
(_b = this.eyeBlink) == null ? void 0 : _b.updateParameters(model, dt);
|
|
}
|
|
this.updateFocus();
|
|
this.updateNaturalMovements(dt * 1e3, now * 1e3);
|
|
(_c = this.physics) == null ? void 0 : _c.evaluate(model, dt);
|
|
(_d = this.pose) == null ? void 0 : _d.updateParameters(model, dt);
|
|
this.emit("beforeModelUpdate");
|
|
model.update();
|
|
model.loadParameters();
|
|
}
|
|
updateFocus() {
|
|
this.coreModel.addParameterValueById(this.idParamEyeBallX, this.focusController.x);
|
|
this.coreModel.addParameterValueById(this.idParamEyeBallY, this.focusController.y);
|
|
this.coreModel.addParameterValueById(this.idParamAngleX, this.focusController.x * 30);
|
|
this.coreModel.addParameterValueById(this.idParamAngleY, this.focusController.y * 30);
|
|
this.coreModel.addParameterValueById(this.idParamAngleZ, this.focusController.x * this.focusController.y * -30);
|
|
this.coreModel.addParameterValueById(this.idParamBodyAngleX, this.focusController.x * 10);
|
|
}
|
|
updateNaturalMovements(dt, now) {
|
|
var _a;
|
|
(_a = this.breath) == null ? void 0 : _a.updateParameters(this.coreModel, dt / 1e3);
|
|
}
|
|
draw(gl) {
|
|
const matrix = this.drawingMatrix;
|
|
const array = tempMatrix.getArray();
|
|
array[0] = matrix.a;
|
|
array[1] = matrix.b;
|
|
array[4] = -matrix.c;
|
|
array[5] = -matrix.d;
|
|
array[12] = matrix.tx;
|
|
array[13] = matrix.ty;
|
|
this.renderer.setMvpMatrix(tempMatrix);
|
|
this.renderer.setRenderState(gl.getParameter(gl.FRAMEBUFFER_BINDING), this.viewport);
|
|
this.renderer.drawModel();
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.renderer.release();
|
|
this.coreModel.release();
|
|
this.renderer = void 0;
|
|
this.coreModel = void 0;
|
|
}
|
|
}
|
|
let startupPromise;
|
|
let startupRetries = 20;
|
|
function cubism4Ready() {
|
|
if (CubismFramework.isStarted()) {
|
|
return Promise.resolve();
|
|
}
|
|
startupPromise != null ? startupPromise : startupPromise = new Promise((resolve, reject) => {
|
|
function startUpWithRetry() {
|
|
try {
|
|
startUpCubism4();
|
|
resolve();
|
|
} catch (e) {
|
|
startupRetries--;
|
|
if (startupRetries < 0) {
|
|
const err = new Error("Failed to start up Cubism 4 framework.");
|
|
err.cause = e;
|
|
reject(err);
|
|
return;
|
|
}
|
|
logger.log("Cubism4", "Startup failed, retrying 10ms later...");
|
|
setTimeout(startUpWithRetry, 10);
|
|
}
|
|
}
|
|
startUpWithRetry();
|
|
});
|
|
return startupPromise;
|
|
}
|
|
function startUpCubism4(options) {
|
|
options = Object.assign({
|
|
logFunction: console.log,
|
|
loggingLevel: LogLevel.LogLevel_Verbose
|
|
}, options);
|
|
CubismFramework.startUp(options);
|
|
CubismFramework.initialize();
|
|
}
|
|
const Epsilon = 1e-3;
|
|
const DefaultFadeInSeconds = 0.5;
|
|
class CubismPose {
|
|
static create(pose3json) {
|
|
const ret = new CubismPose();
|
|
if (typeof pose3json.FadeInTime === "number") {
|
|
ret._fadeTimeSeconds = pose3json.FadeInTime;
|
|
if (ret._fadeTimeSeconds <= 0) {
|
|
ret._fadeTimeSeconds = DefaultFadeInSeconds;
|
|
}
|
|
}
|
|
const poseListInfo = pose3json.Groups;
|
|
const poseCount = poseListInfo.length;
|
|
for (let poseIndex = 0; poseIndex < poseCount; ++poseIndex) {
|
|
const idListInfo = poseListInfo[poseIndex];
|
|
const idCount = idListInfo.length;
|
|
let groupCount = 0;
|
|
for (let groupIndex = 0; groupIndex < idCount; ++groupIndex) {
|
|
const partInfo = idListInfo[groupIndex];
|
|
const partData = new PartData();
|
|
partData.partId = partInfo.Id;
|
|
const linkListInfo = partInfo.Link;
|
|
if (linkListInfo) {
|
|
const linkCount = linkListInfo.length;
|
|
for (let linkIndex = 0; linkIndex < linkCount; ++linkIndex) {
|
|
const linkPart = new PartData();
|
|
linkPart.partId = linkListInfo[linkIndex];
|
|
partData.link.push(linkPart);
|
|
}
|
|
}
|
|
ret._partGroups.push(partData);
|
|
++groupCount;
|
|
}
|
|
ret._partGroupCounts.push(groupCount);
|
|
}
|
|
return ret;
|
|
}
|
|
updateParameters(model, deltaTimeSeconds) {
|
|
if (model != this._lastModel) {
|
|
this.reset(model);
|
|
}
|
|
this._lastModel = model;
|
|
if (deltaTimeSeconds < 0) {
|
|
deltaTimeSeconds = 0;
|
|
}
|
|
let beginIndex = 0;
|
|
for (let i = 0; i < this._partGroupCounts.length; i++) {
|
|
const partGroupCount = this._partGroupCounts[i];
|
|
this.doFade(model, deltaTimeSeconds, beginIndex, partGroupCount);
|
|
beginIndex += partGroupCount;
|
|
}
|
|
this.copyPartOpacities(model);
|
|
}
|
|
reset(model) {
|
|
let beginIndex = 0;
|
|
for (let i = 0; i < this._partGroupCounts.length; ++i) {
|
|
const groupCount = this._partGroupCounts[i];
|
|
for (let j = beginIndex; j < beginIndex + groupCount; ++j) {
|
|
this._partGroups[j].initialize(model);
|
|
const partsIndex = this._partGroups[j].partIndex;
|
|
const paramIndex = this._partGroups[j].parameterIndex;
|
|
if (partsIndex < 0) {
|
|
continue;
|
|
}
|
|
model.setPartOpacityByIndex(partsIndex, j == beginIndex ? 1 : 0);
|
|
model.setParameterValueByIndex(paramIndex, j == beginIndex ? 1 : 0);
|
|
for (let k = 0; k < this._partGroups[j].link.length; ++k) {
|
|
this._partGroups[j].link[k].initialize(model);
|
|
}
|
|
}
|
|
beginIndex += groupCount;
|
|
}
|
|
}
|
|
copyPartOpacities(model) {
|
|
for (let groupIndex = 0; groupIndex < this._partGroups.length; ++groupIndex) {
|
|
const partData = this._partGroups[groupIndex];
|
|
if (partData.link.length == 0) {
|
|
continue;
|
|
}
|
|
const partIndex = this._partGroups[groupIndex].partIndex;
|
|
const opacity = model.getPartOpacityByIndex(partIndex);
|
|
for (let linkIndex = 0; linkIndex < partData.link.length; ++linkIndex) {
|
|
const linkPart = partData.link[linkIndex];
|
|
const linkPartIndex = linkPart.partIndex;
|
|
if (linkPartIndex < 0) {
|
|
continue;
|
|
}
|
|
model.setPartOpacityByIndex(linkPartIndex, opacity);
|
|
}
|
|
}
|
|
}
|
|
doFade(model, deltaTimeSeconds, beginIndex, partGroupCount) {
|
|
let visiblePartIndex = -1;
|
|
let newOpacity = 1;
|
|
const phi = 0.5;
|
|
const backOpacityThreshold = 0.15;
|
|
for (let i = beginIndex; i < beginIndex + partGroupCount; ++i) {
|
|
const partIndex = this._partGroups[i].partIndex;
|
|
const paramIndex = this._partGroups[i].parameterIndex;
|
|
if (model.getParameterValueByIndex(paramIndex) > Epsilon) {
|
|
if (visiblePartIndex >= 0) {
|
|
break;
|
|
}
|
|
visiblePartIndex = i;
|
|
newOpacity = model.getPartOpacityByIndex(partIndex);
|
|
newOpacity += deltaTimeSeconds / this._fadeTimeSeconds;
|
|
if (newOpacity > 1) {
|
|
newOpacity = 1;
|
|
}
|
|
}
|
|
}
|
|
if (visiblePartIndex < 0) {
|
|
visiblePartIndex = 0;
|
|
newOpacity = 1;
|
|
}
|
|
for (let i = beginIndex; i < beginIndex + partGroupCount; ++i) {
|
|
const partsIndex = this._partGroups[i].partIndex;
|
|
if (visiblePartIndex == i) {
|
|
model.setPartOpacityByIndex(partsIndex, newOpacity);
|
|
} else {
|
|
let opacity = model.getPartOpacityByIndex(partsIndex);
|
|
let a1;
|
|
if (newOpacity < phi) {
|
|
a1 = newOpacity * (phi - 1) / phi + 1;
|
|
} else {
|
|
a1 = (1 - newOpacity) * phi / (1 - phi);
|
|
}
|
|
const backOpacity = (1 - a1) * (1 - newOpacity);
|
|
if (backOpacity > backOpacityThreshold) {
|
|
a1 = 1 - backOpacityThreshold / (1 - newOpacity);
|
|
}
|
|
if (opacity > a1) {
|
|
opacity = a1;
|
|
}
|
|
model.setPartOpacityByIndex(partsIndex, opacity);
|
|
}
|
|
}
|
|
}
|
|
constructor() {
|
|
this._fadeTimeSeconds = DefaultFadeInSeconds;
|
|
this._lastModel = void 0;
|
|
this._partGroups = [];
|
|
this._partGroupCounts = [];
|
|
}
|
|
}
|
|
class PartData {
|
|
constructor(v) {
|
|
this.parameterIndex = 0;
|
|
this.partIndex = 0;
|
|
this.partId = "";
|
|
this.link = [];
|
|
if (v != void 0) {
|
|
this.assignment(v);
|
|
}
|
|
}
|
|
assignment(v) {
|
|
this.partId = v.partId;
|
|
this.link = v.link.map((link) => link.clone());
|
|
return this;
|
|
}
|
|
initialize(model) {
|
|
this.parameterIndex = model.getParameterIndex(this.partId);
|
|
this.partIndex = model.getPartIndex(this.partId);
|
|
model.setParameterValueByIndex(this.parameterIndex, 1);
|
|
}
|
|
clone() {
|
|
const clonePartData = new PartData();
|
|
clonePartData.partId = this.partId;
|
|
clonePartData.parameterIndex = this.parameterIndex;
|
|
clonePartData.partIndex = this.partIndex;
|
|
clonePartData.link = this.link.map((link) => link.clone());
|
|
return clonePartData;
|
|
}
|
|
}
|
|
class CubismModel {
|
|
update() {
|
|
this._model.update();
|
|
this._model.drawables.resetDynamicFlags();
|
|
}
|
|
getCanvasWidth() {
|
|
if (this._model == null) {
|
|
return 0;
|
|
}
|
|
return this._model.canvasinfo.CanvasWidth / this._model.canvasinfo.PixelsPerUnit;
|
|
}
|
|
getCanvasHeight() {
|
|
if (this._model == null) {
|
|
return 0;
|
|
}
|
|
return this._model.canvasinfo.CanvasHeight / this._model.canvasinfo.PixelsPerUnit;
|
|
}
|
|
saveParameters() {
|
|
const parameterCount = this._model.parameters.count;
|
|
const savedParameterCount = this._savedParameters.length;
|
|
for (let i = 0; i < parameterCount; ++i) {
|
|
if (i < savedParameterCount) {
|
|
this._savedParameters[i] = this._parameterValues[i];
|
|
} else {
|
|
this._savedParameters.push(this._parameterValues[i]);
|
|
}
|
|
}
|
|
}
|
|
getModel() {
|
|
return this._model;
|
|
}
|
|
getPartIndex(partId) {
|
|
let partIndex;
|
|
const partCount = this._model.parts.count;
|
|
for (partIndex = 0; partIndex < partCount; ++partIndex) {
|
|
if (partId == this._partIds[partIndex]) {
|
|
return partIndex;
|
|
}
|
|
}
|
|
if (partId in this._notExistPartId) {
|
|
return this._notExistPartId[partId];
|
|
}
|
|
partIndex = partCount + this._notExistPartId.length;
|
|
this._notExistPartId[partId] = partIndex;
|
|
this._notExistPartOpacities[partIndex] = 0;
|
|
return partIndex;
|
|
}
|
|
getPartCount() {
|
|
return this._model.parts.count;
|
|
}
|
|
setPartOpacityByIndex(partIndex, opacity) {
|
|
if (partIndex in this._notExistPartOpacities) {
|
|
this._notExistPartOpacities[partIndex] = opacity;
|
|
return;
|
|
}
|
|
CSM_ASSERT(0 <= partIndex && partIndex < this.getPartCount());
|
|
this._partOpacities[partIndex] = opacity;
|
|
}
|
|
setPartOpacityById(partId, opacity) {
|
|
const index = this.getPartIndex(partId);
|
|
if (index < 0) {
|
|
return;
|
|
}
|
|
this.setPartOpacityByIndex(index, opacity);
|
|
}
|
|
getPartOpacityByIndex(partIndex) {
|
|
if (partIndex in this._notExistPartOpacities) {
|
|
return this._notExistPartOpacities[partIndex];
|
|
}
|
|
CSM_ASSERT(0 <= partIndex && partIndex < this.getPartCount());
|
|
return this._partOpacities[partIndex];
|
|
}
|
|
getPartOpacityById(partId) {
|
|
const index = this.getPartIndex(partId);
|
|
if (index < 0) {
|
|
return 0;
|
|
}
|
|
return this.getPartOpacityByIndex(index);
|
|
}
|
|
getParameterIndex(parameterId) {
|
|
let parameterIndex;
|
|
const idCount = this._model.parameters.count;
|
|
for (parameterIndex = 0; parameterIndex < idCount; ++parameterIndex) {
|
|
if (parameterId != this._parameterIds[parameterIndex]) {
|
|
continue;
|
|
}
|
|
return parameterIndex;
|
|
}
|
|
if (parameterId in this._notExistParameterId) {
|
|
return this._notExistParameterId[parameterId];
|
|
}
|
|
parameterIndex = this._model.parameters.count + Object.keys(this._notExistParameterId).length;
|
|
this._notExistParameterId[parameterId] = parameterIndex;
|
|
this._notExistParameterValues[parameterIndex] = 0;
|
|
return parameterIndex;
|
|
}
|
|
getParameterCount() {
|
|
return this._model.parameters.count;
|
|
}
|
|
getParameterMaximumValue(parameterIndex) {
|
|
return this._model.parameters.maximumValues[parameterIndex];
|
|
}
|
|
getParameterMinimumValue(parameterIndex) {
|
|
return this._model.parameters.minimumValues[parameterIndex];
|
|
}
|
|
getParameterDefaultValue(parameterIndex) {
|
|
return this._model.parameters.defaultValues[parameterIndex];
|
|
}
|
|
getParameterValueByIndex(parameterIndex) {
|
|
if (parameterIndex in this._notExistParameterValues) {
|
|
return this._notExistParameterValues[parameterIndex];
|
|
}
|
|
CSM_ASSERT(0 <= parameterIndex && parameterIndex < this.getParameterCount());
|
|
return this._parameterValues[parameterIndex];
|
|
}
|
|
getParameterValueById(parameterId) {
|
|
const parameterIndex = this.getParameterIndex(parameterId);
|
|
return this.getParameterValueByIndex(parameterIndex);
|
|
}
|
|
setParameterValueByIndex(parameterIndex, value, weight = 1) {
|
|
// if (parameterIndex == this.getParameterIndex("ParamMouthOpenY")) {
|
|
// console.log(value)
|
|
// }
|
|
if (parameterIndex in this._notExistParameterValues) {
|
|
this._notExistParameterValues[parameterIndex] = weight == 1 ? value : this._notExistParameterValues[parameterIndex] * (1 - weight) + value * weight;
|
|
return;
|
|
}
|
|
CSM_ASSERT(0 <= parameterIndex && parameterIndex < this.getParameterCount());
|
|
if (this._model.parameters.maximumValues[parameterIndex] < value) {
|
|
value = this._model.parameters.maximumValues[parameterIndex];
|
|
}
|
|
if (this._model.parameters.minimumValues[parameterIndex] > value) {
|
|
value = this._model.parameters.minimumValues[parameterIndex];
|
|
}
|
|
this._parameterValues[parameterIndex] = weight == 1 ? value : this._parameterValues[parameterIndex] = this._parameterValues[parameterIndex] * (1 - weight) + value * weight;
|
|
}
|
|
setParameterValueById(parameterId, value, weight = 1) {
|
|
const index = this.getParameterIndex(parameterId);
|
|
this.setParameterValueByIndex(index, value, weight);
|
|
}
|
|
addParameterValueByIndex(parameterIndex, value, weight = 1) {
|
|
this.setParameterValueByIndex(parameterIndex, this.getParameterValueByIndex(parameterIndex) + value * weight);
|
|
}
|
|
addParameterValueById(parameterId, value, weight = 1) {
|
|
const index = this.getParameterIndex(parameterId);
|
|
this.addParameterValueByIndex(index, value, weight);
|
|
}
|
|
multiplyParameterValueById(parameterId, value, weight = 1) {
|
|
const index = this.getParameterIndex(parameterId);
|
|
this.multiplyParameterValueByIndex(index, value, weight);
|
|
}
|
|
multiplyParameterValueByIndex(parameterIndex, value, weight = 1) {
|
|
this.setParameterValueByIndex(parameterIndex, this.getParameterValueByIndex(parameterIndex) * (1 + (value - 1) * weight));
|
|
}
|
|
getDrawableIds() {
|
|
return this._drawableIds.slice();
|
|
}
|
|
getDrawableIndex(drawableId) {
|
|
const drawableCount = this._model.drawables.count;
|
|
for (let drawableIndex = 0; drawableIndex < drawableCount; ++drawableIndex) {
|
|
if (this._drawableIds[drawableIndex] == drawableId) {
|
|
return drawableIndex;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
getDrawableCount() {
|
|
return this._model.drawables.count;
|
|
}
|
|
getDrawableId(drawableIndex) {
|
|
return this._model.drawables.ids[drawableIndex];
|
|
}
|
|
getDrawableRenderOrders() {
|
|
return this._model.drawables.renderOrders;
|
|
}
|
|
getDrawableTextureIndices(drawableIndex) {
|
|
return this._model.drawables.textureIndices[drawableIndex];
|
|
}
|
|
getDrawableDynamicFlagVertexPositionsDidChange(drawableIndex) {
|
|
const dynamicFlags = this._model.drawables.dynamicFlags;
|
|
return Live2DCubismCore.Utils.hasVertexPositionsDidChangeBit(dynamicFlags[drawableIndex]);
|
|
}
|
|
getDrawableVertexIndexCount(drawableIndex) {
|
|
return this._model.drawables.indexCounts[drawableIndex];
|
|
}
|
|
getDrawableVertexCount(drawableIndex) {
|
|
return this._model.drawables.vertexCounts[drawableIndex];
|
|
}
|
|
getDrawableVertices(drawableIndex) {
|
|
return this.getDrawableVertexPositions(drawableIndex);
|
|
}
|
|
getDrawableVertexIndices(drawableIndex) {
|
|
return this._model.drawables.indices[drawableIndex];
|
|
}
|
|
getDrawableVertexPositions(drawableIndex) {
|
|
return this._model.drawables.vertexPositions[drawableIndex];
|
|
}
|
|
getDrawableVertexUvs(drawableIndex) {
|
|
return this._model.drawables.vertexUvs[drawableIndex];
|
|
}
|
|
getDrawableOpacity(drawableIndex) {
|
|
return this._model.drawables.opacities[drawableIndex];
|
|
}
|
|
getDrawableCulling(drawableIndex) {
|
|
const constantFlags = this._model.drawables.constantFlags;
|
|
return !Live2DCubismCore.Utils.hasIsDoubleSidedBit(constantFlags[drawableIndex]);
|
|
}
|
|
getDrawableBlendMode(drawableIndex) {
|
|
const constantFlags = this._model.drawables.constantFlags;
|
|
return Live2DCubismCore.Utils.hasBlendAdditiveBit(constantFlags[drawableIndex]) ? CubismBlendMode.CubismBlendMode_Additive : Live2DCubismCore.Utils.hasBlendMultiplicativeBit(constantFlags[drawableIndex]) ? CubismBlendMode.CubismBlendMode_Multiplicative : CubismBlendMode.CubismBlendMode_Normal;
|
|
}
|
|
getDrawableInvertedMaskBit(drawableIndex) {
|
|
const constantFlags = this._model.drawables.constantFlags;
|
|
return Live2DCubismCore.Utils.hasIsInvertedMaskBit(constantFlags[drawableIndex]);
|
|
}
|
|
getDrawableMasks() {
|
|
return this._model.drawables.masks;
|
|
}
|
|
getDrawableMaskCounts() {
|
|
return this._model.drawables.maskCounts;
|
|
}
|
|
isUsingMasking() {
|
|
for (let d = 0; d < this._model.drawables.count; ++d) {
|
|
if (this._model.drawables.maskCounts[d] <= 0) {
|
|
continue;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
getDrawableDynamicFlagIsVisible(drawableIndex) {
|
|
const dynamicFlags = this._model.drawables.dynamicFlags;
|
|
return Live2DCubismCore.Utils.hasIsVisibleBit(dynamicFlags[drawableIndex]);
|
|
}
|
|
getDrawableDynamicFlagVisibilityDidChange(drawableIndex) {
|
|
const dynamicFlags = this._model.drawables.dynamicFlags;
|
|
return Live2DCubismCore.Utils.hasVisibilityDidChangeBit(dynamicFlags[drawableIndex]);
|
|
}
|
|
getDrawableDynamicFlagOpacityDidChange(drawableIndex) {
|
|
const dynamicFlags = this._model.drawables.dynamicFlags;
|
|
return Live2DCubismCore.Utils.hasOpacityDidChangeBit(dynamicFlags[drawableIndex]);
|
|
}
|
|
getDrawableDynamicFlagRenderOrderDidChange(drawableIndex) {
|
|
const dynamicFlags = this._model.drawables.dynamicFlags;
|
|
return Live2DCubismCore.Utils.hasRenderOrderDidChangeBit(dynamicFlags[drawableIndex]);
|
|
}
|
|
loadParameters() {
|
|
let parameterCount = this._model.parameters.count;
|
|
const savedParameterCount = this._savedParameters.length;
|
|
if (parameterCount > savedParameterCount) {
|
|
parameterCount = savedParameterCount;
|
|
}
|
|
for (let i = 0; i < parameterCount; ++i) {
|
|
this._parameterValues[i] = this._savedParameters[i];
|
|
}
|
|
}
|
|
initialize() {
|
|
this._parameterValues = this._model.parameters.values;
|
|
this._partOpacities = this._model.parts.opacities;
|
|
this._parameterMaximumValues = this._model.parameters.maximumValues;
|
|
this._parameterMinimumValues = this._model.parameters.minimumValues;
|
|
{
|
|
const parameterIds = this._model.parameters.ids;
|
|
const parameterCount = this._model.parameters.count;
|
|
for (let i = 0; i < parameterCount; ++i) {
|
|
this._parameterIds.push(parameterIds[i]);
|
|
}
|
|
}
|
|
{
|
|
const partIds = this._model.parts.ids;
|
|
const partCount = this._model.parts.count;
|
|
for (let i = 0; i < partCount; ++i) {
|
|
this._partIds.push(partIds[i]);
|
|
}
|
|
}
|
|
{
|
|
const drawableIds = this._model.drawables.ids;
|
|
const drawableCount = this._model.drawables.count;
|
|
for (let i = 0; i < drawableCount; ++i) {
|
|
this._drawableIds.push(drawableIds[i]);
|
|
}
|
|
}
|
|
}
|
|
constructor(model) {
|
|
this._model = model;
|
|
this._savedParameters = [];
|
|
this._parameterIds = [];
|
|
this._drawableIds = [];
|
|
this._partIds = [];
|
|
this._notExistPartId = {};
|
|
this._notExistParameterId = {};
|
|
this._notExistParameterValues = {};
|
|
this._notExistPartOpacities = {};
|
|
this.initialize();
|
|
}
|
|
release() {
|
|
this._model.release();
|
|
this._model = void 0;
|
|
}
|
|
}
|
|
class CubismMoc {
|
|
static create(mocBytes) {
|
|
const moc = Live2DCubismCore.Moc.fromArrayBuffer(mocBytes);
|
|
if (moc) {
|
|
return new CubismMoc(moc);
|
|
}
|
|
throw new Error("Unknown error");
|
|
}
|
|
createModel() {
|
|
let cubismModel;
|
|
const model = Live2DCubismCore.Model.fromMoc(this._moc);
|
|
if (model) {
|
|
cubismModel = new CubismModel(model);
|
|
++this._modelCount;
|
|
return cubismModel;
|
|
}
|
|
throw new Error("Unknown error");
|
|
}
|
|
deleteModel(model) {
|
|
if (model != null) {
|
|
--this._modelCount;
|
|
}
|
|
}
|
|
constructor(moc) {
|
|
this._moc = moc;
|
|
this._modelCount = 0;
|
|
}
|
|
release() {
|
|
this._moc._release();
|
|
this._moc = void 0;
|
|
}
|
|
}
|
|
var CubismPhysicsTargetType = /* @__PURE__ */ ((CubismPhysicsTargetType2) => {
|
|
CubismPhysicsTargetType2[CubismPhysicsTargetType2["CubismPhysicsTargetType_Parameter"] = 0] = "CubismPhysicsTargetType_Parameter";
|
|
return CubismPhysicsTargetType2;
|
|
})(CubismPhysicsTargetType || {});
|
|
var CubismPhysicsSource = /* @__PURE__ */ ((CubismPhysicsSource2) => {
|
|
CubismPhysicsSource2[CubismPhysicsSource2["CubismPhysicsSource_X"] = 0] = "CubismPhysicsSource_X";
|
|
CubismPhysicsSource2[CubismPhysicsSource2["CubismPhysicsSource_Y"] = 1] = "CubismPhysicsSource_Y";
|
|
CubismPhysicsSource2[CubismPhysicsSource2["CubismPhysicsSource_Angle"] = 2] = "CubismPhysicsSource_Angle";
|
|
return CubismPhysicsSource2;
|
|
})(CubismPhysicsSource || {});
|
|
class CubismPhysicsParticle {
|
|
constructor() {
|
|
this.initialPosition = new CubismVector2(0, 0);
|
|
this.position = new CubismVector2(0, 0);
|
|
this.lastPosition = new CubismVector2(0, 0);
|
|
this.lastGravity = new CubismVector2(0, 0);
|
|
this.force = new CubismVector2(0, 0);
|
|
this.velocity = new CubismVector2(0, 0);
|
|
}
|
|
}
|
|
class CubismPhysicsSubRig {
|
|
constructor() {
|
|
this.normalizationPosition = {};
|
|
this.normalizationAngle = {};
|
|
}
|
|
}
|
|
class CubismPhysicsInput {
|
|
constructor() {
|
|
this.source = {};
|
|
}
|
|
}
|
|
class CubismPhysicsOutput {
|
|
constructor() {
|
|
this.destination = {};
|
|
this.translationScale = new CubismVector2(0, 0);
|
|
}
|
|
}
|
|
class CubismPhysicsRig {
|
|
constructor() {
|
|
this.settings = [];
|
|
this.inputs = [];
|
|
this.outputs = [];
|
|
this.particles = [];
|
|
this.gravity = new CubismVector2(0, 0);
|
|
this.wind = new CubismVector2(0, 0);
|
|
}
|
|
}
|
|
class CubismPhysicsJson {
|
|
constructor(json) {
|
|
this._json = json;
|
|
}
|
|
release() {
|
|
this._json = void 0;
|
|
}
|
|
getGravity() {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this._json.Meta.EffectiveForces.Gravity.X;
|
|
ret.y = this._json.Meta.EffectiveForces.Gravity.Y;
|
|
return ret;
|
|
}
|
|
getWind() {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this._json.Meta.EffectiveForces.Wind.X;
|
|
ret.y = this._json.Meta.EffectiveForces.Wind.Y;
|
|
return ret;
|
|
}
|
|
getSubRigCount() {
|
|
return this._json.Meta.PhysicsSettingCount;
|
|
}
|
|
getTotalInputCount() {
|
|
return this._json.Meta.TotalInputCount;
|
|
}
|
|
getTotalOutputCount() {
|
|
return this._json.Meta.TotalOutputCount;
|
|
}
|
|
getVertexCount() {
|
|
return this._json.Meta.VertexCount;
|
|
}
|
|
getNormalizationPositionMinimumValue(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Normalization.Position.Minimum;
|
|
}
|
|
getNormalizationPositionMaximumValue(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Normalization.Position.Maximum;
|
|
}
|
|
getNormalizationPositionDefaultValue(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Normalization.Position.Default;
|
|
}
|
|
getNormalizationAngleMinimumValue(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Normalization.Angle.Minimum;
|
|
}
|
|
getNormalizationAngleMaximumValue(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Normalization.Angle.Maximum;
|
|
}
|
|
getNormalizationAngleDefaultValue(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Normalization.Angle.Default;
|
|
}
|
|
getInputCount(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Input.length;
|
|
}
|
|
getInputWeight(physicsSettingIndex, inputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Input[inputIndex].Weight;
|
|
}
|
|
getInputReflect(physicsSettingIndex, inputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Input[inputIndex].Reflect;
|
|
}
|
|
getInputType(physicsSettingIndex, inputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Input[inputIndex].Type;
|
|
}
|
|
getInputSourceId(physicsSettingIndex, inputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Input[inputIndex].Source.Id;
|
|
}
|
|
getOutputCount(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output.length;
|
|
}
|
|
getOutputVertexIndex(physicsSettingIndex, outputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output[outputIndex].VertexIndex;
|
|
}
|
|
getOutputAngleScale(physicsSettingIndex, outputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output[outputIndex].Scale;
|
|
}
|
|
getOutputWeight(physicsSettingIndex, outputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output[outputIndex].Weight;
|
|
}
|
|
getOutputDestinationId(physicsSettingIndex, outputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output[outputIndex].Destination.Id;
|
|
}
|
|
getOutputType(physicsSettingIndex, outputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output[outputIndex].Type;
|
|
}
|
|
getOutputReflect(physicsSettingIndex, outputIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Output[outputIndex].Reflect;
|
|
}
|
|
getParticleCount(physicsSettingIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Vertices.length;
|
|
}
|
|
getParticleMobility(physicsSettingIndex, vertexIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Vertices[vertexIndex].Mobility;
|
|
}
|
|
getParticleDelay(physicsSettingIndex, vertexIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Vertices[vertexIndex].Delay;
|
|
}
|
|
getParticleAcceleration(physicsSettingIndex, vertexIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Vertices[vertexIndex].Acceleration;
|
|
}
|
|
getParticleRadius(physicsSettingIndex, vertexIndex) {
|
|
return this._json.PhysicsSettings[physicsSettingIndex].Vertices[vertexIndex].Radius;
|
|
}
|
|
getParticlePosition(physicsSettingIndex, vertexIndex) {
|
|
const ret = new CubismVector2(0, 0);
|
|
ret.x = this._json.PhysicsSettings[physicsSettingIndex].Vertices[vertexIndex].Position.X;
|
|
ret.y = this._json.PhysicsSettings[physicsSettingIndex].Vertices[vertexIndex].Position.Y;
|
|
return ret;
|
|
}
|
|
}
|
|
const PhysicsTypeTagX = "X";
|
|
const PhysicsTypeTagY = "Y";
|
|
const PhysicsTypeTagAngle = "Angle";
|
|
const AirResistance = 5;
|
|
const MaximumWeight = 100;
|
|
const MovementThreshold = 1e-3;
|
|
class CubismPhysics {
|
|
static create(json) {
|
|
const ret = new CubismPhysics();
|
|
ret.parse(json);
|
|
ret._physicsRig.gravity.y = 0;
|
|
return ret;
|
|
}
|
|
evaluate(model, deltaTimeSeconds) {
|
|
let totalAngle;
|
|
let weight;
|
|
let radAngle;
|
|
let outputValue;
|
|
const totalTranslation = new CubismVector2();
|
|
let currentSetting;
|
|
let currentInput;
|
|
let currentOutput;
|
|
let currentParticles;
|
|
let parameterValue;
|
|
let parameterMaximumValue;
|
|
let parameterMinimumValue;
|
|
let parameterDefaultValue;
|
|
parameterValue = model.getModel().parameters.values;
|
|
parameterMaximumValue = model.getModel().parameters.maximumValues;
|
|
parameterMinimumValue = model.getModel().parameters.minimumValues;
|
|
parameterDefaultValue = model.getModel().parameters.defaultValues;
|
|
for (let settingIndex = 0; settingIndex < this._physicsRig.subRigCount; ++settingIndex) {
|
|
totalAngle = { angle: 0 };
|
|
totalTranslation.x = 0;
|
|
totalTranslation.y = 0;
|
|
currentSetting = this._physicsRig.settings[settingIndex];
|
|
currentInput = this._physicsRig.inputs.slice(currentSetting.baseInputIndex);
|
|
currentOutput = this._physicsRig.outputs.slice(currentSetting.baseOutputIndex);
|
|
currentParticles = this._physicsRig.particles.slice(currentSetting.baseParticleIndex);
|
|
for (let i = 0; i < currentSetting.inputCount; ++i) {
|
|
weight = currentInput[i].weight / MaximumWeight;
|
|
if (currentInput[i].sourceParameterIndex == -1) {
|
|
currentInput[i].sourceParameterIndex = model.getParameterIndex(currentInput[i].source.id);
|
|
}
|
|
currentInput[i].getNormalizedParameterValue(totalTranslation, totalAngle, parameterValue[currentInput[i].sourceParameterIndex], parameterMinimumValue[currentInput[i].sourceParameterIndex], parameterMaximumValue[currentInput[i].sourceParameterIndex], parameterDefaultValue[currentInput[i].sourceParameterIndex], currentSetting.normalizationPosition, currentSetting.normalizationAngle, currentInput[i].reflect, weight);
|
|
}
|
|
radAngle = CubismMath.degreesToRadian(-totalAngle.angle);
|
|
totalTranslation.x = totalTranslation.x * CubismMath.cos(radAngle) - totalTranslation.y * CubismMath.sin(radAngle);
|
|
totalTranslation.y = totalTranslation.x * CubismMath.sin(radAngle) + totalTranslation.y * CubismMath.cos(radAngle);
|
|
updateParticles(currentParticles, currentSetting.particleCount, totalTranslation, totalAngle.angle, this._options.wind, MovementThreshold * currentSetting.normalizationPosition.maximum, deltaTimeSeconds, AirResistance);
|
|
for (let i = 0; i < currentSetting.outputCount; ++i) {
|
|
const particleIndex = currentOutput[i].vertexIndex;
|
|
if (particleIndex < 1 || particleIndex >= currentSetting.particleCount) {
|
|
break;
|
|
}
|
|
if (currentOutput[i].destinationParameterIndex == -1) {
|
|
currentOutput[i].destinationParameterIndex = model.getParameterIndex(currentOutput[i].destination.id);
|
|
}
|
|
const translation = new CubismVector2();
|
|
translation.x = currentParticles[particleIndex].position.x - currentParticles[particleIndex - 1].position.x;
|
|
translation.y = currentParticles[particleIndex].position.y - currentParticles[particleIndex - 1].position.y;
|
|
outputValue = currentOutput[i].getValue(translation, currentParticles, particleIndex, currentOutput[i].reflect, this._options.gravity);
|
|
const destinationParameterIndex = currentOutput[i].destinationParameterIndex;
|
|
const outParameterValue = !Float32Array.prototype.slice && "subarray" in Float32Array.prototype ? JSON.parse(JSON.stringify(parameterValue.subarray(destinationParameterIndex))) : parameterValue.slice(destinationParameterIndex);
|
|
updateOutputParameterValue(outParameterValue, parameterMinimumValue[destinationParameterIndex], parameterMaximumValue[destinationParameterIndex], outputValue, currentOutput[i]);
|
|
for (let offset = destinationParameterIndex, outParamIndex = 0; offset < parameterValue.length; offset++, outParamIndex++) {
|
|
parameterValue[offset] = outParameterValue[outParamIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
setOptions(options) {
|
|
this._options = options;
|
|
}
|
|
getOption() {
|
|
return this._options;
|
|
}
|
|
constructor() {
|
|
this._options = new Options();
|
|
this._options.gravity.y = -1;
|
|
this._options.gravity.x = 0;
|
|
this._options.wind.x = 0;
|
|
this._options.wind.y = 0;
|
|
}
|
|
release() {
|
|
this._physicsRig = void 0;
|
|
}
|
|
parse(physicsJson) {
|
|
this._physicsRig = new CubismPhysicsRig();
|
|
let json = new CubismPhysicsJson(physicsJson);
|
|
this._physicsRig.gravity = json.getGravity();
|
|
this._physicsRig.wind = json.getWind();
|
|
this._physicsRig.subRigCount = json.getSubRigCount();
|
|
let inputIndex = 0, outputIndex = 0, particleIndex = 0;
|
|
for (let i = 0; i < this._physicsRig.subRigCount; ++i) {
|
|
const setting = new CubismPhysicsSubRig();
|
|
setting.normalizationPosition.minimum = json.getNormalizationPositionMinimumValue(i);
|
|
setting.normalizationPosition.maximum = json.getNormalizationPositionMaximumValue(i);
|
|
setting.normalizationPosition.defalut = json.getNormalizationPositionDefaultValue(i);
|
|
setting.normalizationAngle.minimum = json.getNormalizationAngleMinimumValue(i);
|
|
setting.normalizationAngle.maximum = json.getNormalizationAngleMaximumValue(i);
|
|
setting.normalizationAngle.defalut = json.getNormalizationAngleDefaultValue(i);
|
|
setting.inputCount = json.getInputCount(i);
|
|
setting.baseInputIndex = inputIndex;
|
|
inputIndex += setting.inputCount;
|
|
for (let j = 0; j < setting.inputCount; ++j) {
|
|
const input = new CubismPhysicsInput();
|
|
input.sourceParameterIndex = -1;
|
|
input.weight = json.getInputWeight(i, j);
|
|
input.reflect = json.getInputReflect(i, j);
|
|
switch (json.getInputType(i, j)) {
|
|
case PhysicsTypeTagX:
|
|
input.type = CubismPhysicsSource.CubismPhysicsSource_X;
|
|
input.getNormalizedParameterValue = getInputTranslationXFromNormalizedParameterValue;
|
|
break;
|
|
case PhysicsTypeTagY:
|
|
input.type = CubismPhysicsSource.CubismPhysicsSource_Y;
|
|
input.getNormalizedParameterValue = getInputTranslationYFromNormalizedParamterValue;
|
|
break;
|
|
case PhysicsTypeTagAngle:
|
|
input.type = CubismPhysicsSource.CubismPhysicsSource_Angle;
|
|
input.getNormalizedParameterValue = getInputAngleFromNormalizedParameterValue;
|
|
break;
|
|
}
|
|
input.source.targetType = CubismPhysicsTargetType.CubismPhysicsTargetType_Parameter;
|
|
input.source.id = json.getInputSourceId(i, j);
|
|
this._physicsRig.inputs.push(input);
|
|
}
|
|
setting.outputCount = json.getOutputCount(i);
|
|
setting.baseOutputIndex = outputIndex;
|
|
outputIndex += setting.outputCount;
|
|
for (let j = 0; j < setting.outputCount; ++j) {
|
|
const output = new CubismPhysicsOutput();
|
|
output.destinationParameterIndex = -1;
|
|
output.vertexIndex = json.getOutputVertexIndex(i, j);
|
|
output.angleScale = json.getOutputAngleScale(i, j);
|
|
output.weight = json.getOutputWeight(i, j);
|
|
output.destination.targetType = CubismPhysicsTargetType.CubismPhysicsTargetType_Parameter;
|
|
output.destination.id = json.getOutputDestinationId(i, j);
|
|
switch (json.getOutputType(i, j)) {
|
|
case PhysicsTypeTagX:
|
|
output.type = CubismPhysicsSource.CubismPhysicsSource_X;
|
|
output.getValue = getOutputTranslationX;
|
|
output.getScale = getOutputScaleTranslationX;
|
|
break;
|
|
case PhysicsTypeTagY:
|
|
output.type = CubismPhysicsSource.CubismPhysicsSource_Y;
|
|
output.getValue = getOutputTranslationY;
|
|
output.getScale = getOutputScaleTranslationY;
|
|
break;
|
|
case PhysicsTypeTagAngle:
|
|
output.type = CubismPhysicsSource.CubismPhysicsSource_Angle;
|
|
output.getValue = getOutputAngle;
|
|
output.getScale = getOutputScaleAngle;
|
|
break;
|
|
}
|
|
output.reflect = json.getOutputReflect(i, j);
|
|
this._physicsRig.outputs.push(output);
|
|
}
|
|
setting.particleCount = json.getParticleCount(i);
|
|
setting.baseParticleIndex = particleIndex;
|
|
particleIndex += setting.particleCount;
|
|
for (let j = 0; j < setting.particleCount; ++j) {
|
|
const particle = new CubismPhysicsParticle();
|
|
particle.mobility = json.getParticleMobility(i, j);
|
|
particle.delay = json.getParticleDelay(i, j);
|
|
particle.acceleration = json.getParticleAcceleration(i, j);
|
|
particle.radius = json.getParticleRadius(i, j);
|
|
particle.position = json.getParticlePosition(i, j);
|
|
this._physicsRig.particles.push(particle);
|
|
}
|
|
this._physicsRig.settings.push(setting);
|
|
}
|
|
this.initialize();
|
|
json.release();
|
|
}
|
|
initialize() {
|
|
let strand;
|
|
let currentSetting;
|
|
let radius;
|
|
for (let settingIndex = 0; settingIndex < this._physicsRig.subRigCount; ++settingIndex) {
|
|
currentSetting = this._physicsRig.settings[settingIndex];
|
|
strand = this._physicsRig.particles.slice(currentSetting.baseParticleIndex);
|
|
strand[0].initialPosition = new CubismVector2(0, 0);
|
|
strand[0].lastPosition = new CubismVector2(strand[0].initialPosition.x, strand[0].initialPosition.y);
|
|
strand[0].lastGravity = new CubismVector2(0, -1);
|
|
strand[0].lastGravity.y *= -1;
|
|
strand[0].velocity = new CubismVector2(0, 0);
|
|
strand[0].force = new CubismVector2(0, 0);
|
|
for (let i = 1; i < currentSetting.particleCount; ++i) {
|
|
radius = new CubismVector2(0, 0);
|
|
radius.y = strand[i].radius;
|
|
strand[i].initialPosition = new CubismVector2(strand[i - 1].initialPosition.x + radius.x, strand[i - 1].initialPosition.y + radius.y);
|
|
strand[i].position = new CubismVector2(strand[i].initialPosition.x, strand[i].initialPosition.y);
|
|
strand[i].lastPosition = new CubismVector2(strand[i].initialPosition.x, strand[i].initialPosition.y);
|
|
strand[i].lastGravity = new CubismVector2(0, -1);
|
|
strand[i].lastGravity.y *= -1;
|
|
strand[i].velocity = new CubismVector2(0, 0);
|
|
strand[i].force = new CubismVector2(0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
class Options {
|
|
constructor() {
|
|
this.gravity = new CubismVector2(0, 0);
|
|
this.wind = new CubismVector2(0, 0);
|
|
}
|
|
}
|
|
function getInputTranslationXFromNormalizedParameterValue(targetTranslation, targetAngle, value, parameterMinimumValue, parameterMaximumValue, parameterDefaultValue, normalizationPosition, normalizationAngle, isInverted, weight) {
|
|
targetTranslation.x += normalizeParameterValue(value, parameterMinimumValue, parameterMaximumValue, parameterDefaultValue, normalizationPosition.minimum, normalizationPosition.maximum, normalizationPosition.defalut, isInverted) * weight;
|
|
}
|
|
function getInputTranslationYFromNormalizedParamterValue(targetTranslation, targetAngle, value, parameterMinimumValue, parameterMaximumValue, parameterDefaultValue, normalizationPosition, normalizationAngle, isInverted, weight) {
|
|
targetTranslation.y += normalizeParameterValue(value, parameterMinimumValue, parameterMaximumValue, parameterDefaultValue, normalizationPosition.minimum, normalizationPosition.maximum, normalizationPosition.defalut, isInverted) * weight;
|
|
}
|
|
function getInputAngleFromNormalizedParameterValue(targetTranslation, targetAngle, value, parameterMinimumValue, parameterMaximumValue, parameterDefaultValue, normalizaitionPosition, normalizationAngle, isInverted, weight) {
|
|
targetAngle.angle += normalizeParameterValue(value, parameterMinimumValue, parameterMaximumValue, parameterDefaultValue, normalizationAngle.minimum, normalizationAngle.maximum, normalizationAngle.defalut, isInverted) * weight;
|
|
}
|
|
function getOutputTranslationX(translation, particles, particleIndex, isInverted, parentGravity) {
|
|
let outputValue = translation.x;
|
|
if (isInverted) {
|
|
outputValue *= -1;
|
|
}
|
|
return outputValue;
|
|
}
|
|
function getOutputTranslationY(translation, particles, particleIndex, isInverted, parentGravity) {
|
|
let outputValue = translation.y;
|
|
if (isInverted) {
|
|
outputValue *= -1;
|
|
}
|
|
return outputValue;
|
|
}
|
|
function getOutputAngle(translation, particles, particleIndex, isInverted, parentGravity) {
|
|
let outputValue;
|
|
if (particleIndex >= 2) {
|
|
parentGravity = particles[particleIndex - 1].position.substract(particles[particleIndex - 2].position);
|
|
} else {
|
|
parentGravity = parentGravity.multiplyByScaler(-1);
|
|
}
|
|
outputValue = CubismMath.directionToRadian(parentGravity, translation);
|
|
if (isInverted) {
|
|
outputValue *= -1;
|
|
}
|
|
return outputValue;
|
|
}
|
|
function getRangeValue(min, max) {
|
|
return Math.abs(Math.max(min, max) - Math.min(min, max));
|
|
}
|
|
function getDefaultValue(min, max) {
|
|
const minValue = Math.min(min, max);
|
|
return minValue + getRangeValue(min, max) / 2;
|
|
}
|
|
function getOutputScaleTranslationX(translationScale, angleScale) {
|
|
return translationScale.x;
|
|
}
|
|
function getOutputScaleTranslationY(translationScale, angleScale) {
|
|
return translationScale.y;
|
|
}
|
|
function getOutputScaleAngle(translationScale, angleScale) {
|
|
return angleScale;
|
|
}
|
|
function updateParticles(strand, strandCount, totalTranslation, totalAngle, windDirection, thresholdValue, deltaTimeSeconds, airResistance) {
|
|
let totalRadian;
|
|
let delay;
|
|
let radian;
|
|
let currentGravity;
|
|
let direction = new CubismVector2(0, 0);
|
|
let velocity = new CubismVector2(0, 0);
|
|
let force = new CubismVector2(0, 0);
|
|
let newDirection = new CubismVector2(0, 0);
|
|
strand[0].position = new CubismVector2(totalTranslation.x, totalTranslation.y);
|
|
totalRadian = CubismMath.degreesToRadian(totalAngle);
|
|
currentGravity = CubismMath.radianToDirection(totalRadian);
|
|
currentGravity.normalize();
|
|
for (let i = 1; i < strandCount; ++i) {
|
|
strand[i].force = currentGravity.multiplyByScaler(strand[i].acceleration).add(windDirection);
|
|
strand[i].lastPosition = new CubismVector2(strand[i].position.x, strand[i].position.y);
|
|
delay = strand[i].delay * deltaTimeSeconds * 30;
|
|
direction = strand[i].position.substract(strand[i - 1].position);
|
|
radian = CubismMath.directionToRadian(strand[i].lastGravity, currentGravity) / airResistance;
|
|
direction.x = CubismMath.cos(radian) * direction.x - direction.y * CubismMath.sin(radian);
|
|
direction.y = CubismMath.sin(radian) * direction.x + direction.y * CubismMath.cos(radian);
|
|
strand[i].position = strand[i - 1].position.add(direction);
|
|
velocity = strand[i].velocity.multiplyByScaler(delay);
|
|
force = strand[i].force.multiplyByScaler(delay).multiplyByScaler(delay);
|
|
strand[i].position = strand[i].position.add(velocity).add(force);
|
|
newDirection = strand[i].position.substract(strand[i - 1].position);
|
|
newDirection.normalize();
|
|
strand[i].position = strand[i - 1].position.add(newDirection.multiplyByScaler(strand[i].radius));
|
|
if (CubismMath.abs(strand[i].position.x) < thresholdValue) {
|
|
strand[i].position.x = 0;
|
|
}
|
|
if (delay != 0) {
|
|
strand[i].velocity = strand[i].position.substract(strand[i].lastPosition);
|
|
strand[i].velocity = strand[i].velocity.divisionByScalar(delay);
|
|
strand[i].velocity = strand[i].velocity.multiplyByScaler(strand[i].mobility);
|
|
}
|
|
strand[i].force = new CubismVector2(0, 0);
|
|
strand[i].lastGravity = new CubismVector2(currentGravity.x, currentGravity.y);
|
|
}
|
|
}
|
|
function updateOutputParameterValue(parameterValue, parameterValueMinimum, parameterValueMaximum, translation, output) {
|
|
let outputScale;
|
|
let value;
|
|
let weight;
|
|
outputScale = output.getScale(output.translationScale, output.angleScale);
|
|
value = translation * outputScale;
|
|
if (value < parameterValueMinimum) {
|
|
if (value < output.valueBelowMinimum) {
|
|
output.valueBelowMinimum = value;
|
|
}
|
|
value = parameterValueMinimum;
|
|
} else if (value > parameterValueMaximum) {
|
|
if (value > output.valueExceededMaximum) {
|
|
output.valueExceededMaximum = value;
|
|
}
|
|
value = parameterValueMaximum;
|
|
}
|
|
weight = output.weight / MaximumWeight;
|
|
if (weight >= 1) {
|
|
parameterValue[0] = value;
|
|
} else {
|
|
value = parameterValue[0] * (1 - weight) + value * weight;
|
|
parameterValue[0] = value;
|
|
}
|
|
}
|
|
function normalizeParameterValue(value, parameterMinimum, parameterMaximum, parameterDefault, normalizedMinimum, normalizedMaximum, normalizedDefault, isInverted) {
|
|
let result = 0;
|
|
const maxValue = CubismMath.max(parameterMaximum, parameterMinimum);
|
|
if (maxValue < value) {
|
|
value = maxValue;
|
|
}
|
|
const minValue = CubismMath.min(parameterMaximum, parameterMinimum);
|
|
if (minValue > value) {
|
|
value = minValue;
|
|
}
|
|
const minNormValue = CubismMath.min(normalizedMinimum, normalizedMaximum);
|
|
const maxNormValue = CubismMath.max(normalizedMinimum, normalizedMaximum);
|
|
const middleNormValue = normalizedDefault;
|
|
const middleValue = getDefaultValue(minValue, maxValue);
|
|
const paramValue = value - middleValue;
|
|
switch (Math.sign(paramValue)) {
|
|
case 1: {
|
|
const nLength = maxNormValue - middleNormValue;
|
|
const pLength = maxValue - middleValue;
|
|
if (pLength != 0) {
|
|
result = paramValue * (nLength / pLength);
|
|
result += middleNormValue;
|
|
}
|
|
break;
|
|
}
|
|
case -1: {
|
|
const nLength = minNormValue - middleNormValue;
|
|
const pLength = minValue - middleValue;
|
|
if (pLength != 0) {
|
|
result = paramValue * (nLength / pLength);
|
|
result += middleNormValue;
|
|
}
|
|
break;
|
|
}
|
|
case 0: {
|
|
result = middleNormValue;
|
|
break;
|
|
}
|
|
}
|
|
return isInverted ? result : result * -1;
|
|
}
|
|
Live2DFactory.registerRuntime({
|
|
version: 4,
|
|
ready: cubism4Ready,
|
|
test(source) {
|
|
return source instanceof Cubism4ModelSettings || Cubism4ModelSettings.isValidJSON(source);
|
|
},
|
|
isValidMoc(modelData) {
|
|
if (modelData.byteLength < 4) {
|
|
return false;
|
|
}
|
|
const view = new Int8Array(modelData, 0, 4);
|
|
return String.fromCharCode(...view) === "MOC3";
|
|
},
|
|
createModelSettings(json) {
|
|
return new Cubism4ModelSettings(json);
|
|
},
|
|
createCoreModel(data) {
|
|
const moc = CubismMoc.create(data);
|
|
try {
|
|
const model = moc.createModel();
|
|
model.__moc = moc;
|
|
return model;
|
|
} catch (e) {
|
|
try {
|
|
moc.release();
|
|
} catch (ignored) {
|
|
}
|
|
throw e;
|
|
}
|
|
},
|
|
createInternalModel(coreModel, settings, options) {
|
|
const model = new Cubism4InternalModel(coreModel, settings, options);
|
|
const coreModelWithMoc = coreModel;
|
|
if (coreModelWithMoc.__moc) {
|
|
model.__moc = coreModelWithMoc.__moc;
|
|
delete coreModelWithMoc.__moc;
|
|
model.once("destroy", releaseMoc);
|
|
}
|
|
return model;
|
|
},
|
|
createPhysics(coreModel, data) {
|
|
return CubismPhysics.create(data);
|
|
},
|
|
createPose(coreModel, data) {
|
|
return CubismPose.create(data);
|
|
}
|
|
});
|
|
function releaseMoc() {
|
|
var _a;
|
|
(_a = this.__moc) == null ? void 0 : _a.release();
|
|
}
|
|
exports2.Cubism2ExpressionManager = Cubism2ExpressionManager;
|
|
exports2.Cubism2InternalModel = Cubism2InternalModel;
|
|
exports2.Cubism2ModelSettings = Cubism2ModelSettings;
|
|
exports2.Cubism2MotionManager = Cubism2MotionManager;
|
|
exports2.Cubism4ExpressionManager = Cubism4ExpressionManager;
|
|
exports2.Cubism4InternalModel = Cubism4InternalModel;
|
|
exports2.Cubism4ModelSettings = Cubism4ModelSettings;
|
|
exports2.Cubism4MotionManager = Cubism4MotionManager;
|
|
exports2.ExpressionManager = ExpressionManager;
|
|
exports2.FileLoader = FileLoader;
|
|
exports2.FocusController = FocusController;
|
|
exports2.InteractionMixin = InteractionMixin;
|
|
exports2.InternalModel = InternalModel;
|
|
exports2.LOGICAL_HEIGHT = LOGICAL_HEIGHT;
|
|
exports2.LOGICAL_WIDTH = LOGICAL_WIDTH;
|
|
exports2.Live2DExpression = Live2DExpression;
|
|
exports2.Live2DEyeBlink = Live2DEyeBlink;
|
|
exports2.Live2DFactory = Live2DFactory;
|
|
exports2.Live2DLoader = Live2DLoader;
|
|
exports2.Live2DModel = Live2DModel;
|
|
exports2.Live2DPhysics = Live2DPhysics;
|
|
exports2.Live2DPose = Live2DPose;
|
|
exports2.Live2DTransform = Live2DTransform;
|
|
exports2.ModelSettings = ModelSettings;
|
|
exports2.MotionManager = MotionManager;
|
|
exports2.MotionPreloadStrategy = MotionPreloadStrategy;
|
|
exports2.MotionPriority = MotionPriority;
|
|
exports2.MotionState = MotionState;
|
|
exports2.SoundManager = SoundManager;
|
|
exports2.VERSION = VERSION;
|
|
exports2.XHRLoader = XHRLoader;
|
|
exports2.ZipLoader = ZipLoader;
|
|
exports2.applyMixins = applyMixins;
|
|
exports2.clamp = clamp;
|
|
exports2.copyArray = copyArray;
|
|
exports2.copyProperty = copyProperty;
|
|
exports2.cubism4Ready = cubism4Ready;
|
|
exports2.folderName = folderName;
|
|
exports2.logger = logger;
|
|
exports2.rand = rand;
|
|
exports2.remove = remove;
|
|
exports2.startUpCubism4 = startUpCubism4;
|
|
Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
});
|