1
0
Fork 0

Update to Cubism 4 SDK for Web R1

hfjnulyz-patch-1
Jun Koyama 2020-01-30 18:28:13 +09:00
parent ce2585a919
commit 3b711b8a80
54 changed files with 16247 additions and 0 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

31
.eslintrc.yml Normal file
View File

@ -0,0 +1,31 @@
extends:
- eslint:recommended
- plugin:@typescript-eslint/eslint-recommended
- plugin:@typescript-eslint/recommended
- plugin:@typescript-eslint/recommended-requiring-type-checking
- plugin:prettier/recommended
- prettier/@typescript-eslint
plugins:
- '@typescript-eslint'
parser: '@typescript-eslint/parser'
parserOptions:
sourceType: module
ecmaVersion: 2020
project: ./tsconfig.json
rules:
prettier/prettier:
- error
- singleQuote: true
'@typescript-eslint/camelcase': warn
'@typescript-eslint/no-use-before-define': off
no-empty-function: off
'@typescript-eslint/no-empty-function':
- error
- allow:
- constructors
'@typescript-eslint/no-namespace': warn
'no-fallthrough': warn
'@typescript-eslint/unbound-method': off
'no-inner-declarations': off
'@typescript-eslint/class-name-casing': warn
'prefer-const': warn

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
# Package files
node_modules/
# Build files
dist/
# Other files
.vs/
.idea/
*.iml
.DS_Store
# Exclude some VSCode setting files.
.vscode/*
!/.vscode/extensions.json
!/.vscode/tasks.json

5
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"recommendations": [
"editorconfig.editorconfig"
]
}

39
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,39 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "install",
"problemMatcher": []
},
{
"type": "npm",
"script": "build",
"group": "build",
"problemMatcher": []
},
{
"type": "npm",
"script": "test",
"group": "test",
"problemMatcher": []
},
{
"type": "npm",
"script": "lint",
"group": "test",
"problemMatcher": []
},
{
"type": "npm",
"script": "lint:fix",
"group": "test",
"problemMatcher": []
},
{
"type": "npm",
"script": "clear",
"problemMatcher": []
}
]
}

23
CHANGELOG.md Normal file
View File

@ -0,0 +1,23 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [4-r.1] - 2020-01-30
### Added
* Add `.editorconfig`, `.gitattributes` and `.gitignore`.
* Add document `README.md` and `CHANGELOG.md`.
* Add `package.json` for development and build.
* Add Prettier and ESLint for format and check code quolity.
### Changed
* Move source files to `/src` directory.
* Reformat code using Prettier and ESLint.
[4-r.1]: https://github.com/Live2D/CubismWebFramework/compare/ce2585a919ac6e99f64dd468933772c6f1abbcc7...4-r.1

39
LICENSE.md Normal file
View File

@ -0,0 +1,39 @@
## Definitions
### Live2D Cubism Components
Cubism Web Framework is included in Live2D Cubism Components.
Cubism Web Framework は Live2D Cubism Components に含まれます。
## Cubism SDK Release License
*All business* users must obtain a Cubism SDK Release License. "Business" means an entity with the annual gross revenue more than ten million (10,000,000) JPY for the most recent fiscal year.
* [Cubism SDK Release License](https://www.live2d.com/en/download/cubism-sdk/release-license/)
直近会計年度の売上高が 1000 万円以上の事業者様がご利用になる場合は、Cubism SDK リリースライセンス(出版許諾契約)に同意していただく必要がございます。
* [Cubism SDK リリースライセンス](https://www.live2d.com/ja/download/cubism-sdk/release-license/)
## Live2D Open Software License
Live2D Cubism Components is available under Live2D Open Software License.
* [Live2D Open Software License](https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html)
* [Live2D Open Software 使用許諾契約書](https://www.live2d.com/eula/live2d-open-software-license-agreement_jp.html)
## Live2D Proprietary Software License
Live2D Cubism Core is available under Live2D Proprietary Software License.
* [Live2D Proprietary Software License Agreement](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_en.html)
* [Live2D Proprietary Software 使用許諾契約書](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_jp.html)
---
Please contact us from [here](https://www.live2d.jp/contact/) for more license information.

134
README.md Normal file
View File

@ -0,0 +1,134 @@
# Cubism Web Framework
Live2D Cubism 4 Editor で出力したモデルをアプリケーションで利用するためのフレームワークです。
モデルを表示、操作するための各種機能を提供します。
モデルをロードするには Live2D Cubism Core ライブラリと組み合わせて使用します。
ビルドを行うことで、ブラウザで利用可能な JavaScript ライブラリとして利用することができます。
## ライセンス
本 SDK を使用する前に、[ライセンス](LICENSE.md)をご確認ください。
## 開発環境
### Node.js
* 13.7.0
* 12.14.1
* 10.18.1
### TypeScript
3.7.5
## 開発環境構築
1. [Node.js] と [Visual Studio Code] をインストールします
1. Visual Studio Code で本プロジェクトを開き、推奨拡張機能をインストールします
* 拡張機能タブから `@recommended` と入力することで確認できます
1. コマンドパレット(*View > Command Palette...*)で `>Tasks: Run Task` を入力してタスク一覧を表示します
1. `npm: install` を選択して依存パッケージのダウンロードを行います
コマンドパレットのタスク一覧から各種コマンドを実行することができます。
NOTE: デバック用の設定は、`.vscode/tasks.json` に記述しています。
## タスク一覧
### `npm: build`
ソースファイルのビルドを行い、`dist` ディレクトリに出力します。
`tsconfig.json` を編集することで設定内容を変更できます。
### `npm: test`
TypeScript の型チェックテストを行います。
`tsconfig.json` を編集することで設定内容を変更できます。
### `npm: lint`
`src` ディレクトリ内の TypeScript ファイルの静的解析を行います。
`.eslintrc.yml` を編集することで設定内容を変更できます。
### `npm: lint:fix`
`src` ディレクトリ内の TypeScript ファイルの静的解析及び自動修正を行います。
`.eslintrc.yml` を編集することで設定内容を変更できます。
### `npm: clean`
ビルド成果物ディレクトリ(`dist`)を削除します。
## コンポーネント
### effect
自動まばたきやリップシンクなど、モデルに対してモーション情報をエフェクト的に付加する機能を提供します。
### id
モデルに設定されたパラメータ名・パーツ名・Drawable名を独自の型で管理する機能を提供します。
### math
行列計算やベクトル計算など、モデルの操作や描画に必要な算術演算の機能を提供します。
### model
モデルを取り扱うための各種機能(生成、更新、破棄)を提供します。
### motion
モデルにモーションデータを適用するための各種機能(モーション再生、パラメータブレンド)を提供します。
### physics
モデルに物理演算による変形操作を適用するための機能を提供します。
### rendering
モデルを描画するためのグラフィックス命令を実装したレンダラを提供します。
### type
フレームワーク内で使用する型定義を提供します。
### utils
JSONパーサーやログ出力などのユーティリティ機能を提供します。
## Live2D Cubism Core for Web
当リポジトリには Cubism Core for Web は同梱されていません。
[Cubism SDK for Web] からダウンロードしてください。
[Cubism SDK for Web]: https://www.live2d.com/download/cubism-sdk/download-web/
## サンプル
標準的なアプリケーションの実装例は [CubismWebSamples] を参照ください。
[CubismWebSamples]: https://github.com/Live2D/CubismWebSamples
## マニュアル
[Cubism SDK Manual](https://docs.live2d.com/cubism-sdk-manual/top/)
## 変更履歴
当リポジトリの変更履歴については [CHANGELOG.md](CHANGELOG.md) を参照ください。

1155
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"private": true,
"scripts": {
"build": "tsc",
"test": "tsc --noEmit",
"lint": "eslint src -f codeframe --ext .ts",
"lint:fix": "eslint src -f codeframe --ext .ts --fix",
"clean": "rimraf dist"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.18.0",
"@typescript-eslint/parser": "^2.18.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-prettier": "^3.1.2",
"prettier": "^1.19.1",
"rimraf": "^3.0.1",
"typescript": "^3.7.5"
}
}

View File

@ -0,0 +1,65 @@
/**
* 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.
*/
/**
* @brief ID<br>
* <br>
* https://docs.live2d.com/cubism-editor-manual/standard-parametor-list/
*/
export namespace Live2DCubismFramework {
// パーツID
export const HitAreaPrefix = 'HitArea';
export const HitAreaHead = 'Head';
export const HitAreaBody = 'Body';
export const PartsIdCore = 'Parts01Core';
export const PartsArmPrefix = 'Parts01Arm_';
export const PartsArmLPrefix = 'Parts01ArmL_';
export const PartsArmRPrefix = 'Parts01ArmR_';
// パラメータID
export const ParamAngleX = 'ParamAngleX';
export const ParamAngleY = 'ParamAngleY';
export const ParamAngleZ = 'ParamAngleZ';
export const ParamEyeLOpen = 'ParamEyeLOpen';
export const ParamEyeLSmile = 'ParamEyeLSmile';
export const ParamEyeROpen = 'ParamEyeROpen';
export const ParamEyeRSmile = 'ParamEyeRSmile';
export const ParamEyeBallX = 'ParamEyeBallX';
export const ParamEyeBallY = 'ParamEyeBallY';
export const ParamEyeBallForm = 'ParamEyeBallForm';
export const ParamBrowLY = 'ParamBrowLY';
export const ParamBrowRY = 'ParamBrowRY';
export const ParamBrowLX = 'ParamBrowLX';
export const ParamBrowRX = 'ParamBrowRX';
export const ParamBrowLAngle = 'ParamBrowLAngle';
export const ParamBrowRAngle = 'ParamBrowRAngle';
export const ParamBrowLForm = 'ParamBrowLForm';
export const ParamBrowRForm = 'ParamBrowRForm';
export const ParamMouthForm = 'ParamMouthForm';
export const ParamMouthOpenY = 'ParamMouthOpenY';
export const ParamCheek = 'ParamCheek';
export const ParamBodyAngleX = 'ParamBodyAngleX';
export const ParamBodyAngleY = 'ParamBodyAngleY';
export const ParamBodyAngleZ = 'ParamBodyAngleZ';
export const ParamBreath = 'ParamBreath';
export const ParamArmLA = 'ParamArmLA';
export const ParamArmRA = 'ParamArmRA';
export const ParamArmLB = 'ParamArmLB';
export const ParamArmRB = 'ParamArmRB';
export const ParamHandL = 'ParamHandL';
export const ParamHandR = 'ParamHandR';
export const ParamHairFront = 'ParamHairFront';
export const ParamHairSide = 'ParamHairSide';
export const ParamHairBack = 'ParamHairBack';
export const ParamHairFluffy = 'ParamHairFluffy';
export const ParamShoulderY = 'ParamShoulderY';
export const ParamBustX = 'ParamBustX';
export const ParamBustY = 'ParamBustY';
export const ParamBaseX = 'ParamBaseX';
export const ParamBaseY = 'ParamBaseY';
export const ParamNONE = 'NONE:';
}

View File

@ -0,0 +1,32 @@
/**
* 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 const CSM_LOG_LEVEL_VERBOSE = 0;
// デバッグログ出力設定
export const CSM_LOG_LEVEL_DEBUG = 1;
// Infoログ出力設定
export const CSM_LOG_LEVEL_INFO = 2;
// 警告ログ出力設定
export const CSM_LOG_LEVEL_WARNING = 3;
// エラーログ出力設定
export const CSM_LOG_LEVEL_ERROR = 4;
// ログ出力オフ設定
export const CSM_LOG_LEVEL_OFF = 5;
/**
*
*
*
* CSM_LOG_LEVEL_VERBOSE CSM_LOG_LEVEL_OFF
*/
export const CSM_LOG_LEVEL: number = CSM_LOG_LEVEL_VERBOSE;

View File

@ -0,0 +1,842 @@
/**
* 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 cubismframework } from './live2dcubismframework';
import { Live2DCubismFramework as icubismmodelsetting } from './icubismmodelsetting';
import { Live2DCubismFramework as cubismid } from './id/cubismid';
import { Live2DCubismFramework as cubismjson } from './utils/cubismjson';
import { Live2DCubismFramework as csmmap } from './type/csmmap';
import { Live2DCubismFramework as csmvector } from './type/csmvector';
import csmVector = csmvector.csmVector;
import csmMap = csmmap.csmMap;
import iterator = csmmap.iterator;
import CubismFramework = cubismframework.CubismFramework;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismJson = cubismjson.CubismJson;
import Value = cubismjson.Value;
import ICubismModelSetting = icubismmodelsetting.ICubismModelSetting;
export namespace Live2DCubismFramework {
/**
* Model3Json
*/
// JSON Keys
const Version = 'Version';
const FileReferences = 'FileReferences';
const Groups = 'Groups';
const Layout = 'Layout';
const HitAreas = 'HitAreas';
const Moc = 'Moc';
const Textures = 'Textures';
const Physics = 'Physics';
const Pose = 'Pose';
const Expressions = 'Expressions';
const Motions = 'Motions';
const UserData = 'UserData';
const Name = 'Name';
const FilePath = 'File';
const Id = 'Id';
const Ids = 'Ids';
const Target = 'Target';
// Motions
const Idle = 'Idle';
const TapBody = 'TapBody';
const PinchIn = 'PinchIn';
const PinchOut = 'PinchOut';
const Shake = 'Shake';
const FlickHead = 'FlickHead';
const Parameter = 'Parameter';
const SoundPath = 'Sound';
const FadeInTime = 'FadeInTime';
const FadeOutTime = 'FadeOutTime';
// Layout
const CenterX = 'CenterX';
const CenterY = 'CenterY';
const X = 'X';
const Y = 'Y';
const Width = 'Width';
const Height = 'Height';
const LipSync = 'LipSync';
const EyeBlink = 'EyeBlink';
const InitParameter = 'init_param';
const InitPartsVisible = 'init_parts_visible';
const Val = 'val';
enum FrequestNode {
FrequestNode_Groups, // getRoot().getValueByString(Groups)
FrequestNode_Moc, // getRoot().getValueByString(FileReferences).getValueByString(Moc)
FrequestNode_Motions, // getRoot().getValueByString(FileReferences).getValueByString(Motions)
FrequestNode_Expressions, // getRoot().getValueByString(FileReferences).getValueByString(Expressions)
FrequestNode_Textures, // getRoot().getValueByString(FileReferences).getValueByString(Textures)
FrequestNode_Physics, // getRoot().getValueByString(FileReferences).getValueByString(Physics)
FrequestNode_Pose, // getRoot().getValueByString(FileReferences).getValueByString(Pose)
FrequestNode_HitAreas // getRoot().getValueByString(HitAreas)
}
/**
* Model3Json
*
* model3.json
*/
export class CubismModelSettingJson extends ICubismModelSetting {
/**
*
*
* @param buffer Model3Json
* @param size Model3Json
*/
public constructor(buffer: ArrayBuffer, size: number) {
super();
this._json = CubismJson.create(buffer, size);
if (this._json) {
this._jsonValue = new csmVector<Value>();
// 順番はenum FrequestNodeと一致させる
this._jsonValue.pushBack(this._json.getRoot().getValueByString(Groups));
this._jsonValue.pushBack(
this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(Moc)
);
this._jsonValue.pushBack(
this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(Motions)
);
this._jsonValue.pushBack(
this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(Expressions)
);
this._jsonValue.pushBack(
this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(Textures)
);
this._jsonValue.pushBack(
this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(Physics)
);
this._jsonValue.pushBack(
this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(Pose)
);
this._jsonValue.pushBack(
this._json.getRoot().getValueByString(HitAreas)
);
}
}
/**
*
*/
public release(): void {
CubismJson.delete(this._json);
this._jsonValue = null;
}
/**
* CubismJson
*
* @return CubismJson
*/
public GetJson(): CubismJson {
return this._json;
}
/**
* Moc
* @return Moc
*/
public getModelFileName(): string {
if (!this.isExistModelFile()) {
return '';
}
return this._jsonValue.at(FrequestNode.FrequestNode_Moc).getRawString();
}
/**
* 使
*
*/
public getTextureCount(): number {
if (!this.isExistTextureFiles()) {
return 0;
}
return this._jsonValue.at(FrequestNode.FrequestNode_Textures).getSize();
}
/**
*
* @return
*/
public getTextureDirectory(): string {
return this._jsonValue
.at(FrequestNode.FrequestNode_Textures)
.getRawString();
}
/**
* 使
* @param index
* @return
*/
public getTextureFileName(index: number): string {
return this._jsonValue
.at(FrequestNode.FrequestNode_Textures)
.getValueByIndex(index)
.getRawString();
}
/**
*
* @return
*/
public getHitAreasCount(): number {
if (!this.isExistHitAreas()) {
return 0;
}
return this._jsonValue.at(FrequestNode.FrequestNode_HitAreas).getSize();
}
/**
* ID
*
* @param index index
* @return ID
*/
public getHitAreaId(index: number): CubismIdHandle {
return CubismFramework.getIdManager().getId(
this._jsonValue
.at(FrequestNode.FrequestNode_HitAreas)
.getValueByIndex(index)
.getValueByString(Id)
.getRawString()
);
}
/**
*
* @param index
* @return
*/
public getHitAreaName(index: number): string {
return this._jsonValue
.at(FrequestNode.FrequestNode_HitAreas)
.getValueByIndex(index)
.getValueByString(Name)
.getRawString();
}
/**
*
* @return
*/
public getPhysicsFileName(): string {
if (!this.isExistPhysicsFile()) {
return '';
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Physics)
.getRawString();
}
/**
*
* @return
*/
public getPoseFileName(): string {
if (!this.isExistPoseFile()) {
return '';
}
return this._jsonValue.at(FrequestNode.FrequestNode_Pose).getRawString();
}
/**
*
* @return
*/
public getExpressionCount(): number {
if (!this.isExistExpressionFile()) {
return 0;
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Expressions)
.getSize();
}
/**
*
* @param index
* @return
*/
public getExpressionName(index: number): string {
return this._jsonValue
.at(FrequestNode.FrequestNode_Expressions)
.getValueByIndex(index)
.getValueByString(Name)
.getRawString();
}
/**
*
* @param index
* @return
*/
public getExpressionFileName(index: number): string {
return this._jsonValue
.at(FrequestNode.FrequestNode_Expressions)
.getValueByIndex(index)
.getValueByString(FilePath)
.getRawString();
}
/**
*
* @return
*/
public getMotionGroupCount(): number {
if (!this.isExistMotionGroups()) {
return 0;
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getKeys()
.getSize();
}
/**
*
* @param index
* @return
*/
public getMotionGroupName(index: number): string {
if (!this.isExistMotionGroups()) {
return null;
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getKeys()
.at(index);
}
/**
*
* @param groupName
* @return
*/
public getMotionCount(groupName: string): number {
if (!this.isExistMotionGroupName(groupName)) {
return 0;
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getSize();
}
/**
*
* @param groupName
* @param index
* @return
*/
public getMotionFileName(groupName: string, index: number): string {
if (!this.isExistMotionGroupName(groupName)) {
return '';
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(FilePath)
.getRawString();
}
/**
*
* @param groupName
* @param index
* @return
*/
public getMotionSoundFileName(groupName: string, index: number): string {
if (!this.isExistMotionSoundFile(groupName, index)) {
return '';
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(SoundPath)
.getRawString();
}
/**
*
* @param groupName
* @param index
* @return []
*/
public getMotionFadeInTimeValue(groupName: string, index: number): number {
if (!this.isExistMotionFadeIn(groupName, index)) {
return -1.0;
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(FadeInTime)
.toFloat();
}
/**
*
* @param groupName
* @param index
* @return []
*/
public getMotionFadeOutTimeValue(groupName: string, index: number): number {
if (!this.isExistMotionFadeOut(groupName, index)) {
return -1.0;
}
return this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(FadeOutTime)
.toFloat();
}
/**
*
* @return
*/
public getUserDataFile(): string {
if (!this.isExistUserDataFile()) {
return '';
}
return this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(UserData)
.getRawString();
}
/**
*
* @param outLayoutMap csmMap
* @return true
* @return false
*/
public getLayoutMap(outLayoutMap: csmMap<string, number>): boolean {
// 存在しない要素にアクセスするとエラーになるためValueがnullの場合はnullを代入する
const map: csmMap<string, Value> = this._json
.getRoot()
.getValueByString(Layout)
.getMap();
if (map == null) {
return false;
}
let ret = false;
for (
const ite: iterator<string, Value> = map.begin();
ite.notEqual(map.end());
ite.preIncrement()
) {
outLayoutMap.setValue(ite.ptr().first, ite.ptr().second.toFloat());
ret = true;
}
return ret;
}
/**
*
* @return
*/
public getEyeBlinkParameterCount(): number {
if (!this.isExistEyeBlinkParameters()) {
return 0;
}
let num = 0;
for (
let i = 0;
i < this._jsonValue.at(FrequestNode.FrequestNode_Groups).getSize();
i++
) {
const refI: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Groups)
.getValueByIndex(i);
if (refI.isNull() || refI.isError()) {
continue;
}
if (refI.getValueByString(Name).getRawString() == EyeBlink) {
num = refI
.getValueByString(Ids)
.getVector()
.getSize();
break;
}
}
return num;
}
/**
* ID
* @param index
* @return ID
*/
public getEyeBlinkParameterId(index: number): CubismIdHandle {
if (!this.isExistEyeBlinkParameters()) {
return null;
}
for (
let i = 0;
i < this._jsonValue.at(FrequestNode.FrequestNode_Groups).getSize();
i++
) {
const refI: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Groups)
.getValueByIndex(i);
if (refI.isNull() || refI.isError()) {
continue;
}
if (refI.getValueByString(Name).getRawString() == EyeBlink) {
return CubismFramework.getIdManager().getId(
refI
.getValueByString(Ids)
.getValueByIndex(index)
.getRawString()
);
}
}
return null;
}
/**
*
* @return
*/
public getLipSyncParameterCount(): number {
if (!this.isExistLipSyncParameters()) {
return 0;
}
let num = 0;
for (
let i = 0;
i < this._jsonValue.at(FrequestNode.FrequestNode_Groups).getSize();
i++
) {
const refI: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Groups)
.getValueByIndex(i);
if (refI.isNull() || refI.isError()) {
continue;
}
if (refI.getValueByString(Name).getRawString() == LipSync) {
num = refI
.getValueByString(Ids)
.getVector()
.getSize();
break;
}
}
return num;
}
/**
*
* @param index
* @return ID
*/
public getLipSyncParameterId(index: number): CubismIdHandle {
if (!this.isExistLipSyncParameters()) {
return null;
}
for (
let i = 0;
i < this._jsonValue.at(FrequestNode.FrequestNode_Groups).getSize();
i++
) {
const refI: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Groups)
.getValueByIndex(i);
if (refI.isNull() || refI.isError()) {
continue;
}
if (refI.getValueByString(Name).getRawString() == LipSync) {
return CubismFramework.getIdManager().getId(
refI
.getValueByString(Ids)
.getValueByIndex(index)
.getRawString()
);
}
}
return null;
}
/**
*
* @return true
* @return false
*/
private isExistModelFile(): boolean {
const node: Value = this._jsonValue.at(FrequestNode.FrequestNode_Moc);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistTextureFiles(): boolean {
const node: Value = this._jsonValue.at(
FrequestNode.FrequestNode_Textures
);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistHitAreas(): boolean {
const node: Value = this._jsonValue.at(
FrequestNode.FrequestNode_HitAreas
);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistPhysicsFile(): boolean {
const node: Value = this._jsonValue.at(FrequestNode.FrequestNode_Physics);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistPoseFile(): boolean {
const node: Value = this._jsonValue.at(FrequestNode.FrequestNode_Pose);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistExpressionFile(): boolean {
const node: Value = this._jsonValue.at(
FrequestNode.FrequestNode_Expressions
);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistMotionGroups(): boolean {
const node: Value = this._jsonValue.at(FrequestNode.FrequestNode_Motions);
return !node.isNull() && !node.isError();
}
/**
*
* @param groupName
* @return true
* @return false
*/
private isExistMotionGroupName(groupName: string): boolean {
const node: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName);
return !node.isNull() && !node.isError();
}
/**
*
* @param groupName
* @param index
* @return true
* @return false
*/
private isExistMotionSoundFile(groupName: string, index: number): boolean {
const node: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(SoundPath);
return !node.isNull() && !node.isError();
}
/**
*
* @param groupName
* @param index
* @return true
* @return false
*/
private isExistMotionFadeIn(groupName: string, index: number): boolean {
const node: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(FadeInTime);
return !node.isNull() && !node.isError();
}
/**
*
* @param groupName
* @param index
* @return true
* @return false
*/
private isExistMotionFadeOut(groupName: string, index: number): boolean {
const node: Value = this._jsonValue
.at(FrequestNode.FrequestNode_Motions)
.getValueByString(groupName)
.getValueByIndex(index)
.getValueByString(FadeOutTime);
return !node.isNull() && !node.isError();
}
/**
* UserData
* @return true
* @return false
*/
private isExistUserDataFile(): boolean {
const node: Value = this._json
.getRoot()
.getValueByString(FileReferences)
.getValueByString(UserData);
return !node.isNull() && !node.isError();
}
/**
*
* @return true
* @return false
*/
private isExistEyeBlinkParameters(): boolean {
if (
this._jsonValue.at(FrequestNode.FrequestNode_Groups).isNull() ||
this._jsonValue.at(FrequestNode.FrequestNode_Groups).isError()
) {
return false;
}
for (
let i = 0;
i < this._jsonValue.at(FrequestNode.FrequestNode_Groups).getSize();
++i
) {
if (
this._jsonValue
.at(FrequestNode.FrequestNode_Groups)
.getValueByIndex(i)
.getValueByString(Name)
.getRawString() == EyeBlink
) {
return true;
}
}
return false;
}
/**
*
* @return true
* @return false
*/
private isExistLipSyncParameters(): boolean {
if (
this._jsonValue.at(FrequestNode.FrequestNode_Groups).isNull() ||
this._jsonValue.at(FrequestNode.FrequestNode_Groups).isError()
) {
return false;
}
for (
let i = 0;
i < this._jsonValue.at(FrequestNode.FrequestNode_Groups).getSize();
++i
) {
if (
this._jsonValue
.at(FrequestNode.FrequestNode_Groups)
.getValueByIndex(i)
.getValueByString(Name)
.getRawString() == LipSync
) {
return true;
}
}
return false;
}
private _json: CubismJson;
private _jsonValue: csmVector<Value>;
}
}

124
src/effect/cubismbreath.ts Normal file
View File

@ -0,0 +1,124 @@
/**
* 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 csmvector } from '../type/csmvector';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismModel = cubismmodel.CubismModel;
import csmVector = csmvector.csmVector;
export namespace Live2DCubismFramework {
/**
*
*
*
*/
export class CubismBreath {
/**
*
*/
public static create(): CubismBreath {
return new CubismBreath();
}
/**
*
* @param instance CubismBreath
*/
public static delete(instance: CubismBreath): void {
if (instance != null) {
instance = null;
}
}
/**
*
* @param breathParameters
*/
public setParameters(
breathParameters: csmVector<BreathParameterData>
): void {
this._breathParameters = breathParameters;
}
/**
*
* @return
*/
public getParameters(): csmVector<BreathParameterData> {
return this._breathParameters;
}
/**
*
* @param model
* @param deltaTimeSeconds []
*/
public updateParameters(
model: CubismModel,
deltaTimeSeconds: number
): void {
this._currentTime += deltaTimeSeconds;
const t: number = this._currentTime * 2.0 * 3.14159;
for (let i = 0; i < this._breathParameters.getSize(); ++i) {
const data: BreathParameterData = this._breathParameters.at(i);
model.addParameterValueById(
data.parameterId,
data.offset + data.peak * Math.sin(t / data.cycle),
data.weight
);
}
}
/**
*
*/
public constructor() {
this._currentTime = 0.0;
}
_breathParameters: csmVector<BreathParameterData>; // 呼吸にひもづいているパラメータのリスト
_currentTime: number; // 積算時間[秒]
}
/**
*
*/
export class BreathParameterData {
/**
*
* @param parameterId ID
* @param offset
* @param peak
* @param cycle
* @param weight
*/
constructor(
parameterId?: CubismIdHandle,
offset?: number,
peak?: number,
cycle?: number,
weight?: number
) {
this.parameterId = parameterId == undefined ? null : parameterId;
this.offset = offset == undefined ? 0.0 : offset;
this.peak = peak == undefined ? 0.0 : peak;
this.cycle = cycle == undefined ? 0.0 : cycle;
this.weight = weight == undefined ? 0.0 : weight;
}
parameterId: CubismIdHandle; // 呼吸をひもづけるパラメータID\
offset: number; // 呼吸を正弦波としたときの、波のオフセット
peak: number; // 呼吸を正弦波としたときの、波の高さ
cycle: number; // 呼吸を正弦波としたときの、波の周期
weight: number; // パラメータへの重み
}
}

View File

@ -0,0 +1,232 @@
/**
* 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 csmvector } from '../type/csmvector';
import { Live2DCubismFramework as icubismmodelsetting } from '../icubismmodelsetting';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import CubismModel = cubismmodel.CubismModel;
import CubismIdHandle = cubismid.CubismIdHandle;
import ICubismModelSetting = icubismmodelsetting.ICubismModelSetting;
import csmVector = csmvector.csmVector;
export namespace Live2DCubismFramework {
/**
*
*
*
*/
export class CubismEyeBlink {
/**
*
* @param modelSetting
* @return
* @note NULLID
*/
public static create(
modelSetting: ICubismModelSetting = null
): CubismEyeBlink {
return new CubismEyeBlink(modelSetting);
}
/**
*
* @param eyeBlink CubismEyeBlink
*/
public static delete(eyeBlink: CubismEyeBlink): void {
if (eyeBlink != null) {
eyeBlink = null;
}
}
/**
*
* @param blinkingInterval []
*/
public setBlinkingInterval(blinkingInterval: number): void {
this._blinkingIntervalSeconds = blinkingInterval;
}
/**
*
* @param closing []
* @param closed []
* @param opening []
*/
public setBlinkingSetting(
closing: number,
closed: number,
opening: number
): void {
this._closingSeconds = closing;
this._closedSeconds = closed;
this._openingSeconds = opening;
}
/**
* ID
* @param parameterIds ID
*/
public setParameterIds(parameterIds: csmVector<CubismIdHandle>): void {
this._parameterIds = parameterIds;
}
/**
* ID
* @return ID
*/
public getParameterIds(): csmVector<CubismIdHandle> {
return this._parameterIds;
}
/**
*
* @param model
* @param deltaTimeSeconds []
*/
public updateParameters(
model: CubismModel,
deltaTimeSeconds: number
): void {
this._userTimeSeconds += deltaTimeSeconds;
let parameterValue: number;
let t = 0.0;
switch (this._blinkingState) {
case EyeState.EyeState_Closing:
t =
(this._userTimeSeconds - this._stateStartTimeSeconds) /
this._closingSeconds;
if (t >= 1.0) {
t = 1.0;
this._blinkingState = EyeState.EyeState_Closed;
this._stateStartTimeSeconds = this._userTimeSeconds;
}
parameterValue = 1.0 - t;
break;
case EyeState.EyeState_Closed:
t =
(this._userTimeSeconds - this._stateStartTimeSeconds) /
this._closedSeconds;
if (t >= 1.0) {
this._blinkingState = EyeState.EyeState_Opening;
this._stateStartTimeSeconds = this._userTimeSeconds;
}
parameterValue = 0.0;
break;
case EyeState.EyeState_Opening:
t =
(this._userTimeSeconds - this._stateStartTimeSeconds) /
this._openingSeconds;
if (t >= 1.0) {
t = 1.0;
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.0;
break;
case EyeState.EyeState_First:
default:
this._blinkingState = EyeState.EyeState_Interval;
this._nextBlinkingTime = this.determinNextBlinkingTiming();
parameterValue = 1.0;
break;
}
if (!CubismEyeBlink.CloseIfZero) {
parameterValue = -parameterValue;
}
for (let i = 0; i < this._parameterIds.getSize(); ++i) {
model.setParameterValueById(this._parameterIds.at(i), parameterValue);
}
}
/**
*
* @param modelSetting
*/
public constructor(modelSetting: ICubismModelSetting) {
this._blinkingState = EyeState.EyeState_First;
this._nextBlinkingTime = 0.0;
this._stateStartTimeSeconds = 0.0;
this._blinkingIntervalSeconds = 4.0;
this._closingSeconds = 0.1;
this._closedSeconds = 0.05;
this._openingSeconds = 0.15;
this._userTimeSeconds = 0.0;
this._parameterIds = new csmVector<CubismIdHandle>();
if (modelSetting == null) {
return;
}
for (let i = 0; i < modelSetting.getEyeBlinkParameterCount(); ++i) {
this._parameterIds.pushBack(modelSetting.getEyeBlinkParameterId(i));
}
}
/**
*
*
* @return []
*/
public determinNextBlinkingTiming(): number {
const r: number = Math.random();
return (
this._userTimeSeconds + r * (2.0 * this._blinkingIntervalSeconds - 1.0)
);
}
_blinkingState: number; // 現在の状態
_parameterIds: csmVector<CubismIdHandle>; // 操作対象のパラメータのIDのリスト
_nextBlinkingTime: number; // 次のまばたきの時刻[秒]
_stateStartTimeSeconds: number; // 現在の状態が開始した時刻[秒]
_blinkingIntervalSeconds: number; // まばたきの間隔[秒]
_closingSeconds: number; // まぶたを閉じる動作の所要時間[秒]
_closedSeconds: number; // まぶたを閉じている動作の所要時間[秒]
_openingSeconds: number; // まぶたを開く動作の所要時間[秒]
_userTimeSeconds: number; // デルタ時間の積算値[秒]
/**
* ID0 true 1 false
*/
static readonly CloseIfZero: boolean = true;
}
/**
*
*
*
*/
export enum EyeState {
EyeState_First = 0, // 初期状態
EyeState_Interval, // まばたきしていない状態
EyeState_Closing, // まぶたが閉じていく途中の状態
EyeState_Closed, // まぶたが閉じている状態
EyeState_Opening // まぶたが開いていく途中の状態
}
}

405
src/effect/cubismpose.ts Normal file
View File

@ -0,0 +1,405 @@
/**
* 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 cubismid } from '../id/cubismid';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import { Live2DCubismFramework as cubismjson } from '../utils/cubismjson';
import CubismIdHandle = cubismid.CubismIdHandle;
import csmVector = csmvector.csmVector;
import iterator = csmvector.iterator;
import CubismModel = cubismmodel.CubismModel;
import CubismFramework = cubismframework.CubismFramework;
import CubismJson = cubismjson.CubismJson;
import Value = cubismjson.Value;
export namespace Live2DCubismFramework {
const Epsilon = 0.001;
const DefaultFadeInSeconds = 0.5;
// Pose.jsonのタグ
const FadeIn = 'FadeInTime';
const Link = 'Link';
const Groups = 'Groups';
const Id = 'Id';
/**
*
*
*
*/
export class CubismPose {
/**
*
* @param pose3json pose3.json
* @param size pose3.json[byte]
* @return
*/
public static create(pose3json: ArrayBuffer, size: number): CubismPose {
const ret: CubismPose = new CubismPose();
const json: CubismJson = CubismJson.create(pose3json, size);
const root: Value = json.getRoot();
// フェード時間の指定
if (!root.getValueByString(FadeIn).isNull()) {
ret._fadeTimeSeconds = root
.getValueByString(FadeIn)
.toFloat(DefaultFadeInSeconds);
if (ret._fadeTimeSeconds <= 0.0) {
ret._fadeTimeSeconds = DefaultFadeInSeconds;
}
}
// パーツグループ
const poseListInfo: Value = root.getValueByString(Groups);
const poseCount: number = poseListInfo.getSize();
for (let poseIndex = 0; poseIndex < poseCount; ++poseIndex) {
const idListInfo: Value = poseListInfo.getValueByIndex(poseIndex);
const idCount: number = idListInfo.getSize();
let groupCount = 0;
for (let groupIndex = 0; groupIndex < idCount; ++groupIndex) {
const partInfo: Value = idListInfo.getValueByIndex(groupIndex);
const partData: PartData = new PartData();
const parameterId: CubismIdHandle = CubismFramework.getIdManager().getId(
partInfo.getValueByString(Id).getRawString()
);
partData.partId = parameterId;
// リンクするパーツの設定
if (!partInfo.getValueByString(Link).isNull()) {
const linkListInfo: Value = partInfo.getValueByString(Link);
const linkCount: number = linkListInfo.getSize();
for (let linkIndex = 0; linkIndex < linkCount; ++linkIndex) {
const linkPart: PartData = new PartData();
const linkId: CubismIdHandle = CubismFramework.getIdManager().getId(
linkListInfo.getValueByIndex(linkIndex).getString()
);
linkPart.partId = linkId;
partData.link.pushBack(linkPart);
}
}
ret._partGroups.pushBack(partData.clone());
++groupCount;
}
ret._partGroupCounts.pushBack(groupCount);
}
CubismJson.delete(json);
return ret;
}
/**
*
* @param pose CubismPose
*/
public static delete(pose: CubismPose): void {
if (pose != null) {
pose = null;
}
}
/**
*
* @param model
* @param deltaTimeSeconds []
*/
public updateParameters(
model: CubismModel,
deltaTimeSeconds: number
): void {
// 前回のモデルと同じでない場合は初期化が必要
if (model != this._lastModel) {
// パラメータインデックスの初期化
this.reset(model);
}
this._lastModel = model;
// 設定から時間を変更すると、経過時間がマイナスになる事があるので、経過時間0として対応
if (deltaTimeSeconds < 0.0) {
deltaTimeSeconds = 0.0;
}
let beginIndex = 0;
for (let i = 0; i < this._partGroupCounts.getSize(); i++) {
const partGroupCount: number = this._partGroupCounts.at(i);
this.doFade(model, deltaTimeSeconds, beginIndex, partGroupCount);
beginIndex += partGroupCount;
}
this.copyPartOpacities(model);
}
/**
*
* @param model
* @note 0
*/
public reset(model: CubismModel): void {
let beginIndex = 0;
for (let i = 0; i < this._partGroupCounts.getSize(); ++i) {
const groupCount: number = this._partGroupCounts.at(i);
for (let j: number = beginIndex; j < beginIndex + groupCount; ++j) {
this._partGroups.at(j).initialize(model);
const partsIndex: number = this._partGroups.at(j).partIndex;
const paramIndex: number = this._partGroups.at(j).parameterIndex;
if (partsIndex < 0) {
continue;
}
model.setPartOpacityByIndex(partsIndex, j == beginIndex ? 1.0 : 0.0);
model.setParameterValueByIndex(
paramIndex,
j == beginIndex ? 1.0 : 0.0
);
for (let k = 0; k < this._partGroups.at(j).link.getSize(); ++k) {
this._partGroups
.at(j)
.link.at(k)
.initialize(model);
}
}
beginIndex += groupCount;
}
}
/**
*
*
* @param model
*/
public copyPartOpacities(model: CubismModel): void {
for (
let groupIndex = 0;
groupIndex < this._partGroups.getSize();
++groupIndex
) {
const partData: PartData = this._partGroups.at(groupIndex);
if (partData.link.getSize() == 0) {
continue; // 連動するパラメータはない
}
const partIndex: number = this._partGroups.at(groupIndex).partIndex;
const opacity: number = model.getPartOpacityByIndex(partIndex);
for (
let linkIndex = 0;
linkIndex < partData.link.getSize();
++linkIndex
) {
const linkPart: PartData = partData.link.at(linkIndex);
const linkPartIndex: number = linkPart.partIndex;
if (linkPartIndex < 0) {
continue;
}
model.setPartOpacityByIndex(linkPartIndex, opacity);
}
}
}
/**
*
* @param model
* @param deltaTimeSeconds []
* @param beginIndex
* @param partGroupCount
*/
public doFade(
model: CubismModel,
deltaTimeSeconds: number,
beginIndex: number,
partGroupCount: number
): void {
let visiblePartIndex = -1;
let newOpacity = 1.0;
const phi = 0.5;
const backOpacityThreshold = 0.15;
// 現在、表示状態になっているパーツを取得
for (let i: number = beginIndex; i < beginIndex + partGroupCount; ++i) {
const partIndex: number = this._partGroups.at(i).partIndex;
const paramIndex: number = this._partGroups.at(i).parameterIndex;
if (model.getParameterValueByIndex(paramIndex) > Epsilon) {
if (visiblePartIndex >= 0) {
break;
}
visiblePartIndex = i;
newOpacity = model.getPartOpacityByIndex(partIndex);
// 新しい不透明度を計算
newOpacity += deltaTimeSeconds / this._fadeTimeSeconds;
if (newOpacity > 1.0) {
newOpacity = 1.0;
}
}
}
if (visiblePartIndex < 0) {
visiblePartIndex = 0;
newOpacity = 1.0;
}
// 表示パーツ、非表示パーツの不透明度を設定する
for (let i: number = beginIndex; i < beginIndex + partGroupCount; ++i) {
const partsIndex: number = this._partGroups.at(i).partIndex;
// 表示パーツの設定
if (visiblePartIndex == i) {
model.setPartOpacityByIndex(partsIndex, newOpacity); // 先に設定
}
// 非表示パーツの設定
else {
let opacity: number = model.getPartOpacityByIndex(partsIndex);
let a1: number; // 計算によって求められる不透明度
if (newOpacity < phi) {
a1 = (newOpacity * (phi - 1)) / phi + 1.0; // (0,1),(phi,phi)を通る直線式
} else {
a1 = ((1 - newOpacity) * phi) / (1.0 - phi); // (1,0),(phi,phi)を通る直線式
}
// 背景の見える割合を制限する場合
const backOpacity: number = (1.0 - a1) * (1.0 - newOpacity);
if (backOpacity > backOpacityThreshold) {
a1 = 1.0 - backOpacityThreshold / (1.0 - newOpacity);
}
if (opacity > a1) {
opacity = a1; // 計算の不透明度よりも大きければ(濃ければ)不透明度を上げる
}
model.setPartOpacityByIndex(partsIndex, opacity);
}
}
}
/**
*
*/
public constructor() {
this._fadeTimeSeconds = DefaultFadeInSeconds;
this._lastModel = null;
this._partGroups = new csmVector<PartData>();
this._partGroupCounts = new csmVector<number>();
}
_partGroups: csmVector<PartData>; // パーツグループ
_partGroupCounts: csmVector<number>; // それぞれのパーツグループの個数
_fadeTimeSeconds: number; // フェード時間[秒]
_lastModel: CubismModel; // 前回操作したモデル
}
/**
*
*/
export class PartData {
/**
*
*/
constructor(v?: PartData) {
this.parameterIndex = 0;
this.partIndex = 0;
this.link = new csmVector<PartData>();
if (v != undefined) {
this.partId = v.partId;
for (
const ite: iterator<PartData> = v.link.begin();
ite.notEqual(v.link.end());
ite.preIncrement()
) {
this.link.pushBack(ite.ptr().clone());
}
}
}
/**
* =
*/
public assignment(v: PartData): PartData {
this.partId = v.partId;
for (
const ite: iterator<PartData> = v.link.begin();
ite.notEqual(v.link.end());
ite.preIncrement()
) {
this.link.pushBack(ite.ptr().clone());
}
return this;
}
/**
*
* @param model 使
*/
public initialize(model: CubismModel): void {
this.parameterIndex = model.getParameterIndex(this.partId);
this.partIndex = model.getPartIndex(this.partId);
model.setParameterValueByIndex(this.parameterIndex, 1);
}
/**
*
*/
public clone(): PartData {
const clonePartData: PartData = new PartData();
clonePartData.partId = this.partId;
clonePartData.parameterIndex = this.parameterIndex;
clonePartData.partIndex = this.partIndex;
clonePartData.link = new csmVector<PartData>();
for (
let ite: iterator<PartData> = this.link.begin();
ite.notEqual(this.link.end());
ite.increment()
) {
clonePartData.link.pushBack(ite.ptr().clone());
}
return clonePartData;
}
partId: CubismIdHandle; // パーツID
parameterIndex: number; // パラメータのインデックス
partIndex: number; // パーツのインデックス
link: csmVector<PartData>; // 連動するパラメータ
}
}

45
src/icubismallcator.ts Normal file
View File

@ -0,0 +1,45 @@
/**
* 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 {
/**
*
*
*
*
*/
export abstract class ICubismAllocator {
/**
*
*
* @param size
* @return '0'
*/
public abstract allocate(size: number): any;
/**
*
*
* @param memory
*/
public abstract deallocate(memory: any): void;
/**
*
* @param size
* @param alignment
* @return '0'
*/
public abstract allocateAligned(size: number, alignment: number): any;
/**
*
* @param alignedMemory
*/
public abstract deallocateAligned(alignedMemory: any): void;
}
}

199
src/icubismmodelsetting.ts Normal file
View File

@ -0,0 +1,199 @@
/**
* 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 cubismid } from './id/cubismid';
import { Live2DCubismFramework as csmmap } from './type/csmmap';
import csmMap = csmmap.csmMap;
import CubismIdHandle = cubismid.CubismIdHandle;
export namespace Live2DCubismFramework {
/**
*
*
*
*/
export abstract class ICubismModelSetting {
/**
* Moc
* @return Moc
*/
public abstract getModelFileName(): string;
/**
* 使
*
*/
public abstract getTextureCount(): number;
/**
*
* @return
*/
public abstract getTextureDirectory(): string;
/**
* 使
* @param index
* @return
*/
public abstract getTextureFileName(index: number): string;
/**
*
* @return
*/
public abstract getHitAreasCount(): number;
/**
* ID
*
* @param index index
* @return ID
*/
public abstract getHitAreaId(index: number): CubismIdHandle;
/**
*
* @param index
* @return
*/
public abstract getHitAreaName(index: number): string;
/**
*
* @return
*/
public abstract getPhysicsFileName(): string;
/**
*
* @return
*/
public abstract getPoseFileName(): string;
/**
*
* @return
*/
public abstract getExpressionCount(): number;
/**
*
* @param index
* @return
*/
public abstract getExpressionName(index: number): string;
/**
*
* @param index
* @return
*/
public abstract getExpressionFileName(index: number): string;
/**
*
* @return
*/
public abstract getMotionGroupCount(): number;
/**
*
* @param index
* @return
*/
public abstract getMotionGroupName(index: number): string;
/**
*
* @param groupName
* @return
*/
public abstract getMotionCount(groupName: string): number;
/**
*
* @param groupName
* @param index
* @return
*/
public abstract getMotionFileName(groupName: string, index: number): string;
/**
*
* @param groupName
* @param index
* @return
*/
public abstract getMotionSoundFileName(
groupName: string,
index: number
): string;
/**
*
* @param groupName
* @param index
* @return []
*/
public abstract getMotionFadeInTimeValue(
groupName: string,
index: number
): number;
/**
*
* @param groupName
* @param index
* @return []
*/
public abstract getMotionFadeOutTimeValue(
groupName: string,
index: number
): number;
/**
*
* @return
*/
public abstract getUserDataFile(): string;
/**
*
* @param outLayoutMap csmMap
* @return true
* @return false
*/
public abstract getLayoutMap(outLayoutMap: csmMap<string, number>): boolean;
/**
*
* @return
*/
public abstract getEyeBlinkParameterCount(): number;
/**
* ID
* @param index
* @return ID
*/
public abstract getEyeBlinkParameterId(index: number): CubismIdHandle;
/**
*
* @return
*/
public abstract getLipSyncParameterCount(): number;
/**
*
* @param index
* @return ID
*/
public abstract getLipSyncParameterId(index: number): CubismIdHandle;
}
}

73
src/id/cubismid.ts Normal file
View File

@ -0,0 +1,73 @@
/**
* 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 csmstring } from '../type/csmstring';
import csmString = csmstring.csmString;
export namespace Live2DCubismFramework {
/**
* Drawable
*
* Drawable
*/
export class CubismId {
/**
* ID
*/
public getString(): csmString {
return this._id;
}
/**
*
*/
public constructor(id: string | csmString) {
if (typeof id === 'string') {
this._id = new csmString(id);
return;
}
this._id = id;
}
/**
* id
* @param c id
* @return true,false
*/
public isEqual(c: string | csmString | CubismId): boolean {
if (typeof c === 'string') {
return this._id.isEqual(c);
} else if (c instanceof csmString) {
return this._id.isEqual(c.s);
} else if (c instanceof CubismId) {
return this._id.isEqual(c._id.s);
}
return false;
}
/**
* id
* @param c id
* @return true,false
*/
public isNotEqual(c: string | csmString | CubismId): boolean {
if (typeof c == 'string') {
return !this._id.isEqual(c);
} else if (c instanceof csmString) {
return !this._id.isEqual(c.s);
} else if (c instanceof CubismId) {
return !this._id.isEqual(c._id.s);
}
return false;
}
private _id: csmString; // ID名
}
export declare type CubismIdHandle = CubismId;
}

118
src/id/cubismidmanager.ts Normal file
View File

@ -0,0 +1,118 @@
/**
* 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 csmvector } from '../type/csmvector';
import { Live2DCubismFramework as cubismid } from './cubismid';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import csmString = csmstring.csmString;
import CubismId = cubismid.CubismId;
import csmVector = csmvector.csmVector;
export namespace Live2DCubismFramework {
/**
* ID
*
* ID
*/
export class CubismIdManager {
/**
*
*/
public constructor() {
this._ids = new csmVector<CubismId>();
}
/**
*
*/
public release(): void {
for (let i = 0; i < this._ids.getSize(); ++i) {
this._ids.set(i, void 0);
}
this._ids = null;
}
/**
* ID
*
* @param ids ID
* @param count ID
*/
public registerIds(ids: string[] | csmString[]): void {
for (let i = 0; i < ids.length; i++) {
this.registerId(ids[i]);
}
}
/**
* ID
*
* @param id ID
*/
public registerId(id: string | csmString): CubismId {
let result: CubismId = null;
if ('string' == typeof id) {
if ((result = this.findId(id)) != null) {
return result;
}
result = new CubismId(id);
this._ids.pushBack(result);
} else {
return this.registerId(id.s);
}
return result;
}
/**
* IDID
*
* @param id ID
*/
public getId(id: csmString | string): CubismId {
return this.registerId(id);
}
/**
* IDID
*
* @return true
* @return false
*/
public isExist(id: csmString | string): boolean {
if ('string' == typeof id) {
return this.findId(id) != null;
}
return this.isExist(id.s);
}
/**
* IDID
*
* @param id ID
* @return IDNULL
*/
private findId(id: string): CubismId {
for (let i = 0; i < this._ids.getSize(); ++i) {
if (
this._ids
.at(i)
.getString()
.isEqual(id)
) {
return this._ids.at(i);
}
}
return null;
}
private _ids: csmVector<CubismId>; // 登録されているIDのリスト
}
}

View File

@ -0,0 +1,272 @@
/**
* 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 cubismjson } from './utils/cubismjson';
import { Live2DCubismFramework as cubismidmanager } from './id/cubismidmanager';
import { Live2DCubismFramework as cubismrenderer } from './rendering/cubismrenderer';
import {
CubismLogInfo,
CubismLogWarning,
CSM_ASSERT
} from './utils/cubismdebug';
import Value = cubismjson.Value;
import CubismIdManager = cubismidmanager.CubismIdManager;
import CubismRenderer = cubismrenderer.CubismRenderer;
export function strtod(s: string, endPtr: string[]): number {
let index = 0;
for (let i = 1; ; i++) {
const testC: string = s.slice(i - 1, i);
// 指数・マイナスの可能性があるのでスキップする
if (testC == 'e' || testC == '-' || testC == 'E') {
continue;
} // 文字列の範囲を広げていく
const test: string = s.substring(0, i);
const number = Number(test);
if (isNaN(number)) {
// 数値として認識できなくなったので終了
break;
} // 最後に数値としてできたindexを格納しておく
index = i;
}
let d = parseFloat(s); // パースした数値
if (isNaN(d)) {
// 数値として認識できなくなったので終了
d = NaN;
}
endPtr[0] = s.slice(index); // 後続の文字列
return d;
}
export namespace Live2DCubismFramework {
// ファイルスコープの変数を初期化
let s_isStarted = false;
let s_isInitialized = false;
let s_option: Option = null;
let s_cubismIdManager: CubismIdManager = null;
/**
* Framework使
*/
export namespace Constant {
export const vertexOffset = 0; // メッシュ頂点のオフセット値
export const vertexStep = 2; // メッシュ頂点のステップ値
}
export function csmDelete<T>(address: T): void {
if (!address) {
return;
}
address = void 0;
}
/**
* Live2D Cubism SDK Original Workflow SDK
* CubismFramework.initialize()CubismFramework.dispose()
*/
export class CubismFramework {
/**
* Cubism FrameworkAPI使
* API
*
*
* @param option Option
*
* @return true
*/
public static startUp(option: Option = null): boolean {
if (s_isStarted) {
CubismLogInfo('CubismFramework.startUp() is already done.');
return s_isStarted;
}
s_option = option;
if (s_option != null) {
Live2DCubismCore.Logging.csmSetLogFunction(s_option.logFunction);
}
s_isStarted = true;
// Live2D Cubism Coreバージョン情報を表示
if (s_isStarted) {
const version: number = Live2DCubismCore.Version.csmGetVersion();
const major: number = (version & 0xff000000) >> 24;
const minor: number = (version & 0x00ff0000) >> 16;
const patch: number = version & 0x0000ffff;
const versionNumber: number = 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;
}
/**
* StartUp()CubismFramework
* Dispose()CubismFramework
*/
public static cleanUp(): void {
s_isStarted = false;
s_isInitialized = false;
s_option = null;
s_cubismIdManager = null;
}
/**
* Cubism Framework<br>
* Initialize()Dispose()
*/
public static initialize(): void {
CSM_ASSERT(s_isStarted);
if (!s_isStarted) {
CubismLogWarning('CubismFramework is not started.');
return;
}
// --- s_isInitializedによる連続初期化ガード ---
// 連続してリソース確保が行われないようにする。
// 再度Initialize()するには先にDispose()を実行する必要がある。
if (s_isInitialized) {
CubismLogWarning(
'CubismFramework.initialize() skipped, already initialized.'
);
return;
}
//---- static 初期化 ----
Value.staticInitializeNotForClientCall();
s_cubismIdManager = new CubismIdManager();
s_isInitialized = true;
CubismLogInfo('CubismFramework.initialize() is complete.');
}
/**
* Cubism Framework
*
*
*/
public static dispose(): void {
CSM_ASSERT(s_isStarted);
if (!s_isStarted) {
CubismLogWarning('CubismFramework is not started.');
return;
}
// --- s_isInitializedによる未初期化解放ガード ---
// dispose()するには先にinitialize()を実行する必要がある。
if (!s_isInitialized) {
// false...リソース未確保の場合
CubismLogWarning('CubismFramework.dispose() skipped, not initialized.');
return;
}
Value.staticReleaseNotForClientCall();
s_cubismIdManager.release();
s_cubismIdManager = null;
// レンダラの静的リソース(シェーダプログラム他)を解放する
CubismRenderer.staticRelease();
s_isInitialized = false;
CubismLogInfo('CubismFramework.dispose() is complete.');
}
/**
* Cubism FrameworkAPI使
* @return API使true
*/
public static isStarted(): boolean {
return s_isStarted;
}
/**
* Cubism Framework
* @return true
*/
public static isInitialized(): boolean {
return s_isInitialized;
}
/**
* Core API
*
* @praram message
*/
public static coreLogFunction(message: string): void {
// Return if logging not possible.
if (!Live2DCubismCore.Logging.csmGetLogFunction()) {
return;
}
Live2DCubismCore.Logging.csmGetLogFunction()(message);
}
/**
*
*
* @return
*/
public static getLoggingLevel(): LogLevel {
if (s_option != null) {
return s_option.loggingLevel;
}
return LogLevel.LogLevel_Off;
}
/**
* ID
* @return CubismManager
*/
public static getIdManager(): CubismIdManager {
return s_cubismIdManager;
}
/**
* 使
*
*/
private constructor() {}
}
}
export class Option {
logFunction: Live2DCubismCore.csmLogFunction; // ログ出力の関数オブジェクト
loggingLevel: LogLevel; // ログ出力レベルの設定
}
/**
*
*/
export enum LogLevel {
LogLevel_Verbose = 0, // 詳細ログ
LogLevel_Debug, // デバッグログ
LogLevel_Info, // Infoログ
LogLevel_Warning, // 警告ログ
LogLevel_Error, // エラーログ
LogLevel_Off // ログ出力無効
}

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;
}
/**
*
*
* @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;
}
/**
*
*
* @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();
}
/**
*
*
* @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 164x4
*/
public setMatrix(tr: Float32Array): void {
for (let i = 0; i < 16; ++i) {
this._tr[i] = tr[i];
}
}
/**
*
*
* @return 164x4
*/
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 widthheight
*/
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;
}
/**
*
* @return X
*/
public getScreenLeft(): number {
return this._screenLeft;
}
/**
*
* @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; // 拡大率の最小値
}
}

100
src/model/cubismmoc.ts Normal file
View File

@ -0,0 +1,100 @@
/**
* 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 cubismmodel } from './cubismmodel';
import CubismModel = cubismmodel.CubismModel;
import { CSM_ASSERT } from '../utils/cubismdebug';
export namespace Live2DCubismFramework {
/**
* Moc
*
* Moc
*/
export class CubismMoc {
/**
* Moc
*/
public static create(mocBytes: ArrayBuffer): CubismMoc {
let cubismMoc: CubismMoc = null;
const moc: Live2DCubismCore.Moc = Live2DCubismCore.Moc.fromArrayBuffer(
mocBytes
);
if (moc) {
cubismMoc = new CubismMoc(moc);
}
return cubismMoc;
}
/**
* Moc
*
* Moc
*/
public static delete(moc: CubismMoc): void {
moc._moc._release();
moc._moc = null;
moc = null;
}
/**
*
*
* @return Moc
*/
createModel(): CubismModel {
let cubismModel: CubismModel = null;
const model: Live2DCubismCore.Model = Live2DCubismCore.Model.fromMoc(
this._moc
);
if (model) {
cubismModel = new CubismModel(model);
cubismModel.initialize();
++this._modelCount;
}
return cubismModel;
}
/**
*
*/
deleteModel(model: CubismModel): void {
if (model != null) {
model.release();
model = null;
--this._modelCount;
}
}
/**
*
*/
private constructor(moc: Live2DCubismCore.Moc) {
this._moc = moc;
this._modelCount = 0;
}
/**
*
*/
public release(): void {
CSM_ASSERT(this._modelCount == 0);
this._moc._release();
this._moc = null;
}
_moc: Live2DCubismCore.Moc; // Mocデータ
_modelCount: number; // Mocデータから作られたモデルの個数
}
}

822
src/model/cubismmodel.ts Normal file
View File

@ -0,0 +1,822 @@
/**
* 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 cubismrenderer } from '../rendering/cubismrenderer';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import { Live2DCubismFramework as csmmap } from '../type/csmmap';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import { CSM_ASSERT } from '../utils/cubismdebug';
import CubismFramework = cubismframework.CubismFramework;
import CubismBlendMode = cubismrenderer.CubismBlendMode;
import csmVector = csmvector.csmVector;
import csmMap = csmmap.csmMap;
import CubismIdHandle = cubismid.CubismIdHandle;
export namespace Live2DCubismFramework {
/**
*
*
* Moc
*/
export class CubismModel {
/**
*
*/
public update(): void {
// Update model
this._model.update();
this._model.drawables.resetDynamicFlags();
}
/**
*
*/
public getCanvasWidth(): number {
if (this._model == null) {
return 0.0;
}
return (
this._model.canvasinfo.CanvasWidth /
this._model.canvasinfo.PixelsPerUnit
);
}
/**
*
*/
public getCanvasHeight(): number {
if (this._model == null) {
return 0.0;
}
return (
this._model.canvasinfo.CanvasHeight /
this._model.canvasinfo.PixelsPerUnit
);
}
/**
*
*/
public saveParameters(): void {
const parameterCount: number = this._model.parameters.count;
const savedParameterCount: number = this._savedParameters.getSize();
for (let i = 0; i < parameterCount; ++i) {
if (i < savedParameterCount) {
this._savedParameters.set(i, this._parameterValues[i]);
} else {
this._savedParameters.pushBack(this._parameterValues[i]);
}
}
}
/**
*
*/
public getModel(): Live2DCubismCore.Model {
return this._model;
}
/**
*
* @param partId ID
* @return
*/
public getPartIndex(partId: CubismIdHandle): number {
let partIndex: number;
const partCount: number = this._model.parts.count;
for (partIndex = 0; partIndex < partCount; ++partIndex) {
if (partId == this._partIds.at(partIndex)) {
return partIndex;
}
}
// モデルに存在していない場合、非存在パーツIDリスト内にあるかを検索し、そのインデックスを返す
if (this._notExistPartId.isExist(partId)) {
return this._notExistPartId.getValue(partId);
}
// 非存在パーツIDリストにない場合、新しく要素を追加する
partIndex = partCount + this._notExistPartId.getSize();
this._notExistPartId.setValue(partId, partIndex);
this._notExistPartOpacities.appendKey(partIndex);
return partIndex;
}
/**
*
* @return
*/
public getPartCount(): number {
const partCount: number = this._model.parts.count;
return partCount;
}
/**
* (Index)
* @param partIndex
* @param opacity
*/
public setPartOpacityByIndex(partIndex: number, opacity: number): void {
if (this._notExistPartOpacities.isExist(partIndex)) {
this._notExistPartOpacities.setValue(partIndex, opacity);
return;
}
// インデックスの範囲内検知
CSM_ASSERT(0 <= partIndex && partIndex < this.getPartCount());
this._partOpacities[partIndex] = opacity;
}
/**
* (Id)
* @param partId ID
* @param opacity
*/
public setPartOpacityById(partId: CubismIdHandle, opacity: number): void {
// 高速化のためにPartIndexを取得できる機構になっているが、外部からの設定の時は呼び出し頻度が低いため不要
const index: number = this.getPartIndex(partId);
if (index < 0) {
return; // パーツがないのでスキップ
}
this.setPartOpacityByIndex(index, opacity);
}
/**
* (index)
* @param partIndex
* @return
*/
public getPartOpacityByIndex(partIndex: number): number {
if (this._notExistPartOpacities.isExist(partIndex)) {
// モデルに存在しないパーツIDの場合、非存在パーツリストから不透明度を返す。
return this._notExistPartOpacities.getValue(partIndex);
}
// インデックスの範囲内検知
CSM_ASSERT(0 <= partIndex && partIndex < this.getPartCount());
return this._partOpacities[partIndex];
}
/**
* (id)
* @param partId
* @return
*/
public getPartOpacityById(partId: CubismIdHandle): number {
// 高速化のためにPartIndexを取得できる機構になっているが、外部からの設定の時は呼び出し頻度が低いため不要
const index: number = this.getPartIndex(partId);
if (index < 0) {
return 0; // パーツが無いのでスキップ
}
return this.getPartOpacityByIndex(index);
}
/**
*
* @param ID
* @return
*/
public getParameterIndex(parameterId: CubismIdHandle): number {
let parameterIndex: number;
const idCount: number = this._model.parameters.count;
for (parameterIndex = 0; parameterIndex < idCount; ++parameterIndex) {
if (parameterId != this._parameterIds.at(parameterIndex)) {
continue;
}
return parameterIndex;
}
// モデルに存在していない場合、非存在パラメータIDリスト内を検索し、そのインデックスを返す
if (this._notExistParameterId.isExist(parameterId)) {
return this._notExistParameterId.getValue(parameterId);
}
// 非存在パラメータIDリストにない場合新しく要素を追加する
parameterIndex =
this._model.parameters.count + this._notExistParameterId.getSize();
this._notExistParameterId.setValue(parameterId, parameterIndex);
this._notExistParameterValues.appendKey(parameterIndex);
return parameterIndex;
}
/**
*
* @return
*/
public getParameterCount(): number {
return this._model.parameters.count;
}
/**
*
* @param parameterIndex
* @return
*/
public getParameterMaximumValue(parameterIndex: number): number {
return this._model.parameters.maximumValues[parameterIndex];
}
/**
*
* @param parameterIndex
* @return
*/
public getParameterMinimumValue(parameterIndex: number): number {
return this._model.parameters.minimumValues[parameterIndex];
}
/**
*
* @param parameterIndex
* @return
*/
public getParameterDefaultValue(parameterIndex: number): number {
return this._model.parameters.defaultValues[parameterIndex];
}
/**
*
* @param parameterIndex
* @return
*/
public getParameterValueByIndex(parameterIndex: number): number {
if (this._notExistParameterValues.isExist(parameterIndex)) {
return this._notExistParameterValues.getValue(parameterIndex);
}
// インデックスの範囲内検知
CSM_ASSERT(
0 <= parameterIndex && parameterIndex < this.getParameterCount()
);
return this._parameterValues[parameterIndex];
}
/**
*
* @param parameterId ID
* @return
*/
public getParameterValueById(parameterId: CubismIdHandle): number {
// 高速化のためにparameterIndexを取得できる機構になっているが、外部からの設定の時は呼び出し頻度が低いため不要
const parameterIndex: number = this.getParameterIndex(parameterId);
return this.getParameterValueByIndex(parameterIndex);
}
/**
*
* @param parameterIndex
* @param value
* @param weight
*/
public setParameterValueByIndex(
parameterIndex: number,
value: number,
weight = 1.0
): void {
if (this._notExistParameterValues.isExist(parameterIndex)) {
this._notExistParameterValues.setValue(
parameterIndex,
weight == 1
? value
: this._notExistParameterValues.getValue(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);
}
/**
*
* @param parameterId ID
* @param value
* @param weight
*/
public setParameterValueById(
parameterId: CubismIdHandle,
value: number,
weight = 1.0
): void {
const index: number = this.getParameterIndex(parameterId);
this.setParameterValueByIndex(index, value, weight);
}
/**
* (index)
* @param parameterIndex
* @param value
* @param weight
*/
public addParameterValueByIndex(
parameterIndex: number,
value: number,
weight = 1.0
): void {
this.setParameterValueByIndex(
parameterIndex,
this.getParameterValueByIndex(parameterIndex) + value * weight
);
}
/**
* (id)
* @param parameterId
* @param value
* @param weight
*/
public addParameterValueById(
parameterId: any,
value: number,
weight = 1.0
): void {
const index: number = this.getParameterIndex(parameterId);
this.addParameterValueByIndex(index, value, weight);
}
/**
*
* @param parameterId ID
* @param value
* @param weight
*/
public multiplyParameterValueById(
parameterId: CubismIdHandle,
value: number,
weight = 1.0
): void {
const index: number = this.getParameterIndex(parameterId);
this.multiplyParameterValueByIndex(index, value, weight);
}
/**
*
* @param parameterIndex
* @param value
* @param weight
*/
public multiplyParameterValueByIndex(
parameterIndex: number,
value: number,
weight = 1.0
): void {
this.setParameterValueByIndex(
parameterIndex,
this.getParameterValueByIndex(parameterIndex) *
(1.0 + (value - 1.0) * weight)
);
}
/**
* Drawable
* @param drawableId DrawableID
* @return Drawable
*/
public getDrawableIndex(drawableId: CubismIdHandle): number {
const drawableCount = this._model.drawables.count;
for (
let drawableIndex = 0;
drawableIndex < drawableCount;
++drawableIndex
) {
if (this._drawableIds.at(drawableIndex) == drawableId) {
return drawableIndex;
}
}
return -1;
}
/**
* Drawable
* @return drawable
*/
public getDrawableCount(): number {
const drawableCount = this._model.drawables.count;
return drawableCount;
}
/**
* DrawableID
* @param drawableIndex Drawable
* @return drawableID
*/
public getDrawableId(drawableIndex: number): CubismIdHandle {
const parameterIds: string[] = this._model.drawables.ids;
return CubismFramework.getIdManager().getId(parameterIds[drawableIndex]);
}
/**
* Drawable
* @return Drawable
*/
public getDrawableRenderOrders(): Int32Array {
const renderOrders: Int32Array = this._model.drawables.renderOrders;
return renderOrders;
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableTextureIndices(drawableIndex: number): number {
const textureIndices: Int32Array = this._model.drawables.textureIndices;
return textureIndices[drawableIndex];
}
/**
* DrawableVertexPositions
*
* CubismModel.updateDrawable
*
* @param drawableIndex Drawable
* @retval true DrawableCubismModel.update
* @retval false DrawableCubismModel.update
*/
public getDrawableDynamicFlagVertexPositionsDidChange(
drawableIndex: number
): boolean {
const dynamicFlags: Uint8Array = this._model.drawables.dynamicFlags;
return Live2DCubismCore.Utils.hasVertexPositionsDidChangeBit(
dynamicFlags[drawableIndex]
);
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableVertexIndexCount(drawableIndex: number): number {
const indexCounts: Int32Array = this._model.drawables.indexCounts;
return indexCounts[drawableIndex];
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableVertexCount(drawableIndex: number): number {
const vertexCounts = this._model.drawables.vertexCounts;
return vertexCounts[drawableIndex];
}
/**
* Drawable
* @param drawableIndex drawable
* @return drawable
*/
public getDrawableVertices(drawableIndex: number): Float32Array {
return this.getDrawableVertexPositions(drawableIndex);
}
/**
* Drawable
* @param drarableIndex Drawable
* @return drawable
*/
public getDrawableVertexIndices(drawableIndex: number): Uint16Array {
const indicesArray: Uint16Array[] = this._model.drawables.indices;
return indicesArray[drawableIndex];
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableVertexPositions(drawableIndex: number): Float32Array {
const verticesArray: Float32Array[] = this._model.drawables
.vertexPositions;
return verticesArray[drawableIndex];
}
/**
* DrawableUV
* @param drawableIndex Drawable
* @return drawableUV
*/
public getDrawableVertexUvs(drawableIndex: number): Float32Array {
const uvsArray: Float32Array[] = this._model.drawables.vertexUvs;
return uvsArray[drawableIndex];
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableOpacity(drawableIndex: number): number {
const opacities: Float32Array = this._model.drawables.opacities;
return opacities[drawableIndex];
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableCulling(drawableIndex: number): boolean {
const constantFlags = this._model.drawables.constantFlags;
return !Live2DCubismCore.Utils.hasIsDoubleSidedBit(
constantFlags[drawableIndex]
);
}
/**
* Drawable
* @param drawableIndex Drawable
* @return drawable
*/
public getDrawableBlendMode(drawableIndex: number): CubismBlendMode {
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;
}
/**
* Drawable使
*
* Drawable使
* 使
*
* @param drawableIndex Drawable
* @return Drawable
*/
public getDrawableInvertedMaskBit(drawableIndex: number): boolean {
const constantFlags: Uint8Array = this._model.drawables.constantFlags;
return Live2DCubismCore.Utils.hasIsInvertedMaskBit(
constantFlags[drawableIndex]
);
}
/**
* Drawable
* @return Drawable
*/
public getDrawableMasks(): Int32Array[] {
const masks: Int32Array[] = this._model.drawables.masks;
return masks;
}
/**
* Drawable
* @return Drawable
*/
public getDrawableMaskCounts(): Int32Array {
const maskCounts: Int32Array = this._model.drawables.maskCounts;
return maskCounts;
}
/**
* 使
*
* @return true 使
* @return false 使
*/
public isUsingMasking(): boolean {
for (let d = 0; d < this._model.drawables.count; ++d) {
if (this._model.drawables.maskCounts[d] <= 0) {
continue;
}
return true;
}
return false;
}
/**
* Drawable
*
* @param drawableIndex Drawable
* @return true Drawable
* @return false Drawable
*/
public getDrawableDynamicFlagIsVisible(drawableIndex: number): boolean {
const dynamicFlags: Uint8Array = this._model.drawables.dynamicFlags;
return Live2DCubismCore.Utils.hasIsVisibleBit(
dynamicFlags[drawableIndex]
);
}
/**
* DrawableDrawOrder
*
* CubismModel.updatedrawabledrawOrder
* drawOrderartMesh01000
* @param drawableIndex drawable
* @return true drawableCubismModel.update
* @return false drawableCubismModel.update
*/
public getDrawableDynamicFlagVisibilityDidChange(
drawableIndex: number
): boolean {
const dynamicFlags: Uint8Array = this._model.drawables.dynamicFlags;
return Live2DCubismCore.Utils.hasVisibilityDidChangeBit(
dynamicFlags[drawableIndex]
);
}
/**
* Drawable
*
* CubismModel.updatedrawable
*
* @param drawableIndex drawable
* @return true DrawableCubismModel.update
* @return false DrawableCubismModel.update
*/
public getDrawableDynamicFlagOpacityDidChange(
drawableIndex: number
): boolean {
const dynamicFlags: Uint8Array = this._model.drawables.dynamicFlags;
return Live2DCubismCore.Utils.hasOpacityDidChangeBit(
dynamicFlags[drawableIndex]
);
}
/**
* Drawable
*
* CubismModel.updateDrawable
*
* @param drawableIndex Drawable
* @return true DrawableCubismModel.update
* @return false DrawableCubismModel.update
*/
public getDrawableDynamicFlagRenderOrderDidChange(
drawableIndex: number
): boolean {
const dynamicFlags: Uint8Array = this._model.drawables.dynamicFlags;
return Live2DCubismCore.Utils.hasRenderOrderDidChangeBit(
dynamicFlags[drawableIndex]
);
}
/**
*
*/
public loadParameters(): void {
let parameterCount: number = this._model.parameters.count;
const savedParameterCount: number = this._savedParameters.getSize();
if (parameterCount > savedParameterCount) {
parameterCount = savedParameterCount;
}
for (let i = 0; i < parameterCount; ++i) {
this._parameterValues[i] = this._savedParameters.at(i);
}
}
/**
*
*/
public initialize(): void {
CSM_ASSERT(this._model);
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: string[] = this._model.parameters.ids;
const parameterCount: number = this._model.parameters.count;
this._parameterIds.prepareCapacity(parameterCount);
for (let i = 0; i < parameterCount; ++i) {
this._parameterIds.pushBack(
CubismFramework.getIdManager().getId(parameterIds[i])
);
}
}
{
const partIds: string[] = this._model.parts.ids;
const partCount: number = this._model.parts.count;
this._partIds.prepareCapacity(partCount);
for (let i = 0; i < partCount; ++i) {
this._partIds.pushBack(
CubismFramework.getIdManager().getId(partIds[i])
);
}
}
{
const drawableIds: string[] = this._model.drawables.ids;
const drawableCount: number = this._model.drawables.count;
this._drawableIds.prepareCapacity(drawableCount);
for (let i = 0; i < drawableCount; ++i) {
this._drawableIds.pushBack(
CubismFramework.getIdManager().getId(drawableIds[i])
);
}
}
}
/**
*
* @param model
*/
public constructor(model: Live2DCubismCore.Model) {
this._model = model;
this._parameterValues = null;
this._parameterMaximumValues = null;
this._parameterMinimumValues = null;
this._partOpacities = null;
this._savedParameters = new csmVector<number>();
this._parameterIds = new csmVector<CubismIdHandle>();
this._drawableIds = new csmVector<CubismIdHandle>();
this._partIds = new csmVector<CubismIdHandle>();
this._notExistPartId = new csmMap<CubismIdHandle, number>();
this._notExistParameterId = new csmMap<CubismIdHandle, number>();
this._notExistParameterValues = new csmMap<number, number>();
this._notExistPartOpacities = new csmMap<number, number>();
}
/**
*
*/
public release(): void {
this._model.release();
this._model = null;
}
private _notExistPartOpacities: csmMap<number, number>; // 存在していないパーツの不透明度のリスト
private _notExistPartId: csmMap<CubismIdHandle, number>; // 存在していないパーツIDのリスト
private _notExistParameterValues: csmMap<number, number>; // 存在していないパラメータの値のリスト
private _notExistParameterId: csmMap<CubismIdHandle, number>; // 存在していないパラメータIDのリスト
private _savedParameters: csmVector<number>; // 保存されたパラメータ
private _model: Live2DCubismCore.Model; // モデル
private _parameterValues: Float32Array; // パラメータの値のリスト
private _parameterMaximumValues: Float32Array; // パラメータの最大値のリスト
private _parameterMinimumValues: Float32Array; // パラメータの最小値のリスト
private _partOpacities: Float32Array; // パーツの不透明度のリスト
private _parameterIds: csmVector<CubismIdHandle>;
private _partIds: csmVector<CubismIdHandle>;
private _drawableIds: csmVector<CubismIdHandle>;
}
}

View File

@ -0,0 +1,136 @@
/**
* 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 cubismmodeluserdatajson } from './cubismmodeluserdatajson';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import CubismFramework = cubismframework.CubismFramework;
import csmVector = csmvector.csmVector;
import csmString = csmstring.csmString;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismModelUserDataJson = cubismmodeluserdatajson.CubismModelUserDataJson;
export namespace Live2DCubismFramework {
const ArtMesh = 'ArtMesh';
/**
*
*
* Json
*/
export class CubismModelUserDataNode {
targetType: CubismIdHandle; // ユーザーデータターゲットタイプ
targetId: CubismIdHandle; // ユーザーデータターゲットのID
value: csmString; // ユーザーデータ
}
/**
*
*
*
*/
export class CubismModelUserData {
/**
*
*
* @param buffer userdata3.json
* @param size
* @return
*/
public static create(
buffer: ArrayBuffer,
size: number
): CubismModelUserData {
const ret: CubismModelUserData = new CubismModelUserData();
ret.parseUserData(buffer, size);
return ret;
}
/**
*
*
* @param modelUserData
*/
public static delete(modelUserData: CubismModelUserData): void {
if (modelUserData != null) {
modelUserData.release();
modelUserData = null;
}
}
/**
* ArtMesh
*
* @return
*/
public getArtMeshUserDatas(): csmVector<CubismModelUserDataNode> {
return this._artMeshUserDataNode;
}
/**
* userdata3.json
*
* @param buffer userdata3.json
* @param size
*/
public parseUserData(buffer: ArrayBuffer, size: number): void {
let json: CubismModelUserDataJson = new CubismModelUserDataJson(
buffer,
size
);
const typeOfArtMesh = CubismFramework.getIdManager().getId(ArtMesh);
const nodeCount: number = json.getUserDataCount();
for (let i = 0; i < nodeCount; i++) {
const addNode: CubismModelUserDataNode = new CubismModelUserDataNode();
addNode.targetId = json.getUserDataId(i);
addNode.targetType = CubismFramework.getIdManager().getId(
json.getUserDataTargetType(i)
);
addNode.value = new csmString(json.getUserDataValue(i));
this._userDataNodes.pushBack(addNode);
if (addNode.targetType == typeOfArtMesh) {
this._artMeshUserDataNode.pushBack(addNode);
}
}
json.release();
json = void 0;
}
/**
*
*/
public constructor() {
this._userDataNodes = new csmVector<CubismModelUserDataNode>();
this._artMeshUserDataNode = new csmVector<CubismModelUserDataNode>();
}
/**
*
*
*
*/
public release(): void {
for (let i = 0; i < this._userDataNodes.getSize(); ++i) {
this._userDataNodes.set(i, null);
}
this._userDataNodes = null;
}
private _userDataNodes: csmVector<CubismModelUserDataNode>; // ユーザーデータ構造体配列
private _artMeshUserDataNode: csmVector<CubismModelUserDataNode>; // 閲覧リストの保持
}
}

View File

@ -0,0 +1,114 @@
/**
* 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 cubismjson } from '../utils/cubismjson';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import CubismFramework = cubismframework.CubismFramework;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismJson = cubismjson.CubismJson;
export namespace Live2DCubismFramework {
const Meta = 'Meta';
const UserDataCount = 'UserDataCount';
const TotalUserDataSize = 'TotalUserDataSize';
const UserData = 'UserData';
const Target = 'Target';
const Id = 'Id';
const Value = 'Value';
export class CubismModelUserDataJson {
/**
*
* @param buffer userdata3.json
* @param size
*/
public constructor(buffer: ArrayBuffer, size: number) {
this._json = CubismJson.create(buffer, size);
}
/**
*
*/
public release(): void {
CubismJson.delete(this._json);
}
/**
*
* @return
*/
public getUserDataCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(UserDataCount)
.toInt();
}
/**
*
*
* @return
*/
public getTotalUserDataSize(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(TotalUserDataSize)
.toInt();
}
/**
*
*
* @return
*/
public getUserDataTargetType(i: number): string {
return this._json
.getRoot()
.getValueByString(UserData)
.getValueByIndex(i)
.getValueByString(Target)
.getRawString();
}
/**
* ID
*
* @param i
* @return ID
*/
public getUserDataId(i: number): CubismIdHandle {
return CubismFramework.getIdManager().getId(
this._json
.getRoot()
.getValueByString(UserData)
.getValueByIndex(i)
.getValueByString(Id)
.getRawString()
);
}
/**
*
*
* @param i
* @return
*/
public getUserDataValue(i: number): string {
return this._json
.getRoot()
.getValueByString(UserData)
.getValueByIndex(i)
.getValueByString(Value)
.getRawString();
}
private _json: CubismJson;
}
}

View File

@ -0,0 +1,453 @@
/**
* 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 cubismframework } from '../live2dcubismframework';
import { Live2DCubismFramework as cubismmotionmanager } from '../motion/cubismmotionmanager';
import { Live2DCubismFramework as cubismtargetpoint } from '../math/cubismtargetpoint';
import { Live2DCubismFramework as cubismmodelmatrix } from '../math/cubismmodelmatrix';
import { Live2DCubismFramework as cubismmoc } from './cubismmoc';
import { Live2DCubismFramework as cubismmodel } from './cubismmodel';
import { Live2DCubismFramework as acubismmotion } from '../motion/acubismmotion';
import { Live2DCubismFramework as cubismmotion } from '../motion/cubismmotion';
import { Live2DCubismFramework as cubismexpressionmotion } from '../motion/cubismexpressionmotion';
import { Live2DCubismFramework as cubismpose } from '../effect/cubismpose';
import { Live2DCubismFramework as cubismmodeluserdata } from './cubismmodeluserdata';
import { Live2DCubismFramework as cubismphysics } from '../physics/cubismphysics';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import { Live2DCubismFramework as cubismmotionqueuemanager } from '../motion/cubismmotionqueuemanager';
import { Live2DCubismFramework as cubismbreath } from '../effect/cubismbreath';
import { Live2DCubismFramework as cubismeyeblink } from '../effect/cubismeyeblink';
import { Live2DCubismFramework as cubismrenderer_webgl } from '../rendering/cubismrenderer_webgl';
import { CubismLogError, CubismLogInfo } from '../utils/cubismdebug';
import CubismRenderer_WebGL = cubismrenderer_webgl.CubismRenderer_WebGL;
import CubismEyeBlink = cubismeyeblink.CubismEyeBlink;
import CubismBreath = cubismbreath.CubismBreath;
import CubismMotionQueueManager = cubismmotionqueuemanager.CubismMotionQueueManager;
import csmString = csmstring.csmString;
import Constant = cubismframework.Constant;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismPhysics = cubismphysics.CubismPhysics;
import CubismModelUserData = cubismmodeluserdata.CubismModelUserData;
import CubismPose = cubismpose.CubismPose;
import CubismExpressionMotion = cubismexpressionmotion.CubismExpressionMotion;
import CubismMotion = cubismmotion.CubismMotion;
import ACubismMotion = acubismmotion.ACubismMotion;
import FinishedMotionCallback = acubismmotion.FinishedMotionCallback;
import CubismModel = cubismmodel.CubismModel;
import CubismMoc = cubismmoc.CubismMoc;
import CubismModelMatrix = cubismmodelmatrix.CubismModelMatrix;
import CubismTargetPoint = cubismtargetpoint.CubismTargetPoint;
import CubismMotionManager = cubismmotionmanager.CubismMotionManager;
export namespace Live2DCubismFramework {
/**
* 使
*
* 使
*/
export class CubismUserModel {
/**
*
*
*
*
* @return true
* @return false
*/
public isInitialized(): boolean {
return this._initialized;
}
/**
*
*
*
*
* @param v
*/
public setInitialized(v: boolean): void {
this._initialized = v;
}
/**
*
*
*
*
* @return true
* @return false
*/
public isUpdating(): boolean {
return this._updating;
}
/**
*
*
*
*
* @param v
*/
public setUpdating(v: boolean): void {
this._updating = v;
}
/**
*
* @param X
* @param Y
*/
public setDragging(x: number, y: number): void {
this._dragManager.set(x, y);
}
/**
*
* @param x X
* @param y Y
* @param z Z
*/
public setAcceleration(x: number, y: number, z: number): void {
this._accelerationX = x;
this._accelerationY = y;
this._accelerationZ = z;
}
/**
*
* @return
*/
public getModelMatrix(): CubismModelMatrix {
return this._modelMatrix;
}
/**
*
* @param a
*/
public setOpacity(a: number): void {
this._opacity = a;
}
/**
*
* @return
*/
public getOpacity(): number {
return this._opacity;
}
/**
*
*
* @param buffer moc3
*/
public loadModel(buffer: ArrayBuffer) {
this._moc = CubismMoc.create(buffer);
this._model = this._moc.createModel();
this._model.saveParameters();
if (this._moc == null || this._model == null) {
CubismLogError('Failed to CreateModel().');
return;
}
this._modelMatrix = new CubismModelMatrix(
this._model.getCanvasWidth(),
this._model.getCanvasHeight()
);
}
/**
*
* @param buffer motion3.json
* @param size
* @param name
* @param onFinishedMotionHandler
* @return
*/
public loadMotion = (
buffer: ArrayBuffer,
size: number,
name: string,
onFinishedMotionHandler?: FinishedMotionCallback
) => CubismMotion.create(buffer, size, onFinishedMotionHandler);
/**
*
* @param buffer exp
* @param size
* @param name
*/
public loadExpression(
buffer: ArrayBuffer,
size: number,
name: string
): ACubismMotion {
return CubismExpressionMotion.create(buffer, size);
}
/**
*
* @param buffer pose3.json
* @param size
*/
public loadPose(buffer: ArrayBuffer, size: number): void {
this._pose = CubismPose.create(buffer, size);
}
/**
*
* @param buffer userdata3.json
* @param size
*/
public loadUserData(buffer: ArrayBuffer, size: number): void {
this._modelUserData = CubismModelUserData.create(buffer, size);
}
/**
*
* @param buffer physics3.json
* @param size
*/
public loadPhysics(buffer: ArrayBuffer, size: number): void {
this._physics = CubismPhysics.create(buffer, size);
}
/**
*
* @param drawableId DrawableID
* @param pointX X
* @param pointY Y
* @return true
* @return false
*/
public isHit(
drawableId: CubismIdHandle,
pointX: number,
pointY: number
): boolean {
const drawIndex: number = this._model.getDrawableIndex(drawableId);
if (drawIndex < 0) {
return false; // 存在しない場合はfalse
}
const count: number = this._model.getDrawableVertexCount(drawIndex);
const vertices: Float32Array = this._model.getDrawableVertices(drawIndex);
let left: number = vertices[0];
let right: number = vertices[0];
let top: number = vertices[1];
let bottom: number = vertices[1];
for (let j = 1; j < count; ++j) {
const x = vertices[Constant.vertexOffset + j * Constant.vertexStep];
const y = vertices[Constant.vertexOffset + j * Constant.vertexStep + 1];
if (x < left) {
left = x; // Min x
}
if (x > right) {
right = x; // Max x
}
if (y < top) {
top = y; // Min y
}
if (y > bottom) {
bottom = y; // Max y
}
}
const tx: number = this._modelMatrix.invertTransformX(pointX);
const ty: number = this._modelMatrix.invertTransformY(pointY);
return left <= tx && tx <= right && top <= ty && ty <= bottom;
}
/**
*
* @return
*/
public getModel(): CubismModel {
return this._model;
}
/**
*
* @return
*/
public getRenderer(): CubismRenderer_WebGL {
return this._renderer;
}
/**
*
*/
public createRenderer(): void {
if (this._renderer) {
this.deleteRenderer();
}
this._renderer = new CubismRenderer_WebGL();
this._renderer.initialize(this._model);
}
/**
*
*/
public deleteRenderer(): void {
if (this._renderer != null) {
this._renderer.release();
this._renderer = null;
}
}
/**
*
*
* Event
*
*
*
* @param eventValue
*/
public motionEventFired(eventValue: csmString): void {
CubismLogInfo('{0}', eventValue.s);
}
/**
*
*
* CubismMotionQueueManagerCallback
* CubismUserModelEventFired
*
* @param caller
* @param eventValue
* @param customData CubismUserModel
*/
public static cubismDefaultMotionEventCallback(
caller: CubismMotionQueueManager,
eventValue: csmString,
customData: CubismUserModel
): void {
const model: CubismUserModel = customData;
if (model != null) {
model.motionEventFired(eventValue);
}
}
/**
*
*/
public constructor() {
// 各変数初期化
this._moc = null;
this._model = null;
this._motionManager = null;
this._expressionManager = null;
this._eyeBlink = null;
this._breath = null;
this._modelMatrix = null;
this._pose = null;
this._dragManager = null;
this._physics = null;
this._modelUserData = null;
this._initialized = false;
this._updating = false;
this._opacity = 1.0;
this._lipsync = true;
this._lastLipSyncValue = 0.0;
this._dragX = 0.0;
this._dragY = 0.0;
this._accelerationX = 0.0;
this._accelerationY = 0.0;
this._accelerationZ = 0.0;
this._debugMode = false;
this._renderer = null;
// モーションマネージャーを作成
this._motionManager = new CubismMotionManager();
this._motionManager.setEventCallback(
CubismUserModel.cubismDefaultMotionEventCallback,
this
);
// 表情マネージャーを作成
this._expressionManager = new CubismMotionManager();
// ドラッグによるアニメーション
this._dragManager = new CubismTargetPoint();
}
/**
*
*/
public release() {
if (this._motionManager != null) {
this._motionManager.release();
this._motionManager = null;
}
if (this._expressionManager != null) {
this._expressionManager.release();
this._expressionManager = null;
}
if (this._moc != null) {
this._moc.deleteModel(this._model);
this._moc.release();
this._moc = null;
}
this._modelMatrix = null;
CubismPose.delete(this._pose);
CubismEyeBlink.delete(this._eyeBlink);
CubismBreath.delete(this._breath);
this._dragManager = null;
CubismPhysics.delete(this._physics);
CubismModelUserData.delete(this._modelUserData);
this.deleteRenderer();
}
protected _moc: CubismMoc; // Mocデータ
protected _model: CubismModel; // Modelインスタンス
protected _motionManager: CubismMotionManager; // モーション管理
protected _expressionManager: CubismMotionManager; // 表情管理
protected _eyeBlink: CubismEyeBlink; // 自動まばたき
protected _breath: CubismBreath; // 呼吸
protected _modelMatrix: CubismModelMatrix; // モデル行列
protected _pose: CubismPose; // ポーズ管理
protected _dragManager: CubismTargetPoint; // マウスドラッグ
protected _physics: CubismPhysics; // 物理演算
protected _modelUserData: CubismModelUserData; // ユーザーデータ
protected _initialized: boolean; // 初期化されたかどうか
protected _updating: boolean; // 更新されたかどうか
protected _opacity: number; // 不透明度
protected _lipsync: boolean; // リップシンクするかどうか
protected _lastLipSyncValue: number; // 最後のリップシンクの制御地
protected _dragX: number; // マウスドラッグのX位置
protected _dragY: number; // マウスドラッグのY位置
protected _accelerationX: number; // X軸方向の加速度
protected _accelerationY: number; // Y軸方向の加速度
protected _accelerationZ: number; // Z軸方向の加速度
protected _debugMode: boolean; // デバッグモードかどうか
private _renderer: CubismRenderer_WebGL; // レンダラ
}
}

278
src/motion/acubismmotion.ts Normal file
View File

@ -0,0 +1,278 @@
/**
* 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 '../math/cubismmath';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as cubismmotionqueueentry } from './cubismmotionqueueentry';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import { CSM_ASSERT } from '../utils/cubismdebug';
import csmVector = csmvector.csmVector;
import csmString = csmstring.csmString;
import CubismMotionQueueEntry = cubismmotionqueueentry.CubismMotionQueueEntry;
import CubismModel = cubismmodel.CubismModel;
import CubismMath = cubismmath.CubismMath;
export namespace Live2DCubismFramework {
/** モーション再生終了コールバック関数定義 */
export type FinishedMotionCallback = (self: ACubismMotion) => void;
/**
*
*
* MotionQueueManager
*/
export abstract class ACubismMotion {
/**
*
*/
public static delete(motion: ACubismMotion): void {
motion.release();
motion = void 0;
motion = null;
}
/**
*
*/
public constructor() {
this._fadeInSeconds = -1.0;
this._fadeOutSeconds = -1.0;
this._weight = 1.0;
this._offsetSeconds = 0.0; // 再生の開始時刻
this._firedEventValues = new csmVector<csmString>();
}
/**
*
*/
public release(): void {
this._weight = 0.0;
}
/**
*
* @param model
* @param motionQueueEntry CubismMotionQueueManager
* @param userTimeSeconds []
*/
public updateParameters(
model: CubismModel,
motionQueueEntry: CubismMotionQueueEntry,
userTimeSeconds: number
): void {
if (!motionQueueEntry.isAvailable() || motionQueueEntry.isFinished()) {
return;
}
if (!motionQueueEntry.isStarted()) {
motionQueueEntry.setIsStarted(true);
motionQueueEntry.setStartTime(userTimeSeconds - this._offsetSeconds); // モーションの開始時刻を記録
motionQueueEntry.setFadeInStartTime(userTimeSeconds); // フェードインの開始時刻
const duration: number = this.getDuration();
if (motionQueueEntry.getEndTime() < 0) {
// 開始していないうちに終了設定している場合がある。
motionQueueEntry.setEndTime(
duration <= 0 ? -1 : motionQueueEntry.getStartTime() + duration
);
// duration == -1 の場合はループする
}
}
let fadeWeight: number = this._weight; // 現在の値と掛け合わせる割合
//---- フェードイン・アウトの処理 ----
// 単純なサイン関数でイージングする
const fadeIn: number =
this._fadeInSeconds == 0.0
? 1.0
: CubismMath.getEasingSine(
(userTimeSeconds - motionQueueEntry.getFadeInStartTime()) /
this._fadeInSeconds
);
const fadeOut: number =
this._fadeOutSeconds == 0.0 || motionQueueEntry.getEndTime() < 0.0
? 1.0
: CubismMath.getEasingSine(
(motionQueueEntry.getEndTime() - userTimeSeconds) /
this._fadeOutSeconds
);
fadeWeight = fadeWeight * fadeIn * fadeOut;
motionQueueEntry.setState(userTimeSeconds, fadeWeight);
CSM_ASSERT(0.0 <= fadeWeight && fadeWeight <= 1.0);
//---- 全てのパラメータIDをループする ----
this.doUpdateParameters(
model,
userTimeSeconds,
fadeWeight,
motionQueueEntry
);
// 後処理
// 終了時刻を過ぎたら終了フラグを立てる(CubismMotionQueueManager)
if (
motionQueueEntry.getEndTime() > 0 &&
motionQueueEntry.getEndTime() < userTimeSeconds
) {
motionQueueEntry.setIsFinished(true); // 終了
}
}
/**
*
* @param fadeInSeconds []
*/
public setFadeInTime(fadeInSeconds: number): void {
this._fadeInSeconds = fadeInSeconds;
}
/**
*
* @param fadeOutSeconds []
*/
public setFadeOutTime(fadeOutSeconds: number): void {
this._fadeOutSeconds = fadeOutSeconds;
}
/**
*
* @return []
*/
public getFadeOutTime(): number {
return this._fadeOutSeconds;
}
/**
*
* @return []
*/
public getFadeInTime(): number {
return this._fadeInSeconds;
}
/**
*
* @param weight 0.0 - 1.0
*/
public setWeight(weight: number): void {
this._weight = weight;
}
/**
*
* @return 0.0 - 1.0
*/
public getWeight(): number {
return this._weight;
}
/**
*
* @return []
*
* @note -1
*
*
* -1
*/
public getDuration(): number {
return -1.0;
}
/**
* 1
* @return []
*
* @note getDuration()
* ()-1
*/
public getLoopDuration(): number {
return -1.0;
}
/**
*
* @param offsetSeconds []
*/
public setOffsetTime(offsetSeconds: number): void {
this._offsetSeconds = offsetSeconds;
}
/**
*
*
*
*
*
* @param beforeCheckTimeSeconds []
* @param motionTimeSeconds []
*/
public getFiredEvent(
beforeCheckTimeSeconds: number,
motionTimeSeconds: number
): csmVector<csmString> {
return this._firedEventValues;
}
/**
*
* @param model
* @param userTimeSeconds []
* @param weight
* @param motionQueueEntry CubismMotionQueueManager
* @return true
* @return false
*/
public abstract doUpdateParameters(
model: CubismModel,
userTimeSeconds: number,
weight: number,
motionQueueEntry: CubismMotionQueueEntry
): void;
/**
*
*
*
* isFinished
* :
* 1.
* 2.
*
* @param onFinishedMotionHandler
*/
public setFinishedMotionHandler = (
onFinishedMotionHandler: FinishedMotionCallback
) => (this._onFinishedMotion = onFinishedMotionHandler);
/**
*
*
*
*
* @return
*/
public getFinishedMotionHandler = () => this._onFinishedMotion;
public _fadeInSeconds: number; // フェードインにかかる時間[秒]
public _fadeOutSeconds: number; // フェードアウトにかかる時間[秒]
public _weight: number; // モーションの重み
public _offsetSeconds: number; // モーション再生の開始時間[秒]
public _firedEventValues: csmVector<csmString>;
// モーション再生終了コールバック関数
public _onFinishedMotion?: FinishedMotionCallback;
}
}

View File

@ -0,0 +1,199 @@
/**
* 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 acubismmotion } from './acubismmotion';
import { Live2DCubismFramework as cubismjson } from '../utils/cubismjson';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as cubismmotionqueueentry } from './cubismmotionqueueentry';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import JsonFloat = cubismjson.JsonFloat;
import csmVector = csmvector.csmVector;
import CubismMotionQueueEntry = cubismmotionqueueentry.CubismMotionQueueEntry;
import CubismModel = cubismmodel.CubismModel;
import CubismFramework = cubismframework.CubismFramework;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismJson = cubismjson.CubismJson;
import Value = cubismjson.Value;
import ACubismMotion = acubismmotion.ACubismMotion;
export namespace Live2DCubismFramework {
// exp3.jsonのキーとデフォルト
const ExpressionKeyFadeIn = 'FadeInTime';
const ExpressionKeyFadeOut = 'FadeOutTime';
const ExpressionKeyParameters = 'Parameters';
const ExpressionKeyId = 'Id';
const ExpressionKeyValue = 'Value';
const ExpressionKeyBlend = 'Blend';
const BlendValueAdd = 'Add';
const BlendValueMultiply = 'Multiply';
const BlendValueOverwrite = 'Overwrite';
const DefaultFadeTime = 1.0;
/**
*
*
*
*/
export class CubismExpressionMotion extends ACubismMotion {
/**
*
* @param buffer exp
* @param size
* @return
*/
public static create(
buffer: ArrayBuffer,
size: number
): CubismExpressionMotion {
const expression: CubismExpressionMotion = new CubismExpressionMotion();
const json: CubismJson = CubismJson.create(buffer, size);
const root: Value = json.getRoot();
expression.setFadeInTime(
root.getValueByString(ExpressionKeyFadeIn).toFloat(DefaultFadeTime)
); // フェードイン
expression.setFadeOutTime(
root.getValueByString(ExpressionKeyFadeOut).toFloat(DefaultFadeTime)
); // フェードアウト
// 各パラメータについて
const parameterCount = root
.getValueByString(ExpressionKeyParameters)
.getSize();
expression._parameters.prepareCapacity(parameterCount);
for (let i = 0; i < parameterCount; ++i) {
const param: Value = root
.getValueByString(ExpressionKeyParameters)
.getValueByIndex(i);
const parameterId: CubismIdHandle = CubismFramework.getIdManager().getId(
param.getValueByString(ExpressionKeyId).getRawString()
); // パラメータID
const value: number = param
.getValueByString(ExpressionKeyValue)
.toFloat(); // 値
// 計算方法の設定
let blendType: ExpressionBlendType;
if (
param.getValueByString(ExpressionKeyBlend).isNull() ||
param.getValueByString(ExpressionKeyBlend).getString() ==
BlendValueAdd
) {
blendType = ExpressionBlendType.ExpressionBlendType_Add;
} else if (
param.getValueByString(ExpressionKeyBlend).getString() ==
BlendValueMultiply
) {
blendType = ExpressionBlendType.ExpressionBlendType_Multiply;
} else if (
param.getValueByString(ExpressionKeyBlend).getString() ==
BlendValueOverwrite
) {
blendType = ExpressionBlendType.ExpressionBlendType_Overwrite;
} else {
// その他 仕様にない値を設定した時は加算モードにすることで復旧
blendType = ExpressionBlendType.ExpressionBlendType_Add;
}
// 設定オブジェクトを作成してリストに追加する
const item: ExpressionParameter = new ExpressionParameter();
item.parameterId = parameterId;
item.blendType = blendType;
item.value = value;
expression._parameters.pushBack(item);
}
CubismJson.delete(json); // JSONデータは不要になったら削除する
return expression;
}
/**
*
* @param model
* @param userTimeSeconds []
* @param weight
* @param motionQueueEntry CubismMotionQueueManager
*/
public doUpdateParameters(
model: CubismModel,
userTimeSeconds: number,
weight: number,
motionQueueEntry: CubismMotionQueueEntry
): void {
for (let i = 0; i < this._parameters.getSize(); ++i) {
const parameter: ExpressionParameter = this._parameters.at(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;
}
default:
// 仕様にない値を設定した時はすでに加算モードになっている
break;
}
}
}
/**
*
*/
constructor() {
super();
this._parameters = new csmVector<ExpressionParameter>();
}
_parameters: csmVector<ExpressionParameter>; // 表情のパラメータ情報リスト
}
/**
*
*/
export enum ExpressionBlendType {
ExpressionBlendType_Add = 0, // 加算
ExpressionBlendType_Multiply = 1, // 乗算
ExpressionBlendType_Overwrite = 2 // 上書き
}
/**
*
*/
export class ExpressionParameter {
parameterId: CubismIdHandle; // パラメータID
blendType: ExpressionBlendType; // パラメータの演算種類
value: number; // 値
}
}

945
src/motion/cubismmotion.ts Normal file
View File

@ -0,0 +1,945 @@
/**
* 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 cubismmotionjson } from './cubismmotionjson';
import { Live2DCubismFramework as cubismmotioninternal } from './cubismmotioninternal';
import { Live2DCubismFramework as acubismmotion } from './acubismmotion';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import { Live2DCubismFramework as cubismmotionqueueentry } from './cubismmotionqueueentry';
import { Live2DCubismFramework as cubismmath } from '../math/cubismmath';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import { CubismLogDebug, CSM_ASSERT } from '../utils/cubismdebug';
import csmString = csmstring.csmString;
import CubismMotionData = cubismmotioninternal.CubismMotionData;
import CubismMotionSegment = cubismmotioninternal.CubismMotionSegment;
import CubismMotionPoint = cubismmotioninternal.CubismMotionPoint;
import CubismMotionEvent = cubismmotioninternal.CubismMotionEvent;
import CubismMotionSegmentType = cubismmotioninternal.CubismMotionSegmentType;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismMotionCurve = cubismmotioninternal.CubismMotionCurve;
import CubismMotionCurveTarget = cubismmotioninternal.CubismMotionCurveTarget;
import csmVector = csmvector.csmVector;
import CubismMath = cubismmath.CubismMath;
import CubismMotionQueueEntry = cubismmotionqueueentry.CubismMotionQueueEntry;
import CubismFramework = cubismframework.CubismFramework;
import CubismModel = cubismmodel.CubismModel;
import ACubismMotion = acubismmotion.ACubismMotion;
import FinishedMotionCallback = acubismmotion.FinishedMotionCallback;
import CubismMotionJson = cubismmotionjson.CubismMotionJson;
export namespace Live2DCubismFramework {
const EffectNameEyeBlink = 'EyeBlink';
const EffectNameLipSync = 'LipSync';
const TargetNameModel = 'Model';
const TargetNameParameter = 'Parameter';
const TargetNamePartOpacity = 'PartOpacity';
function lerpPoints(
a: CubismMotionPoint,
b: CubismMotionPoint,
t: number
): CubismMotionPoint {
const result: CubismMotionPoint = 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: CubismMotionPoint[], time: number): number {
let t: number = (time - points[0].time) / (points[1].time - points[0].time);
if (t < 0.0) {
t = 0.0;
}
return points[0].value + (points[1].value - points[0].value) * t;
}
function bezierEvaluate(points: CubismMotionPoint[], time: number): number {
let t: number = (time - points[0].time) / (points[3].time - points[0].time);
if (t < 0.0) {
t = 0.0;
}
const p01: CubismMotionPoint = lerpPoints(points[0], points[1], t);
const p12: CubismMotionPoint = lerpPoints(points[1], points[2], t);
const p23: CubismMotionPoint = lerpPoints(points[2], points[3], t);
const p012: CubismMotionPoint = lerpPoints(p01, p12, t);
const p123: CubismMotionPoint = lerpPoints(p12, p23, t);
return lerpPoints(p012, p123, t).value;
}
function steppedEvaluate(points: CubismMotionPoint[], time: number): number {
return points[0].value;
}
function inverseSteppedEvaluate(
points: CubismMotionPoint[],
time: number
): number {
return points[1].value;
}
function evaluateCurve(
motionData: CubismMotionData,
index: number,
time: number
): number {
// Find segment to evaluate.
const curve: CubismMotionCurve = motionData.curves.at(index);
let target = -1;
const totalSegmentCount: number =
curve.baseSegmentIndex + curve.segmentCount;
let pointPosition = 0;
for (let i: number = curve.baseSegmentIndex; i < totalSegmentCount; ++i) {
// Get first point of next segment.
pointPosition =
motionData.segments.at(i).basePointIndex +
(motionData.segments.at(i).segmentType ==
CubismMotionSegmentType.CubismMotionSegmentType_Bezier
? 3
: 1);
// Break if time lies within current segment.
if (motionData.points.at(pointPosition).time > time) {
target = i;
break;
}
}
if (target == -1) {
return motionData.points.at(pointPosition).value;
}
const segment: CubismMotionSegment = motionData.segments.at(target);
return segment.evaluate(
motionData.points.get(segment.basePointIndex),
time
);
}
/**
*
*
*
*/
export class CubismMotion extends ACubismMotion {
/**
*
*
* @param buffer motion3.json
* @param size
* @param onFinishedMotionHandler
* @return
*/
public static create(
buffer: ArrayBuffer,
size: number,
onFinishedMotionHandler?: FinishedMotionCallback
): CubismMotion {
const ret = new CubismMotion();
ret.parse(buffer, size);
ret._sourceFrameRate = ret._motionData.fps;
ret._loopDurationSeconds = ret._motionData.duration;
ret._onFinishedMotion = onFinishedMotionHandler;
// NOTE: Editorではループありのモーション書き出しは非対応
// ret->_loop = (ret->_motionData->Loop > 0);
return ret;
}
/**
*
* @param model
* @param userTimeSeconds []
* @param fadeWeight
* @param motionQueueEntry CubismMotionQueueManager
*/
public doUpdateParameters(
model: CubismModel,
userTimeSeconds: number,
fadeWeight: number,
motionQueueEntry: CubismMotionQueueEntry
): void {
if (this._modelCurveIdEyeBlink == null) {
this._modelCurveIdEyeBlink = CubismFramework.getIdManager().getId(
EffectNameEyeBlink
);
}
if (this._modelCurveIdLipSync == null) {
this._modelCurveIdLipSync = CubismFramework.getIdManager().getId(
EffectNameLipSync
);
}
let timeOffsetSeconds: number =
userTimeSeconds - motionQueueEntry.getStartTime();
if (timeOffsetSeconds < 0.0) {
timeOffsetSeconds = 0.0; // エラー回避
}
let lipSyncValue: number = Number.MAX_VALUE;
let eyeBlinkValue: number = Number.MAX_VALUE;
//まばたき、リップシンクのうちモーションの適用を検出するためのビットmaxFlagCount個まで
const MaxTargetSize = 64;
let lipSyncFlags = 0;
let eyeBlinkFlags = 0;
//瞬き、リップシンクのターゲット数が上限を超えている場合
if (this._eyeBlinkParameterIds.getSize() > MaxTargetSize) {
CubismLogDebug(
'too many eye blink targets : {0}',
this._eyeBlinkParameterIds.getSize()
);
}
if (this._lipSyncParameterIds.getSize() > MaxTargetSize) {
CubismLogDebug(
'too many lip sync targets : {0}',
this._lipSyncParameterIds.getSize()
);
}
const tmpFadeIn: number =
this._fadeInSeconds <= 0.0
? 1.0
: CubismMath.getEasingSine(
(userTimeSeconds - motionQueueEntry.getFadeInStartTime()) /
this._fadeInSeconds
);
const tmpFadeOut: number =
this._fadeOutSeconds <= 0.0 || motionQueueEntry.getEndTime() < 0.0
? 1.0
: CubismMath.getEasingSine(
(motionQueueEntry.getEndTime() - userTimeSeconds) /
this._fadeOutSeconds
);
let value: number;
let c: number, parameterIndex: number;
// 'Repeat' time as necessary.
let time: number = timeOffsetSeconds;
if (this._isLoop) {
while (time > this._motionData.duration) {
time -= this._motionData.duration;
}
}
const curves: csmVector<CubismMotionCurve> = this._motionData.curves;
// Evaluate model curves.
for (
c = 0;
c < this._motionData.curveCount &&
curves.at(c).type ==
CubismMotionCurveTarget.CubismMotionCurveTarget_Model;
++c
) {
// Evaluate curve and call handler.
value = evaluateCurve(this._motionData, c, time);
if (curves.at(c).id == this._modelCurveIdEyeBlink) {
eyeBlinkValue = value;
} else if (curves.at(c).id == this._modelCurveIdLipSync) {
lipSyncValue = value;
}
}
let parameterMotionCurveCount = 0;
for (
;
c < this._motionData.curveCount &&
curves.at(c).type ==
CubismMotionCurveTarget.CubismMotionCurveTarget_Parameter;
++c
) {
parameterMotionCurveCount++;
// Find parameter index.
parameterIndex = model.getParameterIndex(curves.at(c).id);
// Skip curve evaluation if no value in sink.
if (parameterIndex == -1) {
continue;
}
const sourceValue: number = model.getParameterValueByIndex(
parameterIndex
);
// Evaluate curve and apply value.
value = evaluateCurve(this._motionData, c, time);
if (eyeBlinkValue != Number.MAX_VALUE) {
for (
let i = 0;
i < this._eyeBlinkParameterIds.getSize() && i < MaxTargetSize;
++i
) {
if (this._eyeBlinkParameterIds.at(i) == curves.at(c).id) {
value *= eyeBlinkValue;
eyeBlinkFlags |= 1 << i;
break;
}
}
}
if (lipSyncValue != Number.MAX_VALUE) {
for (
let i = 0;
i < this._lipSyncParameterIds.getSize() && i < MaxTargetSize;
++i
) {
if (this._lipSyncParameterIds.at(i) == curves.at(c).id) {
value += lipSyncValue;
lipSyncFlags |= 1 << i;
break;
}
}
}
let v: number;
// パラメータごとのフェード
if (curves.at(c).fadeInTime < 0.0 && curves.at(c).fadeOutTime < 0.0) {
// モーションのフェードを適用
v = sourceValue + (value - sourceValue) * fadeWeight;
} else {
// パラメータに対してフェードインかフェードアウトが設定してある場合はそちらを適用
let fin: number;
let fout: number;
if (curves.at(c).fadeInTime < 0.0) {
fin = tmpFadeIn;
} else {
fin =
curves.at(c).fadeInTime == 0.0
? 1.0
: CubismMath.getEasingSine(
(userTimeSeconds - motionQueueEntry.getFadeInStartTime()) /
curves.at(c).fadeInTime
);
}
if (curves.at(c).fadeOutTime < 0.0) {
fout = tmpFadeOut;
} else {
fout =
curves.at(c).fadeOutTime == 0.0 ||
motionQueueEntry.getEndTime() < 0.0
? 1.0
: CubismMath.getEasingSine(
(motionQueueEntry.getEndTime() - userTimeSeconds) /
curves.at(c).fadeOutTime
);
}
const paramWeight: number = this._weight * fin * fout;
// パラメータごとのフェードを適用
v = sourceValue + (value - sourceValue) * paramWeight;
}
model.setParameterValueByIndex(parameterIndex, v, 1.0);
}
{
if (eyeBlinkValue != Number.MAX_VALUE) {
for (
let i = 0;
i < this._eyeBlinkParameterIds.getSize() && i < MaxTargetSize;
++i
) {
const sourceValue: number = model.getParameterValueById(
this._eyeBlinkParameterIds.at(i)
);
// モーションでの上書きがあった時にはまばたきは適用しない
if ((eyeBlinkFlags >> i) & 0x01) {
continue;
}
const v: number =
sourceValue + (eyeBlinkValue - sourceValue) * fadeWeight;
model.setParameterValueById(this._eyeBlinkParameterIds.at(i), v);
}
}
if (lipSyncValue != Number.MAX_VALUE) {
for (
let i = 0;
i < this._lipSyncParameterIds.getSize() && i < MaxTargetSize;
++i
) {
const sourceValue: number = model.getParameterValueById(
this._lipSyncParameterIds.at(i)
);
// モーションでの上書きがあった時にはリップシンクは適用しない
if ((lipSyncFlags >> i) & 0x01) {
continue;
}
const v: number =
sourceValue + (lipSyncValue - sourceValue) * fadeWeight;
model.setParameterValueById(this._lipSyncParameterIds.at(i), v);
}
}
}
for (
;
c < this._motionData.curveCount &&
curves.at(c).type ==
CubismMotionCurveTarget.CubismMotionCurveTarget_PartOpacity;
++c
) {
// Find parameter index.
parameterIndex = model.getParameterIndex(curves.at(c).id);
// Skip curve evaluation if no value in sink.
if (parameterIndex == -1) {
continue;
}
// Evaluate curve and apply value.
value = evaluateCurve(this._motionData, c, time);
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;
}
/**
*
* @param loop
*/
public setIsLoop(loop: boolean): void {
this._isLoop = loop;
}
/**
*
* @return true
* @return false
*/
public isLoop(): boolean {
return this._isLoop;
}
/**
*
* @param loopFadeIn
*/
public setIsLoopFadeIn(loopFadeIn: boolean): void {
this._isLoopFadeIn = loopFadeIn;
}
/**
*
*
* @return true
* @return false
*/
public isLoopFadeIn(): boolean {
return this._isLoopFadeIn;
}
/**
*
*
* @return []
*/
public getDuration(): number {
return this._isLoop ? -1.0 : this._loopDurationSeconds;
}
/**
*
*
* @return []
*/
public getLoopDuration(): number {
return this._loopDurationSeconds;
}
/**
*
*
* @param parameterId ID
* @param value []
*/
public setParameterFadeInTime(
parameterId: CubismIdHandle,
value: number
): void {
const curves: csmVector<CubismMotionCurve> = this._motionData.curves;
for (let i = 0; i < this._motionData.curveCount; ++i) {
if (parameterId == curves.at(i).id) {
curves.at(i).fadeInTime = value;
return;
}
}
}
/**
*
* @param parameterId ID
* @param value []
*/
public setParameterFadeOutTime(
parameterId: CubismIdHandle,
value: number
): void {
const curves: csmVector<CubismMotionCurve> = this._motionData.curves;
for (let i = 0; i < this._motionData.curveCount; ++i) {
if (parameterId == curves.at(i).id) {
curves.at(i).fadeOutTime = value;
return;
}
}
}
/**
*
* @param parameterId ID
* @return []
*/
public getParameterFadeInTime(parameterId: CubismIdHandle): number {
const curves: csmVector<CubismMotionCurve> = this._motionData.curves;
for (let i = 0; i < this._motionData.curveCount; ++i) {
if (parameterId == curves.at(i).id) {
return curves.at(i).fadeInTime;
}
}
return -1;
}
/**
*
*
* @param parameterId ID
* @return []
*/
public getParameterFadeOutTime(parameterId: CubismIdHandle): number {
const curves: csmVector<CubismMotionCurve> = this._motionData.curves;
for (let i = 0; i < this._motionData.curveCount; ++i) {
if (parameterId == curves.at(i).id) {
return curves.at(i).fadeOutTime;
}
}
return -1;
}
/**
* ID
* @param eyeBlinkParameterIds ID
* @param lipSyncParameterIds ID
*/
public setEffectIds(
eyeBlinkParameterIds: csmVector<CubismIdHandle>,
lipSyncParameterIds: csmVector<CubismIdHandle>
): void {
this._eyeBlinkParameterIds = eyeBlinkParameterIds;
this._lipSyncParameterIds = lipSyncParameterIds;
}
/**
*
*/
public constructor() {
super();
this._sourceFrameRate = 30.0;
this._loopDurationSeconds = -1.0;
this._isLoop = false; // trueから false へデフォルトを変更
this._isLoopFadeIn = true; // ループ時にフェードインが有効かどうかのフラグ
this._lastWeight = 0.0;
this._motionData = null;
this._modelCurveIdEyeBlink = null;
this._modelCurveIdLipSync = null;
this._eyeBlinkParameterIds = null;
this._lipSyncParameterIds = null;
}
/**
*
*/
public release(): void {
this._motionData = void 0;
this._motionData = null;
}
/**
* motion3.json
*
* @param motionJson motion3.json
* @param size
*/
public parse(motionJson: ArrayBuffer, size: number): void {
this._motionData = new CubismMotionData();
let json: CubismMotionJson = new CubismMotionJson(motionJson, size);
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();
if (json.isExistMotionFadeInTime()) {
this._fadeInSeconds =
json.getMotionFadeInTime() < 0.0 ? 1.0 : json.getMotionFadeInTime();
} else {
this._fadeInSeconds = 1.0;
}
if (json.isExistMotionFadeOutTime()) {
this._fadeOutSeconds =
json.getMotionFadeOutTime() < 0.0 ? 1.0 : json.getMotionFadeOutTime();
} else {
this._fadeOutSeconds = 1.0;
}
this._motionData.curves.updateSize(
this._motionData.curveCount,
CubismMotionCurve,
true
);
this._motionData.segments.updateSize(
json.getMotionTotalSegmentCount(),
CubismMotionSegment,
true
);
this._motionData.points.updateSize(
json.getMotionTotalPointCount(),
CubismMotionPoint,
true
);
this._motionData.events.updateSize(
this._motionData.eventCount,
CubismMotionEvent,
true
);
let totalPointCount = 0;
let totalSegmentCount = 0;
// Curves
for (
let curveCount = 0;
curveCount < this._motionData.curveCount;
++curveCount
) {
if (json.getMotionCurveTarget(curveCount) == TargetNameModel) {
this._motionData.curves.at(curveCount).type =
CubismMotionCurveTarget.CubismMotionCurveTarget_Model;
} else if (
json.getMotionCurveTarget(curveCount) == TargetNameParameter
) {
this._motionData.curves.at(curveCount).type =
CubismMotionCurveTarget.CubismMotionCurveTarget_Parameter;
} else if (
json.getMotionCurveTarget(curveCount) == TargetNamePartOpacity
) {
this._motionData.curves.at(curveCount).type =
CubismMotionCurveTarget.CubismMotionCurveTarget_PartOpacity;
}
this._motionData.curves.at(curveCount).id = json.getMotionCurveId(
curveCount
);
this._motionData.curves.at(
curveCount
).baseSegmentIndex = totalSegmentCount;
this._motionData.curves.at(
curveCount
).fadeInTime = json.isExistMotionCurveFadeInTime(curveCount)
? json.getMotionCurveFadeInTime(curveCount)
: -1.0;
this._motionData.curves.at(
curveCount
).fadeOutTime = json.isExistMotionCurveFadeOutTime(curveCount)
? json.getMotionCurveFadeOutTime(curveCount)
: -1.0;
// Segments
for (
let segmentPosition = 0;
segmentPosition < json.getMotionCurveSegmentCount(curveCount);
) {
if (segmentPosition == 0) {
this._motionData.segments.at(
totalSegmentCount
).basePointIndex = totalPointCount;
this._motionData.points.at(
totalPointCount
).time = json.getMotionCurveSegment(curveCount, segmentPosition);
this._motionData.points.at(
totalPointCount
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 1
);
totalPointCount += 1;
segmentPosition += 2;
} else {
this._motionData.segments.at(totalSegmentCount).basePointIndex =
totalPointCount - 1;
}
const segment: number = json.getMotionCurveSegment(
curveCount,
segmentPosition
);
switch (segment) {
case CubismMotionSegmentType.CubismMotionSegmentType_Linear: {
this._motionData.segments.at(totalSegmentCount).segmentType =
CubismMotionSegmentType.CubismMotionSegmentType_Linear;
this._motionData.segments.at(
totalSegmentCount
).evaluate = linearEvaluate;
this._motionData.points.at(
totalPointCount
).time = json.getMotionCurveSegment(
curveCount,
segmentPosition + 1
);
this._motionData.points.at(
totalPointCount
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 2
);
totalPointCount += 1;
segmentPosition += 3;
break;
}
case CubismMotionSegmentType.CubismMotionSegmentType_Bezier: {
this._motionData.segments.at(totalSegmentCount).segmentType =
CubismMotionSegmentType.CubismMotionSegmentType_Bezier;
this._motionData.segments.at(
totalSegmentCount
).evaluate = bezierEvaluate;
this._motionData.points.at(
totalPointCount
).time = json.getMotionCurveSegment(
curveCount,
segmentPosition + 1
);
this._motionData.points.at(
totalPointCount
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 2
);
this._motionData.points.at(
totalPointCount + 1
).time = json.getMotionCurveSegment(
curveCount,
segmentPosition + 3
);
this._motionData.points.at(
totalPointCount + 1
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 4
);
this._motionData.points.at(
totalPointCount + 2
).time = json.getMotionCurveSegment(
curveCount,
segmentPosition + 5
);
this._motionData.points.at(
totalPointCount + 2
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 6
);
totalPointCount += 3;
segmentPosition += 7;
break;
}
case CubismMotionSegmentType.CubismMotionSegmentType_Stepped: {
this._motionData.segments.at(totalSegmentCount).segmentType =
CubismMotionSegmentType.CubismMotionSegmentType_Stepped;
this._motionData.segments.at(
totalSegmentCount
).evaluate = steppedEvaluate;
this._motionData.points.at(
totalPointCount
).time = json.getMotionCurveSegment(
curveCount,
segmentPosition + 1
);
this._motionData.points.at(
totalPointCount
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 2
);
totalPointCount += 1;
segmentPosition += 3;
break;
}
case CubismMotionSegmentType.CubismMotionSegmentType_InverseStepped: {
this._motionData.segments.at(totalSegmentCount).segmentType =
CubismMotionSegmentType.CubismMotionSegmentType_InverseStepped;
this._motionData.segments.at(
totalSegmentCount
).evaluate = inverseSteppedEvaluate;
this._motionData.points.at(
totalPointCount
).time = json.getMotionCurveSegment(
curveCount,
segmentPosition + 1
);
this._motionData.points.at(
totalPointCount
).value = json.getMotionCurveSegment(
curveCount,
segmentPosition + 2
);
totalPointCount += 1;
segmentPosition += 3;
break;
}
default: {
CSM_ASSERT(0);
break;
}
}
++this._motionData.curves.at(curveCount).segmentCount;
++totalSegmentCount;
}
}
for (
let userdatacount = 0;
userdatacount < json.getEventCount();
++userdatacount
) {
this._motionData.events.at(userdatacount).fireTime = json.getEventTime(
userdatacount
);
this._motionData.events.at(userdatacount).value = json.getEventValue(
userdatacount
);
}
json.release();
json = void 0;
json = null;
}
/**
*
*
*
*
*
* @param beforeCheckTimeSeconds []
* @param motionTimeSeconds []
*/
public getFiredEvent(
beforeCheckTimeSeconds: number,
motionTimeSeconds: number
): csmVector<csmString> {
this._firedEventValues.updateSize(0);
// イベントの発火チェック
for (let u = 0; u < this._motionData.eventCount; ++u) {
if (
this._motionData.events.at(u).fireTime > beforeCheckTimeSeconds &&
this._motionData.events.at(u).fireTime <= motionTimeSeconds
) {
this._firedEventValues.pushBack(
new csmString(this._motionData.events.at(u).value.s)
);
}
}
return this._firedEventValues;
}
public _sourceFrameRate: number; // ロードしたファイルのFPS。記述が無ければデフォルト値15fpsとなる
public _loopDurationSeconds: number; // mtnファイルで定義される一連のモーションの長さ
public _isLoop: boolean; // ループするか?
public _isLoopFadeIn: boolean; // ループ時にフェードインが有効かどうかのフラグ。初期値では有効。
public _lastWeight: number; // 最後に設定された重み
public _motionData: CubismMotionData; // 実際のモーションデータ本体
public _eyeBlinkParameterIds: csmVector<CubismIdHandle>; // 自動まばたきを適用するパラメータIDハンドルのリスト。 モデル(モデルセッティング)とパラメータを対応付ける。
public _lipSyncParameterIds: csmVector<CubismIdHandle>; // リップシンクを適用するパラメータIDハンドルのリスト。 モデル(モデルセッティング)とパラメータを対応付ける。
public _modelCurveIdEyeBlink: CubismIdHandle; // モデルが持つ自動まばたき用パラメータIDのハンドル。 モデルとモーションを対応付ける。
public _modelCurveIdLipSync: CubismIdHandle; // モデルが持つリップシンク用パラメータIDのハンドル。 モデルとモーションを対応付ける。
}
}

View File

@ -0,0 +1,140 @@
/**
* 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 cubismid } from '../id/cubismid';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import csmVector = csmvector.csmVector;
import csmString = csmstring.csmString;
import CubismIdHandle = cubismid.CubismIdHandle;
export namespace Live2DCubismFramework {
/**
* @brief
*
*
*/
export enum CubismMotionCurveTarget {
CubismMotionCurveTarget_Model, // モデルに対して
CubismMotionCurveTarget_Parameter, // パラメータに対して
CubismMotionCurveTarget_PartOpacity // パーツの不透明度に対して
}
/**
* @brief
*
*
*/
export enum CubismMotionSegmentType {
CubismMotionSegmentType_Linear = 0, // リニア
CubismMotionSegmentType_Bezier = 1, // ベジェ曲線
CubismMotionSegmentType_Stepped = 2, // ステップ
CubismMotionSegmentType_InverseStepped = 3 // インバースステップ
}
/**
* @brief
*
*
*/
export class CubismMotionPoint {
time = 0.0; // 時間[秒]
value = 0.0; // 値
}
/**
*
*
* @param points
* @param time []
*/
export interface csmMotionSegmentEvaluationFunction {
(points: CubismMotionPoint[], time: number): number;
}
/**
* @brief
*
*
*/
export class CubismMotionSegment {
/**
* @brief
*
*
*/
public constructor() {
this.evaluate = null;
this.basePointIndex = 0;
this.segmentType = 0;
}
evaluate: csmMotionSegmentEvaluationFunction; // 使用する評価関数
basePointIndex: number; // 最初のセグメントへのインデックス
segmentType: number; // セグメントの種類
}
/**
* @brief
*
*
*/
export class CubismMotionCurve {
public constructor() {
this.type = CubismMotionCurveTarget.CubismMotionCurveTarget_Model;
this.segmentCount = 0;
this.baseSegmentIndex = 0;
this.fadeInTime = 0.0;
this.fadeOutTime = 0.0;
}
type: CubismMotionCurveTarget; // カーブの種類
id: CubismIdHandle; // カーブのID
segmentCount: number; // セグメントの個数
baseSegmentIndex: number; // 最初のセグメントのインデックス
fadeInTime: number; // フェードインにかかる時間[秒]
fadeOutTime: number; // フェードアウトにかかる時間[秒]
}
/**
*
*/
export class CubismMotionEvent {
fireTime = 0.0;
value: csmString;
}
/**
* @brief
*
*
*/
export class CubismMotionData {
public constructor() {
this.duration = 0.0;
this.loop = false;
this.curveCount = 0;
this.eventCount = 0;
this.fps = 0.0;
this.curves = new csmVector<CubismMotionCurve>();
this.segments = new csmVector<CubismMotionSegment>();
this.points = new csmVector<CubismMotionPoint>();
this.events = new csmVector<CubismMotionEvent>();
}
duration: number; // モーションの長さ[秒]
loop: boolean; // ループするかどうか
curveCount: number; // カーブの個数
eventCount: number; // UserDataの個数
fps: number; // フレームレート
curves: csmVector<CubismMotionCurve>; // カーブのリスト
segments: csmVector<CubismMotionSegment>; // セグメントのリスト
points: csmVector<CubismMotionPoint>; // ポイントのリスト
events: csmVector<CubismMotionEvent>; // イベントのリスト
}
}

View File

@ -0,0 +1,359 @@
/**
* 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 cubismjson } from '../utils/cubismjson';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import csmString = csmstring.csmString;
import CubismFramework = cubismframework.CubismFramework;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismJson = cubismjson.CubismJson;
export namespace Live2DCubismFramework {
// JSON keys
const Meta = 'Meta';
const Duration = 'Duration';
const Loop = 'Loop';
const CurveCount = 'CurveCount';
const Fps = 'Fps';
const TotalSegmentCount = 'TotalSegmentCount';
const TotalPointCount = 'TotalPointCount';
const Curves = 'Curves';
const Target = 'Target';
const Id = 'Id';
const FadeInTime = 'FadeInTime';
const FadeOutTime = 'FadeOutTime';
const Segments = 'Segments';
const UserData = 'UserData';
const UserDataCount = 'UserDataCount';
const TotalUserDataSize = 'TotalUserDataSize';
const Time = 'Time';
const Value = 'Value';
/**
* motion3.json
*/
export class CubismMotionJson {
/**
*
* @param buffer motion3.json
* @param size
*/
public constructor(buffer: ArrayBuffer, size: number) {
this._json = CubismJson.create(buffer, size);
}
/**
*
*/
public release(): void {
CubismJson.delete(this._json);
}
/**
*
* @return []
*/
public getMotionDuration(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(Duration)
.toFloat();
}
/**
*
* @return true
* @return false
*/
public isMotionLoop(): boolean {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(Loop)
.toBoolean();
}
/**
*
* @return
*/
public getMotionCurveCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(CurveCount)
.toInt();
}
/**
*
* @return [FPS]
*/
public getMotionFps(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(Fps)
.toFloat();
}
/**
*
* @return
*/
public getMotionTotalSegmentCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(TotalSegmentCount)
.toInt();
}
/**
*
* @return
*/
public getMotionTotalPointCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(TotalPointCount)
.toInt();
}
/**
*
* @return true
* @return false
*/
public isExistMotionFadeInTime(): boolean {
return !this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(FadeInTime)
.isNull();
}
/**
*
* @return true
* @return false
*/
public isExistMotionFadeOutTime(): boolean {
return !this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(FadeOutTime)
.isNull();
}
/**
*
* @return []
*/
public getMotionFadeInTime(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(FadeInTime)
.toFloat();
}
/**
*
* @return []
*/
public getMotionFadeOutTime(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(FadeOutTime)
.toFloat();
}
/**
*
* @param curveIndex
* @return
*/
public getMotionCurveTarget(curveIndex: number): string {
return this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(Target)
.getRawString();
}
/**
* ID
* @param curveIndex
* @return ID
*/
public getMotionCurveId(curveIndex: number): CubismIdHandle {
return CubismFramework.getIdManager().getId(
this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(Id)
.getRawString()
);
}
/**
*
* @param curveIndex
* @return true
* @return false
*/
public isExistMotionCurveFadeInTime(curveIndex: number): boolean {
return !this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(FadeInTime)
.isNull();
}
/**
*
* @param curveIndex
* @return true
* @return false
*/
public isExistMotionCurveFadeOutTime(curveIndex: number): boolean {
return !this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(FadeOutTime)
.isNull();
}
/**
*
* @param curveIndex
* @return []
*/
public getMotionCurveFadeInTime(curveIndex: number): number {
return this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(FadeInTime)
.toFloat();
}
/**
*
* @param curveIndex
* @return []
*/
public getMotionCurveFadeOutTime(curveIndex: number): number {
return this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(FadeOutTime)
.toFloat();
}
/**
*
* @param curveIndex
* @return
*/
public getMotionCurveSegmentCount(curveIndex: number): number {
return this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(Segments)
.getVector()
.getSize();
}
/**
*
* @param curveIndex
* @param segmentIndex
* @return
*/
public getMotionCurveSegment(
curveIndex: number,
segmentIndex: number
): number {
return this._json
.getRoot()
.getValueByString(Curves)
.getValueByIndex(curveIndex)
.getValueByString(Segments)
.getValueByIndex(segmentIndex)
.toFloat();
}
/**
*
* @return
*/
public getEventCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(UserDataCount)
.toInt();
}
/**
*
* @return
*/
public getTotalEventValueSize(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(TotalUserDataSize)
.toInt();
}
/**
*
* @param userDataIndex
* @return []
*/
public getEventTime(userDataIndex: number): number {
return this._json
.getRoot()
.getValueByString(UserData)
.getValueByIndex(userDataIndex)
.getValueByString(Time)
.toInt();
}
/**
*
* @param userDataIndex
* @return
*/
public getEventValue(userDataIndex: number): csmString {
return new csmString(
this._json
.getRoot()
.getValueByString(UserData)
.getValueByIndex(userDataIndex)
.getValueByString(Value)
.getRawString()
);
}
_json: CubismJson; // motion3.jsonのデータ
}
}

View File

@ -0,0 +1,124 @@
/**
* 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 cubismmotionqueuemanager } from './cubismmotionqueuemanager';
import { Live2DCubismFramework as acubismmotion } from './acubismmotion';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import CubismMotionQueueEntryHandle = cubismmotionqueuemanager.CubismMotionQueueEntryHandle;
import CubismModel = cubismmodel.CubismModel;
import ACubismMotion = acubismmotion.ACubismMotion;
import CubismMotionQueueManager = cubismmotionqueuemanager.CubismMotionQueueManager;
export namespace Live2DCubismFramework {
/**
*
*
*
*/
export class CubismMotionManager extends CubismMotionQueueManager {
/**
*
*/
public constructor() {
super();
this._currentPriority = 0;
this._reservePriority = 0;
}
/**
*
* @return
*/
public getCurrentPriority(): number {
return this._currentPriority;
}
/**
*
* @return
*/
public getReservePriority(): number {
return this._reservePriority;
}
/**
*
* @param val
*/
public setReservePriority(val: number): void {
this._reservePriority = val;
}
/**
*
*
* @param motion
* @param autoDelete true
* @param priority
* @return IsFinished()使-1
*/
public startMotionPriority(
motion: ACubismMotion,
autoDelete: boolean,
priority: number
): CubismMotionQueueEntryHandle {
if (priority == this._reservePriority) {
this._reservePriority = 0; // 予約を解除
}
this._currentPriority = priority; // 再生中モーションの優先度を設定
return super.startMotion(motion, autoDelete, this._userTimeSeconds);
}
/**
*
*
* @param model
* @param deltaTimeSeconds []
* @return true
* @return false
*/
public updateMotion(model: CubismModel, deltaTimeSeconds: number): boolean {
this._userTimeSeconds += deltaTimeSeconds;
const updated: boolean = super.doUpdateMotion(
model,
this._userTimeSeconds
);
if (this.isFinished()) {
this._currentPriority = 0; // 再生中のモーションの優先度を解除
}
return updated;
}
/**
*
*
* @param priority
* @return true
* @return false
*/
public reserveMotion(priority: number): boolean {
if (
priority <= this._reservePriority ||
priority <= this._currentPriority
) {
return false;
}
this._reservePriority = priority;
return true;
}
_currentPriority: number; // 現在再生中のモーションの優先度
_reservePriority: number; // 再生予定のモーションの優先度。再生中は0になる。モーションファイルを別スレッドで読み込むときの機能。
}
}

View File

@ -0,0 +1,219 @@
/**
* 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 acubismmotion } from './acubismmotion';
import { Live2DCubismFramework as cubismmotionqueuemanager } from './cubismmotionqueuemanager';
import CubismMotionQueueEntryHandle = cubismmotionqueuemanager.CubismMotionQueueEntryHandle;
import ACubismMotion = acubismmotion.ACubismMotion;
export namespace Live2DCubismFramework {
/**
* CubismMotionQueueManager
*/
export class CubismMotionQueueEntry {
/**
*
*/
public constructor() {
this._autoDelete = false;
this._motion = null;
this._available = true;
this._finished = false;
this._started = false;
this._startTimeSeconds = -1.0;
this._fadeInStartTimeSeconds = 0.0;
this._endTimeSeconds = -1.0;
this._stateTimeSeconds = 0.0;
this._stateWeight = 0.0;
this._lastEventCheckSeconds = 0.0;
this._motionQueueEntryHandle = this;
}
/**
*
*/
public release(): void {
if (this._autoDelete && this._motion) {
ACubismMotion.delete(this._motion); //
}
}
/**
*
* @param fadeOutSeconds []
* @param userTimeSeconds []
*/
public startFadeout(fadeoutSeconds: number, userTimeSeconds: number): void {
const newEndTimeSeconds: number = userTimeSeconds + fadeoutSeconds;
if (
this._endTimeSeconds < 0.0 ||
newEndTimeSeconds < this._endTimeSeconds
) {
this._endTimeSeconds = newEndTimeSeconds;
}
}
/**
*
*
* @return true
* @return false
*/
public isFinished(): boolean {
return this._finished;
}
/**
*
* @return true
* @return false
*/
public isStarted(): boolean {
return this._started;
}
/**
*
* @return []
*/
public getStartTime(): number {
return this._startTimeSeconds;
}
/**
*
* @return []
*/
public getFadeInStartTime(): number {
return this._fadeInStartTimeSeconds;
}
/**
*
* @return
*/
public getEndTime(): number {
return this._endTimeSeconds;
}
/**
*
* @param startTime
*/
public setStartTime(startTime: number): void {
this._startTimeSeconds = startTime;
}
/**
*
* @param startTime []
*/
public setFadeInStartTime(startTime: number): void {
this._fadeInStartTimeSeconds = startTime;
}
/**
*
* @param endTime []
*/
public setEndTime(endTime: number): void {
this._endTimeSeconds = endTime;
}
/**
*
* @param f true
*/
public setIsFinished(f: boolean): void {
this._finished = f;
}
/**
*
* @param f true
*/
public setIsStarted(f: boolean): void {
this._started = f;
}
/**
*
* @return true
* @return false
*/
public isAvailable(): boolean {
return this._available;
}
/**
*
* @param v true
*/
public setIsAvailable(v: boolean): void {
this._available = v;
}
/**
*
* @param timeSeconds []
* @param weight
*/
public setState(timeSeconds: number, weight: number): void {
this._stateTimeSeconds = timeSeconds;
this._stateWeight = weight;
}
/**
*
* @return []
*/
public getStateTime(): number {
return this._stateTimeSeconds;
}
/**
*
* @return
*/
public getStateWeight(): number {
return this._stateWeight;
}
/**
*
*
* @return []
*/
public getLastCheckEventTime(): number {
return this._lastEventCheckSeconds;
}
/**
*
* @param checkTime []
*/
public setLastCheckEventTime(checkTime: number): void {
this._lastEventCheckSeconds = checkTime;
}
_autoDelete: boolean; // 自動削除
_motion: ACubismMotion; // モーション
_available: boolean; // 有効化フラグ
_finished: boolean; // 終了フラグ
_started: boolean; // 開始フラグ
_startTimeSeconds: number; // モーション再生開始時刻[秒]
_fadeInStartTimeSeconds: number; // フェードイン開始時刻(ループの時は初回のみ)[秒]
_endTimeSeconds: number; // 終了予定時刻[秒]
_stateTimeSeconds: number; // 時刻の状態[秒]
_stateWeight: number; // 重みの状態
_lastEventCheckSeconds: number; // 最終のMotion側のチェックした時間
_motionQueueEntryHandle: CubismMotionQueueEntryHandle; // インスタンスごとに一意の値を持つ識別番号
}
}

View File

@ -0,0 +1,347 @@
/**
* 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 acubismmotion } from './acubismmotion';
import { Live2DCubismFramework as cubismmotionqueueentry } from './cubismmotionqueueentry';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as csmstring } from '../type/csmstring';
import csmString = csmstring.csmString;
import CubismModel = cubismmodel.CubismModel;
import csmVector = csmvector.csmVector;
import iterator = csmvector.iterator;
import CubismMotionQueueEntry = cubismmotionqueueentry.CubismMotionQueueEntry;
import ACubismMotion = acubismmotion.ACubismMotion;
export namespace Live2DCubismFramework {
/**
*
*
* CubismMotionACubismMotion使
*
* @note StartMotion()
*
* CubismMotionQueueManager使
*/
export class CubismMotionQueueManager {
/**
*
*/
public constructor() {
this._userTimeSeconds = 0.0;
this._eventCallBack = null;
this._eventCustomData = null;
this._motions = new csmVector<CubismMotionQueueEntry>();
}
/**
*
*/
public release(): void {
for (let i = 0; i < this._motions.getSize(); ++i) {
if (this._motions.at(i)) {
this._motions.at(i).release();
this._motions.set(i, void 0);
this._motions.set(i, null);
}
}
this._motions = null;
}
/**
*
*
*
*
* @param motion
* @param autoDelete true
* @param userTimeSeconds []
* @return IsFinished()使-1
*/
public startMotion(
motion: ACubismMotion,
autoDelete: boolean,
userTimeSeconds: number
): CubismMotionQueueEntryHandle {
if (motion == null) {
return InvalidMotionQueueEntryHandleValue;
}
let motionQueueEntry: CubismMotionQueueEntry = null;
// 既にモーションがあれば終了フラグを立てる
for (let i = 0; i < this._motions.getSize(); ++i) {
motionQueueEntry = this._motions.at(i);
if (motionQueueEntry == null) {
continue;
}
motionQueueEntry.startFadeout(
motionQueueEntry._motion.getFadeOutTime(),
userTimeSeconds
); // フェードアウトを開始し終了する
}
motionQueueEntry = new CubismMotionQueueEntry(); // 終了時に破棄する
motionQueueEntry._autoDelete = autoDelete;
motionQueueEntry._motion = motion;
this._motions.pushBack(motionQueueEntry);
return motionQueueEntry._motionQueueEntryHandle;
}
/**
*
* @return true
* @return false
*/
public isFinished(): boolean {
// ------- 処理を行う -------
// 既にモーションがあれば終了フラグを立てる
for (
let ite: iterator<CubismMotionQueueEntry> = this._motions.begin();
ite.notEqual(this._motions.end());
) {
let motionQueueEntry: CubismMotionQueueEntry = ite.ptr();
if (motionQueueEntry == null) {
ite = this._motions.erase(ite); // 削除
continue;
}
const motion: ACubismMotion = motionQueueEntry._motion;
if (motion == null) {
motionQueueEntry.release();
motionQueueEntry = void 0;
motionQueueEntry = null;
ite = this._motions.erase(ite); // 削除
continue;
}
// ----- 終了済みの処理があれば削除する ------
if (!motionQueueEntry.isFinished()) {
return false;
} else {
ite.preIncrement();
}
}
return true;
}
/**
*
* @param motionQueueEntryNumber
* @return true
* @return false
*/
public isFinishedByHandle(
motionQueueEntryNumber: CubismMotionQueueEntryHandle
): boolean {
// 既にモーションがあれば終了フラグを立てる
for (
let ite: iterator<CubismMotionQueueEntry> = this._motions.begin();
ite.notEqual(this._motions.end());
ite.increment()
) {
const motionQueueEntry: CubismMotionQueueEntry = ite.ptr();
if (motionQueueEntry == null) {
continue;
}
if (
motionQueueEntry._motionQueueEntryHandle == motionQueueEntryNumber &&
!motionQueueEntry.isFinished()
) {
return false;
}
}
return true;
}
/**
*
*/
public stopAllMotions(): void {
// ------- 処理を行う -------
// 既にモーションがあれば終了フラグを立てる
for (
let ite: iterator<CubismMotionQueueEntry> = this._motions.begin();
ite.notEqual(this._motions.end());
) {
let motionQueueEntry: CubismMotionQueueEntry = ite.ptr();
if (motionQueueEntry == null) {
ite = this._motions.erase(ite);
continue;
}
// ----- 終了済みの処理があれば削除する ------
motionQueueEntry.release();
motionQueueEntry = void 0;
motionQueueEntry = null;
ite = this._motions.erase(ite); // 削除
}
}
/**
* CubismMotionQueueEntry
* @param motionQueueEntryNumber
* @return CubismMotionQueueEntry
* @return null
*/
public getCubismMotionQueueEntry(
motionQueueEntryNumber: any
): CubismMotionQueueEntry {
//------- 処理を行う -------
// 既にモーションがあれば終了フラグを立てる
for (
let ite: iterator<CubismMotionQueueEntry> = this._motions.begin();
ite.notEqual(this._motions.end());
ite.preIncrement()
) {
const motionQueueEntry: CubismMotionQueueEntry = ite.ptr();
if (motionQueueEntry == null) {
continue;
}
if (
motionQueueEntry._motionQueueEntryHandle == motionQueueEntryNumber
) {
return motionQueueEntry;
}
}
return null;
}
/**
* Callback
*
* @param callback
* @param customData
*/
public setEventCallback(
callback: CubismMotionEventFunction,
customData: any = null
): void {
this._eventCallBack = callback;
this._eventCustomData = customData;
}
/**
*
*
* @param model
* @param userTimeSeconds []
* @return true
* @return false ()
*/
public doUpdateMotion(
model: CubismModel,
userTimeSeconds: number
): boolean {
let updated = false;
// ------- 処理を行う --------
// 既にモーションがあれば終了フラグを立てる
for (
let ite: iterator<CubismMotionQueueEntry> = this._motions.begin();
ite.notEqual(this._motions.end());
) {
let motionQueueEntry: CubismMotionQueueEntry = ite.ptr();
if (motionQueueEntry == null) {
ite = this._motions.erase(ite); // 削除
continue;
}
const motion: ACubismMotion = motionQueueEntry._motion;
if (motion == null) {
motionQueueEntry.release();
motionQueueEntry = void 0;
motionQueueEntry = null;
ite = this._motions.erase(ite); // 削除
continue;
}
// ------ 値を反映する ------
motion.updateParameters(model, motionQueueEntry, userTimeSeconds);
updated = true;
// ------ ユーザトリガーイベントを検査する ----
const firedList: csmVector<csmString> = motion.getFiredEvent(
motionQueueEntry.getLastCheckEventTime() -
motionQueueEntry.getStartTime(),
userTimeSeconds - motionQueueEntry.getStartTime()
);
for (let i = 0; i < firedList.getSize(); ++i) {
this._eventCallBack(this, firedList.at(i), this._eventCustomData);
}
motionQueueEntry.setLastCheckEventTime(userTimeSeconds);
// ------ 終了済みの処理があれば削除する ------
if (motionQueueEntry.isFinished()) {
motionQueueEntry.release();
motionQueueEntry = void 0;
motionQueueEntry = null;
ite = this._motions.erase(ite); // 削除
} else {
ite.preIncrement();
}
}
return updated;
}
_userTimeSeconds: number; // デルタ時間の積算値[秒]
_motions: csmVector<CubismMotionQueueEntry>; // モーション
_eventCallBack: CubismMotionEventFunction; // コールバック関数
_eventCustomData: any; // コールバックに戻されるデータ
}
/**
*
*
*
* @param caller CubismMotionQueueManager
* @param eventValue
* @param customData
*/
export interface CubismMotionEventFunction {
(
caller: CubismMotionQueueManager,
eventValue: csmString,
customData: any
): void;
}
/**
*
*
*
*/
export declare type CubismMotionQueueEntryHandle = any;
export const InvalidMotionQueueEntryHandleValue: CubismMotionQueueEntryHandle = -1;
}

View File

@ -0,0 +1,949 @@
/**
* 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 cubismphysicsinternal } from './cubismphysicsinternal';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import { Live2DCubismFramework as cubismvector2 } from '../math/cubismvector2';
import { Live2DCubismFramework as cubismmath } from '../math/cubismmath';
import { Live2DCubismFramework as cubismphysicsjson } from './cubismphysicsjson';
import CubismPhysicsJson = cubismphysicsjson.CubismPhysicsJson;
import CubismMath = cubismmath.CubismMath;
import CubismPhysicsRig = cubismphysicsinternal.CubismPhysicsRig;
import CubismPhysicsSubRig = cubismphysicsinternal.CubismPhysicsSubRig;
import CubismPhysicsInput = cubismphysicsinternal.CubismPhysicsInput;
import CubismPhysicsOutput = cubismphysicsinternal.CubismPhysicsOutput;
import CubismPhysicsParticle = cubismphysicsinternal.CubismPhysicsParticle;
import CubismPhysicsSource = cubismphysicsinternal.CubismPhysicsSource;
import CubismPhysicsTargetType = cubismphysicsinternal.CubismPhysicsTargetType;
import CubismPhysicsNormalization = cubismphysicsinternal.CubismPhysicsNormalization;
import CubismVector2 = cubismvector2.CubismVector2;
import CubismModel = cubismmodel.CubismModel;
export namespace Live2DCubismFramework {
// physics types tags.
const PhysicsTypeTagX = 'X';
const PhysicsTypeTagY = 'Y';
const PhysicsTypeTagAngle = 'Angle';
// Constant of air resistance.
const AirResistance = 5.0;
// Constant of maximum weight of input and output ratio.
const MaximumWeight = 100.0;
// Constant of threshold of movement.
const MovementThreshold = 0.001;
/**
*
*/
export class CubismPhysics {
/**
*
* @param buffer physics3.json
* @param size
* @return
*/
public static create(buffer: ArrayBuffer, size: number): CubismPhysics {
const ret: CubismPhysics = new CubismPhysics();
ret.parse(buffer, size);
ret._physicsRig.gravity.y = 0;
return ret;
}
/**
*
* @param physics
*/
public static delete(physics: CubismPhysics): void {
if (physics != null) {
physics.release();
physics = null;
}
}
/**
*
* @param model
* @param deltaTimeSeconds []
*/
public evaluate(model: CubismModel, deltaTimeSeconds: number): void {
let totalAngle: { angle: number };
let weight: number;
let radAngle: number;
let outputValue: number;
const totalTranslation: CubismVector2 = new CubismVector2();
let currentSetting: CubismPhysicsSubRig;
let currentInput: CubismPhysicsInput[];
let currentOutput: CubismPhysicsOutput[];
let currentParticles: CubismPhysicsParticle[];
let parameterValue: Float32Array;
let parameterMaximumValue: Float32Array;
let parameterMinimumValue: Float32Array;
let parameterDefaultValue: Float32Array;
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.0 };
totalTranslation.x = 0.0;
totalTranslation.y = 0.0;
currentSetting = this._physicsRig.settings.at(settingIndex);
currentInput = this._physicsRig.inputs.get(
currentSetting.baseInputIndex
);
currentOutput = this._physicsRig.outputs.get(
currentSetting.baseOutputIndex
);
currentParticles = this._physicsRig.particles.get(
currentSetting.baseParticleIndex
);
// Load input parameters
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[0].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);
// Calculate particles position.
updateParticles(
currentParticles,
currentSetting.particleCount,
totalTranslation,
totalAngle.angle,
this._options.wind,
MovementThreshold * currentSetting.normalizationPosition.maximum,
deltaTimeSeconds,
AirResistance
);
// Update output parameters.
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: CubismVector2 = 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: number =
currentOutput[i].destinationParameterIndex;
const outParameterValue: Float32Array =
!Float32Array.prototype.slice &&
'subarray' in Float32Array.prototype
? JSON.parse(
JSON.stringify(
parameterValue.subarray(destinationParameterIndex)
)
) // 値渡しするため、JSON.parse, JSON.stringify
: parameterValue.slice(destinationParameterIndex);
updateOutputParameterValue(
outParameterValue,
parameterMinimumValue[destinationParameterIndex],
parameterMaximumValue[destinationParameterIndex],
outputValue,
currentOutput[i]
);
// 値を反映
for (
let offset: number = destinationParameterIndex, outParamIndex = 0;
offset < parameterValue.length;
offset++, outParamIndex++
) {
parameterValue[offset] = outParameterValue[outParamIndex];
}
}
}
}
/**
*
* @param options
*/
public setOptions(options: Options): void {
this._options = options;
}
/**
*
* @return
*/
public getOption(): Options {
return this._options;
}
/**
*
*/
public constructor() {
this._physicsRig = null;
// set default options
this._options = new Options();
this._options.gravity.y = -1.0;
this._options.gravity.x = 0;
this._options.wind.x = 0;
this._options.wind.y = 0;
}
/**
*
*/
public release(): void {
this._physicsRig = void 0;
this._physicsRig = null;
}
/**
* physics3.json
* @param physicsJson physics3.json
* @param size
*/
public parse(physicsJson: ArrayBuffer, size: number): void {
this._physicsRig = new CubismPhysicsRig();
let json: CubismPhysicsJson = new CubismPhysicsJson(physicsJson, size);
this._physicsRig.gravity = json.getGravity();
this._physicsRig.wind = json.getWind();
this._physicsRig.subRigCount = json.getSubRigCount();
this._physicsRig.settings.updateSize(
this._physicsRig.subRigCount,
CubismPhysicsSubRig,
true
);
this._physicsRig.inputs.updateSize(
json.getTotalInputCount(),
CubismPhysicsInput,
true
);
this._physicsRig.outputs.updateSize(
json.getTotalOutputCount(),
CubismPhysicsOutput,
true
);
this._physicsRig.particles.updateSize(
json.getVertexCount(),
CubismPhysicsParticle,
true
);
let inputIndex = 0,
outputIndex = 0,
particleIndex = 0;
for (let i = 0; i < this._physicsRig.settings.getSize(); ++i) {
this._physicsRig.settings.at(
i
).normalizationPosition.minimum = json.getNormalizationPositionMinimumValue(
i
);
this._physicsRig.settings.at(
i
).normalizationPosition.maximum = json.getNormalizationPositionMaximumValue(
i
);
this._physicsRig.settings.at(
i
).normalizationPosition.defalut = json.getNormalizationPositionDefaultValue(
i
);
this._physicsRig.settings.at(
i
).normalizationAngle.minimum = json.getNormalizationAngleMinimumValue(
i
);
this._physicsRig.settings.at(
i
).normalizationAngle.maximum = json.getNormalizationAngleMaximumValue(
i
);
this._physicsRig.settings.at(
i
).normalizationAngle.defalut = json.getNormalizationAngleDefaultValue(
i
);
// Input
this._physicsRig.settings.at(i).inputCount = json.getInputCount(i);
this._physicsRig.settings.at(i).baseInputIndex = inputIndex;
for (let j = 0; j < this._physicsRig.settings.at(i).inputCount; ++j) {
this._physicsRig.inputs.at(inputIndex + j).sourceParameterIndex = -1;
this._physicsRig.inputs.at(
inputIndex + j
).weight = json.getInputWeight(i, j);
this._physicsRig.inputs.at(
inputIndex + j
).reflect = json.getInputReflect(i, j);
if (json.getInputType(i, j) == PhysicsTypeTagX) {
this._physicsRig.inputs.at(inputIndex + j).type =
CubismPhysicsSource.CubismPhysicsSource_X;
this._physicsRig.inputs.at(
inputIndex + j
).getNormalizedParameterValue = getInputTranslationXFromNormalizedParameterValue;
} else if (json.getInputType(i, j) == PhysicsTypeTagY) {
this._physicsRig.inputs.at(inputIndex + j).type =
CubismPhysicsSource.CubismPhysicsSource_Y;
this._physicsRig.inputs.at(
inputIndex + j
).getNormalizedParameterValue = getInputTranslationYFromNormalizedParamterValue;
} else if (json.getInputType(i, j) == PhysicsTypeTagAngle) {
this._physicsRig.inputs.at(inputIndex + j).type =
CubismPhysicsSource.CubismPhysicsSource_Angle;
this._physicsRig.inputs.at(
inputIndex + j
).getNormalizedParameterValue = getInputAngleFromNormalizedParameterValue;
}
this._physicsRig.inputs.at(inputIndex + j).source.targetType =
CubismPhysicsTargetType.CubismPhysicsTargetType_Parameter;
this._physicsRig.inputs.at(
inputIndex + j
).source.id = json.getInputSourceId(i, j);
}
inputIndex += this._physicsRig.settings.at(i).inputCount;
// Output
this._physicsRig.settings.at(i).outputCount = json.getOutputCount(i);
this._physicsRig.settings.at(i).baseOutputIndex = outputIndex;
for (let j = 0; j < this._physicsRig.settings.at(i).outputCount; ++j) {
this._physicsRig.outputs.at(
outputIndex + j
).destinationParameterIndex = -1;
this._physicsRig.outputs.at(
outputIndex + j
).vertexIndex = json.getOutputVertexIndex(i, j);
this._physicsRig.outputs.at(
outputIndex + j
).angleScale = json.getOutputAngleScale(i, j);
this._physicsRig.outputs.at(
outputIndex + j
).weight = json.getOutputWeight(i, j);
this._physicsRig.outputs.at(outputIndex + j).destination.targetType =
CubismPhysicsTargetType.CubismPhysicsTargetType_Parameter;
this._physicsRig.outputs.at(
outputIndex + j
).destination.id = json.getOutputDestinationId(i, j);
if (json.getOutputType(i, j) == PhysicsTypeTagX) {
this._physicsRig.outputs.at(outputIndex + j).type =
CubismPhysicsSource.CubismPhysicsSource_X;
this._physicsRig.outputs.at(
outputIndex + j
).getValue = getOutputTranslationX;
this._physicsRig.outputs.at(
outputIndex + j
).getScale = getOutputScaleTranslationX;
} else if (json.getOutputType(i, j) == PhysicsTypeTagY) {
this._physicsRig.outputs.at(outputIndex + j).type =
CubismPhysicsSource.CubismPhysicsSource_Y;
this._physicsRig.outputs.at(
outputIndex + j
).getValue = getOutputTranslationY;
this._physicsRig.outputs.at(
outputIndex + j
).getScale = getOutputScaleTranslationY;
} else if (json.getOutputType(i, j) == PhysicsTypeTagAngle) {
this._physicsRig.outputs.at(outputIndex + j).type =
CubismPhysicsSource.CubismPhysicsSource_Angle;
this._physicsRig.outputs.at(
outputIndex + j
).getValue = getOutputAngle;
this._physicsRig.outputs.at(
outputIndex + j
).getScale = getOutputScaleAngle;
}
this._physicsRig.outputs.at(
outputIndex + j
).reflect = json.getOutputReflect(i, j);
}
outputIndex += this._physicsRig.settings.at(i).outputCount;
// Particle
this._physicsRig.settings.at(i).particleCount = json.getParticleCount(
i
);
this._physicsRig.settings.at(i).baseParticleIndex = particleIndex;
for (
let j = 0;
j < this._physicsRig.settings.at(i).particleCount;
++j
) {
this._physicsRig.particles.at(
particleIndex + j
).mobility = json.getParticleMobility(i, j);
this._physicsRig.particles.at(
particleIndex + j
).delay = json.getParticleDelay(i, j);
this._physicsRig.particles.at(
particleIndex + j
).acceleration = json.getParticleAcceleration(i, j);
this._physicsRig.particles.at(
particleIndex + j
).radius = json.getParticleRadius(i, j);
this._physicsRig.particles.at(
particleIndex + j
).position = json.getParticlePosition(i, j);
}
particleIndex += this._physicsRig.settings.at(i).particleCount;
}
this.initialize();
json.release();
json = void 0;
json = null;
}
/**
*
*/
public initialize(): void {
let strand: CubismPhysicsParticle[];
let currentSetting: CubismPhysicsSubRig;
let radius: CubismVector2;
for (
let settingIndex = 0;
settingIndex < this._physicsRig.subRigCount;
++settingIndex
) {
currentSetting = this._physicsRig.settings.at(settingIndex);
strand = this._physicsRig.particles.get(
currentSetting.baseParticleIndex
);
// Initialize the top of particle.
strand[0].initialPosition = new CubismVector2(0.0, 0.0);
strand[0].lastPosition = new CubismVector2(
strand[0].initialPosition.x,
strand[0].initialPosition.y
);
strand[0].lastGravity = new CubismVector2(0.0, -1.0);
strand[0].lastGravity.y *= -1.0;
strand[0].velocity = new CubismVector2(0.0, 0.0);
strand[0].force = new CubismVector2(0.0, 0.0);
// Initialize paritcles.
for (let i = 1; i < currentSetting.particleCount; ++i) {
radius = new CubismVector2(0.0, 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.0, -1.0);
strand[i].lastGravity.y *= -1.0;
strand[i].velocity = new CubismVector2(0.0, 0.0);
strand[i].force = new CubismVector2(0.0, 0.0);
}
}
}
_physicsRig: CubismPhysicsRig; // 物理演算のデータ
_options: Options; // オプション
}
/**
*
*/
export class Options {
constructor() {
this.gravity = new CubismVector2(0, 0);
this.wind = new CubismVector2(0, 0);
}
gravity: CubismVector2; // 重力方向
wind: CubismVector2; // 風の方向
}
/**
* Gets sign.
*
* @param value Evaluation target value.
*
* @return Sign of value.
*/
function sign(value: number): number {
let ret = 0;
if (value > 0.0) {
ret = 1;
} else if (value < 0.0) {
ret = -1;
}
return ret;
}
function getInputTranslationXFromNormalizedParameterValue(
targetTranslation: CubismVector2,
targetAngle: { angle: number },
value: number,
parameterMinimumValue: number,
parameterMaximumValue: number,
parameterDefaultValue: number,
normalizationPosition: CubismPhysicsNormalization,
normalizationAngle: CubismPhysicsNormalization,
isInverted: boolean,
weight: number
): void {
targetTranslation.x +=
normalizeParameterValue(
value,
parameterMinimumValue,
parameterMaximumValue,
parameterDefaultValue,
normalizationPosition.minimum,
normalizationPosition.maximum,
normalizationPosition.defalut,
isInverted
) * weight;
}
function getInputTranslationYFromNormalizedParamterValue(
targetTranslation: CubismVector2,
targetAngle: { angle: number },
value: number,
parameterMinimumValue: number,
parameterMaximumValue: number,
parameterDefaultValue: number,
normalizationPosition: CubismPhysicsNormalization,
normalizationAngle: CubismPhysicsNormalization,
isInverted: boolean,
weight: number
): void {
targetTranslation.y +=
normalizeParameterValue(
value,
parameterMinimumValue,
parameterMaximumValue,
parameterDefaultValue,
normalizationPosition.minimum,
normalizationPosition.maximum,
normalizationPosition.defalut,
isInverted
) * weight;
}
function getInputAngleFromNormalizedParameterValue(
targetTranslation: CubismVector2,
targetAngle: { angle: number },
value: number,
parameterMinimumValue: number,
parameterMaximumValue: number,
parameterDefaultValue: number,
normalizaitionPosition: CubismPhysicsNormalization,
normalizationAngle: CubismPhysicsNormalization,
isInverted: boolean,
weight: number
): void {
targetAngle.angle +=
normalizeParameterValue(
value,
parameterMinimumValue,
parameterMaximumValue,
parameterDefaultValue,
normalizationAngle.minimum,
normalizationAngle.maximum,
normalizationAngle.defalut,
isInverted
) * weight;
}
function getOutputTranslationX(
translation: CubismVector2,
particles: CubismPhysicsParticle[],
particleIndex: number,
isInverted: boolean,
parentGravity: CubismVector2
): number {
let outputValue: number = translation.x;
if (isInverted) {
outputValue *= -1.0;
}
return outputValue;
}
function getOutputTranslationY(
translation: CubismVector2,
particles: CubismPhysicsParticle[],
particleIndex: number,
isInverted: boolean,
parentGravity: CubismVector2
): number {
let outputValue: number = translation.y;
if (isInverted) {
outputValue *= -1.0;
}
return outputValue;
}
function getOutputAngle(
translation: CubismVector2,
particles: CubismPhysicsParticle[],
particleIndex: number,
isInverted: boolean,
parentGravity: CubismVector2
): number {
let outputValue: number;
if (particleIndex >= 2) {
parentGravity = particles[particleIndex - 1].position.substract(
particles[particleIndex - 2].position
);
} else {
parentGravity = parentGravity.multiplyByScaler(-1.0);
}
outputValue = CubismMath.directionToRadian(parentGravity, translation);
if (isInverted) {
outputValue *= -1.0;
}
return outputValue;
}
function getRangeValue(min: number, max: number): number {
const maxValue: number = CubismMath.max(min, max);
const minValue: number = CubismMath.min(min, max);
return CubismMath.abs(maxValue - minValue);
}
function getDefaultValue(min: number, max: number): number {
const minValue: number = CubismMath.min(min, max);
return minValue + getRangeValue(min, max) / 2.0;
}
function getOutputScaleTranslationX(
translationScale: CubismVector2,
angleScale: number
): number {
return JSON.parse(JSON.stringify(translationScale.x));
}
function getOutputScaleTranslationY(
translationScale: CubismVector2,
angleScale: number
): number {
return JSON.parse(JSON.stringify(translationScale.y));
}
function getOutputScaleAngle(
translationScale: CubismVector2,
angleScale: number
): number {
return JSON.parse(JSON.stringify(angleScale));
}
/**
* Updates particles.
*
* @param strand Target array of particle.
* @param strandCount Count of particle.
* @param totalTranslation Total translation value.
* @param totalAngle Total angle.
* @param windDirection Direction of Wind.
* @param thresholdValue Threshold of movement.
* @param deltaTimeSeconds Delta time.
* @param airResistance Air resistance.
*/
function updateParticles(
strand: CubismPhysicsParticle[],
strandCount: number,
totalTranslation: CubismVector2,
totalAngle: number,
windDirection: CubismVector2,
thresholdValue: number,
deltaTimeSeconds: number,
airResistance: number
) {
let totalRadian: number;
let delay: number;
let radian: number;
let currentGravity: CubismVector2;
let direction: CubismVector2 = new CubismVector2(0.0, 0.0);
let velocity: CubismVector2 = new CubismVector2(0.0, 0.0);
let force: CubismVector2 = new CubismVector2(0.0, 0.0);
let newDirection: CubismVector2 = new CubismVector2(0.0, 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.0;
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.0;
}
if (delay != 0.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, 0.0);
strand[i].lastGravity = new CubismVector2(
currentGravity.x,
currentGravity.y
);
}
}
/**
* Updates output parameter value.
* @param parameterValue Target parameter value.
* @param parameterValueMinimum Minimum of parameter value.
* @param parameterValueMaximum Maximum of parameter value.
* @param translation Translation value.
*/
function updateOutputParameterValue(
parameterValue: Float32Array,
parameterValueMinimum: number,
parameterValueMaximum: number,
translation: number,
output: CubismPhysicsOutput
): void {
let outputScale: number;
let value: number;
let weight: number;
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.0) {
parameterValue[0] = value;
} else {
value = parameterValue[0] * (1.0 - weight) + value * weight;
parameterValue[0] = value;
}
}
function normalizeParameterValue(
value: number,
parameterMinimum: number,
parameterMaximum: number,
parameterDefault: number,
normalizedMinimum: number,
normalizedMaximum: number,
normalizedDefault: number,
isInverted: boolean
) {
let result = 0.0;
const maxValue: number = CubismMath.max(parameterMaximum, parameterMinimum);
if (maxValue < value) {
value = maxValue;
}
const minValue: number = CubismMath.min(parameterMaximum, parameterMinimum);
if (minValue > value) {
value = minValue;
}
const minNormValue: number = CubismMath.min(
normalizedMinimum,
normalizedMaximum
);
const maxNormValue: number = CubismMath.max(
normalizedMinimum,
normalizedMaximum
);
const middleNormValue: number = normalizedDefault;
const middleValue: number = getDefaultValue(minValue, maxValue);
const paramValue: number = value - middleValue;
switch (sign(paramValue)) {
case 1: {
const nLength: number = maxNormValue - middleNormValue;
const pLength: number = maxValue - middleValue;
if (pLength != 0.0) {
result = paramValue * (nLength / pLength);
result += middleNormValue;
}
break;
}
case -1: {
const nLength: number = minNormValue - middleNormValue;
const pLength: number = minValue - middleValue;
if (pLength != 0.0) {
result = paramValue * (nLength / pLength);
result += middleNormValue;
}
break;
}
case 0: {
result = middleNormValue;
break;
}
default: {
break;
}
}
return isInverted ? result : result * -1.0;
}
}

View File

@ -0,0 +1,225 @@
/**
* 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 '../math/cubismvector2';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as csmvector } from '../type/csmvector';
import csmVector = csmvector.csmVector;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismVector2 = cubismvector2.CubismVector2;
export namespace Live2DCubismFramework {
/**
*
*/
export enum CubismPhysicsTargetType {
CubismPhysicsTargetType_Parameter // パラメータに対して適用
}
/**
*
*/
export enum CubismPhysicsSource {
CubismPhysicsSource_X, // X軸の位置から
CubismPhysicsSource_Y, // Y軸の位置から
CubismPhysicsSource_Angle // 角度から
}
/**
* @brief 使
*
* 使
*/
export class PhysicsJsonEffectiveForces {
constructor() {
this.gravity = new CubismVector2(0, 0);
this.wind = new CubismVector2(0, 0);
}
gravity: CubismVector2; // 重力
wind: CubismVector2; // 風
}
/**
*
*/
export class CubismPhysicsParameter {
id: CubismIdHandle; // パラメータ
targetType: CubismPhysicsTargetType; // 適用先の種類
}
/**
*
*/
export class CubismPhysicsNormalization {
minimum: number; // 最大値
maximum: number; // 最小値
defalut: number; // デフォルト値
}
/**
* 使
*/
export 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);
}
initialPosition: CubismVector2; // 初期位置
mobility: number; // 動きやすさ
delay: number; // 遅れ
acceleration: number; // 加速度
radius: number; // 距離
position: CubismVector2; // 現在の位置
lastPosition: CubismVector2; // 最後の位置
lastGravity: CubismVector2; // 最後の重力
force: CubismVector2; // 現在かかっている力
velocity: CubismVector2; // 現在の速度
}
/**
*
*/
export class CubismPhysicsSubRig {
constructor() {
this.normalizationPosition = new CubismPhysicsNormalization();
this.normalizationAngle = new CubismPhysicsNormalization();
}
inputCount: number; // 入力の個数
outputCount: number; // 出力の個数
particleCount: number; // 物理点の個数
baseInputIndex: number; // 入力の最初のインデックス
baseOutputIndex: number; // 出力の最初のインデックス
baseParticleIndex: number; // 物理点の最初のインデックス
normalizationPosition: CubismPhysicsNormalization; // 正規化された位置
normalizationAngle: CubismPhysicsNormalization; // 正規化された角度
}
/**
*
* @param targetTranslation // 演算結果の移動値
* @param targetAngle // 演算結果の角度
* @param value // パラメータの値
* @param parameterMinimunValue // パラメータの最小値
* @param parameterMaximumValue // パラメータの最大値
* @param parameterDefaultValue // パラメータのデフォルト値
* @param normalizationPosition // 正規化された位置
* @param normalizationAngle // 正規化された角度
* @param isInverted // 値が反転されているか?
* @param weight // 重み
*/
export interface normalizedPhysicsParameterValueGetter {
(
targetTranslation: CubismVector2,
targetAngle: { angle: number },
value: number,
parameterMinimunValue: number,
parameterMaximumValue: number,
parameterDefaultValue: number,
normalizationPosition: CubismPhysicsNormalization,
normalizationAngle: CubismPhysicsNormalization,
isInverted: boolean,
weight: number
): void;
}
/**
*
* @param translation
* @param particles
* @param isInverted
* @param parentGravity
* @return
*/
export interface physicsValueGetter {
(
translation: CubismVector2,
particles: CubismPhysicsParticle[],
particleIndex: number,
isInverted: boolean,
parentGravity: CubismVector2
): number;
}
/**
*
* @param translationScale
* @param angleScale
* @return
*/
export interface physicsScaleGetter {
(translationScale: CubismVector2, angleScale: number): number;
}
/**
*
*/
export class CubismPhysicsInput {
constructor() {
this.source = new CubismPhysicsParameter();
}
source: CubismPhysicsParameter; // 入力元のパラメータ
sourceParameterIndex: number; // 入力元のパラメータのインデックス
weight: number; // 重み
type: number; // 入力の種類
reflect: boolean; // 値が反転されているかどうか
getNormalizedParameterValue: normalizedPhysicsParameterValueGetter; // 正規化されたパラメータ値の取得関数
}
/**
* @brief
*
*
*/
export class CubismPhysicsOutput {
constructor() {
this.destination = new CubismPhysicsParameter();
this.translationScale = new CubismVector2(0, 0);
}
destination: CubismPhysicsParameter; // 出力先のパラメータ
destinationParameterIndex: number; // 出力先のパラメータのインデックス
vertexIndex: number; // 振り子のインデックス
translationScale: CubismVector2; // 移動値のスケール
angleScale: number; // 角度のスケール
weight: number; // 重み
type: CubismPhysicsSource; // 出力の種類
reflect: boolean; // 値が反転されているかどうか
valueBelowMinimum: number; // 最小値を下回った時の値
valueExceededMaximum: number; // 最大値をこえた時の値
getValue: physicsValueGetter; // 物理演算の値の取得関数
getScale: physicsScaleGetter; // 物理演算のスケール値の取得関数
}
/**
* @brief
*
*
*/
export class CubismPhysicsRig {
constructor() {
this.settings = new csmVector<CubismPhysicsSubRig>();
this.inputs = new csmVector<CubismPhysicsInput>();
this.outputs = new csmVector<CubismPhysicsOutput>();
this.particles = new csmVector<CubismPhysicsParticle>();
this.gravity = new CubismVector2(0, 0);
this.wind = new CubismVector2(0, 0);
}
subRigCount: number; // 物理演算の物理点の個数
settings: csmVector<CubismPhysicsSubRig>; // 物理演算の物理点の管理のリスト
inputs: csmVector<CubismPhysicsInput>; // 物理演算の入力のリスト
outputs: csmVector<CubismPhysicsOutput>; // 物理演算の出力のリスト
particles: csmVector<CubismPhysicsParticle>; // 物理演算の物理点のリスト
gravity: CubismVector2; // 重力
wind: CubismVector2; // 風
}
}

View File

@ -0,0 +1,649 @@
/**
* 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 cubismjson } from '../utils/cubismjson';
import { Live2DCubismFramework as cubismvector2 } from '../math/cubismvector2';
import { Live2DCubismFramework as cubismid } from '../id/cubismid';
import { Live2DCubismFramework as cubismframework } from '../live2dcubismframework';
import CubismFramework = cubismframework.CubismFramework;
import CubismIdHandle = cubismid.CubismIdHandle;
import CubismVector2 = cubismvector2.CubismVector2;
import CubismJson = cubismjson.CubismJson;
export namespace Live2DCubismFramework {
// JSON keys
const Position = 'Position';
const X = 'X';
const Y = 'Y';
const Angle = 'Angle';
const Type = 'Type';
const Id = 'Id';
// Meta
const Meta = 'Meta';
const EffectiveForces = 'EffectiveForces';
const TotalInputCount = 'TotalInputCount';
const TotalOutputCount = 'TotalOutputCount';
const PhysicsSettingCount = 'PhysicsSettingCount';
const Gravity = 'Gravity';
const Wind = 'Wind';
const VertexCount = 'VertexCount';
// PhysicsSettings
const PhysicsSettings = 'PhysicsSettings';
const Normalization = 'Normalization';
const Minimum = 'Minimum';
const Maximum = 'Maximum';
const Default = 'Default';
const Reflect = 'Reflect';
const Weight = 'Weight';
// Input
const Input = 'Input';
const Source = 'Source';
// Output
const Output = 'Output';
const Scale = 'Scale';
const VertexIndex = 'VertexIndex';
const Destination = 'Destination';
// Particle
const Vertices = 'Vertices';
const Mobility = 'Mobility';
const Delay = 'Delay';
const Radius = 'Radius';
const Acceleration = 'Acceleration';
/**
* physics3.json
*/
export class CubismPhysicsJson {
/**
*
* @param buffer physics3.json
* @param size
*/
public constructor(buffer: ArrayBuffer, size: number) {
this._json = CubismJson.create(buffer, size);
}
/**
*
*/
public release(): void {
CubismJson.delete(this._json);
}
/**
*
* @return
*/
public getGravity(): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0, 0);
ret.x = this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(EffectiveForces)
.getValueByString(Gravity)
.getValueByString(X)
.toFloat();
ret.y = this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(EffectiveForces)
.getValueByString(Gravity)
.getValueByString(Y)
.toFloat();
return ret;
}
/**
*
* @return
*/
public getWind(): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0, 0);
ret.x = this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(EffectiveForces)
.getValueByString(Wind)
.getValueByString(X)
.toFloat();
ret.y = this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(EffectiveForces)
.getValueByString(Wind)
.getValueByString(Y)
.toFloat();
return ret;
}
/**
*
* @return
*/
public getSubRigCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(PhysicsSettingCount)
.toInt();
}
/**
*
* @return
*/
public getTotalInputCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(TotalInputCount)
.toInt();
}
/**
*
* @return
*/
public getTotalOutputCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(TotalOutputCount)
.toInt();
}
/**
*
* @return
*/
public getVertexCount(): number {
return this._json
.getRoot()
.getValueByString(Meta)
.getValueByString(VertexCount)
.toInt();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getNormalizationPositionMinimumValue(
physicsSettingIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Normalization)
.getValueByString(Position)
.getValueByString(Minimum)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getNormalizationPositionMaximumValue(
physicsSettingIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Normalization)
.getValueByString(Position)
.getValueByString(Maximum)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getNormalizationPositionDefaultValue(
physicsSettingIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Normalization)
.getValueByString(Position)
.getValueByString(Default)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getNormalizationAngleMinimumValue(
physicsSettingIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Normalization)
.getValueByString(Angle)
.getValueByString(Minimum)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getNormalizationAngleMaximumValue(
physicsSettingIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Normalization)
.getValueByString(Angle)
.getValueByString(Maximum)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getNormalizationAngleDefaultValue(
physicsSettingIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Normalization)
.getValueByString(Angle)
.getValueByString(Default)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getInputCount(physicsSettingIndex: number): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Input)
.getVector()
.getSize();
}
/**
*
* @param physicsSettingIndex
* @param inputIndex
* @return
*/
public getInputWeight(
physicsSettingIndex: number,
inputIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Input)
.getValueByIndex(inputIndex)
.getValueByString(Weight)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @param inputIndex
* @return
*/
public getInputReflect(
physicsSettingIndex: number,
inputIndex: number
): boolean {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Input)
.getValueByIndex(inputIndex)
.getValueByString(Reflect)
.toBoolean();
}
/**
*
* @param physicsSettingIndex
* @param inputIndex
* @return
*/
public getInputType(
physicsSettingIndex: number,
inputIndex: number
): string {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Input)
.getValueByIndex(inputIndex)
.getValueByString(Type)
.getRawString();
}
/**
* ID
* @param physicsSettingIndex
* @param inputIndex
* @return ID
*/
public getInputSourceId(
physicsSettingIndex: number,
inputIndex: number
): CubismIdHandle {
return CubismFramework.getIdManager().getId(
this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Input)
.getValueByIndex(inputIndex)
.getValueByString(Source)
.getValueByString(Id)
.getRawString()
);
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getOutputCount(physicsSettingIndex: number): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getVector()
.getSize();
}
/**
*
* @param physicsSettingIndex
* @param outputIndex
* @return
*/
public getOutputVertexIndex(
physicsSettingIndex: number,
outputIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getValueByIndex(outputIndex)
.getValueByString(VertexIndex)
.toInt();
}
/**
*
* @param physicsSettingIndex
* @param outputIndex
* @return
*/
public getOutputAngleScale(
physicsSettingIndex: number,
outputIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getValueByIndex(outputIndex)
.getValueByString(Scale)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @param outputIndex
* @return
*/
public getOutputWeight(
physicsSettingIndex: number,
outputIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getValueByIndex(outputIndex)
.getValueByString(Weight)
.toFloat();
}
/**
* ID
* @param physicsSettingIndex
* @param outputIndex
* @return ID
*/
public getOutputDestinationId(
physicsSettingIndex: number,
outputIndex: number
): CubismIdHandle {
return CubismFramework.getIdManager().getId(
this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getValueByIndex(outputIndex)
.getValueByString(Destination)
.getValueByString(Id)
.getRawString()
);
}
/**
*
* @param physicsSettingIndex
* @param outputIndex
* @return
*/
public getOutputType(
physicsSettingIndex: number,
outputIndex: number
): string {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getValueByIndex(outputIndex)
.getValueByString(Type)
.getRawString();
}
/**
*
* @param physicsSettingIndex
* @param outputIndex
* @return
*/
public getOutputReflect(
physicsSettingIndex: number,
outputIndex: number
): boolean {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Output)
.getValueByIndex(outputIndex)
.getValueByString(Reflect)
.toBoolean();
}
/**
*
* @param physicsSettingIndex
* @return
*/
public getParticleCount(physicsSettingIndex: number): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getVector()
.getSize();
}
/**
*
* @param physicsSettingIndex
* @param vertexIndex
* @return
*/
public getParticleMobility(
physicsSettingIndex: number,
vertexIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getValueByIndex(vertexIndex)
.getValueByString(Mobility)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @param vertexIndex
* @return
*/
public getParticleDelay(
physicsSettingIndex: number,
vertexIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getValueByIndex(vertexIndex)
.getValueByString(Delay)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @param vertexIndex
* @return
*/
public getParticleAcceleration(
physicsSettingIndex: number,
vertexIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getValueByIndex(vertexIndex)
.getValueByString(Acceleration)
.toFloat();
}
/**
*
* @param physicsSettingIndex
* @param vertexIndex
* @return
*/
public getParticleRadius(
physicsSettingIndex: number,
vertexIndex: number
): number {
return this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getValueByIndex(vertexIndex)
.getValueByString(Radius)
.toInt();
}
/**
*
* @param physicsSettingIndex
* @param vertexInde
* @return
*/
public getParticlePosition(
physicsSettingIndex: number,
vertexIndex: number
): CubismVector2 {
const ret: CubismVector2 = new CubismVector2(0, 0);
ret.x = this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getValueByIndex(vertexIndex)
.getValueByString(Position)
.getValueByString(X)
.toFloat();
ret.y = this._json
.getRoot()
.getValueByString(PhysicsSettings)
.getValueByIndex(physicsSettingIndex)
.getValueByString(Vertices)
.getValueByIndex(vertexIndex)
.getValueByString(Position)
.getValueByString(Y)
.toFloat();
return ret;
}
_json: CubismJson; // physics3.jsonデータ
}
}

View File

@ -0,0 +1,267 @@
/**
* 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 '../math/cubismmatrix44';
import { Live2DCubismFramework as cubismmodel } from '../model/cubismmodel';
import CubismModel = cubismmodel.CubismModel;
import CubismMatrix44 = cubismmatrix44.CubismMatrix44;
export namespace Live2DCubismFramework {
/**
*
*
*
*/
export abstract class CubismRenderer {
/**
*
*
* @return
*/
public static create(): CubismRenderer {
return null;
}
/**
*
*/
public static delete(renderer: CubismRenderer): void {
renderer = null;
}
/**
*
*
* @param model
*/
public initialize(model: CubismModel): void {
this._model = model;
}
/**
*
*/
public drawModel(): void {
if (this.getModel() == null) return;
this.doDrawModel();
}
/**
* Model-View-Projection
*
* @param matrix44 Model-View-Projection
*/
public setMvpMatrix(matrix44: CubismMatrix44): void {
this._mvpMatrix4x4.setMatrix(matrix44.getArray());
}
/**
* Model-View-Projection
* @return Model-View-Projection
*/
public getMvpMatrix(): CubismMatrix44 {
return this._mvpMatrix4x4;
}
/**
*
* 0.0~1.01.0
* @param red
* @param green
* @param blue
* @param alpha α
*/
public setModelColor(
red: number,
green: number,
blue: number,
alpha: number
): void {
if (red < 0.0) {
red = 0.0;
} else if (red > 1.0) {
red = 1.0;
}
if (green < 0.0) {
green = 0.0;
} else if (green > 1.0) {
green = 1.0;
}
if (blue < 0.0) {
blue = 0.0;
} else if (blue > 1.0) {
blue = 1.0;
}
if (alpha < 0.0) {
alpha = 0.0;
} else if (alpha > 1.0) {
alpha = 1.0;
}
this._modelColor.R = red;
this._modelColor.G = green;
this._modelColor.B = blue;
this._modelColor.A = alpha;
}
/**
*
* 0.0~1.0(1.0)
*
* @return RGBA
*/
public getModelColor(): CubismTextureColor {
return JSON.parse(JSON.stringify(this._modelColor));
}
/**
* α
* truefalse
*/
public setIsPremultipliedAlpha(enable: boolean): void {
this._isPremultipliedAlpha = enable;
}
/**
* α
* @return true α
* @return false α
*/
public isPremultipliedAlpha(): boolean {
return this._isPremultipliedAlpha;
}
/**
*
* truefalse
*/
public setIsCulling(culling: boolean): void {
this._isCulling = culling;
}
/**
*
* @return true
* @return false
*/
public isCulling(): boolean {
return this._isCulling;
}
/**
*
*
* @param n
*/
public setAnisotropy(n: number): void {
this._anisortopy = n;
}
/**
*
* @return
*/
public getAnisotropy(): number {
return this._anisortopy;
}
/**
*
* @return
*/
public getModel(): CubismModel {
return this._model;
}
/**
*
*/
protected constructor() {
this._isCulling = false;
this._isPremultipliedAlpha = false;
this._anisortopy = 0.0;
this._model = null;
this._modelColor = new CubismTextureColor();
// 単位行列に初期化
this._mvpMatrix4x4 = new CubismMatrix44();
this._mvpMatrix4x4.loadIdentity();
}
/**
*
*/
public abstract doDrawModel(): void;
/**
*
*
* @param textureNo
* @param indexCount
* @param vertexCount
* @param indexArray
* @param vertexArray
* @param uvArray uv
* @param opacity
* @param colorBlendMode
* @param invertedMask 使使
*/
public abstract drawMesh(
textureNo: number,
indexCount: number,
vertexCount: number,
indexArray: Uint16Array,
vertexArray: Float32Array,
uvArray: Float32Array,
opacity: number,
colorBlendMode: CubismBlendMode,
invertedMask: boolean
): void;
/**
*
*/
public static staticRelease: Function;
protected _mvpMatrix4x4: CubismMatrix44; // Model-View-Projection 行列
protected _modelColor: CubismTextureColor; // モデル自体のカラーRGBA
protected _isCulling: boolean; // カリングが有効ならtrue
protected _isPremultipliedAlpha: boolean; // 乗算済みαならtrue
protected _anisortopy: any; // テクスチャの異方性フィルタリングのパラメータ
protected _model: CubismModel; // レンダリング対象のモデル
}
export enum CubismBlendMode {
CubismBlendMode_Normal = 0, // 通常
CubismBlendMode_Additive = 1, // 加算
CubismBlendMode_Multiplicative = 2 // 乗算
}
/**
* RGBA
*/
export class CubismTextureColor {
/**
*
*/
constructor() {
this.R = 1.0;
this.G = 1.0;
this.B = 1.0;
this.A = 1.0;
}
R: number; // 赤チャンネル
G: number; // 緑チャンネル
B: number; // 青チャンネル
A: number; // αチャンネル
}
}

File diff suppressed because it is too large Load Diff

307
src/type/csmmap.ts Normal file
View File

@ -0,0 +1,307 @@
/**
* 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 { CubismLogDebug } from '../utils/cubismdebug';
export namespace Live2DCubismFramework {
/**
* Key-Value
* csmMap使
*/
export class csmPair<_KeyT, _ValT> {
/**
*
* @param key Key
* @param value Value
*/
public constructor(key?: _KeyT, value?: _ValT) {
this.first = key == undefined ? null : key;
this.second = value == undefined ? null : value;
}
public first: _KeyT; // keyとして用いる変数
public second: _ValT; // valueとして用いる変数
}
/**
*
*/
export class csmMap<_KeyT, _ValT> {
/**
*
* @param size
*/
public constructor(size?: number) {
if (size != undefined) {
if (size < 1) {
this._keyValues = [];
this._dummyValue = null;
this._size = 0;
} else {
this._keyValues = new Array(size);
this._size = size;
}
} else {
this._keyValues = [];
this._dummyValue = null;
this._size = 0;
}
}
/**
*
*/
public release() {
this.clear();
}
/**
*
* @param key
*/
public appendKey(key: _KeyT): void {
// 新しくKey/Valueのペアを作る
this.prepareCapacity(this._size + 1, false); // 1つ以上入る隙間を作る
// 新しいkey/valueのインデックスは_size
this._keyValues[this._size] = new csmPair<_KeyT, _ValT>(key);
this._size += 1;
}
/**
* [key](get)
* @param key Value
*/
public getValue(key: _KeyT): _ValT {
let found = -1;
for (let i = 0; i < this._size; i++) {
if (this._keyValues[i].first == key) {
found = i;
break;
}
}
if (found >= 0) {
return this._keyValues[found].second;
} else {
this.appendKey(key); // 新規キーを追加
return this._keyValues[this._size - 1].second;
}
}
/**
* [key](set)
* @param key Value
* @param value Value
*/
public setValue(key: _KeyT, value: _ValT): void {
let found = -1;
for (let i = 0; i < this._size; i++) {
if (this._keyValues[i].first == key) {
found = i;
break;
}
}
if (found >= 0) {
this._keyValues[found].second = value;
} else {
this.appendKey(key); // 新規キーを追加
this._keyValues[this._size - 1].second = value;
}
}
/**
* Key
* @param key key
* @return true key
* @return false key
*/
public isExist(key: _KeyT): boolean {
for (let i = 0; i < this._size; i++) {
if (this._keyValues[i].first == key) {
return true;
}
}
return false;
}
/**
* keyValue
*/
public clear(): void {
this._keyValues = void 0;
this._keyValues = null;
this._keyValues = [];
this._size = 0;
}
/**
*
*
* @return
*/
public getSize(): number {
return this._size;
}
/**
*
* @param newSize
* @param fitToSize truefalse2
*/
public prepareCapacity(newSize: number, fitToSize: boolean): void {
if (newSize > this._keyValues.length) {
if (this._keyValues.length == 0) {
if (!fitToSize && newSize < csmMap.DefaultSize)
newSize = csmMap.DefaultSize;
this._keyValues.length = newSize;
} else {
if (!fitToSize && newSize < this._keyValues.length * 2)
newSize = this._keyValues.length * 2;
this._keyValues.length = newSize;
}
}
}
/**
*
*/
public begin(): iterator<_KeyT, _ValT> {
const ite: iterator<_KeyT, _ValT> = new iterator<_KeyT, _ValT>(this, 0);
return ite;
}
/**
*
*/
public end(): iterator<_KeyT, _ValT> {
const ite: iterator<_KeyT, _ValT> = new iterator<_KeyT, _ValT>(
this,
this._size
); // 終了
return ite;
}
/**
*
*
* @param ite
*/
public erase(ite: iterator<_KeyT, _ValT>): iterator<_KeyT, _ValT> {
const index: number = ite._index;
if (index < 0 || this._size <= index) {
return ite; // 削除範囲外
}
// 削除
this._keyValues.splice(index, 1);
--this._size;
const ite2: iterator<_KeyT, _ValT> = new iterator<_KeyT, _ValT>(
this,
index
); // 終了
return ite2;
}
/**
* 32
*/
public dumpAsInt() {
for (let i = 0; i < this._size; i++) {
CubismLogDebug('{0} ,', this._keyValues[i]);
CubismLogDebug('\n');
}
}
public static readonly DefaultSize = 10; // コンテナの初期化のデフォルトサイズ
public _keyValues: csmPair<_KeyT, _ValT>[]; // key-valueペアの配列
public _dummyValue: _ValT; // 空の値を返す為のダミー
public _size: number; // コンテナの要素数
}
/**
* csmMap<T>
*/
export class iterator<_KeyT, _ValT> {
/**
*
*/
constructor(v?: csmMap<_KeyT, _ValT>, idx?: number) {
this._map = v != undefined ? v : new csmMap<_KeyT, _ValT>();
this._index = idx != undefined ? idx : 0;
}
/**
* =
*/
public set(ite: iterator<_KeyT, _ValT>): iterator<_KeyT, _ValT> {
this._index = ite._index;
this._map = ite._map;
return this;
}
/**
* ++
*/
public preIncrement(): iterator<_KeyT, _ValT> {
++this._index;
return this;
}
/**
* --
*/
public preDecrement(): iterator<_KeyT, _ValT> {
--this._index;
return this;
}
/**
* ++
*/
public increment(): iterator<_KeyT, _ValT> {
const iteold = new iterator<_KeyT, _ValT>(this._map, this._index++); // 古い値を保存
this._map = iteold._map;
this._index = iteold._index;
return this;
}
/**
* --
*/
public decrement(): iterator<_KeyT, _ValT> {
const iteold = new iterator<_KeyT, _ValT>(this._map, this._index); // 古い値を保存
this._map = iteold._map;
this._index = iteold._index;
return this;
}
/**
* *
*/
public ptr(): csmPair<_KeyT, _ValT> {
return this._map._keyValues[this._index];
}
/**
* !=
*/
public notEqual(ite: iterator<_KeyT, _ValT>): boolean {
return this._index != ite._index || this._map != ite._map;
}
_index: number; // コンテナのインデックス値
_map: csmMap<_KeyT, _ValT>; // コンテナ
}
}

83
src/type/csmrectf.ts Normal file
View File

@ -0,0 +1,83 @@
/**
* 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 {
/**
* float
*/
export class csmRect {
/**
*
* @param x X
* @param y Y
* @param w
* @param h
*/
public constructor(x?: number, y?: number, w?: number, h?: number) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
/**
* X
*/
public getCenterX(): number {
return this.x + 0.5 * this.width;
}
/**
* Y
*/
public getCenterY(): number {
return this.y + 0.5 * this.height;
}
/**
* X
*/
public getRight(): number {
return this.x + this.width;
}
/**
* Y
*/
public getBottom(): number {
return this.y + this.height;
}
/**
*
* @param r
*/
public setRect(r: csmRect): void {
this.x = r.x;
this.y = r.y;
this.width = r.width;
this.height = r.height;
}
/**
*
* @param w
* @param h
*/
public expand(w: number, h: number) {
this.x -= w;
this.y -= h;
this.width += w * 2.0;
this.height += h * 2.0;
}
public x: number; // 左端X座標
public y: number; // 上端Y座標
public width: number; // 幅
public height: number; // 高さ
}
}

101
src/type/csmstring.ts Normal file
View File

@ -0,0 +1,101 @@
/**
* 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 {
/**
*
*/
export class csmString {
/**
*
*
* @param c
* @return
*/
public append(c: string, length?: number): csmString {
this.s += length !== undefined ? c.substr(0, length) : c;
return this;
}
/**
*
* @param length
* @param v
* @return
*/
public expansion(length: number, v: string): csmString {
for (let i = 0; i < length; i++) {
this.append(v);
}
return this;
}
/**
*
*/
public getBytes(): number {
return encodeURIComponent(this.s).replace(/%../g, 'x').length;
}
/**
*
*/
public getLength(): number {
return this.s.length;
}
/**
* <
* @param s
* @return true:
* @return false:
*/
public isLess(s: csmString): boolean {
return this.s < s.s;
}
/**
* >
* @param s
* @return true:
* @return false:
*/
public isGreat(s: csmString): boolean {
return this.s > s.s;
}
/**
* ==
* @param s
* @return true:
* @return false:
*/
public isEqual(s: string): boolean {
return this.s == s;
}
/**
*
* @return true:
* @return false:
*/
public isEmpty(): boolean {
return this.s.length == 0;
}
/**
*
*/
public constructor(s: string) {
this.s = s;
}
s: string;
}
}

348
src/type/csmvector.ts Normal file
View File

@ -0,0 +1,348 @@
/**
* 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 {
/**
*
*/
export class csmVector<T> {
/**
*
* @param iniitalCapacity _capacity * sizeof(T)
* @param zeroClear true0
*/
constructor(initialCapacity = 0) {
if (initialCapacity < 1) {
this._ptr = [];
this._capacity = 0;
this._size = 0;
} else {
this._ptr = new Array(initialCapacity);
this._capacity = initialCapacity;
this._size = 0;
}
}
/**
*
*/
public at(index: number): T {
return this._ptr[index];
}
/**
*
* @param index
* @param value
*/
public set(index: number, value: T): void {
this._ptr[index] = value;
}
/**
*
*/
public get(offset = 0): T[] {
const ret: T[] = new Array<T>();
for (let i = offset; i < this._size; i++) {
ret.push(this._ptr[i]);
}
return ret;
}
/**
* pushBack
* @param value PushBack
*/
public pushBack(value: T): void {
if (this._size >= this._capacity) {
this.prepareCapacity(
this._capacity == 0 ? csmVector.s_defaultSize : this._capacity * 2
);
}
this._ptr[this._size++] = value;
}
/**
*
*/
public clear(): void {
this._ptr.length = 0;
this._size = 0;
}
/**
*
* @return
*/
public getSize(): number {
return this._size;
}
/**
*
* @param newSize
* @param value
*/
public assign(newSize: number, value: T): void {
const curSize = this._size;
if (curSize < newSize) {
this.prepareCapacity(newSize); // capacity更新
}
for (let i = 0; i < newSize; i++) {
this._ptr[i] = value;
}
this._size = newSize;
}
/**
*
*/
public resize(newSize: number, value: T = null): void {
this.updateSize(newSize, value, true);
}
/**
*
*/
public updateSize(
newSize: number,
value: any = null,
callPlacementNew = true
): void {
const curSize: number = this._size;
if (curSize < newSize) {
this.prepareCapacity(newSize); // capacity更新
if (callPlacementNew) {
for (let i: number = this._size; i < newSize; i++) {
if (typeof value == 'function') {
// new
this._ptr[i] = JSON.parse(JSON.stringify(new value()));
} // プリミティブ型なので値渡し
else {
this._ptr[i] = value;
}
}
} else {
for (let i: number = this._size; i < newSize; i++) {
this._ptr[i] = value;
}
}
} else {
// newSize <= this._size
//---
const sub = this._size - newSize;
this._ptr.splice(this._size - sub, sub); // 不要なので破棄する
}
this._size = newSize;
}
/**
*
* @param position
* @param begin
* @param end
*/
public insert(
position: iterator<T>,
begin: iterator<T>,
end: iterator<T>
): void {
let dstSi: number = position._index;
const srcSi: number = begin._index;
const srcEi: number = end._index;
const addCount: number = srcEi - srcSi;
this.prepareCapacity(this._size + addCount);
// 挿入用の既存データをシフトして隙間を作る
const addSize = this._size - dstSi;
if (addSize > 0) {
for (let i = 0; i < addSize; i++) {
this._ptr.splice(dstSi + i, 0, null);
}
}
for (let i: number = srcSi; i < srcEi; i++, dstSi++) {
this._ptr[dstSi] = begin._vector._ptr[i];
}
this._size = this._size + addCount;
}
/**
*
* @param index
* @return true
* @return false
*/
public remove(index: number): boolean {
if (index < 0 || this._size <= index) {
return false; // 削除範囲外
}
this._ptr.splice(index, 1);
--this._size;
return true;
}
/**
*
* @param ite
*/
public erase(ite: iterator<T>): iterator<T> {
const index: number = ite._index;
if (index < 0 || this._size <= index) {
return ite; // 削除範囲外
}
// 削除
this._ptr.splice(index, 1);
--this._size;
const ite2: iterator<T> = new iterator<T>(this, index); // 終了
return ite2;
}
/**
*
* @param newSize .
*/
public prepareCapacity(newSize: number): void {
if (newSize > this._capacity) {
if (this._capacity == 0) {
this._ptr = new Array(newSize);
this._capacity = newSize;
} else {
this._ptr.length = newSize;
this._capacity = newSize;
}
}
}
/**
*
*/
public begin(): iterator<T> {
const ite: iterator<T> =
this._size == 0 ? this.end() : new iterator<T>(this, 0);
return ite;
}
/**
*
*/
public end(): iterator<T> {
const ite: iterator<T> = new iterator<T>(this, this._size);
return ite;
}
public getOffset(offset: number): csmVector<T> {
const newVector = new csmVector<T>();
newVector._ptr = this.get(offset);
newVector._size = this.get(offset).length;
newVector._capacity = this.get(offset).length;
return newVector;
}
_ptr: T[]; // コンテナの先頭アドレス
_size: number; // コンテナの要素数
_capacity: number; // コンテナのキャパシティ
static readonly s_defaultSize = 10; // コンテナ初期化のデフォルトサイズ
}
export class iterator<T> {
/**
*
*/
public constructor(v?: csmVector<T>, index?: number) {
this._vector = v != undefined ? v : null;
this._index = index != undefined ? index : 0;
}
/**
*
*/
public set(ite: iterator<T>): iterator<T> {
this._index = ite._index;
this._vector = ite._vector;
return this;
}
/**
* ++
*/
public preIncrement(): iterator<T> {
++this._index;
return this;
}
/**
* --
*/
public preDecrement(): iterator<T> {
--this._index;
return this;
}
/**
* ++
*/
public increment(): iterator<T> {
const iteold = new iterator<T>(this._vector, this._index++);
this._vector = iteold._vector;
this._index = iteold._index;
return this;
}
/**
* --
*/
public decrement(): iterator<T> {
const iteold = new iterator<T>(this._vector, this._index--); // 古い値を保存
this._vector = iteold._vector;
this._index = iteold._index;
return this;
}
/**
* ptr
*/
public ptr(): T {
return this._vector._ptr[this._index];
}
/**
* =
*/
public substitution(ite: iterator<T>): iterator<T> {
this._index = ite._index;
this._vector = ite._vector;
return this;
}
/**
* !=
*/
public notEqual(ite: iterator<T>): boolean {
return this._index != ite._index || this._vector != ite._vector;
}
_index: number; // コンテナのインデックス値
_vector: csmVector<T>; // コンテナ
}
}

166
src/utils/cubismdebug.ts Normal file
View File

@ -0,0 +1,166 @@
/**
* 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 cubismframework,
LogLevel
} from '../live2dcubismframework';
import {
CSM_LOG_LEVEL,
CSM_LOG_LEVEL_VERBOSE,
CSM_LOG_LEVEL_DEBUG,
CSM_LOG_LEVEL_INFO,
CSM_LOG_LEVEL_WARNING,
CSM_LOG_LEVEL_ERROR
} from '../cubismframeworkconfig';
export const CubismLogPrint = (level: LogLevel, fmt: string, args: any[]) => {
Live2DCubismFramework.CubismDebug.print(level, '[CSM]' + fmt, args);
};
export const CubismLogPrintIn = (level: LogLevel, fmt: string, args: any[]) => {
CubismLogPrint(level, fmt + '\n', args);
};
export const CSM_ASSERT = (expr: any) => {
console.assert(expr);
};
export let CubismLogVerbose: (fmt: string, ...args: any[]) => void;
export let CubismLogDebug: (fmt: string, ...args: any[]) => void;
export let CubismLogInfo: (fmt: string, ...args: any[]) => void;
export let CubismLogWarning: (fmt: string, ...args: any[]) => void;
export let CubismLogError: (fmt: string, ...args: any[]) => void;
if (CSM_LOG_LEVEL <= CSM_LOG_LEVEL_VERBOSE) {
CubismLogVerbose = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Verbose, '[V]' + fmt, args);
};
CubismLogDebug = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Debug, '[D]' + fmt, args);
};
CubismLogInfo = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Info, '[I]' + fmt, args);
};
CubismLogWarning = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Warning, '[W]' + fmt, args);
};
CubismLogError = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Error, '[E]' + fmt, args);
};
} else if (CSM_LOG_LEVEL == CSM_LOG_LEVEL_DEBUG) {
CubismLogDebug = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Debug, '[D]' + fmt, args);
};
CubismLogInfo = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Info, '[I]' + fmt, args);
};
CubismLogWarning = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Warning, '[W]' + fmt, args);
};
CubismLogError = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Error, '[E]' + fmt, args);
};
} else if (CSM_LOG_LEVEL == CSM_LOG_LEVEL_INFO) {
CubismLogInfo = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Info, '[I]' + fmt, args);
};
CubismLogWarning = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Warning, '[W]' + fmt, args);
};
CubismLogError = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Error, '[E]' + fmt, args);
};
} else if (CSM_LOG_LEVEL == CSM_LOG_LEVEL_WARNING) {
CubismLogWarning = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Warning, '[W]' + fmt, args);
};
CubismLogError = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Error, '[E]' + fmt, args);
};
} else if (CSM_LOG_LEVEL == CSM_LOG_LEVEL_ERROR) {
CubismLogError = (fmt: string, ...args: any[]) => {
CubismLogPrintIn(LogLevel.LogLevel_Error, '[E]' + fmt, args);
};
}
//------------ LIVE2D NAMESPACE ------------
export namespace Live2DCubismFramework {
/**
*
*
*/
export class CubismDebug {
/**
*
* CubismFramework.initialize()
*
* @param logLevel
* @param format
* @param args
*/
public static print(
logLevel: LogLevel,
format: string,
args?: any[]
): void {
// オプションで設定されたログ出力レベルを下回る場合はログに出さない
if (logLevel < cubismframework.CubismFramework.getLoggingLevel()) {
return;
}
const logPrint: Live2DCubismCore.csmLogFunction =
cubismframework.CubismFramework.coreLogFunction;
if (!logPrint) return;
const buffer: string = format.replace(/\{(\d+)\}/g, (m, k) => {
return args[k];
});
logPrint(buffer);
}
/**
*
* CubismFramework.initialize()
*
* @param logLevel
* @param data
* @param length
*/
public static dumpBytes(
logLevel: LogLevel,
data: Uint8Array,
length: number
): void {
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] & 0xff]);
}
this.print(logLevel, '\n');
}
/**
* private
*/
private constructor() {}
}
}
//------------ LIVE2D NAMESPACE ------------

1246
src/utils/cubismjson.ts Normal file

File diff suppressed because it is too large Load Diff

123
src/utils/cubismstring.ts Normal file
View File

@ -0,0 +1,123 @@
/**
* 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 {
export class CubismString {
/**
*
* @param format
* @param ...args
* @return
*/
public static getFormatedString(format: string, ...args: any[]): string {
const ret: string = format;
return ret.replace(
/\{(\d+)\}/g,
(
m,
k // m="{0}", k="0"
) => {
return args[k];
}
);
}
/**
* textstartWord
* @param test
* @param startWord
* @return true textstartWord
* @return false textstartWord
*/
public static isStartWith(text: string, startWord: string): boolean {
let textIndex = 0;
let startWordIndex = 0;
while (startWord[startWordIndex] != '\0') {
if (
text[textIndex] == '\0' ||
text[textIndex++] != startWord[startWordIndex++]
) {
return false;
}
}
return false;
}
/**
* position
*
* @param string
* @param length
* @param position
* @param outEndPos (-1)
* @return
*/
public static stringToFloat(
string: string,
length: number,
position: number,
outEndPos: number[]
): number {
let i: number = position;
let minus = false; // マイナスフラグ
let period = false;
let v1 = 0;
//負号の確認
let c: number = parseInt(string[i]);
if (c < 0) {
minus = true;
i++;
}
//整数部の確認
for (; i < length; i++) {
const c = string[i];
if (0 <= parseInt(c) && parseInt(c) <= 9) {
v1 = v1 * 10 + (parseInt(c) - 0);
} else if (c == '.') {
period = true;
i++;
break;
} else {
break;
}
}
//小数部の確認
if (period) {
let mul = 0.1;
for (; i < length; i++) {
c = parseFloat(string[i]) & 0xff;
if (0 <= c && c <= 9) {
v1 += mul * (c - 0);
} else {
break;
}
mul *= 0.1; //一桁下げる
if (!c) break;
}
}
if (i == position) {
//一文字も読み込まなかった場合
outEndPos[0] = -1; //エラー値が入るので呼び出し元で適切な処理を行う
return 0;
}
if (minus) v1 = -v1;
outEndPos[0] = i;
return v1;
}
/**
*
*/
private constructor() {}
}
}

22
tsconfig.json Normal file
View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es5",
"moduleResolution": "node",
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"emitDecoratorMetadata": true
},
"include": [
"src/**/*.ts",
"../Core/*.ts"
],
"exclude": [
"node_modules",
"dist"
]
}