Update to Cubism 4 SDK for Web R1

This commit is contained in:
Jun Koyama
2020-01-30 18:28:13 +09:00
parent ce2585a919
commit 3b711b8a80
54 changed files with 16247 additions and 0 deletions

195
src/math/cubismmath.ts Normal file
View File

@ -0,0 +1,195 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
import { Live2DCubismFramework as cubismvector2 } from './cubismvector2';
import CubismVector2 = cubismvector2.CubismVector2;
export namespace Live2DCubismFramework {
/**
* 数値計算などに使用するユーティリティクラス
*/
export class CubismMath {
/**
* 第一引数の値を最小値と最大値の範囲に収めた値を返す
*
* @param value 収められる値
* @param min 範囲の最小値
* @param max 範囲の最大値
* @return 最小値と最大値の範囲に収めた値
*/
static range(value: number, min: number, max: number): number {
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
return value;
}
/**
* サイン関数の値を求める
*
* @param x 角度値(ラジアン)
* @return サイン関数sin(x)の値
*/
static sin(x: number): number {
return Math.sin(x);
}
/**
* コサイン関数の値を求める
*
* @param x 角度値(ラジアン)
* @return コサイン関数cos(x)の値
*/
static cos(x: number): number {
return Math.cos(x);
}
/**
* 値の絶対値を求める
*
* @param x 絶対値を求める値
* @return 値の絶対値
*/
static abs(x: number): number {
return Math.abs(x);
}
/**
* 平方根(ルート)を求める
* @param x -> 平方根を求める値
* @return 値の平方根
*/
static sqrt(x: number): number {
return Math.sqrt(x);
}
/**
* イージング処理されたサインを求める
* フェードイン・アウト時のイージングに利用できる
*
* @param value イージングを行う値
* @return イージング処理されたサイン値
*/
static getEasingSine(value: number): number {
if (value < 0.0) {
return 0.0;
} else if (value > 1.0) {
return 1.0;
}
return 0.5 - 0.5 * this.cos(value * Math.PI);
}
/**
* 大きい方の値を返す
*
* @param left 左辺の値
* @param right 右辺の値
* @return 大きい方の値
*/
static max(left: number, right: number): number {
return left > right ? left : right;
}
/**
* 小さい方の値を返す
*
* @param left 左辺の値
* @param right 右辺の値
* @return 小さい方の値
*/
static min(left: number, right: number): number {
return left > right ? right : left;
}
/**
* 角度値をラジアン値に変換する
*
* @param degrees 角度値
* @return 角度値から変換したラジアン値
*/
static degreesToRadian(degrees: number): number {
return (degrees / 180.0) * Math.PI;
}
/**
* ラジアン値を角度値に変換する
*
* @param radian ラジアン値
* @return ラジアン値から変換した角度値
*/
static radianToDegrees(radian: number): number {
return (radian * 180.0) / Math.PI;
}
/**
* 2つのベクトルからラジアン値を求める
*
* @param from 始点ベクトル
* @param to 終点ベクトル
* @return ラジアン値から求めた方向ベクトル
*/
static directionToRadian(from: CubismVector2, to: CubismVector2): number {
const q1: number = Math.atan2(to.y, to.x);
const q2: number = Math.atan2(from.y, from.x);
let ret: number = q1 - q2;
while (ret < -Math.PI) {
ret += Math.PI * 2.0;
}
while (ret > Math.PI) {
ret -= Math.PI * 2.0;
}
return ret;
}
/**
* 2つのベクトルから角度値を求める
*
* @param from 始点ベクトル
* @param to 終点ベクトル
* @return 角度値から求めた方向ベクトル
*/
static directionToDegrees(from: CubismVector2, to: CubismVector2): number {
const radian: number = this.directionToRadian(from, to);
let degree: number = this.radianToDegrees(radian);
if (to.x - from.x > 0.0) {
degree = -degree;
}
return degree;
}
/**
* ラジアン値を方向ベクトルに変換する。
*
* @param totalAngle ラジアン値
* @return ラジアン値から変換した方向ベクトル
*/
static radianToDirection(totalAngle: number): CubismVector2 {
const ret: CubismVector2 = new CubismVector2();
ret.x = this.sin(totalAngle);
ret.y = this.cos(totalAngle);
return ret;
}
/**
* コンストラクタ
*/
private constructor() {}
}
}

308
src/math/cubismmatrix44.ts Normal file
View File

@ -0,0 +1,308 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
export namespace Live2DCubismFramework {
/**
* 4x4の行列
*
* 4x4行列の便利クラス。
*/
export class CubismMatrix44 {
/**
* コンストラクタ
*/
public constructor() {
this._tr = new Float32Array(16); // 4 * 4のサイズ
this.loadIdentity();
}
/**
* 受け取った2つの行列の乗算を行う。
*
* @param a 行列a
* @param b 行列b
* @return 乗算結果の行列
*/
public static multiply(
a: Float32Array,
b: Float32Array,
dst: Float32Array
): void {
const c: Float32Array = new Float32Array([
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]);
const n = 4;
for (let i = 0; i < n; ++i) {
for (let j = 0; j < n; ++j) {
for (let k = 0; k < n; ++k) {
c[j + i * 4] += a[k + i * 4] * b[j + k * 4];
}
}
}
for (let i = 0; i < 16; ++i) {
dst[i] = c[i];
}
}
/**
* 単位行列に初期化する
*/
public loadIdentity(): void {
const c: Float32Array = new Float32Array([
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0
]);
this.setMatrix(c);
}
/**
* 行列を設定
*
* @param tr 16個の浮動小数点数で表される4x4の行列
*/
public setMatrix(tr: Float32Array): void {
for (let i = 0; i < 16; ++i) {
this._tr[i] = tr[i];
}
}
/**
* 行列を浮動小数点数の配列で取得
*
* @return 16個の浮動小数点数で表される4x4の行列
*/
public getArray(): Float32Array {
return this._tr;
}
/**
* X軸の拡大率を取得
* @return X軸の拡大率
*/
public getScaleX(): number {
return this._tr[0];
}
/**
* Y軸の拡大率を取得する
*
* @return Y軸の拡大率
*/
public getScaleY(): number {
return this._tr[5];
}
/**
* X軸の移動量を取得
* @return X軸の移動量
*/
public getTranslateX(): number {
return this._tr[12];
}
/**
* Y軸の移動量を取得
* @return Y軸の移動量
*/
public getTranslateY(): number {
return this._tr[13];
}
/**
* X軸の値を現在の行列で計算
*
* @param src X軸の値
* @return 現在の行列で計算されたX軸の値
*/
public transformX(src: number): number {
return this._tr[0] * src + this._tr[12];
}
/**
* Y軸の値を現在の行列で計算
*
* @param src Y軸の値
* @return 現在の行列で計算されたY軸の値
*/
public transformY(src: number): number {
return this._tr[5] * src + this._tr[13];
}
/**
* X軸の値を現在の行列で逆計算
*/
public invertTransformX(src: number): number {
return (src - this._tr[12]) / this._tr[0];
}
/**
* Y軸の値を現在の行列で逆計算
*/
public invertTransformY(src: number): number {
return (src - this._tr[13]) / this._tr[5];
}
/**
* 現在の行列の位置を起点にして移動
*
* 現在の行列の位置を起点にして相対的に移動する。
*
* @param x X軸の移動量
* @param y Y軸の移動量
*/
public translateRelative(x: number, y: number): void {
const tr1: Float32Array = new Float32Array([
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
x,
y,
0.0,
1.0
]);
CubismMatrix44.multiply(tr1, this._tr, this._tr);
}
/**
* 現在の行列の位置を移動
*
* 現在の行列の位置を指定した位置へ移動する
*
* @param x X軸の移動量
* @param y y軸の移動量
*/
public translate(x: number, y: number): void {
this._tr[12] = x;
this._tr[13] = y;
}
/**
* 現在の行列のX軸の位置を指定した位置へ移動する
*
* @param x X軸の移動量
*/
public translateX(x: number): void {
this._tr[12] = x;
}
/**
* 現在の行列のY軸の位置を指定した位置へ移動する
*
* @param y Y軸の移動量
*/
public translateY(y: number): void {
this._tr[13] = y;
}
/**
* 現在の行列の拡大率を相対的に設定する
*
* @param x X軸の拡大率
* @param y Y軸の拡大率
*/
public scaleRelative(x: number, y: number): void {
const tr1: Float32Array = new Float32Array([
x,
0.0,
0.0,
0.0,
0.0,
y,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0
]);
CubismMatrix44.multiply(tr1, this._tr, this._tr);
}
/**
* 現在の行列の拡大率を指定した倍率に設定する
*
* @param x X軸の拡大率
* @param y Y軸の拡大率
*/
public scale(x: number, y: number): void {
this._tr[0] = x;
this._tr[5] = y;
}
/**
* 現在の行列に行列を乗算
*
* @param m 行列
*/
public multiplyByMatrix(m: CubismMatrix44): void {
CubismMatrix44.multiply(m.getArray(), this._tr, this._tr);
}
/**
* オブジェクトのコピーを生成する
*/
public clone(): CubismMatrix44 {
const cloneMatrix: CubismMatrix44 = new CubismMatrix44();
for (let i = 0; i < this._tr.length; i++) {
cloneMatrix._tr[i] = this._tr[i];
}
return cloneMatrix;
}
protected _tr: Float32Array; // 4x4行列データ
}
}

View File

@ -0,0 +1,223 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
import { Live2DCubismFramework as csmmap } from '../type/csmmap';
import { Live2DCubismFramework as cubismmatrix44 } from './cubismmatrix44';
import csmMap = csmmap.csmMap;
import iterator = csmmap.iterator;
import CubismMatrix44 = cubismmatrix44.CubismMatrix44;
export namespace Live2DCubismFramework {
/**
* モデル座標設定用の4x4行列
*
* モデル座標設定用の4x4行列クラス
*/
export class CubismModelMatrix extends CubismMatrix44 {
/**
* コンストラクタ
*
* @param w 横幅
* @param h 縦幅
*/
constructor(w?: number, h?: number) {
super();
this._width = w !== undefined ? w : 0.0;
this._height = h !== undefined ? h : 0.0;
this.setHeight(1.0);
}
/**
* 横幅を設定
*
* @param w 横幅
*/
public setWidth(w: number): void {
const scaleX: number = w / this._width;
const scaleY: number = scaleX;
this.scale(scaleX, scaleY);
}
/**
* 縦幅を設定
* @param h 縦幅
*/
public setHeight(h: number): void {
const scaleX: number = h / this._height;
const scaleY: number = scaleX;
this.scale(scaleX, scaleY);
}
/**
* 位置を設定
*
* @param x X軸の位置
* @param y Y軸の位置
*/
public setPosition(x: number, y: number): void {
this.translate(x, y);
}
/**
* 中心位置を設定
*
* @param x X軸の中心位置
* @param y Y軸の中心位置
*
* @note widthかheightを設定したあとでないと、拡大率が正しく取得できないためずれる。
*/
public setCenterPosition(x: number, y: number) {
this.centerX(x);
this.centerY(y);
}
/**
* 上辺の位置を設定する
*
* @param y 上辺のY軸位置
*/
public top(y: number): void {
this.setY(y);
}
/**
* 下辺の位置を設定する
*
* @param y 下辺のY軸位置
*/
public bottom(y: number) {
const h: number = this._height * this.getScaleY();
this.translateY(y - h);
}
/**
* 左辺の位置を設定
*
* @param x 左辺のX軸位置
*/
public left(x: number): void {
this.setX(x);
}
/**
* 右辺の位置を設定
*
* @param x 右辺のX軸位置
*/
public right(x: number): void {
const w = this._width * this.getScaleX();
this.translateX(x - w);
}
/**
* X軸の中心位置を設定
*
* @param x X軸の中心位置
*/
public centerX(x: number): void {
const w = this._width * this.getScaleX();
this.translateX(x - w / 2.0);
}
/**
* X軸の位置を設定
*
* @param x X軸の位置
*/
public setX(x: number): void {
this.translateX(x);
}
/**
* Y軸の中心位置を設定
*
* @param y Y軸の中心位置
*/
public centerY(y: number): void {
const h: number = this._height * this.getScaleY();
this.translateY(y - h / 2.0);
}
/**
* Y軸の位置を設定する
*
* @param y Y軸の位置
*/
public setY(y: number): void {
this.translateY(y);
}
/**
* レイアウト情報から位置を設定
*
* @param layout レイアウト情報
*/
public setupFromLayout(layout: csmMap<string, number>): void {
const keyWidth = 'width';
const keyHeight = 'height';
const keyX = 'x';
const keyY = 'y';
const keyCenterX = 'center_x';
const keyCenterY = 'center_y';
const keyTop = 'top';
const keyBottom = 'bottom';
const keyLeft = 'left';
const keyRight = 'right';
for (
const ite: iterator<string, number> = layout.begin();
ite.notEqual(layout.end());
ite.preIncrement()
) {
const key: string = ite.ptr().first;
const value: number = ite.ptr().second;
if (key == keyWidth) {
this.setWidth(value);
} else if (key == keyHeight) {
this.setHeight(value);
}
}
for (
const ite: iterator<string, number> = layout.begin();
ite.notEqual(layout.end());
ite.preIncrement()
) {
const key: string = ite.ptr().first;
const value: number = ite.ptr().second;
if (key == keyX) {
this.setX(value);
} else if (key == keyY) {
this.setY(value);
} else if (key == keyCenterX) {
this.centerX(value);
} else if (key == keyCenterY) {
this.centerY(value);
} else if (key == keyTop) {
this.top(value);
} else if (key == keyBottom) {
this.bottom(value);
} else if (key == keyLeft) {
this.left(value);
} else if (key == keyRight) {
this.right(value);
}
}
}
private _width: number; // 横幅
private _height: number; // 縦幅
}
}

View File

@ -0,0 +1,164 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
import { Live2DCubismFramework as cubismmath } from './cubismmath';
import CubismMath = cubismmath.CubismMath;
export namespace Live2DCubismFramework {
const FrameRate = 30;
const Epsilon = 0.01;
/**
* 顔の向きの制御機能
*
* 顔の向きの制御機能を提供するクラス。
*/
export class CubismTargetPoint {
/**
* コンストラクタ
*/
public constructor() {
this._faceTargetX = 0.0;
this._faceTargetY = 0.0;
this._faceX = 0.0;
this._faceY = 0.0;
this._faceVX = 0.0;
this._faceVY = 0.0;
this._lastTimeSeconds = 0.0;
this._userTimeSeconds = 0.0;
}
/**
* 更新処理
*/
public update(deltaTimeSeconds: number): void {
// デルタ時間を加算する
this._userTimeSeconds += deltaTimeSeconds;
// 首を中央から左右に振るときの平均的な速さは 秒速度。加速・減速を考慮して、その2倍を最高速度とする
// 顔の振り具合を、中央0.0)から、左右は(+-1.0)とする
const faceParamMaxV: number = 40.0 / 10.0; // 7.5秒間に40分移動(5.3/sc)
const maxV: number = (faceParamMaxV * 1.0) / FrameRate; // 1frameあたりに変化できる速度の上限
if (this._lastTimeSeconds == 0.0) {
this._lastTimeSeconds = this._userTimeSeconds;
return;
}
const deltaTimeWeight: number =
(this._userTimeSeconds - this._lastTimeSeconds) * FrameRate;
this._lastTimeSeconds = this._userTimeSeconds;
// 最高速度になるまでの時間を
const timeToMaxSpeed = 0.15;
const frameToMaxSpeed: number = timeToMaxSpeed * FrameRate; // sec * frame/sec
const maxA: number = (deltaTimeWeight * maxV) / frameToMaxSpeed; // 1frameあたりの加速度
// 目指す向きは、dx, dy方向のベクトルとなる
const dx: number = this._faceTargetX - this._faceX;
const dy: number = this._faceTargetY - this._faceY;
if (CubismMath.abs(dx) <= Epsilon && CubismMath.abs(dy) <= Epsilon) {
return; // 変化なし
}
// 速度の最大よりも大きい場合は、速度を落とす
const d: number = CubismMath.sqrt(dx * dx + dy * dy);
// 進行方向の最大速度ベクトル
const vx: number = (maxV * dx) / d;
const vy: number = (maxV * dy) / d;
// 現在の速度から、新規速度への変化(加速度)を求める
let ax: number = vx - this._faceVX;
let ay: number = vy - this._faceVY;
const a: number = CubismMath.sqrt(ax * ax + ay * ay);
// 加速のとき
if (a < -maxA || a > maxA) {
ax *= maxA / a;
ay *= maxA / a;
}
// 加速度を元の速度に足して、新速度とする
this._faceVX += ax;
this._faceVY += ay;
// 目的の方向に近づいたとき、滑らかに減速するための処理
// 設定された加速度で止まる事の出来る距離と速度の関係から
// 現在とりうる最高速度を計算し、それ以上の時は速度を落とす
// ※本来、人間は筋力で力(加速度)を調整できるため、より自由度が高いが、簡単な処理で済ませている
{
// 加速度、速度、距離の関係式。
// 2 6 2 3
// sqrt(a t + 16 a h t - 8 a h) - a t
// v = --------------------------------------
// 2
// 4 t - 2
// (t=1)
// 時刻tは、あらかじめ加速度、速度を1/60(フレームレート、単位なし)で
// 考えているので、tとして消してよい※未検証
const maxV: number =
0.5 *
(CubismMath.sqrt(maxA * maxA + 16.0 * maxA * d - 8.0 * maxA * d) -
maxA);
const curV: number = CubismMath.sqrt(
this._faceVX * this._faceVX + this._faceVY * this._faceVY
);
if (curV > maxV) {
// 現在の速度 > 最高速度のとき、最高速度まで減速
this._faceVX *= maxV / curV;
this._faceVY *= maxV / curV;
}
}
this._faceX += this._faceVX;
this._faceY += this._faceVY;
}
/**
* X軸の顔の向きの値を取得
*
* @return X軸の顔の向きの値-1.0 ~ 1.0
*/
public getX(): number {
return this._faceX;
}
/**
* Y軸の顔の向きの値を取得
*
* @return Y軸の顔の向きの値-1.0 ~ 1.0
*/
public getY(): number {
return this._faceY;
}
/**
* 顔の向きの目標値を設定
*
* @param x X軸の顔の向きの値-1.0 ~ 1.0
* @param y Y軸の顔の向きの値-1.0 ~ 1.0
*/
public set(x: number, y: number): void {
this._faceTargetX = x;
this._faceTargetY = y;
}
private _faceTargetX: number; // 顔の向きのX目標値この値に近づいていく
private _faceTargetY: number; // 顔の向きのY目標値この値に近づいていく
private _faceX: number; // 顔の向きX-1.0 ~ 1.0
private _faceY: number; // 顔の向きY-1.0 ~ 1.0
private _faceVX: number; // 顔の向きの変化速度X
private _faceVY: number; // 顔の向きの変化速度Y
private _lastTimeSeconds: number; // 最後の実行時間[秒]
private _userTimeSeconds: number; // デルタ時間の積算値[秒]
}
}

163
src/math/cubismvector2.ts Normal file
View File

@ -0,0 +1,163 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
export namespace Live2DCubismFramework {
/**
* 2次元ベクトル型
*
* 2次元ベクトル型の機能を提供する。
*/
export class CubismVector2 {
/**
* コンストラクタ
*/
public constructor(public x?: number, public y?: number) {
this.x = x == undefined ? 0.0 : x;
this.y = y == undefined ? 0.0 : y;
}
/**
* ベクトルの加算
*
* @param vector2 加算するベクトル値
* @return 加算結果 ベクトル値
*/
public add(vector2: CubismVector2): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0.0, 0.0);
ret.x = this.x + vector2.x;
ret.y = this.y + vector2.y;
return ret;
}
/**
* ベクトルの減算
*
* @param vector2 減算するベクトル値
* @return 減算結果 ベクトル値
*/
public substract(vector2: CubismVector2): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0.0, 0.0);
ret.x = this.x - vector2.x;
ret.y = this.y - vector2.y;
return ret;
}
/**
* ベクトルの乗算
*
* @param vector2 乗算するベクトル値
* @return 乗算結果 ベクトル値
*/
public multiply(vector2: CubismVector2): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0.0, 0.0);
ret.x = this.x * vector2.x;
ret.y = this.y * vector2.y;
return ret;
}
/**
* ベクトルの乗算(スカラー)
*
* @param scalar 乗算するスカラー値
* @return 乗算結果 ベクトル値
*/
public multiplyByScaler(scalar: number): CubismVector2 {
return this.multiply(new CubismVector2(scalar, scalar));
}
/**
* ベクトルの除算
*
* @param vector2 除算するベクトル値
* @return 除算結果 ベクトル値
*/
public division(vector2: CubismVector2): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0.0, 0.0);
ret.x = this.x / vector2.x;
ret.y = this.y / vector2.y;
return ret;
}
/**
* ベクトルの除算(スカラー)
*
* @param scalar 除算するスカラー値
* @return 除算結果 ベクトル値
*/
public divisionByScalar(scalar: number): CubismVector2 {
return this.division(new CubismVector2(scalar, scalar));
}
/**
* ベクトルの長さを取得する
*
* @return ベクトルの長さ
*/
public getLength(): number {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
/**
* ベクトルの距離の取得
*
* @param a 点
* @return ベクトルの距離
*/
public getDistanceWith(a: CubismVector2): number {
return Math.sqrt(
(this.x - a.x) * (this.x - a.x) + (this.y - a.y) * (this.y - a.y)
);
}
/**
* ドット積の計算
*
* @param a 値
* @return 結果
*/
public dot(a: CubismVector2): number {
return this.x * a.x + this.y * a.y;
}
/**
* 正規化の適用
*/
public normalize(): void {
const length: number = Math.pow(this.x * this.x + this.y * this.y, 0.5);
this.x = this.x / length;
this.y = this.y / length;
}
/**
* 等しさの確認(等しいか?)
*
* 値が等しいか?
*
* @param rhs 確認する値
* @return true 値は等しい
* @return false 値は等しくない
*/
public isEqual(rhs: CubismVector2): boolean {
return this.x == rhs.x && this.y == rhs.y;
}
/**
* 等しさの確認(等しくないか?)
*
* 値が等しくないか?
*
* @param rhs 確認する値
* @return true 値は等しくない
* @return false 値は等しい
*/
public isNotEqual(rhs: CubismVector2): boolean {
return !this.isEqual(rhs);
}
}
}

View File

@ -0,0 +1,337 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
import { Live2DCubismFramework as cubismmatrix44 } from './cubismmatrix44';
import CubismMatrix44 = cubismmatrix44.CubismMatrix44;
export namespace Live2DCubismFramework {
/**
* カメラの位置変更に使うと便利な4x4行列
*
* カメラの位置変更に使うと便利な4x4行列のクラス。
*/
export class CubismViewMatrix extends CubismMatrix44 {
/**
* コンストラクタ
*/
public constructor() {
super();
this._screenLeft = 0.0;
this._screenRight = 0.0;
this._screenTop = 0.0;
this._screenBottom = 0.0;
this._maxLeft = 0.0;
this._maxRight = 0.0;
this._maxTop = 0.0;
this._maxBottom = 0.0;
this._maxScale = 0.0;
this._minScale = 0.0;
}
/**
* 移動を調整
*
* @param x X軸の移動量
* @param y Y軸の移動量
*/
public adjustTranslate(x: number, y: number): void {
if (this._tr[0] * this._maxLeft + (this._tr[12] + x) > this._screenLeft) {
x = this._screenLeft - this._tr[0] * this._maxLeft - this._tr[12];
}
if (
this._tr[0] * this._maxRight + (this._tr[12] + x) <
this._screenRight
) {
x = this._screenRight - this._tr[0] * this._maxRight - this._tr[12];
}
if (this._tr[5] * this._maxTop + (this._tr[13] + y) < this._screenTop) {
y = this._screenTop - this._tr[5] * this._maxTop - this._tr[13];
}
if (
this._tr[5] * this._maxBottom + (this._tr[13] + y) >
this._screenBottom
) {
y = this._screenBottom - this._tr[5] * this._maxBottom - this._tr[13];
}
const tr1: Float32Array = new Float32Array([
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
x,
y,
0.0,
1.0
]);
CubismMatrix44.multiply(tr1, this._tr, this._tr);
}
/**
* 拡大率を調整
*
* @param cx 拡大を行うX軸の中心位置
* @param cy 拡大を行うY軸の中心位置
* @param scale 拡大率
*/
public adjustScale(cx: number, cy: number, scale: number): void {
const maxScale: number = this.getMaxScale();
const minScale: number = this.getMinScale();
const targetScale = scale * this._tr[0];
if (targetScale < minScale) {
if (this._tr[0] > 0.0) {
scale = minScale / this._tr[0];
}
} else if (targetScale > maxScale) {
if (this._tr[0] > 0.0) {
scale = maxScale / this._tr[0];
}
}
const tr1: Float32Array = new Float32Array([
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
cx,
cy,
0.0,
1.0
]);
const tr2: Float32Array = new Float32Array([
scale,
0.0,
0.0,
0.0,
0.0,
scale,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0
]);
const tr3: Float32Array = new Float32Array([
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
-cx,
-cy,
0.0,
1.0
]);
CubismMatrix44.multiply(tr3, this._tr, this._tr);
CubismMatrix44.multiply(tr2, this._tr, this._tr);
CubismMatrix44.multiply(tr1, this._tr, this._tr);
}
/**
* デバイスに対応する論理座養生の範囲の設定
*
* @param left 左辺のX軸の位置
* @param right 右辺のX軸の位置
* @param bottom 下辺のY軸の位置
* @param top 上辺のY軸の位置
*/
public setScreenRect(
left: number,
right: number,
bottom: number,
top: number
): void {
this._screenLeft = left;
this._screenRight = right;
this._screenBottom = bottom;
this._screenTop = top;
}
/**
* デバイスに対応する論理座標上の移動可能範囲の設定
* @param left 左辺のX軸の位置
* @param right 右辺のX軸の位置
* @param bottom 下辺のY軸の位置
* @param top 上辺のY軸の位置
*/
public setMaxScreenRect(
left: number,
right: number,
bottom: number,
top: number
): void {
this._maxLeft = left;
this._maxRight = right;
this._maxTop = top;
this._maxBottom = bottom;
}
/**
* 最大拡大率の設定
* @param maxScale 最大拡大率
*/
public setMaxScale(maxScale: number): void {
this._maxScale = maxScale;
}
/**
* 最小拡大率の設定
* @param minScale 最小拡大率
*/
public setMinScale(minScale: number): void {
this._minScale = minScale;
}
/**
* 最大拡大率の取得
* @return 最大拡大率
*/
public getMaxScale(): number {
return this._maxScale;
}
/**
* 最小拡大率の取得
* @return 最小拡大率
*/
public getMinScale(): number {
return this._minScale;
}
/**
* 拡大率が最大になっているかを確認する
*
* @return true 拡大率は最大
* @return false 拡大率は最大ではない
*/
public isMaxScale(): boolean {
return this.getScaleX() >= this._maxScale;
}
/**
* 拡大率が最小になっているかを確認する
*
* @return true 拡大率は最小
* @return false 拡大率は最小ではない
*/
public isMinScale(): boolean {
return this.getScaleX() <= this._minScale;
}
/**
* デバイスに対応する論理座標の左辺のX軸位置を取得する
* @return デバイスに対応する論理座標の左辺のX軸位置
*/
public getScreenLeft(): number {
return this._screenLeft;
}
/**
* デバイスに対応する論理座標の右辺のX軸位置を取得する
* @return デバイスに対応する論理座標の右辺のX軸位置
*/
public getScreenRight(): number {
return this._screenRight;
}
/**
* デバイスに対応する論理座標の下辺のY軸位置を取得する
* @return デバイスに対応する論理座標の下辺のY軸位置
*/
public getScreenBottom(): number {
return this._screenBottom;
}
/**
* デバイスに対応する論理座標の上辺のY軸位置を取得する
* @return デバイスに対応する論理座標の上辺のY軸位置
*/
public getScreenTop(): number {
return this._screenTop;
}
/**
* 左辺のX軸位置の最大値の取得
* @return 左辺のX軸位置の最大値
*/
public getMaxLeft(): number {
return this._maxLeft;
}
/**
* 右辺のX軸位置の最大値の取得
* @return 右辺のX軸位置の最大値
*/
public getMaxRight(): number {
return this._maxRight;
}
/**
* 下辺のY軸位置の最大値の取得
* @return 下辺のY軸位置の最大値
*/
public getMaxBottom(): number {
return this._maxBottom;
}
/**
* 上辺のY軸位置の最大値の取得
* @return 上辺のY軸位置の最大値
*/
public getMaxTop(): number {
return this._maxTop;
}
private _screenLeft: number; // デバイスに対応する論理座標上の範囲左辺X軸位置
private _screenRight: number; // デバイスに対応する論理座標上の範囲右辺X軸位置
private _screenTop: number; // デバイスに対応する論理座標上の範囲上辺Y軸位置
private _screenBottom: number; // デバイスに対応する論理座標上の範囲下辺Y軸位置
private _maxLeft: number; // 論理座標上の移動可能範囲左辺X軸位置
private _maxRight: number; // 論理座標上の移動可能範囲右辺X軸位置
private _maxTop: number; // 論理座標上の移動可能範囲上辺Y軸位置
private _maxBottom: number; // 論理座標上の移動可能範囲下辺Y軸位置
private _maxScale: number; // 拡大率の最大値
private _minScale: number; // 拡大率の最小値
}
}