diff --git a/Live2DFramework/CHANGELOG.md b/Live2DFramework/CHANGELOG.md new file mode 100644 index 0000000..06fac9e --- /dev/null +++ b/Live2DFramework/CHANGELOG.md @@ -0,0 +1,287 @@ +# 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/). + + +## [5-r.4.1] - 2025-07-17 + +### Changed + +* Implement support for Android 16KB page size. + * See `CHANGELOG.md` in Core. + + +## [5-r.4] - 2025-05-15 + +### Added + +* Add an API to `CubismMotionJson` for verifying the consistency of `motion3.json`. +* Add a flag to the arguments of the following methods to enable the function that verifies the consistency of `motion3.json`: + * `CubismUserModel.loadMotion()` + * `CubismMotion.create()` + * `CubismMotion.parse()` +* Add parameter repeat processing that connects the right and left ends of the parameter to create a loop, allowing the motion to repeat. + * Add the variable `isOverriddenParameterRepeat` to the `CubismModel` class for managing parameter repeat flags at the model level. + * Add the variable `userParameterRepeatDataList` to the `CubismModel` class for managing parameter repeat flags for each parameter. +* Add a `getPartParentPartIndices()` function. + +### Changed + +* Change the access level of the private members in the `CubismModelSettingJson` class to protected. +* Change the default JDK version for compilation to 17 using Gradle's Java toolchain. + +### Fixed + +* Fix an issue in the `CubismPose` class where the opacity calculation for non-displayed parts differed from the implementation in the other Cubism SDK. + + +## [5-r.3] - 2025-02-18 + +### Added + +* Add new motion loop processing that seamlessly connects the start and end points of the loop. + * The `isLooped` variable has been moved from the `CubismMotion` class to the `ACubismMotion` class as `isLoop`. + * Add the setter for `isLoop`, `setLoop(boolean loop)`, to class `ACubismMotion`. + * Add the getter for `isLoop`, `getLoop()`, to class `ACubismMotion`. + * The `isLoopFadeIn` variable was moved from class `CubismMotion` to class `ACubismMotion`. + * Add the setter for `isLoopFadeIn`, `setLoopFadeIn(boolean loopFadeIn)`, to class `ACubismMotion`. + * Add the getter for `isLoopFadeIn`, `getLoopFadeIn()`, to class `ACubismMotion`. + * Add a variable `motionBehavior` for version control to the `CubismMotion` class. + +### Changed + +* Change the compile and target SDK version of Android OS to 15.0 (API 35). + * Upgrade the version of Android Gradle Plugin from 8.1.1 to 8.6.1. + * Upgrade the version of Gradle from 8.2 to 8.7. + * Change the minimum version of Android Studio to Ladybug(2024.2.1). +* Change the arguments of `CsmMotionSegmentEvaluationFunction.evaluate` from `(float time, int basePointIndex)` to `(final List points, final float time)` to align with the Cubism SDK for Native codebase. + * Accordingly, change the implementation of the following methods. + * CubismMotion.LinearEvaluator.evaluate() + * CubismMotion.BezierEvaluator.evaluate() + * CubismMotion.BezierEvaluatorCardanoInterpretation.evaluate() + * CubismMotion.SteppedEvaluator.evaluate() + * CubismMotion.InverseSteppedEvaluator.evaluate() + * CubismMotion.bezierEvaluateBinarySearch() +* Change the access level of `CubismMotionQueueEntry` class to public. + +### Deprecated + +* Deprecate the following elements due to the change in the variable declaration location. + * `CubismMotion.isLoop(boolean loop)` + * `CubismMotion.isLoop()` + * `CubismMotion.isLoopFadeIn(boolean loopFadeIn)` + * `CubismMotion.isLoopFadeIn()` + + +## [5-r.2] - 2024-11-07 + +### Added + +* Add function to get `CombinedParameters` listed in `cdi3.json`. +* Add the functionality to call a function when motion playback starts. + +### Changed + +* Change an expression "overwrite" to "override" for multiply color, screen color, and culling to adapt the actual behavior. +* Change the access level of `CubismMotionJson` class to public. +* Change the threshold for enabling anisotropic filtering. + +### Fixed + +* Fix a bug in which a method to acquire events fired during motion playback returned incorrect values when called multiple times. +* Fix a potential problem with division by 0 when a pose fade time is set to 0 seconds. +* Fix a bug that thrown an exception when playing CubismExpresionMotion with CubismMotionQueueManager.startMotion(). + + +## [5-r.1] - 2024-03-26 + +### Added + +* Add type constraint to the generics type of `getRenderer` function in `CubismUserModel`. +* Add function `modF()` to compute floating-point remainder in `CubismMath` class. + +### Changed + +* Change the default value of the flag for debugging from `true` to `false`. +* Change to output log if the argument `motionQueueEntry` is `null` in the `updateFadeWeight()` function of the `ACubismMotion` class. + +### Deprecated + +* Deprecate the `fadeWeight` variable and the `getFadeWeight()` function of the `CubismExpressionMotion` class. + * The `fadeWeight` variable of the `CubismExpressionMotion` class can cause problems. + * Please use the `getFadeWeight()` function of the `CubismExpressionMotionManager` class with one argument from now on. +* The `startMotion()` function of the `CubismMotionQueueManager` class with the unnecessary second argument `userTimeSeconds` is deprecated. + * Please use the `startMotion()` function with one argument from now on. + +### Fixed + +* Fix a bug that caused incorrect weight values when expression motions were shared by multiple models. + * Change the way fadeWeight is managed for expression motions. + + +## [5-r.1-beta.3] - 2024-01-18 + +### Added + +* Add exception catching and error logging handling when an exception is thrown while loading a JSON file. + +### Changed + +* Change the compile and target SDK version of Android OS to 14.0 (API 34). + * Upgrade the version of Android Gradle Plugin from 8.0.2 to 8.1.1. + * Upgrade the version of Gradle from 8.1.1 to 8.2. + * Change the minimum version of Android Studio to Hedgehog(2023.1.1). +* Change the visibility of the `CubismPhysicsInternal` and `CubismPhysicsJson` classes to `public`. + +### Fixed + +* Fix an issue where models with a specific number of masks could not be drawn correctly. +* Replace deprecated notation in `build.gradle`. + + +## [5-r.1-beta.2] - 2023-09-28 + +### Added + +* Add final modifier to some private fields in `CubismModel`. + +### Changed + +* Change getter functions to get some data without `getIdManager` in `CubismModel`. +* Change some private fields in `CubismModel` to `final` variable. + + +## [5-r.1-beta.1] - 2023-08-17 + +### Added + +* Add the function to get the ID of a given parameter.(`CubismModel.getParameterId`) +* Add the `CubismExpressionMotionManager` class. + +### Changed + +* Change the minimum support version of Android OS to 5.0 (API 21). +* Unify Offscreen drawing-related terminology with `OffscreenSurface`. +* Change the visibility of the `CubismId` constructor to package-private. + +### Fixed + +* Fix the structure of the class in renderer. +* Separate the high precision mask process from the clipping mask setup process. +* Fix a bug that the value applied by multiply was not appropriate during expression transitions. +* Fix a issue that `CubismIdManager` was not used when retrieving `CubismId`. + * Please use `CubismFramework.getIdManager().getId` to get `CubismId`. + +### Removed + +* Remove an unnecessary dependency from `build.gradle`. +* Remove several arguments of `drawMesh` function. + + +## [4-r.1] - 2023-05-25 + +### Added + +* Add some functions for checking consistency of MOC3 files. + * Add the function of checking consistency in `CubismMoc.create()`. + * Add the function of checking consistency before loading a model. (`CubismUserModel.loadModel()`) +* Add some functions to change Multiply and Screen colors on a per part basis. + +### Changed + +* Change access modifiers for methods in `CubismExpressionMotion`. And also chenge it to non-final class, allowing it to be extended by inheritance. +* Change to get opacity according to the current time of the motion. + +### Fixed +* Refactor codes of cacheing vertex information in renderer. + * This change does not affect the behavior of this SDK. +* Fix a crash when specifying the number of mask buffers as an integer less than or equal to 0 in the second argument of `setupRenderer` function in `CubismUserModel`. +* Fix the redundant process regarding the renderer to make the code more concise. +* Optimize a drawing process of clipping masks. + * `CubismClippingManagerAndroid` class has a flag to indicate whether mask textures have been cleared or not, and the texture clearing process is only called if they have not been cleared. + +## [4-r.1-beta.4] - 2023-03-16 + +### Fixed + +* Fix some problems related to Cubism Core. + * See `CHANGELOG.md` in Core. + +## [4-r.1-beta.3] - 2023-03-10 + +### Added + +* Add function to validate MOC3 files. + +## [4-r.1-beta.2] - 2023-01-26 + +### Added + +* Add a description of type package to `README.md`. + +### Changed + +* Change Android SDK API level from 31 (Android 12) to 33 (Android 13). +* Change the name and package of the `CubismRectangle` class to `type/csmRect` to match SDK for Native. +* Move constants related to debugging from `CubismFramework` class to the newly created `CubismFrameworkConfig` class. +* Change implementation to hide `CubismJsonString` from shallow layers. The following functions are affcted by this change. + * `getLayoutMap` function in `ICubismModelSetting` class + * `getLayoutMap` function in `CubismModelSettingJson` class + * `setupFromLayout` function in `CubismModelMatrix` class +* Change the name and arguments of `createRenderer` function in `CubismUserModel`. + * The `RendererType` enumurator is abolished. Please generate a renderer you want to use by yourself and put it in the function as an argument. + +### Fixed + +* Fix JSON data parsing process to improve performance. +* Fix a problem where `setClippingMaskBufferSize` in `CubismRendererAndroid` would be thrown a `NullPointerException` if there are no clipping masks in the model. + +### Removed + +* Remove dependencies not to be used. +* Remove the unused method `getMotionMap` in `ICubismModelSetting` and `CubismModelSettingJson` class. + +## [4-r.1-beta.1] - 2022-12-08 + +### Added + +* Add support for high-precision masks. +* Implement to throw an exception when a user attempt to give null value to a setter method. +* Add API to allow users to configure culling. +* The number of render textures used can now be increased arbitrarily. + * The maximum number of masks when using multiple render textures has been increased to "number of render textures * 32". + +### Changed + +* Change the visibility of field variables in CubismClippingContext class from private to public and remove the getter and setter methods. +* Change the specification of the logging functions in `CubismDebug` so that they can take a format string as an argument. + +### Fixed + +* Change `radianToDirection` function in `CubismMath` so that an instance of CubismVector2 created by an API user is given as second argument, and the calculation result is stored in that instance and returned. +* Change the type of cache variables for vertex information used in `doDrawModel` function in `CubismRendererAndroid` and `setupClippingContext` function in `CubismClippingManagerAndroid` from `Map` to array. + * The cost of converting `int` type to `Integer` type (auto-boxing) that was incurred every frame was removed by this change. +* Fix `updateParticles` and `updateParticlesForStabilization` function in `CubismPhysics` not to create an instance of CubismVector2. + +## 4-r.1-alpha.1 - 2022-10-06 + +### Added + +* New released! + + +[5-r.4.1]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.4...5-r.4.1 +[5-r.4]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.3...5-r.4 +[5-r.3]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.2...5-r.3 +[5-r.2]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.1...5-r.2 +[5-r.1]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.1-beta.3...5-r.1 +[5-r.1-beta.3]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.1-beta.2...5-r.1-beta.3 +[5-r.1-beta.2]: https://github.com/Live2D/CubismJavaFramework/compare/5-r.1-beta.1...5-r.1-beta.2 +[5-r.1-beta.1]: https://github.com/Live2D/CubismJavaFramework/compare/4-r.1...5-r.1-beta.1 +[4-r.1]: https://github.com/Live2D/CubismJavaFramework/compare/4-r.1-beta.4...4-r.1 +[4-r.1-beta.4]: https://github.com/Live2D/CubismJavaFramework/compare/4-r.1-beta.3...4-r.1-beta.4 +[4-r.1-beta.3]: https://github.com/Live2D/CubismJavaFramework/compare/4-r.1-beta.2...4-r.1-beta.3 +[4-r.1-beta.2]: https://github.com/Live2D/CubismJavaFramework/compare/4-r.1-beta.1...4-r.1-beta.2 +[4-r.1-beta.1]: https://github.com/Live2D/CubismJavaFramework/compare/4-r.1-alpha.1...4-r.1-beta.1 diff --git a/Live2DFramework/Core/CHANGELOG.md b/Live2DFramework/Core/CHANGELOG.md new file mode 100644 index 0000000..9923264 --- /dev/null +++ b/Live2DFramework/Core/CHANGELOG.md @@ -0,0 +1,371 @@ +# 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/). + + +## 2025-07-17 + +### Changed + +* [Unity,Native,Java] Implement support for Android 16KB page size. + + +## 2025-04-24 + +### Added + +* Add the function `csmGetParameterRepeats`. + * This function retrieves whether the parameters are set to repeat. + +### Changed + +* Upgrade Core version to 05.01.0000. + +### Fixed + +* Fix `csmGetParameterKeyCounts()` and `csmGetParameterKeyValues()` symbols in the DLL. + + +## 2024-12-19 + +### Removed + +* [Native] Remove Visual Studio 2013 (MSVC 120) static library. + + +## 2024-11-07 + +### Added + +* [Native] Add experimental support `arm64` library for linux. + +### Removed + +* [Unity,Native,Java] Remove Android ARM v7 library. + + +## 2024-04-04 + +### Added + +* [Unity] Add library(.so) for HarmonyOS build. + + +## 2024-03-26 + +### Remove + +* [Unity] Remove built with Emscripten 1.38.48. + * Unity 2021.2 or later uses only Core under `Assets/Live2D/Cubism/Plugins/Experimental/Emscripten/latest`. + + +## 2023-09-28 + +### Remove + +* Remove bitcode from IOS build. + + +## 2023-08-17 + +### Added + +* Enhance Blend Shape features. + * Please see [here](https://docs.live2d.com/en/cubism-editor-manual/blend-shape/). + +### Changed + +* Upgrade Core version to 05.00.0000. + + +## 2023-05-09 + +### Changed + +* Change the GCC version of the library for Linux from 6.5.0 to 8.3.0. + + +## 2023-03-16 + +### Fixed + +* Fix a case in which the index of the mask's drawable object was negative value for `csmGetDrawableMasks()`. +* Fix a problem in which `csmHasMocConsistency()` was returned as 0 even though the MOC3 file was in the correct format. + * This problem was occurring in some models using the blendshape weight limit settings. +* Fix a problem that could cause a crash if a MOC3 file that is not in the correct format is loaded with `csmHasMocConsistency()`. + +### Changed + +* Upgrade Core version to 04.02.0004. + + +## 2023-03-10 + +### Added + +* Add the function `csmHasMocConsistency`. + * This function verifies that the `MOC3` file is valid. + +### Changed + +* Upgrade Core version to 04.02.0003. + + +## 2023-02-21 + +### Added + +* [Web] Added classes related to `Memory`. + * Add the funciton `initializeAmountOfMemory()` to adjust the amount of memory at initialization. + + +## 2022-10-28 + +### Fixed + +* [Java] Remove unnecessary methods. + + +## 2022-10-06 + +### Added + +* [Java] Add AAR file for Android. + + +## 2022-09-08 + +### Added + +* Add the multilingual supported documents. +* Support Visual Studio 2022. + + +## 2022-08-04 + +### Fixed + +* [Web] Fix `csmGetMocVersion` function argument. + + +## 2022-07-07 + +### Added + +* Add functions + * `csmGetParameterTypes` + * `csmGetDrawableParentPartIndices` + +* Add type `csmMocVersion` and enum. This type is the return value of `csmGetMocVersion`, `csmGetLatestMocVersion`. + +### Changed + +* Upgrade Core version to 04.02.0002. + + +## 2022-06-02 + +### Changed + +* Upgrade Core version to 04.02.0001. + +### Fixed + +* Fixed a bug that caused Multiply Color / Screen Color of different objects to be applied. + + +## 2022-05-19 + +### Added + +* Support new Multiply Color / Screen Color features. +* Support new Blend Shape features. + +### Changed + +* Upgrade Core version to 04.02.0000. This upgrade is following Cubism Editor 4.2 features. + + +## 2022-02-10 + +### Added + +* [Unity] Add bitcode library(.bc) for Emscripten latest version build. + +### Changed + +* [Unity] Change the bitcode file directory location. + * emsdk latest version build bitcode file in `latest` directory. + * emsdk 1.38.48 build bitcode file in `1_38_48` directory. + + +## 2021-12-09 + +### Added + +* Add static library(.a) for Mac Catalyst. + + +## 2021-10-07 + +### Added + +* Add `x86_64` library for Android. +* Add `arm64` library for macOS. + + +## 2021-03-09 + +### Added + +* Add funtcions for Viewer. + * `csmGetParameterKeyCounts` + * `csmGetParameterKeyValues` + + +### Changed + +* Update Core version to `04.01.0000`. + + +## 2020-01-30 + +### Added + +* Add static library(.lib) for statically linking DLL. +* Add symbol file for Windows dynamic library (dll). + + +## 2019-11-19 + +### Fixed + +* Fix linking static libraries for Windows (.lib). + + +## 2019-11-14 + +### Added + +* Support Visual Studio 2019. +* Support macOS dynamic library (dylib). + +### Changed + +* Update Windows dynamic library: Use Visual Studio 2019 for building. + +### Security + +* Bundle certificate and notary ticket to macOS shared library. + + +## 2019-09-04 + +### Added + +* Support new Inverted Masking features. +* Support ARM64 architecture for Universal Windows Platform. + +### Changed + +* Upgrade Core version to 04.00.0000 (67108864). This upgrade is following Cubism Editor 4.0 features. +* Add calling convention for *Windows/x86 DLL* only. + +### Removed + +* Remove bitcode binary due to suspension of *Cubism Bindings.* + + +## 2019-04-09 + +### Added + +* Support Universal Windows Platform for Windows Store Application. + + +## 2019-01-31 + +### Added + +* Add API to get the parent part of the specified part. +* Add API to get moc3 version. + + +## 2018-12-20 + +### Added + +* [Native] Add new function: `csmGetPartParentPartIndices`. +* [Native, 3.3 Support] Support new Warp Deformer features. + +### Changed + +* Upgrade Core version to 03.03.0000 (50528256). This upgrade is following Cubism Editor 3.3 features. + + +## 2018-08-22 + +### Added + +* [Native] Add support for Neon. + + +## 2018-05-14 + +### Added + +* [Native] Add Windows **Visual C++ 2013** library. +* [Windows] Add runtime library choice `MT`, `MD`, `MTd`, `MDd`. +* [iOS] Add support for iPhone Simulator SDK. + +### Fixed + +* Fix an error occurred when linking libraries for Android `arm64-v8a`. + + +## 2017-11-17 + +### Fixed + +* Fix processing of vertex index. + + +## 2017-10-05 + +### Added + +* Provide bitcode for iOS. + + +## 2017-08-09 + +### Added + +* [Native] Add Android *arm64-v8a* ABI library. + +### Fixed + +* Fix drawing order in certain scenarios. + + +## 2017-07-12 + +### Added + +* Add experimental support for Emscripten. +* Add `CHANGELOG.md`. + +### Fixed + +* Fix access violation in certain scenarios. +* Fix update result in certain scenarios. + + +## 2017-05-02 + +### Added + +* [Native] Add experimental support for Raspberry PI. +* Add `README.md`. diff --git a/Live2DFramework/Core/LICENSE.md b/Live2DFramework/Core/LICENSE.md new file mode 100644 index 0000000..4139d4f --- /dev/null +++ b/Live2DFramework/Core/LICENSE.md @@ -0,0 +1,7 @@ +## 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) +* [Live2D Proprietary Software 使用授权协议](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_cn.html) diff --git a/Live2DFramework/Core/README.ja.md b/Live2DFramework/Core/README.ja.md new file mode 100644 index 0000000..9c022b6 --- /dev/null +++ b/Live2DFramework/Core/README.ja.md @@ -0,0 +1,22 @@ +[English](README.md) / [日本語](README.ja.md) + +--- + +# Live2D Cubism Core + +このフォルダーには、Javaアプリケーションを開発するためのコアライブラリファイルが含まれています。 + +## ファイルリスト + +### Live2DCubismCore.aar + +このファイルには、CubismCoreの機能といくつかのラッパーが含まれています。 +Javaで開発する場合は、このファイルを使用してください。 + +## ライブラリリスト + +| プラットフォーム | アーキテクチャ | jar | aar | パス | 注記 | +| --- |----------|---|-----|---|-----| +| Android | ARM64 | | ✓ | android/Live2DCubismCore.aar | | +| Android | x86 | | ✓ | android/Live2DCubismCore.aar | | +| Android | x86_64 | | ✓ | android/Live2DCubismCore.aar | | diff --git a/Live2DFramework/Core/README.md b/Live2DFramework/Core/README.md new file mode 100644 index 0000000..096f6fc --- /dev/null +++ b/Live2DFramework/Core/README.md @@ -0,0 +1,22 @@ +[English](README.md) / [日本語](README.ja.md) + +--- + +# Live2D Cubism Core + +This folder contains core library files for developing Java applications. + +## File List + +### Live2DCubismCore.aar + +This file contains Cubism Core features and some wrapper features. +Use this file when developing with Java. + +## Library List + +| Platform | Architecture | jar | aar | Path | Note | +| --- | --- | --- | --- |------------------------------| --- | +| Android | ARM64 | |✓ | android/Live2DCubismCore.aar | | +| Android | x86 | | ✓ | android/Live2DCubismCore.aar | | +| Android | x86_64 | | ✓ | android/Live2DCubismCore.aar | | diff --git a/Live2DFramework/Core/RedistributableFiles.txt b/Live2DFramework/Core/RedistributableFiles.txt new file mode 100644 index 0000000..69e0dec --- /dev/null +++ b/Live2DFramework/Core/RedistributableFiles.txt @@ -0,0 +1,4 @@ +The following is a list of files available for redistribution +under the terms of the Live2D Proprietary Software License Agreement: + +- android/Live2DCubismCore.aar diff --git a/Live2DFramework/Core/android/Live2DCubismCore.aar b/Live2DFramework/Core/android/Live2DCubismCore.aar new file mode 100644 index 0000000..fbf1a1c Binary files /dev/null and b/Live2DFramework/Core/android/Live2DCubismCore.aar differ diff --git a/Live2DFramework/LICENSE.md b/Live2DFramework/LICENSE.md new file mode 100644 index 0000000..a22f892 --- /dev/null +++ b/Live2DFramework/LICENSE.md @@ -0,0 +1,43 @@ +## Definitions + +### Live2D Cubism Components + +Cubism Java Framework is included in Live2D Cubism Components. + +Cubism Java Framework は Live2D Cubism Components に含まれます。 + +Cubism Java 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/) + +如果您的企业在最近一个会计年度的销售额达到或超过1000万日元,您必须得到Cubism SDK的出版授权许可(出版许可协议)。 + +* [Cubism SDK发行许可证](https://www.live2d.com/zh-CHS/download/cubism-sdk/release-license/) + +## Live2D Open Software License + +Live2D Cubism Components is available under Live2D Open Software License. + +* [Live2D Open Software License Agreement](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 Open Software 使用授权协议](https://www.live2d.com/eula/live2d-open-software-license-agreement_cn.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) +* [Live2D Proprietary Software 使用授权协议](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_cn.html) + +--- + +Please contact us from [here](https://www.live2d.jp/contact/) for more license information. diff --git a/Live2DFramework/README.ja.md b/Live2DFramework/README.ja.md new file mode 100644 index 0000000..ce73038 --- /dev/null +++ b/Live2DFramework/README.ja.md @@ -0,0 +1,112 @@ +[English](README.md) / [日本語](README.ja.md) + +--- + +# Cubism Java Framework + +Live2D Cubism Editor で出力したモデルをアプリケーションで利用するためのフレームワークです。 + +モデルを表示、操作するための各種機能を提供します。モデルをロードするにはCubism Coreライブラリと組み合わせて使用します。 + +## 対応Javaバージョン + +このFrameworkは**Java SE 7**以上でコンパイルが可能です。 + +## ライセンス + +本フレームワークを使用する前に、[ライセンス](LICENSE.md)をご確認ください。 + + +## Cubism 5新機能や過去バージョンとの互換性について + +本 SDK はCubism 5に対応した製品です。 +Cubism 5 Editorに搭載された新機能のSDK対応については [こちら](https://docs.live2d.com/cubism-sdk-manual/cubism-5-new-functions/)をご確認ください。 +過去バージョンのCubism SDKとの互換性については [こちら](https://docs.live2d.com/cubism-sdk-manual/compatibility-with-cubism-5/)をご確認ください。 + + +## コンポーネント + +各コンポーネントはパッケージごとに提供しています。 + +### effect + +自動まばたきやリップシンクなど、モデルに対してモーション情報をエフェクト的に付加する機能を提供します。 + +### exception + +Cubism SDK frameworkに関連する例外クラス群を提供します。 + +### id + +モデルに設定されたパラメータ名・パーツ名・Drawable 名を独自の型で管理する機能を提供します。 + +### math + +行列計算やベクトル計算など、モデルの操作や描画に必要な算術演算の機能を提供します。 + +### model + +モデルを取り扱うための各種機能(生成、更新、破棄)を提供します。 + +### motion + +モデルにモーションデータを適用するための各種機能(モーション再生、パラメータブレンド)を提供します。 + +### physics + +モデルに物理演算による変形操作を適用するための機能を提供します。 + +### rendering + +各種プラットフォームでモデルを描画するためのグラフィックス命令を実装したレンダラを提供します。 + +### type + +本フレームワーク内で使用する基本的な型をクラスとして定義したものを提供します。 + +### utils + +JSON パーサーやログ出力などのユーティリティ機能を提供します。 + +## Live2D Cubism Core for Java + +当リポジトリには Live2D Cubism Core for Java は同梱されていません。 + +ダウンロードするには[こちら](https://www.live2d.com/download/cubism-sdk/download-java/)のページを参照ください。 + +## サンプル + +標準的なアプリケーションの実装例については、下記サンプルリポジトリを参照ください。 + +[CubismJavaSamples](https://github.com/Live2D/CubismJavaSamples) + +## マニュアル + +[Cubism SDK Manual](https://docs.live2d.com/cubism-sdk-manual/top/) + +## 変更履歴 + +当リポジトリの変更履歴については [CHANGELOG.md](CHANGELOG.md) を参照ください。 + +## プロジェクトへの貢献 + +プロジェクトに貢献する方法はたくさんあります。バグのログの記録、このGitHubでのプルリクエストの送信、Live2Dコミュニティでの問題の報告と提案の作成です。 + +### フォークとプルリクエスト + +修正、改善、さらには新機能をもたらすかどうかにかかわらず、プルリクエストに感謝します。メインリポジトリを可能な限りクリーンに保つために、必要に応じて個人用フォークと機能ブランチを作成してください。 + +### バグ + +Live2Dコミュニティでは、問題のレポートと機能リクエストを定期的にチェックしています。バグレポートを提出する前に、Live2Dコミュニティで検索して、問題のレポートまたは機能リクエストがすでに投稿されているかどうかを確認してください。問題がすでに存在する場合は、関連するコメントを追記してください。 + +### 提案 + +SDKの将来についてのフィードバックにも関心があります。Live2Dコミュニティで提案や機能のリクエストを送信できます。このプロセスをより効果的にするために、それらをより明確に定義するのに役立つより多くの情報を含めるようお願いしています。 + +## フォーラム + +ユーザー同士でCubism SDKの活用方法の提案や質問をしたい場合は、是非フォーラムをご活用ください。 + +- [Live2D 公式クリエイターズフォーラム](https://creatorsforum.live2d.com/) +- [Live2D Creator's Forum(English)](https://community.live2d.com/) diff --git a/Live2DFramework/README.md b/Live2DFramework/README.md new file mode 100644 index 0000000..8ae1a34 --- /dev/null +++ b/Live2DFramework/README.md @@ -0,0 +1,112 @@ +[English](README.md) / [日本語](README.ja.md) + +--- + +# Cubism Java Framework + +This is a framework for using models output by Live2D Cubism Editor in applications. + +It provides various functions for displaying and manipulating the model. It is used in conjunction with the Cubism Core library to load the model. + +## Supported Java Versions + +This framework can be compiled with **Java SE 7** or higher. + +## License + +Please check the [license](LICENSE.md) before using the framework. + + +## Compatibility with Cubism 5 new features and previous Cubism SDK versions + +This SDK is compatible with Cubism 5. +For SDK compatibility with new features in Cubism 5 Editor, please refer to [here](https://docs.live2d.com/en/cubism-sdk-manual/cubism-5-new-functions/). +For compatibility with previous versions of Cubism SDK, please refer to [here](https://docs.live2d.com/en/cubism-sdk-manual/compatibility-with-cubism-5/). + + +## Components + +Each component is offered in the form of Java packages. + +### effect + +Provides functions such as automatic blinking and lip sync to add motion information as an effect to the model. + +### exception + +Provides exception classes related to Cubism SDK Framework. + +### id + +Provides functions to manage the parameter name, part name, and Drawable name set in the model with unique types. + +### math + +Provides arithmetic functions required for manipulating and drawing the model, such as matrix and vector calculations. + +### model + +Provides various functions (generate, update, destroy) for handling the model. + +### motion + +Provides various functions (motion playback, parameter blending) for applying motion data to the model. + +### physics + +Provides functions for applying transformation manipulations due to physics to the model. + +### rendering + +Provides a renderer that implements graphics instructions for drawing the model on various platforms. + +### type + +Provides classes that are defined from the basic types used within this framework. + +### utils + +Provides utility functions such as JSON parser and log output. + +## Live2D Cubism Core for Java + +Live2D Cubism Core for Java is not included in this repository. + +To download, please refer to [this](https://www.live2d.com/download/cubism-sdk/download-java/) page. + +## Samples + +Please refer to the following sample repository for implementation examples of standard applications. + +[CubismJavaSamples](https://github.com/Live2D/CubismJavaSamples) + +## Manual + +[Cubism SDK Manual](https://docs.live2d.com/cubism-sdk-manual/top/) + +## Changelog + +Please refer to [CHANGELOG.md](CHANGELOG.md) for the changelog of this repository. + +## Contributing + +There are many ways to contribute to the project: logging bugs, submitting pull requests on this GitHub, and reporting issues and making suggestions in Live2D Community. + +### Forking And Pull Requests + +We very much appreciate your pull requests, whether they bring fixes, improvements, or even new features. To keep the main repository as clean as possible, create a personal fork and feature branches there as needed. + +### Bugs + +We are regularly checking issue-reports and feature requests at Live2D Community. Before filing a bug report, please do a search in Live2D Community to see if the issue-report or feature request has already been posted. If you find your issue already exists, make relevant comments and add your reaction. + +### Suggestions + +We're also interested in your feedback for the future of the SDK. You can submit a suggestion or feature request at Live2D Community. To make this process more effective, we're asking that you include more information to help define them more clearly. + +## Forum + +If you want to suggest or ask questions about how to use the Cubism SDK between users, please use the forum. + +- [Live2D Creator's Forum](https://community.live2d.com/) +- [Live2D 公式クリエイターズフォーラム (Japanese)](https://creatorsforum.live2d.com/) diff --git a/Live2DFramework/build.gradle b/Live2DFramework/build.gradle new file mode 100644 index 0000000..32e5ee8 --- /dev/null +++ b/Live2DFramework/build.gradle @@ -0,0 +1,17 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.6.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/Live2DFramework/framework/build.gradle b/Live2DFramework/framework/build.gradle new file mode 100644 index 0000000..a73d1f0 --- /dev/null +++ b/Live2DFramework/framework/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'com.android.library' +} + +android { + namespace = "com.live2d.sdk.cubism.framework" + compileSdk ((project.findProperty("PROP_COMPILE_SDK_VERSION") ?: "33").toString().toInteger()) + + defaultConfig { + minSdkVersion ((project.findProperty("PROP_MIN_SDK_VERSION") ?: "21").toString().toInteger()) + targetSdkVersion ((project.findProperty("PROP_TARGET_SDK_VERSION") ?: "33").toString().toInteger()) + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +dependencies { + compileOnly(fileTree(dir: '../Core/android', include: ['Live2DCubismCore.aar'])) + + testImplementation 'junit:junit:4.13.2' +} diff --git a/Live2DFramework/framework/consumer-rules.pro b/Live2DFramework/framework/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/Live2DFramework/framework/gradle.properties b/Live2DFramework/framework/gradle.properties new file mode 100644 index 0000000..0529722 --- /dev/null +++ b/Live2DFramework/framework/gradle.properties @@ -0,0 +1,25 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Android SDK version that will be used as the compiled project +PROP_COMPILE_SDK_VERSION=35 +# Android SDK version that will be used as the earliest version of android this application can run on +PROP_MIN_SDK_VERSION=21 +# Android SDK version that will be used as the latest version of android this application has been tested on +PROP_TARGET_SDK_VERSION=35 diff --git a/Live2DFramework/framework/proguard-rules.pro b/Live2DFramework/framework/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/Live2DFramework/framework/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Live2DFramework/framework/src/main/AndroidManifest.xml b/Live2DFramework/framework/src/main/AndroidManifest.xml new file mode 100644 index 0000000..fc06563 --- /dev/null +++ b/Live2DFramework/framework/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismCdiJson.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismCdiJson.java new file mode 100644 index 0000000..6915580 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismCdiJson.java @@ -0,0 +1,238 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + + +package com.live2d.sdk.cubism.framework; + +import com.live2d.sdk.cubism.framework.utils.jsonparser.ACubismJsonValue; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; + +import java.util.List; + +/** + * This class handles cdi.json data. + */ +public class CubismCdiJson { + public static CubismCdiJson create(byte[] buffer) { + CubismJson json; + json = CubismJson.create(buffer); + + return new CubismCdiJson(json); + } + + // ----Parameters----// + + /** + * Get the parameters number. + * + * @return number of parameters + */ + public int getParametersCount() { + if (!existsParameters()) { + return 0; + } + return json.getRoot().get(JsonKey.PARAMETERS.key).size(); + } + + /** + * Get Parameters ID + * + * @param index index + * @return parameter ID + */ + public String getParametersId(int index) { + return json.getRoot().get(JsonKey.PARAMETERS.key).get(index).get(JsonKey.ID.key).getString(); + } + + /** + * Get parameters group ID. + * + * @param index index + * @return parameters group ID + */ + public String getParametersGroupId(int index) { + return json.getRoot().get(JsonKey.PARAMETERS.key).get(index).get(JsonKey.GROUP_ID.key).getString(); + } + + /** + * Get parameters name + * + * @param index index + * @return parameters name + */ + public String getParametersName(int index) { + return json.getRoot().get(JsonKey.PARAMETERS.key).get(index).get(JsonKey.NAME.key).getString(); + } + + // ----ParameterGroups----// + + /** + * Get the number of parameter groups. + * + * @return number of parameter groups + */ + public int getParameterGroupsCount() { + if (!existsParameterGroups()) { + return 0; + } + return json.getRoot().get(JsonKey.PARAMETER_GROUPS.key).size(); + } + + /** + * ZGet parameter groups ID + * + * @param index index + * @return parameter groups ID + */ + public String getParameterGroupsId(int index) { + return json.getRoot().get(JsonKey.PARAMETER_GROUPS.key).get(index).get(JsonKey.ID.key).getString(); + } + + /** + * Get parameter groups' group ID. + * + * @param index index + * @return parameter groups' group ID + */ + public String getParameterGroupsGroupId(int index) { + return json.getRoot().get(JsonKey.PARAMETER_GROUPS.key).get(index).get(JsonKey.GROUP_ID.key).getString(); + } + + /** + * Get parameter groups name + * + * @param index index + * @return parameter groups name + */ + public String getParameterGroupsName(int index) { + return json.getRoot().get(JsonKey.PARAMETER_GROUPS.key).get(index).get(JsonKey.NAME.key).getString(); + } + + // ----Parts---- + + /** + * Get the number of parts. + * + * @return number of parts + */ + public int getPartsCount() { + if (!existsParts()) { + return 0; + } + return json.getRoot().get(JsonKey.PARTS.key).size(); + } + + /** + * Get parts ID. + * + * @param index index + * @return parts ID + */ + public String getPartsId(int index) { + return json.getRoot().get(JsonKey.PARTS.key).get(index).get(JsonKey.ID.key).getString(); + } + + /** + * Get parts name. + * + * @param index index + * @return parts name + */ + public String getPartsName(int index) { + return json.getRoot().get(JsonKey.PARTS.key).get(index).get(JsonKey.NAME.key).getString(); + } + + // ----- Combined Parameters -----// + /** + * Returns the number of combined parameters. + * + * @return number of combined parameters + */ + public int getCombinedParametersCount() { + if (!existsCombinedParameters()) { + return 0; + } + return json.getRoot().get(JsonKey.COMBINED_PARAMETERS.key).size(); + } + + /** + * Returns the pair list of the combined parameter. + * + * @param index index to the desired combined parameters. + * @return pair list of the combined parameter + */ + public List getCombinedParameter(int index) { + return json.getRoot().get(JsonKey.COMBINED_PARAMETERS.key).get(index).getList(); + } + + // JSON keys + private enum JsonKey { + VERSION("Version"), + PARAMETERS("Parameters"), + PARAMETER_GROUPS("ParameterGroups"), + PARTS("Parts"), + COMBINED_PARAMETERS("CombinedParameters"), + ID("Id"), + GROUP_ID("GroupId"), + NAME("Name"); + + private final String key; + + JsonKey(String key) { + this.key = key; + } + } + + private CubismCdiJson(CubismJson json) { + this.json = json; + } + + /** + * Check if the parameter key exists. + * + * @return If true, the key exists + */ + private boolean existsParameters() { + ACubismJsonValue node = json.getRoot().get(JsonKey.PARAMETERS.key); + return !node.isNull() && !node.isError(); + } + + /** + * Check if the parameter group key exists. + * + * @return If true, the key exists + */ + private boolean existsParameterGroups() { + ACubismJsonValue node = json.getRoot().get(JsonKey.PARAMETER_GROUPS.key); + return !node.isNull() && !node.isError(); + } + + /** + * Check if the part's key exists. + * + * @return If true, the key exists + */ + private boolean existsParts() { + ACubismJsonValue node = json.getRoot().get(JsonKey.PARTS.key); + return !node.isNull() && !node.isError(); + } + + /** + * Returns whether the combined parameters exist in the Display Information File(cdi3.json). + * + * @return If true, the key exists. + */ + private boolean existsCombinedParameters() { + ACubismJsonValue node = json.getRoot().get(JsonKey.COMBINED_PARAMETERS.key); + return !node.isNull() && !node.isError(); + } + + /** + * cdi.json data + */ + private final CubismJson json; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismDefaultParameterId.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismDefaultParameterId.java new file mode 100644 index 0000000..a4a2cdb --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismDefaultParameterId.java @@ -0,0 +1,122 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework; + +/** + * Constant class that holds the default value of the parameter ID. + *

+ * Default value specifications are based on the following manual. + * ... + */ +public class CubismDefaultParameterId { + public enum HitAreaId { + PREFIX("HitArea"), + HEAD("Head"), + BODY("Body"); + + private final String id; + + HitAreaId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + } + + public enum PartId { + CORE("Parts01Core"), + ARM_PREFIX("Parts01Arm_"), + ARM_L_PREFIX("Parts01ArmL_"), + ARM_R_PREFIX("Parts01ArmR_"); + + private final String id; + + PartId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + } + + public enum ParameterId { + ANGLE_X("ParamAngleX"), + ANGLE_Y("ParamAngleY"), + ANGLE_Z("ParamAngleZ"), + + EYE_L_OPEN("ParamEyeLOpen"), + EYE_L_SMILE("ParamEyeLSmile"), + EYE_R_OPEN("ParamEyeROpen"), + EYE_R_SMILE("ParamEyeRSmile"), + EYE_W_L_Y("ParamBrowLY"), + EYE_BALL_X("ParamEyeBallX"), + EYE_BALL_Y("ParamEyeBallY"), + EYE_BALL_FORM("ParamEyeBallForm"), + + BROW_L_X("ParamBrowLX"), + BROW_L_Y("ParamBrowLY"), + BROW_R_X("ParamBrowRX"), + BROW_R_Y("ParamBrowRY"), + BROW_L_ANGLE("ParamBrowLAngle"), + BROW_R_ANGLE("ParamBrowRAngle"), + BROW_L_FORM("ParamBrowLForm"), + BROW_R_FORM("ParamBrowRForm"), + + MOUTH_FORM("ParamMouthForm"), + MOUTH_OPEN_Y("ParamMouthOpenY"), + + CHEEK("ParamCheek"), + + BODY_ANGLE_X("ParamBodyAngleX"), + BODY_ANGLE_Y("ParamBodyAngleY"), + BODY_ANGLE_Z("ParamBodyAngleZ"), + + BREATH("ParamBreath"), + + ARM_L_A("ParamArmLA"), + ARM_L_B("ParamArmLB"), + ARM_R_A("ParamArmRA"), + ARM_R_B("ParamArmRB"), + + HAND_L("ParamHandL"), + HAND_R("ParamHandR"), + + HAIR_FRONT("ParamHairFront"), + HAIR_SIDE("ParamHairSide"), + HAIR_BACK("ParamHairBack"), + HAIR_FLUFFY("ParamHairFluffy"), + + SHOULDER_Y("ParamShoulderY"), + + BUST_X("ParamBustX"), + BUST_Y("ParamBustY"), + + BASE_X("ParamBaseX"), + BASE_Y("ParamBaseY"), + + NONE("NONE"); + + private final String id; + + ParameterId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + } + + /** + * private constructor + */ + private CubismDefaultParameterId() {} +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismFramework.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismFramework.java new file mode 100644 index 0000000..9572404 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismFramework.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework; + +import com.live2d.sdk.cubism.core.CubismCoreVersion; +import com.live2d.sdk.cubism.core.ICubismLogger; +import com.live2d.sdk.cubism.core.Live2DCubismCore; +import com.live2d.sdk.cubism.framework.CubismFrameworkConfig.LogLevel; +import com.live2d.sdk.cubism.framework.id.CubismIdManager; +import com.live2d.sdk.cubism.framework.rendering.android.CubismRendererAndroid; + +import java.util.Locale; + +import static com.live2d.sdk.cubism.framework.utils.CubismDebug.cubismLogInfo; +import static com.live2d.sdk.cubism.framework.utils.CubismDebug.cubismLogWarning; + +/** + * Entrypoint of Live2D Cubism Original Workflow SDK. + *

+ * Beginning to use this Framework, call CubismFramework.initialize() method. Terminating the application, call CubismFramework.dispose() method. + */ +public class CubismFramework { + /** + * Inner class that define optional elements to be set in CubismFramework. + */ + public static class Option { + /** + * Set the log output function. + * + * @param logger log output function + */ + public void setLogFunction(ICubismLogger logger) { + if (logger == null) { + throw new IllegalArgumentException("logger is null."); + } + logFunction = logger; + } + + /** + * Functional interface of logging. + */ + public ICubismLogger logFunction; + /** + * Log output level. + * (Default value is OFF(Log outputting is not executed.)) + */ + public LogLevel loggingLevel = LogLevel.OFF; + } + + /** + * Offset value for mesh vertices + */ + public static final int VERTEX_OFFSET = 0; + /** + * Step value for mesh vertices + */ + public static final int VERTEX_STEP = 2; + + + /** + * Enable Cubism Framework API. + * Required to run this method before using API. + * Once prepared, if you run this again, the inner processes are skipped. + * + * @param option Option Class's instance + * @return if preparing process has finished, return true + */ + public static boolean startUp(final Option option) { + if (s_isStarted) { + cubismLogInfo("CubismFramework.startUp() is already done."); + + return s_isStarted; + } + + s_option = option; + + if (s_option != null) { + Live2DCubismCore.setLogger(option.logFunction); + } + + s_isStarted = true; + + // Display the version information of Live2D Cubism Core. + final CubismCoreVersion version = Live2DCubismCore.getVersion(); + + cubismLogInfo(String.format(Locale.US, "Live2D Cubism Core version: %02d.%02d.%04d (%d)", version.getMajor(), version.getMinor(), version.getPatch(), version.getVersionNumber())); + + cubismLogInfo("CubismFramework.startUp() is complete."); + + return s_isStarted; + } + + /** + * Clear each parameter in CubismFramework initialized by startUp() method. + * Use this method at reusing CubismFramework done dispose() method. + */ + public static void cleanUp() { + s_isStarted = false; + s_isInitialized = false; + s_option = null; + s_cubismIdManager = null; + } + + /** + * Whether Cubism Framework API has been prepared already. + * + * @return if API has been already prepared, return true + */ + public static boolean isStarted() { + return s_isStarted; + } + + /** + * Initializing resources in Cubism Framework, the model is enabled to display. + * If you would like to use initialize() method again, first you need to run dispose() method. + */ + public static void initialize() { + assert (s_isStarted); + + if (!s_isStarted) { + cubismLogWarning("CubismFramework is not started."); + return; + } + + // Disturb consecutive securing resources. + if (s_isInitialized) { + cubismLogWarning("CubismFramework.initialize() skipped, already initialized."); + return; + } + + // ----- Static Release ----- + s_cubismIdManager = new CubismIdManager(); + s_isInitialized = true; + + cubismLogInfo("CubismFramework::Initialize() is complete."); + } + + /** + * Releases all resources in the Cubism Framework. + */ + public static void dispose() { + assert (s_isStarted); + + if (!s_isStarted) { + cubismLogWarning("CubismFramework is not started."); + return; + } + + // If you use dispose() method, it is required to run initialize() method firstly. + if (!s_isInitialized) { + cubismLogWarning("CubismFramework.dispose() skipped, not initialized."); + return; + } + + //---- static release ---- + s_cubismIdManager = null; + // Release static resources of renderer(cf. Shader programs) + CubismRendererAndroid.staticRelease(); + + s_isInitialized = false; + + cubismLogInfo("CubismFramework.dispose() is complete."); + } + + /** + * Whether having already initialized CubismFramework's resources. + * + * @return If securing resources have already done, return true + */ + public static boolean isInitialized() { + return s_isInitialized; + } + + /** + * Execute log function bound Core API + * + * @param message log message + */ + public static void coreLogFunction(final String message) { + if (Live2DCubismCore.getLogger() != null) { + Live2DCubismCore.getLogger().print(message); + } + } + + /** + * Return the current value of log output level setting. + * + * @return the current value of log output level setting + */ + public static LogLevel getLoggingLevel() { + if (s_option != null) { + return s_option.loggingLevel; + } + return LogLevel.OFF; + } + + /** + * Get the instance of ID manager. + * + * @return CubismIdManager class's instance + */ + public static CubismIdManager getIdManager() { + return s_cubismIdManager; + } + + /** + * private constructor + */ + private CubismFramework() {} + + /** + * Flag whether the framework has been started or not. + */ + private static boolean s_isStarted; + /** + * Flag whether the framework has been initialized or not. + */ + private static boolean s_isInitialized; + /** + * Option object + */ + private static Option s_option; + /** + * CubismIDManager object + */ + private static CubismIdManager s_cubismIdManager; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismFrameworkConfig.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismFrameworkConfig.java new file mode 100644 index 0000000..bc88fc3 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismFrameworkConfig.java @@ -0,0 +1,67 @@ +package com.live2d.sdk.cubism.framework; + +/** + * CubismFrameworkで使用される定数の定義クラス。
+ * デバッグやログに関わる設定をデフォルトから変更したい場合は、このクラスの定数の値を書き換えること。 + */ +public class CubismFrameworkConfig { + /** + * ログ出力レベルを定義する列挙体。 + */ + public enum LogLevel { + /** + * 詳細ログ出力設定 + */ + VERBOSE(0), + /** + * デバッグログ出力設定 + */ + DEBUG(1), + /** + * Infoログ出力設定 + */ + INFO(2), + /** + * 警告ログ出力設定 + */ + WARNING(3), + /** + * エラーログ出力設定 + */ + ERROR(4), + /** + * ログ出力オフ設定 + */ + OFF(5); + + private final int id; + + LogLevel(final int id) { + this.id = id; + } + + public int getId() { + return id; + } + } + + /** + * Cubism SDKにおけるデバッグ機能の有効状態。trueなら有効。 + */ + public static final boolean CSM_DEBUG = false; + + /** + * ログ出力設定。
+ * 強制的にログ出力レベルを変える時に定義を有効にする。 + * + * @note LogLevel.VERBOSE ~ LogLevel.OFF のいずれかを指定する。 + */ + public static final LogLevel CSM_LOG_LEVEL = LogLevel.VERBOSE; + + /** + * privateコンストラクタ。 + * + * @note 定数クラスのためインスタンス化させない + */ + private CubismFrameworkConfig() {} +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismModelSettingJson.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismModelSettingJson.java new file mode 100644 index 0000000..d507bf4 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/CubismModelSettingJson.java @@ -0,0 +1,503 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework; + +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.utils.jsonparser.ACubismJsonValue; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJsonString; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * This class deals with model3.json data. + */ +public class CubismModelSettingJson implements ICubismModelSetting { + public CubismModelSettingJson(byte[] buffer) { + CubismJson json; + json = CubismJson.create(buffer); + + this.json = json; + + if (jsonFrequencyValue != null) { + jsonFrequencyValue.clear(); + } else { + jsonFrequencyValue = new ArrayList(); + } + + // The order should match the enum FrequentNode + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.GROUPS.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.MOC.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.MOTIONS.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.DISPLAY_INFO.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.EXPRESSIONS.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.TEXTURES.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.PHYSICS.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.POSE.key)); + jsonFrequencyValue.add(this.json.getRoot().get(JsonKey.HIT_AREAS.key)); + } + + @Override + public CubismJson getJson() { + return json; + } + + @Override + public String getModelFileName() { + if (!existsModelFile()) { + return ""; + } + + return jsonFrequencyValue.get(FrequentNode.MOC.id).getString(); + } + + @Override + public int getTextureCount() { + if (!existsTextureFiles()) { + return 0; + } + + return json.getRoot() + .get(JsonKey.FILE_REFERENCES.key) + .get(JsonKey.TEXTURES.key) + .size(); + } + + @Override + public String getTextureDirectory() { + if (!existsTextureFiles()) { + return ""; + } + + String rowString = jsonFrequencyValue.get(FrequentNode.TEXTURES.id).get(0).getString(); + return rowString.split("/")[0]; + } + + @Override + public String getTextureFileName(int index) { + return jsonFrequencyValue.get(FrequentNode.TEXTURES.id).get(index).getString(); + } + + @Override + public int getHitAreasCount() { + if (!existsHitAreas()) { + return 0; + } + return jsonFrequencyValue.get(FrequentNode.HIT_AREAS.id).size(); + } + + @Override + public CubismId getHitAreaId(int index) { + return CubismFramework.getIdManager().getId(jsonFrequencyValue.get(FrequentNode.HIT_AREAS.id).get(index).get(JsonKey.ID.key).getString()); + } + + @Override + public String getHitAreaName(int index) { + return jsonFrequencyValue.get(FrequentNode.HIT_AREAS.id).get(index).get(JsonKey.NAME.key).getString(); + } + + @Override + public String getPhysicsFileName() { + if (!existsPhysicsFile()) { + return ""; + } + return jsonFrequencyValue.get(FrequentNode.PHYSICS.id).getString(); + } + + @Override + public String getPoseFileName() { + if (!existsPoseFile()) { + return ""; + } + + return jsonFrequencyValue.get(FrequentNode.POSE.id).getString(); + } + + @Override + public String getDisplayInfoFileName() { + if (!existsDisplayInfoFile()) { + return ""; + } + return jsonFrequencyValue.get(FrequentNode.DISPLAY_INFO.id).getString(); + } + + @Override + public int getExpressionCount() { + if (!existsExpressionFile()) { + return 0; + } + return jsonFrequencyValue.get(FrequentNode.EXPRESSIONS.id).size(); + + } + + @Override + public String getExpressionName(int index) { + return jsonFrequencyValue.get(FrequentNode.EXPRESSIONS.id).get(index).get(JsonKey.NAME.key).getString(); + } + + @Override + public String getExpressionFileName(int index) { + return jsonFrequencyValue.get(FrequentNode.EXPRESSIONS.id).get(index).get(JsonKey.FILEPATH.key).getString(); + } + + @Override + public int getMotionGroupCount() { + if (!existsMotionGroups()) { + return 0; + } + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).size(); + } + + @Override + public String getMotionGroupName(int index) { + if (!existsMotionGroups()) { + return null; + } + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).getKeys().get(index).getString(); + } + + @Override + public int getMotionCount(final String groupName) { + if (!existsMotionGroupName(groupName)) { + return 0; + } + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).size(); + + } + + @Override + public String getMotionFileName(final String groupName, int index) { + if (!existsMotionGroupName(groupName)) { + return ""; + } + + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.FILEPATH.key).getString(); + } + + @Override + public String getMotionSoundFileName(final String groupName, int index) { + if (!existsMotionSoundFile(groupName, index)) { + return ""; + } + + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.SOUND_PATH.key).getString(); + } + + @Override + public float getMotionFadeInTimeValue(final String groupName, int index) { + if (!existsMotionFadeIn(groupName, index)) { + return -1.0f; + } + + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.FADE_IN_TIME.key).toFloat(); + } + + @Override + public float getMotionFadeOutTimeValue(String groupName, int index) { + if (!existsMotionFadeOut(groupName, index)) { + return -1.0f; + } + + return jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.FADE_OUT_TIME.key).toFloat(); + } + + @Override + public String getUserDataFile() { + if (!existsUserDataFile()) { + return ""; + } + return json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.USER_DATA.key).getString(); + } + + @Override + public boolean getLayoutMap(Map outLayoutMap) { + Map map = json.getRoot().get(JsonKey.LAYOUT.key).getMap(); + + if (map == null) { + return false; + } + + boolean result = false; + for (Map.Entry entry : map.entrySet()) { + outLayoutMap.put(entry.getKey().getString(), entry.getValue().toFloat()); + result = true; + } + + return result; + } + + @Override + public int getEyeBlinkParameterCount() { + if (!existsEyeBlinkParameters()) { + return 0; + } + + int eyeBlinkParameterCount = 0; + for (int i = 0; i < jsonFrequencyValue.get(FrequentNode.GROUPS.id).size(); i++) { + ACubismJsonValue refI = jsonFrequencyValue.get(FrequentNode.GROUPS.id).get(i); + + if (refI.isNull() || refI.isError()) { + continue; + } + + if (refI.get(JsonKey.NAME.key).getString().equals(JsonKey.EYE_BLINK.key)) { + eyeBlinkParameterCount = refI.get(JsonKey.IDS.key).getList().size(); + break; + } + } + + return eyeBlinkParameterCount; + } + + @Override + public CubismId getEyeBlinkParameterId(int index) { + if (!existsEyeBlinkParameters()) { + return null; + } + + for (int i = 0; i < jsonFrequencyValue.get(FrequentNode.GROUPS.id).size(); ++i) { + ACubismJsonValue refI = jsonFrequencyValue.get(FrequentNode.GROUPS.id).get(i); + + if (refI.isNull() || refI.isError()) { + continue; + } + + if (refI.get(JsonKey.NAME.key).getString().equals(JsonKey.EYE_BLINK.key)) { + return CubismFramework.getIdManager().getId(refI.get(JsonKey.IDS.key).get(index).getString()); + } + } + return null; + } + + + @Override + public int getLipSyncParameterCount() { + if (!existsLipSyncParameters()) { + return 0; + } + + + int lipSyncParameterCount = 0; + for (int i = 0; i < jsonFrequencyValue.get(FrequentNode.GROUPS.id).size(); i++) { + ACubismJsonValue refI = jsonFrequencyValue.get(FrequentNode.GROUPS.id).get(i); + + if (refI.isNull() || refI.isError()) { + continue; + } + + if (refI.get(JsonKey.NAME.key).getString().equals(JsonKey.LIP_SYNC.key)) { + lipSyncParameterCount = refI.get(JsonKey.IDS.key).getList().size(); + break; + } + } + return lipSyncParameterCount; + } + + @Override + public CubismId getLipSyncParameterId(int index) { + if (!existsLipSyncParameters()) { + return null; + } + + for (int i = 0; i < jsonFrequencyValue.get(FrequentNode.GROUPS.id).size(); i++) { + ACubismJsonValue refI = jsonFrequencyValue.get(FrequentNode.GROUPS.id).get(i); + + if (refI.isNull() || refI.isError()) { + continue; + } + + if (refI.get(JsonKey.NAME.key).getString().equals(JsonKey.LIP_SYNC.key)) { + return CubismFramework.getIdManager().getId(refI.get(JsonKey.IDS.key).get(index).getString()); + } + } + return null; + } + + /** + * Enum class for frequent nodes. + */ + protected enum FrequentNode { + GROUPS(0), + MOC(1), + MOTIONS(2), + DISPLAY_INFO(3), + EXPRESSIONS(4), + TEXTURES(5), + PHYSICS(6), + POSE(7), + HIT_AREAS(8); + + protected final int id; + + FrequentNode(final int id) { + this.id = id; + } + } + + protected enum JsonKey { + VERSION("Version"), + FILE_REFERENCES("FileReferences"), + GROUPS("Groups"), + LAYOUT("Layout"), + HIT_AREAS("HitAreas"), + + MOC("Moc"), + TEXTURES("Textures"), + PHYSICS("Physics"), + DISPLAY_INFO("DisplayInfo"), + POSE("Pose"), + EXPRESSIONS("Expressions"), + MOTIONS("Motions"), + + USER_DATA("UserData"), + NAME("Name"), + FILEPATH("File"), + ID("Id"), + IDS("Ids"), + TARGET("Target"), + + // Motions + IDLE("Idle"), + TAP_BODY("TapBody"), + PINCH_IN("PinchIn"), + PINCH_OUT("PinchOut"), + SHAKE("Shake"), + FLICK_HEAD("FlickHead"), + PARAMETER("Parameter"), + + SOUND_PATH("Sound"), + FADE_IN_TIME("FadeInTime"), + FADE_OUT_TIME("FadeOutTime"), + + // Layout + CENTER_X("CenterX"), + CENTER_Y("CenterY"), + X("X"), + Y("Y"), + WIDTH("Width"), + HEIGHT("Height"), + + LIP_SYNC("LipSync"), + EYE_BLINK("EyeBlink"), + + INIT_PARAMETER("init_param"), + INIT_PARTS_VISIBLE("init_parts_visible"), + VAL("val"); + + protected final String key; + + JsonKey(String key) { + this.key = key; + } + } + + + // キーが存在するかどうかのチェック + protected boolean existsModelFile() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.MOC.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsTextureFiles() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.TEXTURES.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsHitAreas() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.HIT_AREAS.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsPhysicsFile() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.PHYSICS.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsPoseFile() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.POSE.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsDisplayInfoFile() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.DISPLAY_INFO.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsExpressionFile() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.EXPRESSIONS.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsMotionGroups() { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.MOTIONS.id); + return !node.isNull() && !node.isError(); + } + + protected boolean existsMotionGroupName(String groupName) { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName); + return !node.isNull() && !node.isError(); + } + + protected boolean existsMotionSoundFile(String groupName, int index) { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.SOUND_PATH.key); + return !node.isNull() && !node.isError(); + } + + protected boolean existsMotionFadeIn(String groupName, int index) { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.FADE_IN_TIME.key); + return !node.isNull() && !node.isError(); + } + + protected boolean existsMotionFadeOut(String groupName, int index) { + ACubismJsonValue node = jsonFrequencyValue.get(FrequentNode.MOTIONS.id).get(groupName).get(index).get(JsonKey.FADE_OUT_TIME.key); + return !node.isNull() && !node.isError(); + } + + protected boolean existsUserDataFile() { + return !json.getRoot().get(JsonKey.FILE_REFERENCES.key).get(JsonKey.USER_DATA.key).isNull(); + } + + protected boolean existsEyeBlinkParameters() { + if (jsonFrequencyValue.get(FrequentNode.GROUPS.id).isNull() || jsonFrequencyValue.get(FrequentNode.GROUPS.id).isError()) { + return false; + } + + for (int i = 0; i < jsonFrequencyValue.get(FrequentNode.GROUPS.id).size(); ++i) { + if (jsonFrequencyValue.get(FrequentNode.GROUPS.id).get(i).get(JsonKey.NAME.key).getString().equals(JsonKey.EYE_BLINK.key)) { + return true; + } + } + + return false; + } + + protected boolean existsLipSyncParameters() { + if (jsonFrequencyValue.get(FrequentNode.GROUPS.id).isNull() || jsonFrequencyValue.get(FrequentNode.GROUPS.id).isError()) { + return false; + } + + for (int i = 0; i < jsonFrequencyValue.get(FrequentNode.GROUPS.id).size(); i++) { + if (jsonFrequencyValue.get(FrequentNode.GROUPS.id).get(i).get(JsonKey.NAME.key).getString().equals(JsonKey.LIP_SYNC.key)) { + return true; + } + } + return false; + } + + /** + * model3.json data + */ + protected final CubismJson json; + /** + * Frequent nodes in the _json data + */ + protected List jsonFrequencyValue; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/ICubismModelSetting.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/ICubismModelSetting.java new file mode 100644 index 0000000..b665689 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/ICubismModelSetting.java @@ -0,0 +1,222 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework; + +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.utils.jsonparser.ACubismJsonValue; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJsonString; + +import java.util.Map; + +/** + * This interface deal with model setting information. + *

+ * The class implemented this interface can deal with model setting info. + */ +public interface ICubismModelSetting { + /** + * Get model3.json. + * + * @return model3.json + */ + CubismJson getJson(); + + /** + * Get the name of Moc file. + * + * @return name of Moc file + */ + String getModelFileName(); + + /** + * Get a number of textures model uses. + * + * @return number of textures + */ + int getTextureCount(); + + /** + * Get the name of directory is located textures. + * + * @return name of directory is located textures. + */ + String getTextureDirectory(); + + /** + * Get the name of textures used by model. + * + * @param index index value of array + * @return the name of textures + */ + String getTextureFileName(int index); + + /** + * Get the number of collision detection set to model. + * + * @return the number of collision detection set to model + */ + int getHitAreasCount(); + + /** + * Get the ID set to collision detection. + * + * @param index index value of array + * @return the ID set to collision detection + */ + CubismId getHitAreaId(int index); + + /** + * Get the name set to collision detection + * + * @param index index value of array + * @return the name set to collision detection + */ + String getHitAreaName(int index); + + /** + * Get the name of the physics setting file. + * + * @return the name of the physics setting file. + */ + String getPhysicsFileName(); + + /** + * Get the name of parts switching setting file. + * + * @return Parts switching setting file + */ + String getPoseFileName(); + + /** + * Get the name of cdi3.json file. + * + * @return + */ + String getDisplayInfoFileName(); + + /** + * Get the number of expression setting file. + * + * @return the number of expression setting file + */ + int getExpressionCount(); + + /** + * Get the name(Alias) identifying expression setting file. + * + * @param index index value of array + * @return the name of expression + */ + String getExpressionName(int index); + + /** + * Get the name of expression setting file. + * + * @param index index value of array + * @return the name of expression setting file + */ + String getExpressionFileName(int index); + + /** + * Get the number of motion groups. + * + * @return the number of motion groups + */ + int getMotionGroupCount(); + + String getMotionGroupName(int index); + + /** + * Get the number of motion included in motion group given to this method by an argument. + * + * @param groupName the name of motion group + * @return the number of motion included in the motion group. + */ + int getMotionCount(final String groupName); + + /** + * Get the name of the motion file from group name and index value. + * + * @param groupName the name of the motion group + * @param index index value of array + * @return the name of motion file + */ + String getMotionFileName(final String groupName, int index); + + /** + * Get the name of sound file mapped to the motion. + * + * @param groupName the name of motion group + * @param index index value of arrayz + * @return the name of sound file + */ + String getMotionSoundFileName(final String groupName, int index); + + /** + * Get the fade-in processing time at start of motion + * + * @param groupName the name of motion group + * @param index index value of array + * @return fade-in processing time[s] + */ + float getMotionFadeInTimeValue(final String groupName, int index); + + /** + * Get fade-out processing time at end of motion. + * + * @param groupName the name of motion group + * @param index index value of array + * @return fade-out processing time[s] + */ + float getMotionFadeOutTimeValue(final String groupName, int index); + + /** + * Get the name of userdata file. + * + * @return the name of userdata file + */ + String getUserDataFile(); + + /** + * Get the layout information. + * + * @return if layout information exists, return true + */ + boolean getLayoutMap(Map outLayoutMap); + + /** + * Get the number of parameters associated to eye blink. + * + * @return the number of parameters associated to eye blink + */ + int getEyeBlinkParameterCount(); + + /** + * Get the parameter ID associated to eye blink. + * + * @param index index value of array + * @return parameter ID + */ + CubismId getEyeBlinkParameterId(int index); + + /** + * Get the number of parameters associated to lip sync. + * + * @return the number of parameters associated to lip sync + */ + int getLipSyncParameterCount(); + + /** + * Get the parameter ID associated to lip sync. + * + * @param index index value of array + * @return parameter ID + */ + CubismId getLipSyncParameterId(int index); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismBreath.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismBreath.java new file mode 100644 index 0000000..778f59c --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismBreath.java @@ -0,0 +1,165 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.effect; + +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.model.CubismModel; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.live2d.sdk.cubism.framework.math.CubismMath.PI; +import static com.live2d.sdk.cubism.framework.math.CubismMath.sinF; + +/** + * This class offers the breath function. + */ +public class CubismBreath { + /** + * This inner class has breath parameter information. + */ + public static class BreathParameterData { + /** + * Constructor + * + * @param parameterId A parameter ID bound breathing info. + * @param offset A wave offset when breathing is taken as a sine wave + * @param peak A wave height when breathing is taken as a sine wave + * @param cycle A wave cycle when breathing is taken as a sine wave + * @param weight A weight to a parameter + */ + public BreathParameterData( + CubismId parameterId, + float offset, + float peak, + float cycle, + float weight + ) { + this.parameterId = parameterId; + this.offset = offset; + this.peak = peak; + this.cycle = cycle; + this.weight = weight; + } + + /** + * Copy constructor + * + * @param data BreathParameterData instance + */ + public BreathParameterData(BreathParameterData data) { + this.parameterId = data.parameterId; + this.offset = data.offset; + this.peak = data.peak; + this.cycle = data.cycle; + this.weight = data.weight; + } + + /** + * A parameter ID bound breath info. + */ + public final CubismId parameterId; + /** + * A wave offset when breathing is taken as a sine wave + */ + public final float offset; + /** + * A wave height when breathing is taken as a sine wave + */ + public final float peak; + /** + * A wave cycle when breathing is taken as a sine wave + */ + public final float cycle; + /** + * A weight to a parameter + */ + public final float weight; + } + + /** + * Creates a {@code CubismBreath} instance. + * + * @return a {@code CubismBreath} instance + */ + public static CubismBreath create() { + return new CubismBreath(); + } + + /** + * Updates the parameters of the model. + * + * @param model the target model + * @param deltaTimeSeconds the delta time[s] + */ + public void updateParameters(CubismModel model, float deltaTimeSeconds) { + userTimeSeconds += deltaTimeSeconds; + final float t = userTimeSeconds * 2.0f * PI; + + for (int i = 0; i < breathParameters.size(); i++) { + BreathParameterData breathData = breathParameters.get(i); + + final float value = breathData.offset + (breathData.peak * sinF(t / breathData.cycle)); + + model.addParameterValue( + breathData.parameterId, + value, + breathData.weight); + } + } + + /** + * Bind parameters of breath. + * + * @param breathParameters A parameters list bound breath + * @throws IllegalArgumentException if an argument is null + */ + public void setParameters(List breathParameters) { + if (breathParameters == null) { + throw new IllegalArgumentException("breathParameters is null."); + } + + this.breathParameters = breathParameters; + areBreathParametersChanged = true; + } + + /** + * Returns the parameters bound breath. + *

+ * This method returns the copy of list of breath parameters. It is recommended that this method not be used where it is executed every frame. + *

+ * + * @return The parameters bound breath + */ + public List getParameters() { + // If there is a change in the parameters list, the read-only list is made. + if (areBreathParametersChanged) { + cachedImmutableBreathParameters = Collections.unmodifiableList(breathParameters); + areBreathParametersChanged = false; + } + return cachedImmutableBreathParameters; + } + + /** + * private constructor + */ + private CubismBreath() {} + + /** + * A parameters list bound breath + */ + private List breathParameters = new ArrayList(); + private boolean areBreathParametersChanged = true; + private List cachedImmutableBreathParameters; + /** + * total elapsed time[s] + */ + private float userTimeSeconds; +} + diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismEyeBlink.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismEyeBlink.java new file mode 100644 index 0000000..5700cf6 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismEyeBlink.java @@ -0,0 +1,324 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.effect; + +import com.live2d.sdk.cubism.framework.ICubismModelSetting; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.model.CubismModel; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This class offers auto eyeblink function. + */ +public class CubismEyeBlink { + /** + * Eyeblink states + */ + public enum EyeState { + /** + * Initial state + */ + FIRST, + /** + * Non-eyeblink state + */ + INTERVAL, + /** + * Closing-eye state + */ + CLOSING, + /** + * Closed-eye state + */ + CLOSED, + /** + * Opening-eye state + */ + OPENING + } + + /** + * Create a CubismEyeBlink instance. + * (If an argument is not passed, this function creates empty instance.) + * + * @return modelSetting model setting information + */ + public static CubismEyeBlink create() { + return new CubismEyeBlink(null); + } + + /** + * Create instance. + * + * @param modelSetting model setting information + * @return instance + */ + public static CubismEyeBlink create(ICubismModelSetting modelSetting) { + return new CubismEyeBlink(modelSetting); + } + + /** + * Update model's parameters. + * + * @param model the target model + * @param deltaTimeSeconds delta time[s] + */ + public void updateParameters(final CubismModel model, final float deltaTimeSeconds) { + userTimeSeconds += deltaTimeSeconds; + + switch (blinkingState) { + case CLOSING: + updateParametersClosing(model); + break; + case CLOSED: + updateParametersClosed(model); + break; + case OPENING: + updateParametersOpening(model); + break; + case INTERVAL: + updateParametersInterval(model); + break; + case FIRST: + default: + updateParametersFirst(model); + break; + } + } + + /** + * Get the blink interval. + * + * @param blinkingInterval eye-blinking interval[s] + */ + public void setBlinkingInterval(float blinkingInterval) { + blinkingIntervalSeconds = blinkingInterval; + } + + /** + * Set eye-blink motion parameters. + * + * @param closing a duration of the motion at closing eye[s] + * @param closed a duration at closing eye[s] + * @param opening a duration of the motion at opening eye[s] + */ + public void setBlinkingSettings(float closing, float closed, float opening) { + closingSeconds = closing; + closedSeconds = closed; + openingSeconds = opening; + } + + /** + * Set a parameter IDs list to blink. + * + * @param parameterIds A parameter IDs list + * @throws IllegalArgumentException if an argument is null + */ + public void setParameterIds(List parameterIds) { + if (parameterIds == null) { + throw new IllegalArgumentException("parameterIds is null."); + } + this.parameterIds = parameterIds; + } + + /** + * Get the parameter IDs list to eye-blink. + *

This method creates all new elements with the parameter ID and adds them to the list and returns them. + * Therefore, it is recommended that this method not be used where it is executed every frame, as it may affect performance. + * + * @return A parameter IDs list + */ + public List getParameterIds() { + // If there is a change in the ids list, the read-only list is made. + if (areIdsListChanged) { + cachedImmutableIdsList = Collections.unmodifiableList(parameterIds); + areIdsListChanged = false; + } + return cachedImmutableIdsList; + } + + /** + * This constant is becomes "true" if the eye blinking parameter specified by ID is specified to close when the value is 0, and "false" if the parameter is specified to close when the value is 1. + */ + private static final boolean CLOSE_IF_ZERO = true; + + /** + * Update model parameters when _blinkingState is CLOSING. + * + * @param model target model + */ + private void updateParametersClosing(CubismModel model) { + float time = (userTimeSeconds - stateStartTimeSeconds) / closingSeconds; + + if (time >= 1.0f) { + time = 1.0f; + blinkingState = EyeState.CLOSED; + stateStartTimeSeconds = userTimeSeconds; + } + + float parameterValue = 1.0f - time; + setParameterValueToAllIds(model, parameterValue); + } + + /** + * Update model parameters when _blinkingState is CLOSED. + * + * @param model target model + */ + private void updateParametersClosed(CubismModel model) { + float time = (userTimeSeconds - stateStartTimeSeconds) / closedSeconds; + + if (time >= 1.0f) { + blinkingState = EyeState.OPENING; + stateStartTimeSeconds = userTimeSeconds; + } + + float parameterValue = 0.0f; + setParameterValueToAllIds(model, parameterValue); + } + + /** + * Update model parameters when _blinkingState is OPENING. + * + * @param model target model + */ + private void updateParametersOpening(CubismModel model) { + float time = (userTimeSeconds - stateStartTimeSeconds) / openingSeconds; + + if (time >= 1.0f) { + time = 1.0f; + blinkingState = EyeState.INTERVAL; + nextBlinkingTime = determineNextBlinkingTiming(); + } + + float parameterValue = time; + setParameterValueToAllIds(model, parameterValue); + } + + /** + * Update model parameters when _blinkingState is INTERVAL. + * + * @param model target model + */ + private void updateParametersInterval(CubismModel model) { + if (nextBlinkingTime < userTimeSeconds) { + blinkingState = EyeState.CLOSING; + stateStartTimeSeconds = userTimeSeconds; + } + + float parameterValue = 1.0f; + setParameterValueToAllIds(model, parameterValue); + } + + /** + * Update model parameters when _blinkingState is FIRST. + * + * @param model target model + */ + private void updateParametersFirst(CubismModel model) { + blinkingState = EyeState.INTERVAL; + nextBlinkingTime = determineNextBlinkingTiming(); + + float parameterValue = 1.0f; + setParameterValueToAllIds(model, parameterValue); + } + + /** + * Set the given value for all IDs. + * CLOSE_IF_ZERO constant is "false", given argument is reversed(multiplied -1). + * + * @param model target model + * @param value value to be set + */ + private void setParameterValueToAllIds(CubismModel model, float value) { + if (!CubismEyeBlink.CLOSE_IF_ZERO) { + value *= -1; + } + for (int i = 0; i < parameterIds.size(); i++) { + CubismId id = parameterIds.get(i); + model.setParameterValue(id, value); + } + } + + /** + * Decide next eye blinking timing. + * + * @return the time of next eye blink + */ + private float determineNextBlinkingTiming() { + final float r = (float) Math.random(); + return userTimeSeconds + r * (2.0f * blinkingIntervalSeconds - 1.0f); + } + + /** + * private constructor + * + * @param modelSetting model setting information + */ + private CubismEyeBlink(ICubismModelSetting modelSetting) { + if (modelSetting == null) { + return; + } + + for (int i = 0; i < modelSetting.getEyeBlinkParameterCount(); i++) { + CubismId eyeBlinkId = modelSetting.getEyeBlinkParameterId(i); + + if (eyeBlinkId != null) { + parameterIds.add(eyeBlinkId); + } + } + } + + /** + * current blinking state + */ + private EyeState blinkingState = EyeState.FIRST; + /** + * target parameter IDs list + */ + private List parameterIds = new ArrayList(); + /** + * If the elemtns of _parameterIds are changed, this flag becomes true. + */ + private boolean areIdsListChanged = true; + /** + * List of _parameterIds made read-only by the Collections.unmodifiableList method. This class's getter returns this immutable list. + */ + private List cachedImmutableIdsList; + /** + * next blinking time[s] + */ + private float nextBlinkingTime; + /** + * time at starting current state[s] + */ + private float stateStartTimeSeconds; + /** + * interval of eye blink + */ + private float blinkingIntervalSeconds = 4.0f; + /** + * duration of the motion at closing eye[s] + */ + private float closingSeconds = 0.1f; + /** + * duration at the closing eye[s] + */ + private float closedSeconds = 0.05f; + /** + * duration of the motion at opening eye[s] + */ + private float openingSeconds = 0.15f; + /** + * total elapsed time[s] + */ + private float userTimeSeconds; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismPose.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismPose.java new file mode 100644 index 0000000..2c20fd4 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/CubismPose.java @@ -0,0 +1,400 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.effect; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.utils.jsonparser.ACubismJsonValue; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJsonString; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * This class deals with parts opacity value and settings. + */ +public class CubismPose { + /** + * Manage data related parts. + */ + public static class PartData { + /** + * Default constructor + */ + public PartData() {} + + /** + * Copy constructor + * + * @param partData original part data + */ + public PartData(PartData partData) { + partId = partData.partId; + parameterIndex = partData.parameterIndex; + partIndex = partData.partIndex; + + linkedParameter.addAll(partData.linkedParameter); + } + + public void initialize(CubismModel model) { + parameterIndex = model.getParameterIndex(partId); + partIndex = model.getPartIndex(partId); + + model.setParameterValue(parameterIndex, 1); + } + + /** + * Part ID + */ + public CubismId partId; + /** + * Parameter index + */ + public int parameterIndex; + /** + * Part index + */ + public int partIndex; + /** + * Linked parameters list + */ + public List linkedParameter = new ArrayList(); + } + + /** + * Create a CubismPose instance + * + * @param pose3json the byte data of pose3.json + * @return the created instance + */ + public static CubismPose create(byte[] pose3json) { + CubismPose pose = new CubismPose(); + final CubismJson json; + json = CubismJson.create(pose3json); + + ACubismJsonValue root = json.getRoot(); + Map rootMap = root.getMap(); + + // Set the fade time. + if (!root.get(JsonTag.FADE_IN.tag).isNull()) { + pose.fadeTimeSeconds = root.get(JsonTag.FADE_IN.tag).toFloat(DEFAULT_FADE_IN_SECONDS); + + if (pose.fadeTimeSeconds < 0.0f) { + pose.fadeTimeSeconds = DEFAULT_FADE_IN_SECONDS; + } + } + + // Parts group + ACubismJsonValue poseListInfo = root.get(JsonTag.GROUPS.tag); + int poseCount = poseListInfo.size(); + + for (int poseIndex = 0; poseIndex < poseCount; poseIndex++) { + ACubismJsonValue idListInfo = poseListInfo.get(poseIndex); + int idCount = idListInfo.size(); + int groupCount = 0; + + for (int groupIndex = 0; groupIndex < idCount; groupIndex++) { + ACubismJsonValue partInfo = idListInfo.get(groupIndex); + PartData partData = setupPartGroup(partInfo); + pose.partGroups.add(partData); + groupCount++; + } + pose.partGroupCounts.add(groupCount); + } + + return pose; + } + + /** + * Update model's parameters. + * + * @param model the target model + * @param deltaTimeSeconds delta time[s] + */ + public void updateParameters(final CubismModel model, float deltaTimeSeconds) { + // If given model is different from previous model, it is required to initialize some parameters. + if (model != lastModel) { + reset(model); + } + + lastModel = model; + + // If a negative time is given, 0 value is set. + if (deltaTimeSeconds < 0.0f) { + deltaTimeSeconds = 0.0f; + } + + int beginIndex = 0; + + for (int i = 0; i < partGroupCounts.size(); i++) { + int partGroupCount = partGroupCounts.get(i); + + doFade(model, deltaTimeSeconds, beginIndex, partGroupCount); + beginIndex += partGroupCount; + } + copyPartOpacities(model); + } + + private static PartData setupPartGroup(ACubismJsonValue partInfo) { + final CubismId parameterId = CubismFramework.getIdManager().getId(partInfo.get(JsonTag.ID.tag).getString()); + + final PartData partData = new PartData(); + partData.partId = CubismFramework.getIdManager().getId(parameterId); + + ACubismJsonValue link = partInfo.get(JsonTag.LINK.tag); + if (link != null) { + setupLinkedPart(partData, link); + } + return partData; + } + + /** + * Setup linked parts. + * + * @param partData part data to be done setting + * @param linkedListInfo linked parts list information + */ + private static void setupLinkedPart(PartData partData, ACubismJsonValue linkedListInfo) { + final int linkCount = linkedListInfo.size(); + + for (int index = 0; index < linkCount; index++) { + final CubismId linkedPartId = CubismFramework.getIdManager().getId(linkedListInfo.get(index).getString()); + + PartData linkedPart = new PartData(); + linkedPart.partId = linkedPartId; + + partData.linkedParameter.add(linkedPart); + } + } + + /** + * Initialize display. + * + * @param model the target model(Parameters that initial opacity is not 0, the opacity is set to 1.) + */ + private void reset(final CubismModel model) { + int beginIndex = 0; + + for (int j = 0; j < partGroupCounts.size(); j++) { + int groupCount = partGroupCounts.get(j); + + for (int i = beginIndex; i < beginIndex + groupCount; i++) { + partGroups.get(i).initialize(model); + + final int partsIndex = partGroups.get(i).partIndex; + final int paramIndex = partGroups.get(i).parameterIndex; + + if (partsIndex < 0) { + continue; + } + + if (i == beginIndex) { + model.setPartOpacity(partsIndex, 1.0f); + model.setParameterValue(paramIndex, 1.0f); + } + + final float value = + i == beginIndex + ? 1.0f + : 0.0f; + model.setPartOpacity(partsIndex, value); + model.setParameterValue(paramIndex, value); + + List link = partGroups.get(i).linkedParameter; + if (link != null) { + for (PartData data : link) { + data.initialize(model); + } + } + } + beginIndex += groupCount; + } + } + + /** + * Parts opacity is copied and set to linked parts. + * + * @param model the target model + */ + private void copyPartOpacities(CubismModel model) { + for (int i = 0; i < partGroups.size(); i++) { + PartData partData = partGroups.get(i); + if (partData.linkedParameter == null) { + continue; + } + + final int partIndex = partData.partIndex; + final float opacity = model.getPartOpacity(partIndex); + + for (int j = 0; j < partData.linkedParameter.size(); j++) { + PartData linkedPart = partData.linkedParameter.get(j); + + final int linkedPartIndex = linkedPart.partIndex; + + if (linkedPartIndex < 0) { + continue; + } + + model.setPartOpacity(linkedPartIndex, opacity); + } + } + } + + /** + * Fade parts + * + * @param model the target model + * @param deltaTimeSeconds delta time[s] + * @param beginIndex the head index of parts groups done fading + * @param partGroupCount the number of parts groups done fading + */ + private void doFade(CubismModel model, + float deltaTimeSeconds, + int beginIndex, + int partGroupCount) { + int visiblePartIndex = -1; + float newOpacity = 1.0f; + + // Get parts displayed now. + for (int i = beginIndex; i < beginIndex + partGroupCount; i++) { + final int paramIndex = partGroups.get(i).parameterIndex; + + if (model.getParameterValue(paramIndex) > EPSILON) { + if (visiblePartIndex >= 0) { + break; + } + + newOpacity = calculateOpacity(model, i, deltaTimeSeconds); + + visiblePartIndex = i; + } + } + + if (visiblePartIndex < 0) { + visiblePartIndex = 0; + newOpacity = 1.0f; + } + + // Set opacity to displayed, and non-displayed parts + for (int i = beginIndex; i < beginIndex + partGroupCount; i++) { + final int partsIndex = partGroups.get(i).partIndex; + + // Setting of displayed parts + if (visiblePartIndex == i) { + model.setPartOpacity(partsIndex, newOpacity); + } + // Setting of non-displayed parts + else { + final float opacity = model.getPartOpacity(partsIndex); + final float result = calcNonDisplayedPartsOpacity(opacity, newOpacity); + model.setPartOpacity(partsIndex, result); + } + } + } + + /** + * Calculate the new part opacity. This method is used at fading. + * + * @param model target model + * @param index part index + * @param deltaTime delta time[s] + * @return new calculated opacity. If fade time is 0.0[s], return 1.0f. + */ + private float calculateOpacity(CubismModel model, int index, float deltaTime) { + if (fadeTimeSeconds == 0) { + return 1.0f; + } + + final int partIndex = partGroups.get(index).partIndex; + float opacity = model.getPartOpacity(partIndex); + + opacity += deltaTime / fadeTimeSeconds; + + if (opacity > 1.0f) { + opacity = 1.0f; + } + + return opacity; + } + + /** + * Calculate opacity of non-displayed parts. + * + * @param currentOpacity current part opacity + * @param newOpacity calculated opacity + * @return opacity for non-displayed part + */ + private float calcNonDisplayedPartsOpacity(float currentOpacity, final float newOpacity) { + final float PHI = 0.5f; + final float BACK_OPACITY_THRESHOLD = 0.15f; + + float a1; // opacity to be calculated + if (newOpacity < PHI) { + // Linear equation passing through (0,1),(PHI,PHI) + a1 = newOpacity * (PHI - 1) / PHI + 1.0f; + } else { + a1 = (1 - newOpacity) * PHI / (1.0f - PHI); + } + + final float backOpacity = (1.0f - a1) * (1.0f - newOpacity); + + if (backOpacity > BACK_OPACITY_THRESHOLD) { + a1 = 1.0f - BACK_OPACITY_THRESHOLD / (1.0f - newOpacity); + } + + // The opacity is raised if the opacity is larger(more thicken) than the calculated opacity. + if (currentOpacity > a1) { + currentOpacity = a1; + } + + return currentOpacity; + } + + /** + * Epsilon value + */ + private static final float EPSILON = 0.001f; + /** + * Default fade-in duration[s] + */ + private static final float DEFAULT_FADE_IN_SECONDS = 0.5f; + + // Tags of Pose3.json + private enum JsonTag { + FADE_IN("FadeInTime"), + LINK("Link"), + GROUPS("Groups"), + ID("Id"); + + private final String tag; + + JsonTag(String tag) { + this.tag = tag; + } + } + + /** + * Parts group + */ + private final List partGroups = new ArrayList(); + /** + * Each parts group number + */ + private final List partGroupCounts = new ArrayList(); + /** + * Fade time[s] + */ + private float fadeTimeSeconds = DEFAULT_FADE_IN_SECONDS; + /** + * Previous operated model + */ + private CubismModel lastModel; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/package-info.java new file mode 100644 index 0000000..a5929db --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/effect/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide the function to add motion information to the model in an effect-like manner, such as automatic blinking and lip-sync. + */ +package com.live2d.sdk.cubism.framework.effect; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismException.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismException.java new file mode 100644 index 0000000..b934541 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismException.java @@ -0,0 +1,22 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.exception; + +/** + * Cubism SDK専用の例外 + */ +public class CubismException extends Exception { + /** + * エラーメッセージを持つ例外を構築する + * + * @param msg エラーメッセージ + */ + public CubismException(String msg) { + super(msg); + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonParseException.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonParseException.java new file mode 100644 index 0000000..608fdbb --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonParseException.java @@ -0,0 +1,44 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.exception; + +/** + * CubismJsonに関連する例外 + */ +public class CubismJsonParseException extends CubismRuntimeException { + /** + * エラーメッセージを持たない例外を構築する + */ + public CubismJsonParseException() { + super(DEFAULT_MESSAGE); + } + + /** + * 指定されたエラーメッセージを持つ例外を構築する + * + * @param msg エラーメッセージ + */ + public CubismJsonParseException(String msg) { + super(DEFAULT_MESSAGE + msg); + } + + public CubismJsonParseException(String msg, int lineNumber) { + super("line " + lineNumber + "\n" + DEFAULT_MESSAGE + msg); + } + + + public CubismJsonParseException(String msg, Throwable cause) { + super(DEFAULT_MESSAGE + msg, cause); + } + + public CubismJsonParseException(Throwable cause) { + super(cause); + } + + private static final String DEFAULT_MESSAGE = "Failed to parse the JSON data. "; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonRuntimeException.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonRuntimeException.java new file mode 100644 index 0000000..a900540 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonRuntimeException.java @@ -0,0 +1,29 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.exception; + +/** + * CubismJsonに関連する実行時例外 + */ +public class CubismJsonRuntimeException extends CubismRuntimeException { + /** + * エラーメッセージを持たない実行時例外を構築する + */ + public CubismJsonRuntimeException() { + super(""); + } + + /** + * 指定されたエラーメッセージを持つ例外を構築する + * + * @param msg エラーメッセージ + */ + public CubismJsonRuntimeException(String msg) { + super(msg); + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonSyntaxErrorException.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonSyntaxErrorException.java new file mode 100644 index 0000000..674e843 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismJsonSyntaxErrorException.java @@ -0,0 +1,49 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.exception; + +/** + * The exception class which reports that there is a syntax error in the parsed JSON string. + */ +public class CubismJsonSyntaxErrorException extends CubismJsonParseException { + /** + * Construct the exception which has the default message. + */ + public CubismJsonSyntaxErrorException() { + super(DEFAULT_MESSAGE); + } + + /** + * Construct the exception which has the specified message. + */ + public CubismJsonSyntaxErrorException(String msg) { + super(DEFAULT_MESSAGE + msg); + } + + /** + * Create exception with the specified message and the line number at syntax error. + * + * @param msg error message describing what happened. + * @param lineNumber line number at syntax error + */ + public CubismJsonSyntaxErrorException(String msg, int lineNumber) { + super(DEFAULT_MESSAGE + msg, lineNumber); +// String errorPoint = "line " + lineNumber + "\n"; +// super(errorPoint + msg) + } + + public CubismJsonSyntaxErrorException(String msg, Throwable cause) { + super(DEFAULT_MESSAGE + msg, cause); + } + + public CubismJsonSyntaxErrorException(Throwable cause) { + super(cause); + } + + private static final String DEFAULT_MESSAGE = "SyntaxError: "; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismRuntimeException.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismRuntimeException.java new file mode 100644 index 0000000..4362e53 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/CubismRuntimeException.java @@ -0,0 +1,41 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.exception; + +/** + * Cubism SDK専用の実行時例外 + */ +public class CubismRuntimeException extends RuntimeException { + /** + * エラーメッセージを持つ実行時例外を構築する + * + * @param msg エラーメッセージ + */ + public CubismRuntimeException(String msg) { + super(msg); + } + + /** + * Creates exception with the specified message and cause. + * + * @param msg error message describeing what happened. + * @param cause cause root exception that caused this exception to be thrown. + */ + public CubismRuntimeException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * Create exception with the specified cause. Consider using {@link #CubismRuntimeException(String, Throwable)} instead if you can describe what happened. + * + * @param cause cause root exception that caused this exception to be thrown. + */ + public CubismRuntimeException(Throwable cause) { + super(cause); + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/package-info.java new file mode 100644 index 0000000..bdde19b --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/exception/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide the exception classes about Cubism SDK Framework. + */ +package com.live2d.sdk.cubism.framework.exception; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/CubismId.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/CubismId.java new file mode 100644 index 0000000..8dca6ea --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/CubismId.java @@ -0,0 +1,62 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.id; + +/** + * The name of parameters, parts and Drawable is held in this class. + */ +public class CubismId { + /** + * Get ID name + */ + public String getString() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismId cubismId = (CubismId) o; + + return id != null ? id.equals(cubismId.id) : cubismId.id == null; + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } + + /** + * Constructor + * + * @param id A ID name + * @throws IllegalArgumentException if an argument is null + */ + CubismId(String id) { + if (id == null) { + throw new IllegalArgumentException("id is null."); + } + this.id = id; + } + + /** + * Copy constructor + * + * @param id the CubismId instance + */ + CubismId(CubismId id) { + this.id = id.getString(); + } + + /** + * ID name + */ + private final String id; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/CubismIdManager.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/CubismIdManager.java new file mode 100644 index 0000000..73f463c --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/CubismIdManager.java @@ -0,0 +1,143 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.id; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manager class of ID names + */ +public class CubismIdManager { + /** + * Register IDs from list + * + * @param ids id list + */ + public void registerIds(List ids) { + for (int i = 0; i < ids.size(); i++) { + String id = ids.get(i); + registerId(id); + } + } + + /** + * Register the specified number of IDs from the given list. + * + * @param ids ID list + * @param count number of IDs to be registered + */ + public void registerIds(List ids, int count) { + for (int i = 0; i < count; i++) { + registerId(ids.get(i)); + } + } + + /** + * Register ID name + * + * @param id ID name + * @return ID instance + */ + public CubismId registerId(String id) { + CubismId foundId = findId(id); + + if (foundId != null) { + return foundId; + } + + CubismId cubismId = new CubismId(id); + ids.add(cubismId); + + return cubismId; + } + + /** + * Register ID. + * + * @param id ID instance + * @return ID instance + */ + public CubismId registerId(CubismId id) { + return registerId(id.getString()); + } + + /** + * Get ID from ID name. + * If the given ID has not registered, register the ID, too. + * + * @param id ID name + * @return ID instance + */ + public CubismId getId(String id) { + return registerId(id); + } + + /** + * Get ID from ID instance. + * If the given ID has not registered, register the ID, too. + * + * @param id ID instance + * @return ID instance + */ + public CubismId getId(CubismId id) { + return registerId(id); + } + + /** + * Check whether the ID has been already registered from an ID name. + * + * @return If given ID has been already registered, return true + */ + public boolean isExist(String id) { + return findId(id) != null; + } + + public boolean isExist(CubismId id) { + return findId(id) != null; + } + + /** + * Search an ID from given ID name. + * + * @param foundId ID name + * @return If there is a registered ID, return the CubismId instance. + */ + private CubismId findId(String foundId) { + for (int i = 0; i < ids.size(); i++) { + CubismId id = ids.get(i); + + if (id.getString().equals(foundId)) { + return id; + } + } + return null; + } + + /** + * Search an ID from given ID instance. + * + * @param foundId ID instance + * @return If there is a registered ID, return the CubismId instance. + */ + private CubismId findId(CubismId foundId) { + for (int i = 0; i < ids.size(); i++) { + CubismId id = ids.get(i); + + if (id.equals(foundId)) { + return id; + } + } + return null; + } + + /** + * The registered IDs list. + */ + private final List ids = new ArrayList(); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/package-info.java new file mode 100644 index 0000000..ee0abde --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/id/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide the function to manage parameter names, part names, and drawable names set in the model with the Cubism SDK original type. + */ +package com.live2d.sdk.cubism.framework.id; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismMath.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismMath.java new file mode 100644 index 0000000..1bf8fad --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismMath.java @@ -0,0 +1,297 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.math; + +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +/** + * Utility class used for numerical calculations, etc. + */ +public class CubismMath { + public static final float PI = 3.1415926535897932384626433832795f; + public static final float EPSILON = 0.00001f; + + public static float clampF(float val, float min, float max) { + if (val < min) { + return min; + } else if (max < val) { + return max; + } + + return val; + } + + /** + * Returns the value of the first argument in the range of minimum and maximum values. + * + * @param value target value + * @param min lower bound + * @param max upper bound + * @return value within the range of minimum and maximum values + */ + public static float rangeF(float value, float min, float max) { + if (value < min) { + value = min; + } else if (value > max) { + value = max; + } + return value; + } + + /** + * Caluculate sine value from radian angle value. + * + * @param x angle(radian) + * @return sine value + */ + public static float sinF(float x) { + return (float) (Math.sin(x)); + } + + /** + * Caluculate cosine value from radian angle value. + * + * @param x angle(radian) + * @return cosine value + */ + public static float cosF(float x) { + return (float) (Math.cos(x)); + } + + /** + * Calculate the absolute value. + * + * @param x target value + * @return calculated absolute value + */ + public static float absF(float x) { + return Math.abs(x); + } + + /** + * Calculate the square root. + * + * @param x target value + * @return calculated square root value + */ + public static float sqrtF(float x) { + return (float) (Math.sqrt(x)); + } + + /** + * Calculate the easing processed sin. Can be used for easing during fade in/out. + * + * @param value target value + * @return eased sin value + */ + public static float getEasingSine(float value) { + if (value < 0.0f) { + return 0.0f; + } else if (value > 1.0f) { + return 1.0f; + } + return (float) (0.5f - 0.5f * Math.cos(value * PI)); + } + + /** + * Convert an angle value to a radian value. + * + * @param degrees angle value[degree] + * @return radian value converted from angle value + */ + public static float degreesToRadian(float degrees) { + return (degrees / 180.0f) * PI; + } + + /** + * Convert a radian value to an angle value + * + * @param radian radian value[rad] + * @return angle value converted from radian value + */ + public static float radianToDegrees(float radian) { + return (radian * 180.0f) / PI; + } + + /** + * Calculate a radian value from two vectors. + * + * @param from position vector of a starting point + * @param to position vector of an end point + * @return direction vector calculated from radian value + */ + public static float directionToRadian(CubismVector2 from, CubismVector2 to) { + float q1 = (float) Math.atan2(to.y, to.x); + float q2 = (float) Math.atan2(from.y, from.x); + + float radian = q1 - q2; + + while (radian < -PI) { + radian += PI * 2.0f; + } + + while (radian > PI) { + radian -= PI * 2.0f; + } + + return radian; + } + + /** + * Calculate an angle value from two vectors. + * + * @param from position vector of a starting point + * @param to position vector of an end point + * @return direction vector calculated from angle value + */ + public static float directionToDegrees(CubismVector2 from, CubismVector2 to) { + float radian = directionToRadian(from, to); + float degree = radianToDegrees(radian); + + if ((to.x - from.x) > 0.0f) { + degree = -degree; + } + + return degree; + } + + /** + * Convert a radian value to a direction vector. + * + * @param totalAngle radian value + * @param result CubismVector2 instance for storing calculation results + * @return direction vector calculated from radian value + */ + public static CubismVector2 radianToDirection(float totalAngle, CubismVector2 result) { + result.x = sinF(totalAngle); + result.y = cosF(totalAngle); + + return result; + } + + /** + * Calculate the solution to the quadratic equation. + * + * @param a coefficient value of quadratic term + * @param b coefficient value of the first order term + * @param c value of constant term + * @return solution of a quadratic equation + */ + public static float quadraticEquation(float a, float b, float c) { + if (absF(a) < EPSILON) { + if (absF(b) < EPSILON) { + return -c; + } + return -c / b; + } + return -(b + sqrtF(b * b - 4.0f * a * c)) / (2.0f * a); + } + + /** + * Calculate the solution of the cubic equation corresponding to the Bezier's t-value by the Cardano's formula. + * Returns a solution that has a value of 0.0~1.0 when it is a multiple solution. + * + * @param a coefficient value of cubic term + * @param b coefficient value of quadratic term + * @param c coefficient value of the first order term + * @param d value of constant term + * @return solution between 0.0~1.0 + */ + public static float cardanoAlgorithmForBezier(float a, float b, float c, float d) { + if (absF(a) < EPSILON) { + return rangeF(quadraticEquation(b, c, d), 0.0f, 1.0f); + } + float ba = b / a; + float ca = c / a; + float da = d / a; + + float p = (3.0f * ca - ba * ba) / 3.0f; + float p3 = p / 3.0f; + float q = (2.0f * ba * ba * ba - 9.0f * ba * ca + 27.0f * da) / 27.0f; + float q2 = q / 2.0f; + float discriminant = q2 * q2 + p3 * p3 * p3; + + final float center = 0.5f; + final float threshold = center + 0.01f; + + if (discriminant < 0.0f) { + float mp3 = -p / 3.0f; + float mp33 = mp3 * mp3 * mp3; + float r = sqrtF(mp33); + float t = -q / (2.0f * r); + float cosphi = rangeF(t, + -1.0f, 1.0f); + float phi = (float) Math.acos(cosphi); + float crtr = (float) Math.cbrt(r); + float t1 = 2.0f * crtr; + + float root1 = t1 * cosF(phi / 3.0f) - ba / 3.0f; + if (Math.abs(root1 - center) < threshold) { + return rangeF(root1, 0.0f, 1.0f); + } + + float root2 = t1 * cosF((phi + 2.0f * PI) / 3.0f) - ba / 3.0f; + if (Math.abs(root2 - center) < threshold) { + return rangeF(root2, 0.0f, 1.0f); + } + + float root3 = t1 * cosF((phi + 4.0f * PI) / 3.0f) - ba / 3.0f; + return rangeF(root3, 0.0f, 1.0f); + } + + if (discriminant == 0.0f) { + float u1; + if (q2 < 0.0f) { + u1 = (float) Math.cbrt(-q2); + } else { + u1 = (float) -Math.cbrt(q2); + } + + float root1 = 2.0f * u1 - ba / 3.0f; + if (Math.abs(root1 - center) < threshold) { + return rangeF(root1, 0.0f, 1.0f); + } + + float root2 = -u1 - ba / 3.0f; + return rangeF(root2, 0.0f, 1.0f); + } + + float sd = sqrtF(discriminant); + float u1 = (float) Math.cbrt(sd - q2); + float v1 = (float) Math.cbrt(sd + q2); + float root1 = u1 - v1 - ba / 3.0f; + return rangeF(root1, 0.0f, 1.0f); + } + + /** + * 浮動小数点の余りを求める。 + * + * @param dividend 被除数(割られる値) + * @param divisor 除数(割る値) + * @return 余り + */ + public static float modF(float dividend, float divisor) { + if ( + Float.isInfinite(dividend) + || Float.compare(divisor, 0.0f) == 0 + || Float.isNaN(dividend) + || Float.isNaN(divisor) + ) { + CubismDebug.cubismLogWarning("dividend: %f, divisor: %f ModF() returns 'NaN'.", dividend, divisor); + return Float.NaN; + } + + return dividend % divisor; + } + + /** + * private constructor. + * (Prevent instantiation.) + */ + private CubismMath() {} +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismMatrix44.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismMatrix44.java new file mode 100644 index 0000000..2cd8591 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismMatrix44.java @@ -0,0 +1,365 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.math; + +import java.util.Arrays; + +/** + * Utility class for 4x4 matrix. + */ +public class CubismMatrix44 { + /** + * Creates a {@code CubismMatrix4x4} instance. + * The created instance is initialized to a unit matrix. + * + * @return a {@code CubismMatrix44} instance + */ + public static CubismMatrix44 create() { + return new CubismMatrix44(); + } + + /** + * Creates a {@code CubismMatrix44} instance with float array (length == 16). + * If the argument (float array) is either {@code null} or it does not have a size of 16, throws {@code IllegalArgumentException}. + * + * @param matrix the 4x4 (length == 16) matrix represented by 16 floating-point numbers array + * @return a {@code CubismMatrix44} instance + * + * @throws IllegalArgumentException if the argument is either {@code null} or it does not have a size of 16. + */ + public static CubismMatrix44 create(float[] matrix) { + if (isNot4x4Matrix(matrix)) { + throw new IllegalArgumentException("The passed array is either 'null' or does not have a size of 16."); + } + return new CubismMatrix44(matrix); + } + + /** + * Creates new {@code CubismMatrix44} instance with a {@code CubismMatrix44} instance. + * This method works the same as the copy method. + * + *

+ * If the argument {@code null}, throws {@code IllegalArgumentException}. + * + * @param matrix the 4x4 matrix represented by a {@code CubismMatrix44} + * @return a {@code CubismMatrix44} instance + * + * @throws IllegalArgumentException if the argument is either {@code null} or it does not have a size of 16. + */ + public static CubismMatrix44 create(CubismMatrix44 matrix) { + if (matrix == null) { + throw new IllegalArgumentException("The passed CubismMatrix44 instance is 'null'"); + } + return new CubismMatrix44(matrix.tr); + } + + /** + * Returns the product of the two matrices received. + * This is a matrix calculation, therefore note that exchanging the first and second arguments will produce different results. + * + * @param multiplicand the multiplicand matrix + * @param multiplier the multiplier matrix + * @param dst the destination array + * @throws IllegalArgumentException if the argument is either {@code null} or it does not have a size of 16. + */ + public static void multiply(float[] multiplicand, float[] multiplier, float[] dst) { + if (isNot4x4Matrix(multiplicand) || isNot4x4Matrix(multiplier) || isNot4x4Matrix(dst)) { + throw new IllegalArgumentException("The passed array is either 'null' or does not have a size of 16."); + } + + for (int i = 0; i < 16; i++) { + matrixForMultiplication[i] = 0.0f; + } + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + for (int k = 0; k < 4; k++) { + matrixForMultiplication[j + i * 4] += multiplicand[k + i * 4] * multiplier[j + k * 4]; + } + } + } + + System.arraycopy(matrixForMultiplication, 0, dst, 0, 16); + } + + /** + * Initialize to a unit matrix. + */ + public void loadIdentity() { + resetMatrixForCalcToUnitMatrix(); + setMatrix(matrixForCalculation); + } + + /** + * Return the matrix as an array of floating point numbers. + * + * @return the 4x4 matrix represented by 16 floating-point numbers array + */ + public float[] getArray() { + return tr; + } + + /** + * Sets this matrix with the given {@code CubismMatrix44} instance. + * + * @param matrix the new 4x4 matrix represented by {@code CubismMatrix44} instance + */ + public void setMatrix(CubismMatrix44 matrix) { + System.arraycopy(matrix.tr, 0, tr, 0, 16); + } + + /** + * Sets this matrix with the array of float type (length == 16). + * + * @param matrix the new 4x4 matrix represented by 16 floating-point numbers array + * @throws IllegalArgumentException if the argument is either {@code null} or it does not have a size of 16. + */ + public void setMatrix(float[] matrix) { + if (isNot4x4Matrix(matrix)) { + throw new IllegalArgumentException("The passed array is either 'null' or does not have a size of 16."); + } + + System.arraycopy(matrix, 0, tr, 0, 16); + } + + /** + * Returns the scale of the X-axis. + * + * @return the scale of the X-axis + */ + public float getScaleX() { + return tr[0]; + } + + /** + * Returns the scale of the Y-axis. + * + * @return the scale of the Y-axis + */ + public float getScaleY() { + return tr[5]; + } + + /** + * Returns the amount of movement in the X-axis direction. + * + * @return the amount of movement in the X-axis direction + */ + public float getTranslateX() { + return tr[12]; + } + + /** + * Returns the amount of movement in the Y-axis direction. + * + * @return the amount of movement in the Y-axis direction + */ + public float getTranslateY() { + return tr[13]; + } + + /** + * Returns the X-coordinate value transformed by the current matrix. + *

+ * For example, used to obtain the position on the screen from the vertex coordinates of a model in the local coordinate system. + * + * @param src the X-coordinate value to be transformed + * @return the X-coordinate value transformed by the current matrix + */ + public float transformX(float src) { + return tr[0] * src + tr[12]; + } + + /** + * Returns the Y-coordinate value transformed by the current matrix. + *

+ * For example, used to obtain the position on the screen from the vertex coordinates of a model in the local coordinate system. + * + * @param src the Y-coordinate value to be transformed + * @return the Y-coordinate value transformed by the current matrix + */ + public float transformY(float src) { + return tr[5] * src + tr[13]; + } + + /** + * Returns the X-coordinate value inverse-transformed by the current matrix. + *

+ * For example, used to obtain the coordinates in the model's local coordinate system from the entered coordinates in the screen coordinate system, such as collision detection. + * + * @param src the X-coordinate value to be inverse-transformed + * @return the X-coordinate value inverse-transformed by the current matrix + */ + public float invertTransformX(float src) { + return (src - tr[12]) / tr[0]; + } + + /** + * Returns the Y-coordinate value inverse-transformed by the current matrix. + *

+ * For example, used to obtain the coordinates in the model's local coordinate system from the entered coordinates in the screen coordinate system, such as collision detection. + * + * @param src the Y-coordinate value to be inverse-transformed + * @return the Y-coordinate value inverse-transformed by the current matrix + */ + public float invertTransformY(float src) { + return (src - tr[13]) / tr[5]; + } + + /** + * Translates the current matrix relatively by the amount of the arguments. + * The coordinate of the arguments must be entered in a screen coodinate system. + * + * @param x the amount of movement in X-axis direction + * @param y the amount of movement in Y-axis direction + */ + public void translateRelative(float x, float y) { + resetMatrixForCalcToUnitMatrix(); + matrixForCalculation[12] = x; + matrixForCalculation[13] = y; + + multiply(matrixForCalculation, tr, tr); + } + + /** + * Translates the current matrix to the position specified by the arguments. + * The coordinate of the arguments must be entered in a screen coodinate system. + * + * @param x X-coordinate of destination + * @param y Y-coordinate of destination + */ + public void translate(float x, float y) { + tr[12] = x; + tr[13] = y; + } + + /** + * Translates the X-coordinate of the current matrix to the position specified by the argument. + * The coordinate of the argument must be entered in a screen coodinate system. + * + * @param x X-coordinate of destination + */ + public void translateX(float x) { + tr[12] = x; + } + + /** + * Translates the Y-coordinate of the current matrix to the position specified by the argument. + * The coordinate of the argument must be entered in a screen coodinate system. + * + * @param y Y-coordinate of destination + */ + public void translateY(float y) { + tr[13] = y; + } + + /** + * Sets relatively the scaling rate to the current matrix. + * + * @param x the scaling rate in the X-axis direction + * @param y the scaling rate in the Y-axis direction + */ + public void scaleRelative(float x, float y) { + resetMatrixForCalcToUnitMatrix(); + matrixForCalculation[0] = x; + matrixForCalculation[5] = y; + multiply(matrixForCalculation, tr, tr); + } + + /** + * Sets the scaling rate of the current matrix the specified scale by the arguments. + * + * @param x the scaling rate in the X-axis direction + * @param y the scaling rate in the Y-axis direction + */ + public void scale(float x, float y) { + tr[0] = x; + tr[5] = y; + } + + /** + * Returns the product of the current matrix and the given {@code CubismMatrix44} instance for the argument. + * + * @param multiplier the multiplier matrix + */ + public void multiplyByMatrix(CubismMatrix44 multiplier) { + multiply(tr, multiplier.tr, tr); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CubismMatrix44 that = (CubismMatrix44) o; + return Arrays.equals(tr, that.tr); + } + + @Override + public int hashCode() { + return Arrays.hashCode(tr); + } + + /** + * Constructs a new 4x4 matrix initialized with a unit matrix without taking any arguments. + */ + protected CubismMatrix44() { + tr = new float[16]; + loadIdentity(); + } + + /** + * Constructs a new 4x4 matrix. It is initialized with a unit matrix represented by the float array that has a size of 16 passed for the argument. + * + *

+ * This is not a public method, therefore it does not expect that {@code null} value or other illegal value is passed. + * + * @param matrix the 4x4 (length == 16) matrix represented by 16 floating-point numbers array + */ + protected CubismMatrix44(float[] matrix) { + tr = new float[16]; + setMatrix(matrix); + } + + /** + * The 4×4 matrix array. + */ + protected float[] tr; + + /** + * If the argument given is 4x4 matrix array, returns {@code true}. If the argument is {@code null} or does not have a size of 16, returns {@code false}. + * + * @param array the float array to be checked + * @return {@code true} if the argument given is a 4x4 matrix, otherwise {@code false} + */ + private static boolean isNot4x4Matrix(float[] array) { + return (array == null || array.length != 16); + } + + /** + * Resets the variable '_4x4MatrixForCalculation' to a unit matrix. + */ + private static void resetMatrixForCalcToUnitMatrix() { + for (int i = 0; i < 16; i++) { + matrixForCalculation[i] = 0.0f; + } + matrixForCalculation[0] = 1.0f; + matrixForCalculation[5] = 1.0f; + matrixForCalculation[10] = 1.0f; + matrixForCalculation[15] = 1.0f; + } + + /** + * The 4x4 matrix array for matrix calculation. + * This exists for avoiding creating a new float array at running method. + */ + private static final float[] matrixForCalculation = new float[16]; + /** + * The 4x4 matrix array for 'multiply' method. + * Prevents _4x4MatrixForCalculation from resetting the multiplicand information when it is passed to the 'multiply' method. + */ + private static final float[] matrixForMultiplication = new float[16]; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismModelMatrix.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismModelMatrix.java new file mode 100644 index 0000000..d7bc7b8 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismModelMatrix.java @@ -0,0 +1,243 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.math; + +import java.util.Map; + +/** + * 4x4 matrix class for setting model coordinates. + */ +public class CubismModelMatrix extends CubismMatrix44 { + /** + * Create the new CubismModelMatrix instance with the width and height passed as arguments. + * + * @param w width + * @param h height + * @return CubismModelMatrix instance with the width and height + * + * @throws IllegalArgumentException if arguments equals 0 or are less than 0 + */ + public static CubismModelMatrix create(float w, float h) { + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("width or height equals 0 or is less than 0."); + } + return new CubismModelMatrix(w, h); + } + + + /** + * Create the new CubismModelMatrix instance from the CubismModelMatrix instance. + * It works the same way as a copy constructor. + * + * @param modelMatrix CubismModelMatrix instance to be copied + * @return Copied CubismModelMatrix instance + */ + public static CubismModelMatrix create(CubismModelMatrix modelMatrix) { + return new CubismModelMatrix(modelMatrix); + } + + /** + * Set the width. + * + * @param w width + */ + public void setWidth(float w) { + final float scaleX = w / width; + scale(scaleX, scaleX); + } + + /** + * Set the height. + * + * @param h height + */ + public void setHeight(float h) { + final float scaleX = h / height; + scale(scaleX, scaleX); + } + + /** + * Set the position. + * + * @param x X-axis position + * @param y Y-axis position + */ + public void setPosition(float x, float y) { + translate(x, y); + } + + /** + * Set the center position. + * Be sure to set the width or height before using this method. + * + * @param x center position of X-axis + * @param y center position of Y-axis + */ + public void setCenterPosition(float x, float y) { + centerX(x); + centerY(y); + } + + /** + * Set the position of the upper edge. + * + * @param y the position of the upper edge + */ + public void top(float y) { + setY(y); + } + + /** + * Set the position of the bottom edge. + * + * @param y the position of the bottom edge + */ + public void bottom(float y) { + final float h = height * getScaleY(); + translateY(y - h); + } + + /** + * Set the position of the left edge. + * + * @param x the position of the left edge + */ + public void left(float x) { + setX(x); + } + + /** + * Set the position of the right edge. + * + * @param x the position of the right edge + */ + public void right(float x) { + final float w = width * getScaleX(); + translateX(x - w); + } + + /** + * Set the center position of X-axis. + * + * @param x center position of X-axis + */ + public void centerX(float x) { + final float w = width * getScaleX(); + translateX(x - (w / 2.0f)); + } + + /** + * Set the position of X-axis. + * + * @param x position of X-axis + */ + public void setX(float x) { + translateX(x); + } + + /** + * Set the center position of Y-axis. + * + * @param y center position of Y-axis + */ + public void centerY(float y) { + final float h = height * getScaleY(); + translateY(y - (h / 2.0f)); + } + + /** + * Set the position of Y-axis. + * + * @param y position of Y-axis + */ + public void setY(float y) { + translateY(y); + } + + /** + * Set position from layout information. + * + * @param layout layout information + */ + public void setupFromLayout(Map layout) { + final String keyWidth = "width"; + final String keyHeight = "height"; + final String keyX = "x"; + final String keyY = "y"; + final String keyCenterX = "center_x"; + final String keyCenterY = "center_y"; + final String keyTop = "top"; + final String keyBottom = "bottom"; + final String keyLeft = "left"; + final String keyRight = "right"; + + for (Map.Entry entry : layout.entrySet()) { + String key = entry.getKey(); + if (key.equals(keyWidth)) { + setWidth(entry.getValue()); + } else if (key.equals(keyHeight)) { + setHeight(entry.getValue()); + } + } + + for (Map.Entry entry : layout.entrySet()) { + String key = entry.getKey(); + float value = entry.getValue(); + + if (key.equals(keyX)) { + setX(value); + } else if (key.equals(keyY)) { + setY(value); + } else if (key.equals(keyCenterX)) { + centerX(value); + } else if (key.equals(keyCenterY)) { + centerY(value); + } else if (key.equals(keyTop)) { + top(value); + } else if (key.equals(keyBottom)) { + bottom(value); + } else if (key.equals(keyLeft)) { + left(value); + } else if (key.equals(keyRight)) { + right(value); + } + } + } + + /** + * Constructor + */ + private CubismModelMatrix(float w, float h) { + super(); + width = w; + height = h; + + setHeight(2.0f); + } + + /** + * Copy constructor + * + * @param modelMatrix model matrix to be copied + */ + private CubismModelMatrix(CubismModelMatrix modelMatrix) { + super(); + System.arraycopy(modelMatrix.tr, 0, this.tr, 0, 16); + width = modelMatrix.width; + height = modelMatrix.height; + } + + /** + * width + */ + private final float width; + /** + * height + */ + private final float height; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismTargetPoint.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismTargetPoint.java new file mode 100644 index 0000000..8a2c115 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismTargetPoint.java @@ -0,0 +1,170 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.math; + +/** + * This class provides face orientation control functionality. + */ +public class CubismTargetPoint { + /** + * Update face orientation control. + * + * @param deltaTimeSeconds delta time[s] + */ + public void update(float deltaTimeSeconds) { + // Add delta time + userTimeSeconds += deltaTimeSeconds; + + // Set the maximum speed considering the average speed when swinging the head from the center to the left or right. + // The swing of the face is set from the center (0.0) to the left and right (+-1.0). + final float faceParamMaxV = 40.0f / 10.0f; + // Upper limit of the speed that can be changed per frame. + final float maxV = faceParamMaxV / FRAME_RATE; + + if (lastTimeSeconds == 0.0f) { + lastTimeSeconds = userTimeSeconds; + return; + } + + final float deltaTimeWeight = (userTimeSeconds - lastTimeSeconds) * FRAME_RATE; + lastTimeSeconds = userTimeSeconds; + + // Calculate the time it takes to reach the maximum speed. + final float timeToMaxSpeed = 0.15f; + final float frameToMaxSpeed = timeToMaxSpeed * FRAME_RATE; // sec * frame/sec + final float maxA = deltaTimeWeight * maxV / frameToMaxSpeed; + + final float dx = faceTargetX - faceX; + final float dy = faceTargetY - faceY; + + // In the case of there is no change. + if (CubismMath.absF(dx) <= EPSILON && CubismMath.absF(dy) <= EPSILON) { + return; + } + + // If the speed is greater than the maximum speed, reduce the speed. + final float d = CubismMath.sqrtF((dx * dx) + (dy * dy)); + + // Maximum velocity vector in the direction of travel. + final float vx = maxV * dx / d; + final float vy = maxV * dy / d; + + // Calculate the change (acceleration) from the current speed to the new speed. + float ax = vx - faceVX; + float ay = vy - faceVY; + + float a = CubismMath.sqrtF((ax * ax) + (ay * ay)); + + // At acceleration. + if (a < -maxA || a > maxA) { + ax *= maxA / a; + ay *= maxA / a; + } + + // Add the acceleration to the original speed to obtain the new speed. + faceVX += ax; + faceVY += ay; + + + // Processing for smooth deceleration when approaching the desired direction + // Calculate the maximum speed currently available based on the relationship between distance and speed at which an object can stop at a set acceleration, and slow down if the speed is greater than that. + // Humans are inherently more flexible because they can adjust force (acceleration) with muscle power, but this is a simple process. + { + // Relational expression between acceleration, velocity, and distance. + // 2 6 2 3 + // sqrt(a t + 16 a h t - 8 a h) - a t + // v = -------------------------------------- + // 2 + // 4 t - 2 + // (t=1) + // Time t is calculated in advance as 1/60 (frame rate, no units) for acceleration and velocity. Therefore, it can be erased as t = 1 (unverified) + final float maxV2 = 0.5f * (CubismMath.sqrtF((maxA * maxA) + 16.0f * maxA * d - 8.0f * maxA * d) - maxA); + final float curV = CubismMath.sqrtF((faceVX * faceVX) + (faceVY * faceVY)); + + // Decelerate to maximum speed when current speed > maximum speed. + if (curV > maxV2) { + faceVX *= maxV2 / curV; + faceVY *= maxV2 / curV; + } + } + faceX += faceVX; + faceY += faceVY; + } + + + /** + * Get the face orientation value on the X-axis. + * + * @return X-axis face orientation value (-1.0 - 1.0) + */ + public float getX() { + return faceX; + } + + /** + * Get the face orientation value on the Y-axis. + * + * @return Y-axis face orientation value (-1.0 - 1.0) + */ + public float getY() { + return faceY; + } + + /** + * Set a target value for face orientation. + * + * @param x X-axis face orientation value (-1.0 - 1.0) + * @param y Y-axis face orientation value (-1.0 - 1.0) + */ + public void set(float x, float y) { + faceTargetX = x; + faceTargetY = y; + } + + /** + * Framerate per seconds[s] + */ + private static final int FRAME_RATE = 30; + /** + * Epsilon value + */ + private static final float EPSILON = 0.01f; + + /** + * X target value for face orientation (getting closer to this value) + */ + private float faceTargetX; + /** + * Y target value for face orientation (getting closer to this value) + */ + private float faceTargetY; + /** + * face orientation X (-1.0 - 1.0) + */ + private float faceX; + /** + * face orientation Y (-1.0 - 1.0) + */ + private float faceY; + /** + * speed of change in face orientation X + */ + private float faceVX; + /** + * speed of change in face orientation Y + */ + private float faceVY; + /** + * last executed time[s] + */ + private float lastTimeSeconds; + /** + * total elapsed time[s] + */ + private float userTimeSeconds; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismVector2.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismVector2.java new file mode 100644 index 0000000..9510418 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismVector2.java @@ -0,0 +1,310 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.math; + +/** + * This class offers 2D vector function. + */ +public class CubismVector2 { + /** + * Constructor. + */ + public CubismVector2() {} + + /** + * Constructor. + * + * @param x x-value + * @param y y-value + */ + public CubismVector2(float x, float y) { + set(x, y); + } + + /** + * Copy constructor. + * + * @param vec the vector which is copied + */ + public CubismVector2(CubismVector2 vec) { + set(vec); + } + + /** + * 第1引数と第2引数のベクトルを加算して、計算結果を第3引数のベクトルにコピーする。 + * + * @param augend 被加数のベクトル + * @param addend 加数のベクトル + * @param dest 代入先のベクトル + * @return 代入先のベクトル + */ + public static CubismVector2 add(CubismVector2 augend, CubismVector2 addend, CubismVector2 dest) { + dest.x = augend.x + addend.x; + dest.y = augend.y + addend.y; + + return dest; + } + + /** + * 第1引数と第2引数のベクトルを引き算して、計算結果を第3引数のベクトルにコピーする。 + * + * @param minuend 被減数 + * @param subtrahend 減数 + * @param dest 代入先のベクトル + * @return 代入先のベクトル + */ + public static CubismVector2 subtract(CubismVector2 minuend, CubismVector2 subtrahend, CubismVector2 dest) { + dest.x = minuend.x - subtrahend.x; + dest.y = minuend.y - subtrahend.y; + + return dest; + } + + /** + * 第1引数と第2引数のベクトルを掛け算して、計算結果を第3引数のベクトルにコピーする。 + * + * @param multiplicand 被乗数 + * @param multiplier 乗数 + * @param dest 代入先のベクトル + * @return 代入先のベクトル + */ + public static CubismVector2 multiply(CubismVector2 multiplicand, CubismVector2 multiplier, CubismVector2 dest) { + dest.x = multiplicand.x * multiplier.x; + dest.y = multiplicand.y * multiplier.y; + + return dest; + } + + /** + * 第1引数のベクトルと第2引数のスカラーを掛け算して、計算結果を第3引数のベクトルにコピーする。 + * + * @param multiplicand 被乗数のベクトル + * @param multiplier 乗数のスカラー + * @param dest 代入先のベクトル + * @return 代入先のベクトル + */ + public static CubismVector2 multiply(CubismVector2 multiplicand, float multiplier, CubismVector2 dest) { + dest.x = multiplicand.x * multiplier; + dest.y = multiplicand.y * multiplier; + + return dest; + } + + /** + * 第1引数と第2引数のベクトルを割り算して、計算結果を第3引数のベクトルにコピーする。 + * + * @param dividend 被除数 + * @param divisor 除数 + * @param dest 代入先のベクトル + * @return 代入先のベクトル + */ + public static CubismVector2 divide(CubismVector2 dividend, CubismVector2 divisor, CubismVector2 dest) { + dest.x = dividend.x / divisor.x; + dest.y = dividend.y / divisor.y; + + return dest; + } + + /** + * 第1引数のベクトルと第2引数のスカラーを割り算して、計算結果を第3引数のベクトルにコピーする。 + * + * @param dividend 被除数のベクトル + * @param divisor 除数のスカラー + * @param dest 代入先のベクトル + * @return 代入先のベクトル + */ + public static CubismVector2 divide(CubismVector2 dividend, float divisor, CubismVector2 dest) { + dest.x = dividend.x / divisor; + dest.y = dividend.y / divisor; + + return dest; + } + + /** + * Add the given vector to this vector. + * + * @param vec the added vector + * @return calculated result + */ + public CubismVector2 add(CubismVector2 vec) { + this.x += vec.x; + this.y += vec.y; + + return this; + } + + /** + * Subtract the given vector from this. + * + * @param vec the subtracted vector + * @return the calculated result + */ + public CubismVector2 subtract(CubismVector2 vec) { + this.x -= vec.x; + this.y -= vec.y; + + return this; + } + + /** + * Multiply this vector by the given vector. + * + * @param vec multiplier + * @return the calculated result + */ + public CubismVector2 multiply(CubismVector2 vec) { + x *= vec.x; + y *= vec.y; + + return this; + } + + /** + * Multiply this vector by a scalar value. + * + * @param scalar a scalar value + * @return a calculated value + */ + public CubismVector2 multiply(float scalar) { + x *= scalar; + y *= scalar; + + return this; + } + + /** + * Divide this vector by the given vector. + * + * @param vec divisor + * @return the calculated result + */ + public CubismVector2 divide(CubismVector2 vec) { + x /= vec.x; + y /= vec.y; + + return this; + } + + /** + * Divide this vector by a scalar value. + * + * @param scalar a scalar value + * @return a calculated value + */ + public CubismVector2 divide(float scalar) { + this.x /= scalar; + this.y /= scalar; + + return this; + } + + /** + * Normalize this vector. + */ + public void normalize() { + float length = (float) (Math.pow((x * x) + (y * y), 0.5f)); + + x /= length; + y /= length; + } + + /** + * Get the length of this vector. + * + * @return the length of this vector + */ + public float getLength() { + return CubismMath.sqrtF(x * x + y * y); + } + + /** + * Get a distance between vectors. + * + * @param vec a position vector + * @return a distance between vectors + */ + public float getDistanceWith(CubismVector2 vec) { + return CubismMath.sqrtF(((this.x - vec.x) * (this.x - vec.x)) + ((this.y - vec.y) * (this.y - vec.y))); + } + + /** + * Calculate dot product + * + * @param vec a vector + * @return a calculated result + */ + public float dot(CubismVector2 vec) { + return (this.x * vec.x) + (this.y * vec.y); + } + + /** + * 与えられたベクトルのx, yの値をこのベクトルのx, yに設定する。 + * + * @param vec copied vector + * @return this vector for chaining + */ + public CubismVector2 set(CubismVector2 vec) { + this.x = vec.x; + this.y = vec.y; + + return this; + } + + /** + * 与えられたx, yの値をこのベクトルのx, yに設定する。 + * + * @param x x value + * @param y y value + * @return this vector for chaining + */ + public CubismVector2 set(float x, float y) { + this.x = x; + this.y = y; + + return this; + } + + /** + * Sets the components of this vector to 0. + * + * @return this vector for chaining + */ + public CubismVector2 setZero() { + this.x = 0.0f; + this.y = 0.0f; + + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismVector2 that = (CubismVector2) o; + + if (Float.compare(that.x, x) != 0) return false; + return Float.compare(that.y, y) == 0; + } + + @Override + public int hashCode() { + int result = (x != 0.0f ? Float.floatToIntBits(x) : 0); + result = 31 * result + (y != 0.0f ? Float.floatToIntBits(y) : 0); + return result; + } + + /** + * X-value + */ + public float x; + /** + * Y-value + */ + public float y; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismViewMatrix.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismViewMatrix.java new file mode 100644 index 0000000..e19d1f6 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/CubismViewMatrix.java @@ -0,0 +1,294 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.math; + +/** + * Class of 4x4 matrices that can be used to reposition the camera. + */ +public class CubismViewMatrix extends CubismMatrix44 { + public CubismViewMatrix() {} + + /** + * Move for the given arguments. + * The amount of movement is adjusted. + * + * @param x amount of X-axis movement + * @param y amount of Y-axis movement + */ + public void adjustTranslate(float x, float y) { + if (tr[0] * maxLeft + (tr[12] + x) > screenLeft) { + x = screenLeft - tr[0] * maxLeft - tr[12]; + } + + if (tr[0] * maxRight + (tr[12] + x) < screenRight) { + x = screenRight - tr[0] * maxRight - tr[12]; + } + + if (tr[5] * maxTop + (tr[13] + y) < screenTop) { + y = screenTop - tr[5] * maxTop - tr[13]; + } + + if (tr[5] * maxBottom + (tr[13] + y) > screenBottom) { + y = screenBottom - tr[5] * maxBottom - tr[13]; + } + + float[] tr = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + x, y, 0.0f, 1.0f + }; + multiply(tr, this.tr, this.tr); + } + + /** + * Scale with the given arguments. + * The amount of scaling is adjusted. + * + * @param cx center position of X-axis to be scaled + * @param cy center position of Y-axis to be scaled + * @param scale scaling rate + */ + public void adjustScale(final float cx, final float cy, float scale) { + float maxScale = getMaxScale(); + float minScale = getMinScale(); + + float targetScale = scale * tr[0]; + + if (targetScale < minScale) { + if (tr[0] > 0.0f) { + scale = minScale / tr[0]; + } + } else if (targetScale > maxScale) { + if (tr[0] > 0.0f) { + scale = maxScale / tr[0]; + } + } + + float[] tr1 = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + cx, cy, 0.0f, 1.0f + }; + float[] tr2 = { + scale, 0.0f, 0.0f, 0.0f, + 0.0f, scale, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + float[] tr3 = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + -cx, -cy, 0.0f, 1.0f + }; + + multiply(tr3, tr, tr); + multiply(tr2, tr, tr); + multiply(tr1, tr, tr); + } + + /** + * Get the X-axis position of the left side of the logical coordinate corresponding to the device. + * + * @return X-axis position of the left side of the logical coordinate corresponding to the device + */ + public float getScreenLeft() { + return screenLeft; + } + + /** + * Get the X-axis position of the right side of the logical coordinate corresponding to the device. + * + * @return X-axis position of the right side of the logical coordinate corresponding to the device + */ + public float getScreenRight() { + return screenRight; + } + + /** + * Get the Y-axis position of the top side of the logical coordinate corresponding to the device. + * + * @return Y-axis position of the top side of the logical coordinate corresponding to the device + */ + public float getScreenTop() { + return screenTop; + } + + /** + * Get the Y-axis position of the bottom side of the logical coordinate corresponding to the device. + * + * @return Y-axis position of the bottom side of the logical coordinate corresponding to the device + */ + public float getScreenBottom() { + return screenBottom; + } + + /** + * Get the maximum X-axis position of the left side. + * + * @return maximum X-axis position of the left side + */ + public float getMaxLeft() { + return maxLeft; + } + + /** + * Get the maximum X-axis position of the right side. + * + * @return maximum X-axis position of the right side + */ + public float getMaxRight() { + return maxRight; + } + + /** + * Get the maximum Y-axis position of the top side. + * + * @return maximum Y-axis position of the top side + */ + public float getMaxTop() { + return maxTop; + } + + /** + * Get the maximum Y-axis position of the bottom side. + * + * @return maximum Y-axis position of the bottom side + */ + public float getMaxBottom() { + return maxBottom; + } + + /** + * Get the maximum scaling. + * + * @return maximum scaling + */ + public float getMaxScale() { + return maxScale; + } + + /** + * Set the maximum scaling. + * + * @param maxScale maximum scaling + */ + public void setMaxScale(float maxScale) { + this.maxScale = maxScale; + } + + /** + * Check to see if the magnification ratio is at its maximum. + * + * @return Return true if the scaling factor is at its maximum. + */ + public boolean isMaxScale() { + return getScaleX() >= maxScale; + } + + /** + * Get the minimum scaling. + * + * @return minimum scaling + */ + public float getMinScale() { + return minScale; + } + + /** + * Set the minimum scaling. + * + * @param minScale minimum scaling + */ + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + /** + * Check to see if the magnification ratio is at its minimum. + * + * @return Return true if the scaling factor is at its minimum. + */ + public boolean isMinScale() { + return getScaleX() <= minScale; + } + + + /** + * Set the range on the logical coordinates corresponding to the device. + * + * @param left position of X-axis on the left side + * @param right position of X-axis on the right side + * @param bottom position of Y-axis on the bottom side + * @param top position of Y-axis on the top side + */ + public void setScreenRect(float left, float right, float bottom, float top) { + screenLeft = left; + screenRight = right; + screenBottom = bottom; + screenTop = top; + } + + /** + * Set the movable range on the logical coordinates corresponding to the device. + * + * @param left position of X-axis on the left side + * @param right position of X-axis on the right side + * @param bottom position of Y-axis on the bottom side + * @param top position of Y-axis on the top side + */ + public void setMaxScreenRect(float left, float right, float bottom, float top) { + maxLeft = left; + maxRight = right; + maxBottom = bottom; + maxTop = top; + } + + /** + * range on logical coordinates corresponding to device (left side X-axis position) + */ + private float screenLeft; + /** + * range on logical coordinates corresponding to device (right side X-axis position) + */ + private float screenRight; + /** + * range on logical coordinates corresponding to device (top side Y-axis position) + */ + private float screenBottom; + /** + * range on logical coordinates corresponding to device (bottom side Y-axis position) + */ + private float screenTop; + /** + * Moveable range on logical coordinates (left side X-axis position) + */ + private float maxLeft; + /** + * Moveable range on logical coordinates (right side X-axis position) + */ + private float maxRight; + /** + * Moveable range on logical coordinates (top side Y-axis position) + */ + private float maxBottom; + /** + * Moveable range on logical coordinates (bottom side Y-axis position) + */ + private float maxTop; + /** + * maximum value of scaling rate + */ + private float maxScale; + /** + * minimum value of scaling rate + */ + private float minScale; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/package-info.java new file mode 100644 index 0000000..d318fe2 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/math/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide the function for arthmetic operations required for operating and drawing models, such as matrix and vector calculations. + */ +package com.live2d.sdk.cubism.framework.math; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismMoc.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismMoc.java new file mode 100644 index 0000000..eab1ef8 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismMoc.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.model; + +import com.live2d.sdk.cubism.core.Live2DCubismCore; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +import java.text.ParseException; + + +/** + * Moc data manager class + */ +public class CubismMoc { + /** + * バッファからMocファイルを読み取り、Mocデータを作成する。 + * NOTE: デフォルトではMOC3の整合性をチェックしない。 + * + * @param mocBytes MOC3ファイルのバイト配列バッファ + * @return MOC3ファイルのインスタンス + */ + public static CubismMoc create(byte[] mocBytes) { + return create(mocBytes, false); + } + + /** + * バッファからMocファイルを読み取り、Mocデータを作成する。 + * + * @param mocBytes MOC3ファイルのバイト配列バッファ + * @param shouldCheckMocConsistency MOC3の整合性をチェックするか。trueならチェックする。 + * @return MOC3ファイルのインスタンス + */ + public static CubismMoc create(byte[] mocBytes, boolean shouldCheckMocConsistency) { + com.live2d.sdk.cubism.core.CubismMoc moc; + + if (mocBytes == null) { + return null; + } + + if (shouldCheckMocConsistency) { + // .moc3の整合性を確認する。 + boolean consistency = hasMocConsistency(mocBytes); + + if (!consistency) { + CubismDebug.cubismLogError("Inconsistent MOC3."); + return null; + } + } + + try { + moc = com.live2d.sdk.cubism.core.CubismMoc.instantiate(mocBytes); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + + CubismMoc cubismMoc = new CubismMoc(moc); + cubismMoc.mocVersion = Live2DCubismCore.getMocVersion(mocBytes); + + return cubismMoc; + } + + /** + * Return the latest .moc3 Version. + * + * @return the latest .moc3 Version + */ + public static int getLatestMocVersion() { + return Live2DCubismCore.getLatestMocVersion(); + } + + /** + * .moc3ファイルがロードされたメモリを参照し、フォーマットが正しいかチェックする。(不正なファイルかどうかのチェック) + * Native CoreのcsmHasMocConsistencyに対応する。 + * + * @param mocBytes .moc3が読まれたデータ配列 + * + * @return .moc3が有効なデータであるかどうか。有効なデータならtrue + */ + public static boolean hasMocConsistency(byte[] mocBytes) { + return Live2DCubismCore.hasMocConsistency(mocBytes); + } + + /** + * Create a model. + * + * @return the model created from Moc data + */ + public CubismModel createModel() { + com.live2d.sdk.cubism.core.CubismModel model; + + try { + model = moc.instantiateModel(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return null; + } catch (IllegalStateException e) { + e.printStackTrace(); + return null; + } + + CubismModel cubismModel = new CubismModel(model); + cubismModel.initialize(); + modelCount++; + + return cubismModel; + } + + /** + * Close the Moc instance. + */ + public void delete() { + assert (modelCount == 0); + if (moc != null) { + moc.close(); + } + moc = null; + } + + /** + * Delete the model given in the argument. + * + * @param model model instance + */ + public void deleteModel(CubismModel model) { + model.close(); + modelCount--; + } + + /** + * Return the .moc3 Version of the loaded model. + * + * @return the .moc3 Version of the loaded model + */ + public int getMocVersion() { + return mocVersion; + } + + /** + * private constructor + */ + private CubismMoc(com.live2d.sdk.cubism.core.CubismMoc moc) { + this.moc = moc; + } + + /** + * Moc data + */ + private com.live2d.sdk.cubism.core.CubismMoc moc; + /** + * Number of models created by the Moc data + */ + private int modelCount; + /** + * .moc3 version of the loaded model + */ + private int mocVersion; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModel.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModel.java new file mode 100644 index 0000000..9451f52 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModel.java @@ -0,0 +1,2025 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.model; + +import com.live2d.sdk.cubism.core.*; +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismMath; +import com.live2d.sdk.cubism.framework.rendering.CubismRenderer; +import com.live2d.sdk.cubism.framework.rendering.CubismRenderer.CubismBlendMode; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.live2d.sdk.cubism.core.CubismDrawableFlag.ConstantFlag.*; +import static com.live2d.sdk.cubism.core.CubismDrawableFlag.DynamicFlag.*; + + +/** + * Model class created from Mclapoc data. + */ +public class CubismModel { + /** + * Inner class for handling texture colors in RGBA + */ + public static class DrawableColorData { + /** + * Constructor + */ + public DrawableColorData() { + color = new CubismRenderer.CubismTextureColor(); + } + + /** + * Constructor + * + * @param isOverridden flag whether to be overridden + * @param color texture color + * @throws IllegalArgumentException if an argument is null + */ + public DrawableColorData(boolean isOverridden, CubismRenderer.CubismTextureColor color) { + if (color == null) { + throw new IllegalArgumentException("color is null"); + } + this.isOverridden = isOverridden; + this.color = color; + } + + /** + * Copy constructor + * + * @param data DrawableColorData instance to be copied + */ + public DrawableColorData(DrawableColorData data) { + this.isOverridden = data.isOverridden; + this.color = data.color; + } + + /** + * flag whether to be overridden + */ + public boolean isOverridden; + /** + * texture color + */ + public CubismRenderer.CubismTextureColor color; + } + + /** + * パーツの色をRGBAで扱うための内部クラス + */ + public static class PartColorData { + /** + * コンストラクタ + */ + public PartColorData() { + color = new CubismRenderer.CubismTextureColor(); + } + + /** + * コンストラクタ + * + * @param isOverridden SDKで設定した色情報でパーツの描画色を上書きするか。trueなら上書きする。 + * @param color 色情報 + */ + public PartColorData(boolean isOverridden, CubismRenderer.CubismTextureColor color) { + if (color == null) { + throw new IllegalArgumentException("color is null"); + } + this.isOverridden = isOverridden; + this.color = color; + } + + /** + * コピーコンストラクタ + * + * @param data コピーするPartColorDataインスタンス + */ + public PartColorData(PartColorData data) { + this.isOverridden = data.isOverridden; + this.color = data.color; + } + + /** + * SDKで設定した色情報でパーツの描画色を上書きするか。trueなら上書きする。 + */ + public boolean isOverridden; + + /** + * パーツの色情報 + */ + public CubismRenderer.CubismTextureColor color; + } + + /** + * テクスチャのカリング設定を管理するための内部クラス + */ + public static class DrawableCullingData { + /** + * コンストラクタ + */ + DrawableCullingData() {} + + /** + * コンストラクタ + * + * @param isOverridden モデルのカリング設定を上書きするかどうか + * @param isCulling カリングするかどうか + */ + DrawableCullingData(boolean isOverridden, boolean isCulling) { + this.isOverridden = isOverridden; + this.isCulling = isCulling; + } + + /** + * モデルのカリング設定を上書きするかどうか + */ + public boolean isOverridden; + /** + * カリングするかどうか + */ + public boolean isCulling; + } + + /** + * Class for managing the override of parameter repetition settings + */ + public static class ParameterRepeatData { + /** + * Constructor + */ + public ParameterRepeatData() { + this.isOverridden = false; + this.isParameterRepeated = false; + } + + /** + * Constructor + * + * @param isOverridden whether to be overriden + * @param isParameterRepeated override flag for settings + */ + public ParameterRepeatData(boolean isOverridden, boolean isParameterRepeated) { + this.isOverridden = isOverridden; + this.isParameterRepeated = isParameterRepeated; + } + + /** + * Whether to be overridden + */ + public boolean isOverridden; + + /** + * Override flag for settings + */ + public boolean isParameterRepeated; + }; + + /** + * Update model's parameters. + */ + public void update() { + model.update(); + model.resetDrawableDynamicFlags(); + } + + /** + * Get the canvas width in Pixel. + * + * @return canvas width(pixel) + */ + public float getCanvasWidthPixel() { + if (model == null) { + return 0.0f; + } + CubismCanvasInfo canvasInfo = model.getCanvasInfo(); + + return canvasInfo.getSizeInPixels()[0]; + } + + /** + * Get the canvas height in Pixel. + * + * @return canvas height(pixel) + */ + public float getCanvasHeightPixel() { + if (model == null) { + return 0.0f; + } + CubismCanvasInfo canvasInfo = model.getCanvasInfo(); + + return canvasInfo.getSizeInPixels()[1]; + } + + /** + * Get PixelsPerUnit. + * + * @return PixelsPerUnit + */ + public float getPixelPerUnit() { + if (model == null) { + return 0.0f; + } + CubismCanvasInfo canvasInfo = model.getCanvasInfo(); + + return canvasInfo.getPixelsPerUnit(); + } + + /** + * Get the canvas width. + * + * @return canvas width + */ + public float getCanvasWidth() { + if (model == null) { + return 0.0f; + } + + CubismCanvasInfo canvasInfo = model.getCanvasInfo(); + + return canvasInfo.getSizeInPixels()[0] / canvasInfo.getPixelsPerUnit(); + } + + /** + * Get the canvas height. + * + * @return canvas height + */ + public float getCanvasHeight() { + if (model == null) { + return 0.0f; + } + + CubismCanvasInfo canvasInfo = model.getCanvasInfo(); + + return canvasInfo.getSizeInPixels()[1] / canvasInfo.getPixelsPerUnit(); + } + + /** + * Get the index of parts. + * + * @param partId parts ID + * @return parts index + */ + public int getPartIndex(CubismId partId) { + final CubismPartView partView = model.findPartView(partId.getString()); + if (partView != null) { + return partView.getIndex(); + } + + // If the part does not exist in the model, it searches for it in the non-existent part ID list and returns its index. + if (notExistPartIds.containsKey(partId)) { + return notExistPartIds.get(partId); + } + + // If the part does not exist in the non-existent part ID list, add newly the element. + final int partCount = partValues.length; + final int partIndex = partCount + notExistPartIds.size(); + notExistPartIds.put(partId, partIndex); + notExistPartIndices.add(partIndex); + + float[] tmp = new float[notExistPartIndices.size()]; + System.arraycopy(notExistPartOpacities, 0, tmp, 0, notExistPartIndices.size() - 1); + tmp[notExistPartIndices.size() - 1] = 0.0f; + notExistPartOpacities = new float[notExistPartIndices.size()]; + System.arraycopy(tmp, 0, notExistPartOpacities, 0, notExistPartIndices.size()); + + return partIndex; + } + + /** + * パーツのIDを取得する。 + * + * @param partIndex 取得するパーツのインデックス + * @return パーツのID + */ + public CubismId getPartId(int partIndex){ + assert (0 <= partIndex && partIndex < partIds.size()); + return partIds.get(partIndex); + } + + /** + * Get the number of parts. + * + * @return number of parts + */ + public int getPartCount() { + return model.getPartViews().length; + } + + /** + * Returns the indices of the parent parts for the parts. + * + * @return Indices of parent parts for the parts. + */ + public int[] getPartParentPartIndices() { + final int[] partIndices = model.getParts().getParentPartIndices(); + return partIndices; + } + + /** + * Set an opacity of the part. + * + * @param partId part ID + * @param opacity opacity + */ + public void setPartOpacity(CubismId partId, float opacity) { + // Speeding up the process, this can get partIndex. However, it is not necessary when setting externally because it is not frequently called. + final int index = getPartIndex(partId); + + if (index < 0) { + // Skip processes because there is no part. + return; + } + + setPartOpacity(index, opacity); + } + + /** + * Set an opacity of the part. + * + * @param partIndex part index + * @param opacity part opacity + */ + public void setPartOpacity(int partIndex, float opacity) { + if (notExistPartIndices.contains(partIndex)) { + int index = notExistPartIndices.indexOf(partIndex); + notExistPartOpacities[index] = opacity; + return; + } + + // Detect whether partIndex is not out of bounds index + assert 0 <= partIndex && partIndex < getPartCount(); + + partValues[partIndex].setOpacity(opacity); + } + + /** + * Get the opacity of the part. + * + * @param partId part ID + * @return part opacity + */ + public float getPartOpacity(CubismId partId) { + // Speeding up the process, this can get partIndex. However, it is not necessary when setting externally because it is not frequently called. + final int index = getPartIndex(partId); + + if (index < 0) { + // Skip processes because there is no part + return 0; + } + + return getPartOpacity(index); + } + + /** + * Get the opacity of the part. + * + * @param partIndex part index + * @return part opacity + */ + public float getPartOpacity(int partIndex) { + if (notExistPartIndices.contains(partIndex)) { + // If the part ID does not exist in the model, returns the opacity from non-existence parts list. + int index = notExistPartIndices.indexOf(partIndex); + return notExistPartOpacities[index]; + } + + // Detect whether partIndex is not out of bounds index + assert 0 <= partIndex && partIndex < getPartCount(); + + return partValues[partIndex].getOpacity(); + } + + /** + * Get the index of parameters. + * + * @param parameterId parameter ID + * @return parameter index + */ + public int getParameterIndex(CubismId parameterId) { + final CubismParameterView parameterView = model.findParameterView(parameterId.getString()); + if (parameterView != null) { + return parameterView.getIndex(); + } + + // If the parameter does not exist in the model, it searches for it in the non-existent parameter ID list and returns its index. + if (notExistParameterIds.containsKey(parameterId)) { + final Integer index = notExistParameterIds.get(parameterId); + assert index != null; + return index; + } + + // If the parameter does not exist in the non-existent parameter ID list, add newly the element. + final int parameterCount = parameterValues.length; + final int parameterIndex = parameterCount + notExistParameterIds.size(); + notExistParameterIds.put(parameterId, parameterIndex); + notExistParameterIndices.add(parameterIndex); + + float[] tmp = new float[notExistParameterIndices.size()]; + System.arraycopy(notExistParameterValues, 0, tmp, 0, notExistParameterIndices.size() - 1); + tmp[notExistParameterIndices.size() - 1] = 0.0f; + notExistParameterValues = new float[notExistParameterIndices.size()]; + System.arraycopy(tmp, 0, notExistParameterValues, 0, notExistParameterIndices.size()); + + return parameterIndex; + } + + /** + * パラメータのIDを取得する。 + * + * @param parameterIndex パラメータのインデックス + * @return パラメータのID + */ + public CubismId getParameterId(int parameterIndex) { + assert (0 <= parameterIndex && parameterIndex < parameterIds.size()); + return parameterIds.get(parameterIndex); + } + + /** + * Get the number of parameters. + * + * @return the number of parameters + */ + public int getParameterCount() { + return parameterValues.length; + } + + /** + * Return the type of parameter at the index specified by the argument. + * + * @param parameterIndex parameter index + * @return the type of parameter at the index specified by the argument + */ + public CubismParameters.ParameterType getParameterType(int parameterIndex) { + return model.getParameterViews()[parameterIndex].getType(); + } + + /** + * Get the maximum value of parameters. + * + * @param parameterIndex parameter index + * @return the maximum value of parameter + */ + public float getParameterMaximumValue(int parameterIndex) { + return model.getParameterViews()[parameterIndex].getMaximumValue(); + } + + /** + * Get the minimum value of parameters. + * + * @param parameterIndex parameter index + * @return the minimum value of parameter + */ + public float getParameterMinimumValue(int parameterIndex) { + return model.getParameterViews()[parameterIndex].getMinimumValue(); + } + + /** + * Get the default value of parameters. + * + * @param parameterIndex parameter index + * @return the default value of parameter + */ + public float getParameterDefaultValue(int parameterIndex) { + return model.getParameterViews()[parameterIndex].getDefaultValue(); + } + + /** + * Get the value of parameter. + * + * @param parameterId parameter ID + * @return parameter value + */ + public float getParameterValue(CubismId parameterId) { + // Speeding up the process, this can get partIndex. However, it is not necessary when setting externally because it is not frequently called. + final int parameterIndex = getParameterIndex(parameterId); + return getParameterValue(parameterIndex); + } + + /** + * Get the value of parameter. + * + * @param parameterIndex parameter index + * @return the value of parameter + */ + public float getParameterValue(int parameterIndex) { + if (notExistParameterIndices.contains(parameterIndex)) { + int index = notExistParameterIndices.indexOf(parameterIndex); + final float value = notExistParameterValues[index]; + return value; + } + + // Detect whether partIndex is not out of bounds index + assert 0 <= parameterIndex && parameterIndex < getParameterCount(); + + return parameterValues[parameterIndex].getValue(); + } + + /** + * Set the value of parameter. + * + * @param parameterId parameter ID + * @param value parameter value + */ + public void setParameterValue(CubismId parameterId, float value) { + setParameterValue(parameterId, value, 1.0f); + } + + /** + * Set the value of parameter. + * + * @param parameterId parameter ID + * @param value parameter value + * @param weight weight + */ + public void setParameterValue(CubismId parameterId, float value, float weight) { + final int index = getParameterIndex(parameterId); + setParameterValue(index, value, weight); + } + + /** + * Set the value of parameter. + * + * @param parameterIndex parametere index + * @param value parameter value + */ + public void setParameterValue(int parameterIndex, float value) { + setParameterValue(parameterIndex, value, 1.0f); + } + + /** + * Set the value of parameter. + * + * @param parameterIndex parameter index + * @param value parameter value + * @param weight weight + */ + public void setParameterValue(int parameterIndex, float value, float weight) { + if (notExistParameterIndices.contains(parameterIndex)) { + int index = notExistParameterIndices.indexOf(parameterIndex); + final float parameterValue = notExistParameterValues[index]; + final float weightedParameterValue = (weight == 1.0f) + ? value + : (parameterValue * (1.0f - weight)) + (value * weight); + notExistParameterValues[index] = weightedParameterValue; + return; + } + + + // Detect whether partIndex is not out of bounds index + assert 0 <= parameterIndex && parameterIndex < getParameterCount(); + + CubismParameterView parameter = parameterValues[parameterIndex]; + + if (isRepeat(parameterIndex)) { + value = getParameterRepeatValue(parameterIndex, value); + } else { + value = getParameterClampValue(parameterIndex, value); + } + + final float parameterValue = parameter.getValue(); + final float weightedParameterValue = (weight == 1.0f) + ? value + : (parameterValue * (1.0f - weight)) + (value * weight); + parameter.setValue(weightedParameterValue); + } + + /** + * Gets whether the parameter has the repeat setting. + * + * @param parameterIndex Parameter index + * + * @return true if it is set, otherwise returns false. + */ + public boolean isRepeat(int parameterIndex) { + if (notExistParameterIndices.contains(parameterIndex)) { + return false; + } + + // Detect whether partIndex is not out of bounds index + assert 0 <= parameterIndex && parameterIndex < getParameterCount(); + + boolean isRepeat; + + // Determines whether to perform parameter repeat processing + if (isOverriddenParameterRepeat || userParameterRepeatDataList.get(parameterIndex).isOverridden) { + // Use repeat information set on the SDK side + isRepeat = userParameterRepeatDataList.get(parameterIndex).isParameterRepeated; + } else { + // Use repeat information set in Editor + isRepeat = this.model.getParameters().getParameterRepeats()[parameterIndex]; + } + + return isRepeat; + } + + /** + * Returns the calculated result ensuring the value falls within the parameter's range. + * + * @param parameterIndex Parameter index + * @param value Parameter value + * + * @return a value that falls within the parameter’s range. If the parameter does not exist, returns it as is. + */ + public float getParameterRepeatValue(int parameterIndex, float value) { + if (this.notExistParameterIndices.contains(parameterIndex)) { + return value; + } + // In-index range detection + assert (0 <= parameterIndex && parameterIndex < getParameterCount()); + + final float maxValue = this.model.getParameters().getMaximumValues()[parameterIndex]; + final float minValue = this.model.getParameters().getMinimumValues()[parameterIndex]; + final float valueSize = maxValue - minValue; + + if (maxValue < value) { + float overValue = CubismMath.modF(value - maxValue, valueSize); + if (!Float.isNaN(overValue)) { + value = minValue + overValue; + } else { + value = maxValue; + } + } + if (value < minValue) { + float overValue = CubismMath.modF(minValue - value, valueSize); + if (!Float.isNaN(overValue)) { + value = maxValue - overValue; + } else { + value = minValue; + } + } + + return value; + } + + /** + * Returns the result of clamping the value to ensure it falls within the parameter's range. + * + * @param parameterIndex Parameter index + * @param value Parameter value + * + * @return the clamped value. If the parameter does not exist, returns it as is. + */ + public float getParameterClampValue(int parameterIndex, float value) { + if (notExistParameterIndices.contains(parameterIndex)) { + return value; + } + + // In-index range detection + assert (0 <= parameterIndex && parameterIndex < this.getParameterCount()); + + final float maxValue = this.model.getParameters().getMaximumValues()[parameterIndex]; + final float minValue = this.model.getParameters().getMinimumValues()[parameterIndex]; + + return CubismMath.clampF(value, minValue, maxValue); + } + + /** + * Returns the repeat of the parameter. + * + * @param parameterIndex Parameter index + * + * @return the raw data parameter repeat from the Cubism Core. + */ + public boolean getParameterRepeats(int parameterIndex) { + return this.model.getParameters().getParameterRepeats()[parameterIndex]; + } + + /** + * Add the value of parameter. + * + * @param parameterId parameter ID + * @param value the value to be added + */ + public void addParameterValue(CubismId parameterId, float value) { + addParameterValue(parameterId, value, 1.0f); + } + + /** + * Add the value of parameter. + * + * @param parameterId parameter ID + * @param value the value to be added + * @param weight weight + */ + public void addParameterValue(CubismId parameterId, float value, float weight) { + final int index = getParameterIndex(parameterId); + addParameterValue(index, value, weight); + } + + /** + * Add the value of parameter. + * + * @param parameterIndex parameter index + * @param value the value to be added + */ + public void addParameterValue(int parameterIndex, float value) { + addParameterValue(parameterIndex, value, 1.0f); + } + + /** + * Add the value of parameter. + * + * @param parameterIndex parameter index + * @param value the value to be added + * @param weight weight + */ + public void addParameterValue(int parameterIndex, float value, float weight) { + setParameterValue( + parameterIndex, + getParameterValue(parameterIndex) + (value * weight) + ); + } + + /** + * Multiply the value of parameter. + * + * @param parameterId parameter ID + * @param value the value to be multiplied + */ + public void multiplyParameterValue(CubismId parameterId, float value) { + multiplyParameterValue(parameterId, value, 1.0f); + } + + /** + * Multiply the value of parameter. + * + * @param parameterId parameter ID + * @param value the value to be multiplied + * @param weight weight + */ + public void multiplyParameterValue(CubismId parameterId, float value, float weight) { + final int index = getParameterIndex(parameterId); + multiplyParameterValue(index, value, weight); + } + + /** + * Multiply the value of parameter. + * + * @param parameterIndex parameter index + * @param value the value to be multiplied + */ + public void multiplyParameterValue(int parameterIndex, float value) { + multiplyParameterValue(parameterIndex, value, 1.0f); + } + + /** + * Multiply the value of parameter. + * + * @param parameterIndex parameter index + * @param value the value to be multiplied + * @param weight weight + */ + public void multiplyParameterValue(int parameterIndex, float value, float weight) { + setParameterValue( + parameterIndex, + getParameterValue(parameterIndex) * (1.0f + (value - 1.0f) * weight) + ); + } + + /** + * Get the index of Drawable. + * + * @param drawableId Drawable ID + * @return Drawable index. If there is no index, return -1. + */ + public int getDrawableIndex(CubismId drawableId) { + final CubismDrawableView drawableIndex = model.findDrawableView(drawableId.getString()); + if (drawableIndex != null) { + return drawableIndex.getIndex(); + } + + return -1; + } + + /** + * Get the number of Drawable. + * + * @return the number of Drawable + */ + public int getDrawableCount() { + return model.getDrawableViews().length; + } + + /** + * Get Drawable ID. + * + * @param drawableIndex Drawable index + * @return Drawable ID + */ + public CubismId getDrawableId(int drawableIndex) { + assert (0 <= drawableIndex && drawableIndex < drawableIds.size()); + return drawableIds.get(drawableIndex); + } + + /** + * Get the drawing order list of Drawable. + * + * @return the drawing order list of Drawable + */ + public int[] getDrawableRenderOrders() { + final CubismDrawableView[] drawableViews = model.getDrawableViews(); + assert drawableViews != null; + + if (drawableViews.length > 0) { + return drawableViews[0].getDrawables().getRenderOrders(); + } else { + return new int[0]; + } + } + + /** + * Get the texture index of Drawable + * + * @param drawableIndex Drawable index + * @return the texture index of Drawable + */ + public int getDrawableTextureIndex(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getTextureIndex(); + } + + /** + * Get the vertex index list of Drawable. + * + * @param drawableIndex Drawable index + * @return the vertex index list of Drawable + */ + public short[] getDrawableVertexIndices(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getIndices(); + } + + /** + * Get the number of the vertex indices in Drawable. + * + * @param drawableIndex Drawable index + * @return the number of vertex indices in Drawable + */ + public int getDrawableVertexIndexCount(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getIndices().length; + } + + /** + * Get the number of the vertex in Drawable. + * + * @param drawableIndex Drawable index + * @return the number of vertex in Drawable + */ + public int getDrawableVertexCount(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getVertexCount(); + } + + /** + * Get the vertex list of Drawable + * + * @param drawableIndex Drawable index + * @return the vertex list of Drawable + */ + public float[] getDrawableVertices(int drawableIndex) { + return getDrawableVertexPositions(drawableIndex); + } + + /** + * Get the vertex positions list of Drawable + * + * @param drawableIndex Drawable index + * @return the vertex positions list of Drawable + */ + public float[] getDrawableVertexPositions(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getVertexPositions(); + } + + /** + * Get the vertex UV list of Drawable. + * + * @param drawableIndex Drawable index + * @return the vertex UV list of Drawable + */ + public float[] getDrawableVertexUvs(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getVertexUvs(); + } + + /** + * Get the opacity of Drawable. + * + * @param drawableIndex Drawable index + * @return the Drawable opacity + */ + public float getDrawableOpacity(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getOpacity(); + } + + /** + * Get the multiply color of the drawable. + * + * @param drawableIndex index of the drawable + * @return multiply color of the drawable + */ + public float[] getDrawableMultiplyColor(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getMultiplyColors(); + } + + /** + * Get the screen color of the drawable. + * + * @param drawableIndex index of the drawable + * @return screen color of the drawable + */ + public float[] getDrawableScreenColor(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getScreenColors(); + } + + /** + * Return the index of the Drawable's parent part. + * + * @param drawableIndex the drawable index + * @return the index of the Drawable's parent part + */ + public int getDrawableParentPartIndex(int drawableIndex) { + return model.getDrawableViews()[drawableIndex].getParentPartIndex(); + } + + /** + * Get the blend mode of Drawable. + * + * @param drawableIndex Drawable index + * @return the blend mode of Drawable + */ + public CubismBlendMode getDrawableBlendMode(int drawableIndex) { + final byte constantFlag = model.getDrawableViews()[drawableIndex].getConstantFlag(); + return isBitSet(constantFlag, BLEND_ADDITIVE) + ? CubismBlendMode.ADDITIVE + : isBitSet(constantFlag, BLEND_MULTIPLICATIVE) + ? CubismBlendMode.MULTIPLICATIVE + : CubismBlendMode.NORMAL; + } + + /** + * Get Drawable's invert setting when mask is used. + * If mask is not used, nothing happens. + * + * @param drawableIndex Drawable index + * @return the invert setting of Drawable's mask + */ + public boolean getDrawableInvertedMask(int drawableIndex) { + final byte constantFlag = model.getDrawableViews()[drawableIndex].getConstantFlag(); + + return isBitSet(constantFlag, IS_INVERTED_MASK); + } + + /** + * Get the visible information of Drawable. + * + * @param drawableIndex Drawable index + * @return Drawable is visible, return true + */ + public boolean getDrawableDynamicFlagIsVisible(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, IS_VISIBLE); + } + + /** + * In recent {@link CubismModel#update()}, if the visible state is changed, return true. + * + * @param drawableIndex Drawable index + * @return If the visible state is changed, return true + */ + public boolean getDrawableDynamicFlagVisibilityDidChange(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, VISIBILITY_DID_CHANGE); + } + + /** + * In recent {@link CubismModel#update()}, if the opacity of drawable is changed, return true. + * + * @param drawableIndex Drawable index + * @return If the opacity of drawable is changed, return true + */ + public boolean getDrawableDynamicFlagOpacityDidChange(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, OPACITY_DID_CHANGE); + } + + /** + * In recent {@link CubismModel#update()}, if DrawOrder of Drawable is changed, return true. + * DrawOrder is the information from 0 to 1000 specified in ArtMesh. + * + * @param drawableIndex Drawable index + * @return If DrawOrder of Drawable is changed, return true + */ + public boolean getDrawableDynamicFlagDrawOrderDidChange(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, DRAW_ORDER_DID_CHANGE); + } + + /** + * In recent {@link CubismModel#update()}, if the drawing order of Drawable is changed, return true. + * + * @param drawableIndex Drawable index + * @return If the drawing order of Drawable is changed, return true + */ + public boolean getDrawableDynamicFlagRenderOrderDidChange(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, RENDER_ORDER_DID_CHANGE); + } + + /** + * In recent {@link CubismModel#update()}, if the vertex information of Drawable is changed, return true. + * + * @param drawableIndex Drawable index + * @return If the vertex information of Drawable is changed, return true + */ + public boolean getDrawableDynamicFlagVertexPositionsDidChange(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, VERTEX_POSITIONS_DID_CHANGE); + } + + /** + * Get whether the last CubismModel.update() method changed the Drawable's multiply and screen colors. + * + * @param drawableIndex index of the drawable + * @return Whether the drawable's multiply and screen color is changed in the last CubismModel.update() method + */ + public boolean getDrawableDynamicFlagBlendColorDidChange(int drawableIndex) { + final byte dynamicFlag = model.getDrawableViews()[drawableIndex].getDynamicFlag(); + return isBitSet(dynamicFlag, BLEND_COLOR_DID_CHANGE); + } + + /** + * Get the clipping mask list of Drawable. + * + * @return the clipping mask list of Drawable + */ + public int[][] getDrawableMasks() { + final CubismDrawableView[] drawableViews = model.getDrawableViews(); + assert drawableViews != null; + + if (drawableViews.length > 0) { + return drawableViews[0].getDrawables().getMasks(); + } else { + return new int[0][0]; + } + } + + /** + * Get the number list of the clippng mask in Drawable. + * + * @return the number list of the clipping mask in Drawable + */ + public int[] getDrawableMaskCounts() { + final CubismDrawableView[] drawableViews = model.getDrawableViews(); + assert drawableViews != null; + + if (drawableViews.length > 0) { + return drawableViews[0].getDrawables().getMaskCounts(); + } else { + return new int[0]; + } + } + + + /** + * Whether clipping mask is used. + * + * @return If clipping mask is used, return true. + */ + public boolean isUsingMasking() { + final CubismDrawableView[] drawableViews = model.getDrawableViews(); + assert drawableViews != null; + + if (drawableViews.length > 0) { + final int drawableCount = drawableViews.length; + + for (int i = 0; i < drawableCount; ++i) { + final int[] drawableMaskCounts = getDrawableMaskCounts(); + if (drawableMaskCounts != null && drawableMaskCounts[i] <= 0) { + continue; + } + return true; + } + } + + return false; + } + + /** + * Read the saved parameters. + */ + public void loadParameters() { + int parameterCount = getParameterCount(); + final int savedParameterCount = savedParameters.length; + + if (parameterCount > savedParameterCount) { + parameterCount = savedParameterCount; + } + + for (int i = 0; i < parameterCount; ++i) { + parameterValues[i].setValue(savedParameters[i]); + } + } + + /** + * Save the parameters. + */ + public void saveParameters() { + final int parameterCount = getParameterCount(); + + if (savedParameters.length < parameterCount) { + savedParameters = new float[parameterCount]; + } + for (int i = 0; i < parameterCount; i++) { + savedParameters[i] = parameterValues[i].getValue(); + } + } + + /** + * Get the multiply color from the list. + * + * @param drawableIndex index of the drawable + * @return the multiply color + */ + public CubismRenderer.CubismTextureColor getMultiplyColor(int drawableIndex) { + if (getOverrideFlagForModelMultiplyColors() || getOverrideFlagForDrawableMultiplyColors(drawableIndex)) { + return userDrawableMultiplyColors.get(drawableIndex).color; + } + + float[] color = getDrawableMultiplyColor(drawableIndex); + multiplyColor.r = color[0]; + multiplyColor.g = color[1]; + multiplyColor.b = color[2]; + multiplyColor.a = color[3]; + + return multiplyColor; + } + + // This is only used by 'getMultiplyColor' method. + // Avoid creating a new CubismTextureColor instance in getter method. + private final CubismRenderer.CubismTextureColor multiplyColor = new CubismRenderer.CubismTextureColor(); + + /** + * Get the screen color from the list. + * + * @param drawableIndex index of the drawable + * @return the screen color + */ + public CubismRenderer.CubismTextureColor getScreenColor(int drawableIndex) { + if (getOverrideFlagForModelScreenColors() || getOverrideFlagForDrawableScreenColors(drawableIndex)) { + return userDrawableScreenColors.get(drawableIndex).color; + } + + float[] color = getDrawableScreenColor(drawableIndex); + screenColor.r = color[0]; + screenColor.g = color[1]; + screenColor.b = color[2]; + screenColor.a = color[3]; + + return screenColor; + } + + // This is only used by 'getScreenColor' method. + // Avoid creating a new CubismTextureColor instance in getter method. + private final CubismRenderer.CubismTextureColor screenColor = new CubismRenderer.CubismTextureColor(); + + /** + * Set the multiply color of Drawable. + * + * @param drawableIndex index of the drawable + * @param color the multiply color instance + */ + public void setMultiplyColor(int drawableIndex, CubismRenderer.CubismTextureColor color) { + setMultiplyColor(drawableIndex, color.r, color.g, color.b, color.a); + } + + /** + * Set the multiply color of Drawable. + * + * @param drawableIndex index of the drawable + * @param r red value + * @param g green value + * @param b blue value + * @param a alpha value + */ + public void setMultiplyColor(int drawableIndex, float r, float g, float b, float a) { + userDrawableMultiplyColors.get(drawableIndex).color.r = r; + userDrawableMultiplyColors.get(drawableIndex).color.g = g; + userDrawableMultiplyColors.get(drawableIndex).color.b = b; + userDrawableMultiplyColors.get(drawableIndex).color.a = a; + } + + /** + * Partの乗算色を取得する。 + * + * @param partIndex 取得したいPartのインデックス + * @return Partの乗算色 + */ + public CubismRenderer.CubismTextureColor getPartMultiplyColor(int partIndex) { + return userPartMultiplyColors.get(partIndex).color; + } + + /** + * Partのスクリーン色を取得する。 + * + * @param partIndex 取得したいPartのインデックス + * @return Partのスクリーン色 + */ + public CubismRenderer.CubismTextureColor getPartScreenColor(int partIndex) { + return userPartScreenColors.get(partIndex).color; + } + + /** + * Partの乗算色を設定する。 + * + * @param partIndex 乗算色を設定するパーツのインデックス + * @param color 乗算色 + */ + public void setPartMultiplyColor(int partIndex, CubismRenderer.CubismTextureColor color) { + setPartColor(partIndex, color.r, color.g, color.b, color.a, userPartMultiplyColors, userDrawableMultiplyColors); + } + + /** + * Partの乗算色を設定する。 + * + * @param partIndex 乗算色を設定するパーツのインデックス + * @param r 赤 + * @param g 緑 + * @param b 青 + * @param a アルファ + */ + public void setPartMultiplyColor(int partIndex, float r, float g, float b, float a) { + setPartColor(partIndex, r, g, b, a, userPartMultiplyColors, userDrawableMultiplyColors); + } + + /** + * Set the screen color of Drawable. + * + * @param drawableIndex index of the drawable + * @param color the screen color instance + */ + public void setScreenColor(int drawableIndex, CubismRenderer.CubismTextureColor color) { + setScreenColor(drawableIndex, color.r, color.g, color.b, color.a); + } + + /** + * Set the screen color of Drawable. + * + * @param drawableIndex index of the drawable + * @param r red value + * @param g green value + * @param b blue value + * @param a alpha value + */ + public void setScreenColor(int drawableIndex, float r, float g, float b, float a) { + userDrawableScreenColors.get(drawableIndex).color.r = r; + userDrawableScreenColors.get(drawableIndex).color.g = g; + userDrawableScreenColors.get(drawableIndex).color.b = b; + userDrawableScreenColors.get(drawableIndex).color.a = a; + } + + /** + * Partのスクリーン色を設定する。 + * + * @param partIndex スクリーン色を設定するパーツのインデックス + * @param color スクリーン色 + */ + public void setPartScreenColor(int partIndex, CubismRenderer.CubismTextureColor color) { + setPartScreenColor(partIndex, color.r, color.g, color.b, color.a); + } + + /** + * Partのスクリーン色を設定する。 + * + * @param partIndex スクリーン色を設定するパーツのインデックス + * @param r 赤 + * @param g 緑 + * @param b 青 + * @param a アルファ + */ + public void setPartScreenColor(int partIndex, float r, float g, float b, float a) { + setPartColor(partIndex, r, g, b, a, userPartScreenColors, userDrawableScreenColors); + } + + /** + * Whether to override the entire model multiply color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use getOverrideFlagForModelMultiplyColors() instead. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverwriteFlagForModelMultiplyColors() { + CubismDebug.cubismLogWarning("getOverwriteFlagForModelMultiplyColors() is a deprecated function. Please use getOverrideFlagForModelMultiplyColors()."); + return getOverrideFlagForModelMultiplyColors(); + } + + /** + * Whether to override the entire model multiply color from the SDK. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverrideFlagForModelMultiplyColors() { + return isOverriddenModelMultiplyColors; + } + + /** + * Whether to override the entire model screen color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use getOverrideFlagForModelScreenColors() instead. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverwriteFlagForModelScreenColors() { + CubismDebug.cubismLogWarning("getOverwriteFlagForModelScreenColors() is a deprecated function. Please use getOverrideFlagForModelScreenColors()."); + return getOverrideFlagForModelScreenColors(); + } + + /** + * Whether to override the entire model screen color from the SDK. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverrideFlagForModelScreenColors() { + return isOverriddenModelScreenColors; + } + + /** + * Set the flag whether to override the entire model multiply color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use setOverrideFlagForModelMultiplyColors(boolean value) instead. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverwriteFlagForModelMultiplyColors(boolean value) { + CubismDebug.cubismLogWarning("setOverwriteFlagForModelMultiplyColors(boolean value) is a deprecated function. Please use setOverrideFlagForModelMultiplyColors(boolean value)."); + setOverrideFlagForModelMultiplyColors(value); + } + + /** + * Set the flag whether to override the entire model multiply color from the SDK. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverrideFlagForModelMultiplyColors(boolean value) { + isOverriddenModelMultiplyColors = value; + } + + /** + * Set the flag whether to override the entire model screen color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use setOverrideFlagForModelScreenColors(boolean value) instead. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverwriteFlagForModelScreenColors(boolean value) { + CubismDebug.cubismLogWarning("setOverwriteFlagForModelScreenColors(boolean value) is a deprecated function. Please use setOverrideFlagForModelScreenColors(boolean value)."); + setOverrideFlagForModelScreenColors(value); + } + + /** + * Set the flag whether to override the entire model screen color from the SDK. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverrideFlagForModelScreenColors(boolean value) { + isOverriddenModelScreenColors = value; + } + + /** + * Whether to override the drawable multiply color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use getOverrideFlagForDrawableMultiplyColors(int drawableIndex) instead. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverwriteFlagForDrawableMultiplyColors(int drawableIndex) { + CubismDebug.cubismLogWarning("getOverwriteFlagForDrawableMultiplyColors(int drawableIndex) is a deprecated function. Please use getOverrideFlagForDrawableMultiplyColors(int drawableIndex)."); + return getOverrideFlagForDrawableMultiplyColors(drawableIndex); + } + + /** + * Whether to override the drawable multiply color from the SDK. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverrideFlagForDrawableMultiplyColors(int drawableIndex) { + return userDrawableMultiplyColors.get(drawableIndex).isOverridden; + } + + /** + * Whether to override the drawable screen color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use getOverrideFlagForDrawableScreenColors(int drawableIndex) instead. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverwriteFlagForDrawableScreenColors(int drawableIndex) { + CubismDebug.cubismLogWarning("getOverwriteFlagForDrawableScreenColors(int drawableIndex) is a deprecated function. Please use getOverrideFlagForDrawableScreenColors(int drawableIndex)."); + return getOverrideFlagForDrawableScreenColors(drawableIndex); + } + + /** + * Whether to override the drawable screen color from the SDK. + * + * @return If the color information on the SDK is used, return true. If the color information of the model is used, return false. + */ + public boolean getOverrideFlagForDrawableScreenColors(int drawableIndex) { + return userDrawableScreenColors.get(drawableIndex).isOverridden; + } + + /** + * SDKからPartの乗算色を上書きするかどうかのフラグを取得する。 + * + * @deprecated This function is deprecated due to a naming change, use getOverrideColorForPartMultiplyColors(int partIndex) instead. + * + * @param partIndex 上書きするPartのインデックス + * @return SDKからPartの乗算色を上書きするか。上書きするならtrue。 + */ + public boolean getOverwriteColorForPartMultiplyColors(int partIndex) { + CubismDebug.cubismLogWarning("getOverwriteColorForPartMultiplyColors(int partIndex) is a deprecated function. Please use getOverrideColorForPartMultiplyColors(int partIndex)."); + return getOverrideColorForPartMultiplyColors(partIndex); + } + + /** + * SDKからPartの乗算色を上書きするかどうかのフラグを取得する。 + * + * @param partIndex 上書きするPartのインデックス + * @return SDKからPartの乗算色を上書きするか。上書きするならtrue。 + */ + public boolean getOverrideColorForPartMultiplyColors(int partIndex) { + return userPartMultiplyColors.get(partIndex).isOverridden; + } + + /** + * SDKからPartのスクリーン色を上書きするかどうかのフラグを取得する。 + * + * @deprecated This function is deprecated due to a naming change, use getOverrideColorForPartScreenColors(int partIndex) instead. + * + * @param partIndex 上書きするPartのインデックス + * @return SDKからPartのスクリーン色を上書きするか。上書きするならtrue。 + */ + public boolean getOverwriteColorForPartScreenColors(int partIndex) { + CubismDebug.cubismLogWarning("getOverwriteColorForPartScreenColors(int partIndex) is a deprecated function. Please use getOverrideColorForPartScreenColors(int partIndex)."); + return getOverrideColorForPartScreenColors(partIndex); + } + + /** + * SDKからPartのスクリーン色を上書きするかどうかのフラグを取得する。 + * + * @param partIndex 上書きするPartのインデックス + * @return SDKからPartのスクリーン色を上書きするか。上書きするならtrue。 + */ + public boolean getOverrideColorForPartScreenColors(int partIndex) { + return userPartScreenColors.get(partIndex).isOverridden; + } + + /** + * Set the flag whether to override the drawable multiply color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use setOverrideFlagForDrawableMultiplyColors(int drawableIndex, boolean value) instead. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverwriteFlagForDrawableMultiplyColors(int drawableIndex, boolean value) { + CubismDebug.cubismLogWarning("setOverwriteFlagForDrawableMultiplyColors(int drawableIndex, boolean value) is a deprecated function. Please use setOverrideFlagForDrawableMultiplyColors(int drawableIndex, boolean value)."); + setOverrideFlagForDrawableMultiplyColors(drawableIndex, value); + } + + /** + * Set the flag whether to override the drawable multiply color from the SDK. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverrideFlagForDrawableMultiplyColors(int drawableIndex, boolean value) { + userDrawableMultiplyColors.get(drawableIndex).isOverridden = value; + } + + /** + * Set the flag whether to override the drawable screen color from the SDK. + * + * @deprecated This function is deprecated due to a naming change, use setOverrideFlagForDrawableScreenColors(int drawableIndex, boolean value) instead. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverwriteFlagForDrawableScreenColors(int drawableIndex, boolean value) { + CubismDebug.cubismLogWarning("setOverwriteFlagForDrawableScreenColors(int drawableIndex, boolean value) is a deprecated function. Please use setOverrideFlagForDrawableScreenColors(int drawableIndex, boolean value)."); + setOverrideFlagForDrawableScreenColors(drawableIndex, value); + } + + /** + * Set the flag whether to override the drawable screen color from the SDK. + * + * @param value If the color information on the SDK is used, this value is true. If the color information of the model is used, this is false. + */ + public void setOverrideFlagForDrawableScreenColors(int drawableIndex, boolean value) { + userDrawableScreenColors.get(drawableIndex).isOverridden = value; + } + + /** + * SDKからPartの乗算色を上書きするかどうかのフラグを設定する。 + * + * @deprecated This function is deprecated due to a naming change, use setOverrideColorForPartMultiplyColors(int partIndex, boolean value) instead. + * + * @param partIndex 上書きするPartのインデックス + * @param value SDKからPartの乗算色を上書きするかどうか。trueなら上書きする。 + */ + public void setOverwriteColorForPartMultiplyColors(int partIndex, boolean value) { + CubismDebug.cubismLogWarning("setOverwriteColorForPartMultiplyColors(int partIndex, boolean value) is a deprecated function. Please use setOverrideColorForPartMultiplyColors(int partIndex, boolean value)."); + setOverrideColorForPartMultiplyColors(partIndex, value); + } + + /** + * SDKからPartの乗算色を上書きするかどうかのフラグを設定する。 + * + * @param partIndex 上書きするPartのインデックス + * @param value SDKからPartの乗算色を上書きするかどうか。trueなら上書きする。 + */ + public void setOverrideColorForPartMultiplyColors(int partIndex, boolean value) { + userPartMultiplyColors.get(partIndex).isOverridden = value; + setOverrideColorsForPartColors(partIndex, value, userPartMultiplyColors, userDrawableMultiplyColors); + } + + /** + * SDKからPartのスクリーン色を上書きするかどうかのフラグを設定する。 + * + * @deprecated This function is deprecated due to a naming change, use setOverrideColorForPartScreenColors(int partIndex, boolean value) instead. + * + * @param partIndex 上書きするPartのインデックス + * @param value SDKからPartのスクリーン色を上書きするかどうか。trueなら上書きする。 + */ + public void setOverwriteColorForPartScreenColors(int partIndex, boolean value) { + CubismDebug.cubismLogWarning("setOverwriteColorForPartScreenColors(int partIndex, boolean value) is a deprecated function. Please use setOverrideColorForPartScreenColors(int partIndex, boolean value)."); + setOverrideColorForPartScreenColors(partIndex, value); + } + + /** + * SDKからPartのスクリーン色を上書きするかどうかのフラグを設定する。 + * + * @param partIndex 上書きするPartのインデックス + * @param value SDKからPartのスクリーン色を上書きするかどうか。trueなら上書きする。 + */ + public void setOverrideColorForPartScreenColors(int partIndex, boolean value) { + userPartScreenColors.get(partIndex).isOverridden = value; + setOverrideColorsForPartColors(partIndex, value, userPartScreenColors, userDrawableScreenColors); + } + + /** + * Get the culling inforamtion of Drawable. + * + * @param drawableIndex Drawable index + * @return the culling inforamtion of Drawable + */ + public boolean getDrawableCulling(int drawableIndex) { + if (getOverrideFlagForModelCullings() || getOverrideFlagForDrawableCullings(drawableIndex)) { + return userCullings.get(drawableIndex).isCulling; + } + + final byte constantFlag = model.getDrawableViews()[drawableIndex].getConstantFlag(); + return !isBitSet(constantFlag, IS_DOUBLE_SIDED); + } + + /** + * Drawableのカリング情報を設定する + * + * @param drawableIndex drawableのインデックス + * @param isCulling カリングするかどうか + */ + public void setDrawableCulling(int drawableIndex, boolean isCulling) { + userCullings.get(drawableIndex).isCulling = isCulling; + } + + /** + * Checks whether parameter repetition is performed for the entire model. + * + * @return true if parameter repetition is performed for the entire model; otherwise returns false. + */ + public boolean getOverrideFlagForModelParameterRepeat() { + return isOverriddenParameterRepeat; + } + + /** + * Sets whether parameter repetition is performed for the entire model. + * Use true to perform parameter repetition for the entire model, or false to not perform it. + */ + public void setOverrideFlagForModelParameterRepeat(boolean isRepeat) { + isOverriddenParameterRepeat = isRepeat; + } + + /** + * Sets the flag indicating whether to override the parameter repeat. + * + * @param parameterIndex Parameter index + * @param value true if it is to be overridden; otherwise, false. + */ + public void setOverrideFlagForParameterRepeat(int parameterIndex, boolean value) { + this.userParameterRepeatDataList.get(parameterIndex).isOverridden = value; + } + + /** + * Returns the repeat flag. + * + * @param parameterIndex Parameter index + * + * @return true if repeating, false otherwise. + */ + public boolean getRepeatFlagForParameterRepeat(int parameterIndex) { + return this.userParameterRepeatDataList.get(parameterIndex).isParameterRepeated; + } + + /** + * Sets the repeat flag. + * + * @param parameterIndex Parameter index + * @param value true to enable repeating, false otherwise. + */ + public void setRepeatFlagForParameterRepeat(int parameterIndex, boolean value) { + this.userParameterRepeatDataList.get(parameterIndex).isParameterRepeated = value; + } + + /** + * SDKからモデル全体のカリング設定を上書きするか + * + * @deprecated This function is deprecated due to a naming change, use getOverrideFlagForModelCullings() instead. + * + * @return trueならSDK上のカリング設定を使用し、falseならモデルのカリング設定を使用する + */ + public boolean getOverwriteFlagForModelCullings() { + CubismDebug.cubismLogWarning("getOverwriteFlagForModelCullings() is a deprecated function. Please use getOverrideFlagForModelCullings()."); + return getOverrideFlagForModelCullings(); + } + + /** + * SDKからモデル全体のカリング設定を上書きするか + * + * @return trueならSDK上のカリング設定を使用し、falseならモデルのカリング設定を使用する + */ + public boolean getOverrideFlagForModelCullings() { + return isOverriddenCullings; + } + + /** + * SDK上からモデル全体のカリング設定を上書きするかをセットする + * + * @deprecated This function is deprecated due to a naming change, use setOverrideFlagForModelCullings(boolean value) instead. + * + * @param value SDK上のカリング設定を使うならtrue, モデルのカリング設定を使うならfalse + */ + public void setOverwriteFlagForModelCullings(boolean value) { + CubismDebug.cubismLogWarning("setOverwriteFlagForModelCullings(boolean value) is a deprecated function. Please use setOverrideFlagForModelCullings(boolean value)."); + setOverrideFlagForModelCullings(value); + } + + /** + * SDK上からモデル全体のカリング設定を上書きするかをセットする + * + * @param value SDK上のカリング設定を使うならtrue, モデルのカリング設定を使うならfalse + */ + public void setOverrideFlagForModelCullings(boolean value) { + isOverriddenCullings = value; + } + + /** + * SDKからdrawableのカリング設定を上書きするか + * + * @deprecated This function is deprecated due to a naming change, use getOverrideFlagForDrawableCullings(int drawableIndex) instead. + * + * @param drawableIndex drawableのインデックス + * @return trueならSDK上のカリング設定を使用し、falseならモデルのカリング設定を使用する + */ + public boolean getOverwriteFlagForDrawableCullings(int drawableIndex) { + CubismDebug.cubismLogWarning("getOverwriteFlagForDrawableCullings(int drawableIndex) is a deprecated function. Please use getOverrideFlagForDrawableCullings(int drawableIndex)."); + return getOverrideFlagForDrawableCullings(drawableIndex); + } + + /** + * SDKからdrawableのカリング設定を上書きするか + * + * @param drawableIndex drawableのインデックス + * @return trueならSDK上のカリング設定を使用し、falseならモデルのカリング設定を使用する + */ + public boolean getOverrideFlagForDrawableCullings(int drawableIndex) { + return userCullings.get(drawableIndex).isOverridden; + } + + /** + * SDKからdrawableのカリング設定を上書きするかをセットする + * + * @deprecated This function is deprecated due to a naming change, use setOverrideFlagForDrawableCullings(int drawableIndex, boolean value) instead. + * + * @param drawableIndex drawableのインデックス + * @param value SDK上のカリング設定を使うならtrue, モデルのカリング設定を使うならfalse + */ + public void setOverwriteFlagForDrawableCullings(int drawableIndex, boolean value) { + CubismDebug.cubismLogWarning("setOverwriteFlagForDrawableCullings(int drawableIndex, boolean value) is a deprecated function. Please use setOverrideFlagForDrawableCullings(int drawableIndex, boolean value)."); + setOverrideFlagForDrawableCullings(drawableIndex, value); + } + + /** + * SDKからdrawableのカリング設定を上書きするかをセットする + * + * @param drawableIndex drawableのインデックス + * @param value SDK上のカリング設定を使うならtrue, モデルのカリング設定を使うならfalse + */ + public void setOverrideFlagForDrawableCullings(int drawableIndex, boolean value) { + userCullings.get(drawableIndex).isOverridden = value; + } + + /** + * モデルの不透明度を取得する。 + * + * @return 不透明度の値 + */ + public float getModelOpacity() { + return modelOpacity; + } + + /** + * モデルの不透明度を設定する。 + * + * @param value 不透明度の値 + */ + public void setModelOpacity(float value) { + modelOpacity = value; + } + + /** + * Get the model. + * + * @return model + */ + public com.live2d.sdk.cubism.core.CubismModel getModel() { + return model; + } + + /** + * Close the CubismModel instance. + */ + public void close() { + if (model != null) { + model.close(); + model.getMoc().close(); + } + } + + /** + * Initialize the model. + */ + void initialize() { + assert model != null; + + parameterValues = model.getParameterViews(); + partValues = model.getPartViews(); + + // Set parameter IDs to _parameterIds. + for (CubismParameterView parameterValue : parameterValues) { + String id = parameterValue.getId(); + + parameterIds.add(CubismFramework.getIdManager().getId(id)); + userParameterRepeatDataList.add(new ParameterRepeatData(false, false)); + } + + // Set part IDs to _partIds. + for (CubismPartView partValue : partValues) { + String id = partValue.getId(); + + partIds.add(CubismFramework.getIdManager().getId(id)); + } + + // Set drawable IDs to _drawableIds. + CubismDrawableView[] drawableValues = model.getDrawableViews(); + + // MultiplyColors + CubismRenderer.CubismTextureColor mutiplyColor = new CubismRenderer.CubismTextureColor( + 1.0f, + 1.0f, + 1.0f, + 1.f + ); + DrawableColorData userDrawableMultiplyColor = new DrawableColorData(false, mutiplyColor); + PartColorData userPartMultiplyColor = new PartColorData(false, mutiplyColor); + + // ScreenColors + CubismRenderer.CubismTextureColor screenColor = new CubismRenderer.CubismTextureColor( + 0.0f, + 0.0f, + 0.0f, + 1.0f + ); + DrawableColorData userDrawableScreenColor = new DrawableColorData(false, screenColor); + PartColorData userPartScreenColor = new PartColorData(false, screenColor); + + // To prevent performance degradation due to capacity expansion, HashMap is generated with initial capacity reserved. + int partCount = model.getPartViews().length; + partChildDrawablesMap = new HashMap>(partCount); + + // Setting for Drawables. + for (CubismDrawableView drawableValue : drawableValues) { + String id = drawableValue.getId(); + drawableIds.add(CubismFramework.getIdManager().getId(id)); + + userDrawableMultiplyColors.add(new DrawableColorData(userDrawableMultiplyColor)); + userDrawableScreenColors.add(new DrawableColorData(userDrawableScreenColor)); + userCullings.add(new DrawableCullingData(false, false)); + + // Bind parent Parts and child Drawables. + int parentIndex = drawableValue.getParentPartIndex(); + if (parentIndex >= 0) { + List childDrawables = partChildDrawablesMap.get(parentIndex); + if (childDrawables == null) { + childDrawables = new ArrayList(); + partChildDrawablesMap.put(parentIndex, childDrawables); + } + childDrawables.add(drawableValue.getIndex()); + } + } + + // Setting for Parts. + for (int i = 0; i < partCount; i++) { + userPartMultiplyColors.add(new PartColorData(userPartMultiplyColor)); + userPartScreenColors.add(new PartColorData(userPartScreenColor)); + } + } + + /** + * Constructor + * + * @param model model instance + */ + CubismModel(final com.live2d.sdk.cubism.core.CubismModel model) { + this.model = model; + } + + /** + * Return true if the logical product of flag and mask matches the mask. + * + * @return Return true if the logical product of flag and mask matches the mask. + */ + private boolean isBitSet(final byte flag, final byte mask) { + return (flag & mask) == mask; + } + + /** + * PartのOverrideColorを設定する。 + * + * @param partIndex 設定するPartのインデックス + * @param r 赤 + * @param g 緑 + * @param b 青 + * @param a アルファ + * @param partColors 設定するPartの上書き色のリスト + * @param drawableColors Drawableの上書き色のリスト + */ + private void setPartColor( + int partIndex, + float r, float g, float b, float a, + List partColors, + List drawableColors + ) { + partColors.get(partIndex).color.r = r; + partColors.get(partIndex).color.g = g; + partColors.get(partIndex).color.b = b; + partColors.get(partIndex).color.a = a; + + if (partColors.get(partIndex).isOverridden) { + List childDrawables = partChildDrawablesMap.get(partIndex); + if(childDrawables == null) return; + + for (int i = 0; i < childDrawables.size(); i++) { + int drawableIndex = childDrawables.get(i); + + drawableColors.get(drawableIndex).color.r = r; + drawableColors.get(drawableIndex).color.g = g; + drawableColors.get(drawableIndex).color.b = b; + drawableColors.get(drawableIndex).color.a = a; + } + } + } + + /** + * PartのOverrideFlagを設定する。 + * + * @param partIndex 設定するPartのインデックス + * @param value 真偽値 + * @param partColors 設定するPartの上書き色のリスト + * @param drawableColors Drawableの上書き色のリスト + */ + private void setOverrideColorsForPartColors( + int partIndex, + boolean value, + List partColors, + List drawableColors + ) { + partColors.get(partIndex).isOverridden = value; + + List childDrawables = partChildDrawablesMap.get(partIndex); + if (childDrawables == null) return; + + for (int i = 0; i < childDrawables.size(); i++) { + int drawableIndex = childDrawables.get(i); + drawableColors.get(drawableIndex).isOverridden = value; + + if (value) { + drawableColors.get(drawableIndex).color.r = partColors.get(partIndex).color.r; + drawableColors.get(drawableIndex).color.g = partColors.get(partIndex).color.g; + drawableColors.get(drawableIndex).color.b = partColors.get(partIndex).color.b; + drawableColors.get(drawableIndex).color.a = partColors.get(partIndex).color.a; + } + } + } + + /** + * List of opacities for non-existent parts + */ + private float[] notExistPartOpacities = new float[1]; + private final List notExistPartIndices = new ArrayList(); + + /** + * List of IDs for non-existent parts + */ + private final Map notExistPartIds = new HashMap(); + /** + * List of values for non-existent parameters + */ + private float[] notExistParameterValues = new float[1]; + private final List notExistParameterIndices = new ArrayList(); + /** + * List of IDs for non-existent parameters + */ + private final Map notExistParameterIds = new HashMap(); + /** + * Saved parameters + */ + private float[] savedParameters = new float[1]; + /** + * model + */ + private final com.live2d.sdk.cubism.core.CubismModel model; + + private CubismParameterView[] parameterValues; + private CubismPartView[] partValues; + + /** + * モデルの不透明度 + */ + private float modelOpacity = 1.0f; + + private final List parameterIds = new ArrayList<>(); + private final List partIds = new ArrayList<>(); + private final List drawableIds = new ArrayList<>(); + + /** + * Drawableの乗算色のリスト + */ + private final List userDrawableMultiplyColors = new ArrayList(); + /** + * Drawableのスクリーン色のリスト + */ + private final List userDrawableScreenColors = new ArrayList(); + + /** + * パーツの乗算色のリスト + */ + private final List userPartMultiplyColors = new ArrayList(); + /** + * パーツのスクリーン色のリスト + */ + private final List userPartScreenColors = new ArrayList(); + /** + * Partとその子DrawableのListとのMap + */ + private Map> partChildDrawablesMap; + + /** + * カリング設定のリスト + */ + private final List userCullings = new ArrayList(); + + /** + * List to manage ParameterRepeat and Override flag to be set for each Parameter + */ + private final List userParameterRepeatDataList = new ArrayList(); + + /** + * Flag whether to Override all the parameter repeat + */ + private boolean isOverriddenParameterRepeat = true; + + /** + * Flag whether to override all the multiply colors + */ + private boolean isOverriddenModelMultiplyColors; + /** + * Flag whether to override all the screen colors + */ + private boolean isOverriddenModelScreenColors; + /** + * モデルのカリング設定をすべて上書きするか? + */ + private boolean isOverriddenCullings; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModelUserData.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModelUserData.java new file mode 100644 index 0000000..7b0438a --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModelUserData.java @@ -0,0 +1,147 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.model; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This class is a manager of user data. It can load, manage user data. + */ +public class CubismModelUserData { + /** + * Class for recording the user data read from JSON. + */ + public static class CubismModelUserDataNode { + /** + * Constructor + * + * @param targetType user data target type + * @param targetId ID of user data target + * @param value user data + */ + public CubismModelUserDataNode( + CubismId targetType, + CubismId targetId, + String value + ) { + if (value == null) { + throw new IllegalArgumentException("value is null."); + } + this.targetType = CubismFramework.getIdManager().getId(targetType); + this.targetId = CubismFramework.getIdManager().getId(targetId); + this.value = value; + } + + /** + * User data target type + */ + public final CubismId targetType; + /** + * User data target ID + */ + public final CubismId targetId; + /** + * User data + */ + public final String value; + } + + /** + * Create an instance. + * + * @param buffer a buffer where userdata3.json is loaded. + * @return the created instance. If parsing JSON data failed, return null. + */ + public static CubismModelUserData create(byte[] buffer) { + CubismModelUserData modelUserData = new CubismModelUserData(); + boolean isSuccessful = modelUserData.parseUserData(buffer); + + if (isSuccessful) { + return modelUserData; + } + return null; + } + + /** + * Get the user data list of ArtMesh. + * + * @return the user data list + */ + public List getArtMeshUserData() { + if (areArtMeshUserDataNodesChanged) { + cachedImmutableArtMeshUserDataNodes = Collections.unmodifiableList(artMeshUserDataNodes); + areArtMeshUserDataNodesChanged = false; + } + return cachedImmutableArtMeshUserDataNodes; + } + + /** + * Get the user data of ArtMesh. + * + * @param index index of data to be obtained + * @return CubismModelUserDataNode instance + */ + public CubismModelUserDataNode getArtMeshUserData(int index) { + return artMeshUserDataNodes.get(index); + } + + /** + * ID name "ArtMesh" + */ + private static final String ART_MESH = "ArtMesh"; + + /** + * Parse a userdata3.json data. + * + * @param buffer a buffer where userdata3.json is loaded. + * @return If parsing userdata3.json is successful, return true. + */ + private boolean parseUserData(byte[] buffer) { + CubismModelUserDataJson userdata3Json; + userdata3Json = new CubismModelUserDataJson(buffer); + + final CubismId artMeshType = CubismFramework.getIdManager().getId(ART_MESH); + final int nodeCount = userdata3Json.getUserDataCount(); + + for (int i = 0; i < nodeCount; i++) { + final CubismId targetType = CubismFramework.getIdManager().getId(userdata3Json.getUserDataTargetType(i)); + final CubismId targetId = userdata3Json.getUserDataId(i); + final String value = userdata3Json.getUserDataValue(i); + final CubismModelUserDataNode addedNode = new CubismModelUserDataNode( + targetType, + targetId, + value + ); + userDataNodes.add(addedNode); + + if (addedNode.targetType.equals(artMeshType)) { + artMeshUserDataNodes.add(addedNode); + } + } + + return true; + } + + /** + * the list which has a user data struct class + */ + private final List userDataNodes = new ArrayList(); + /** + * 閲覧リスト保持 + */ + private final List artMeshUserDataNodes = new ArrayList(); + + private boolean areArtMeshUserDataNodesChanged = true; + + private List cachedImmutableArtMeshUserDataNodes; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModelUserDataJson.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModelUserDataJson.java new file mode 100644 index 0000000..2690a26 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismModelUserDataJson.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.model; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.exception.CubismJsonParseException; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; + +/** + * This class deals with an userdata3.json data. + */ +class CubismModelUserDataJson { + /** + * Constructor + * + * @param userdata3Json byte data of userdata3.json + * @throws CubismJsonParseException If parsing JSON failed, return CubismJsonException is thrown. + */ + public CubismModelUserDataJson(byte[] userdata3Json) { + final CubismJson json; + json = CubismJson.create(userdata3Json); + + this.json = json; + } + + + /** + * Get the number of user data in userdata3.json. + * + * @return the number of user data + */ + public int getUserDataCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.USER_DATA_COUNT.key).toInt(); + } + + /** + * Get the total user data string number. + * + * @return the total user data string number + */ + public int getTotalUserDataSize() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.TOTAL_USER_DATA_SIZE.key).toInt(); + } + + /** + * Get the user data type of specified number. + * + * @param index index + * @return user data type + */ + public String getUserDataTargetType(int index) { + return json.getRoot().get(JsonKey.USER_DATA.key).get(index).get(JsonKey.TARGET.key).getString(); + } + + /** + * Get the user data target ID of the specified number. + * + * @param index index + * @return a user data target ID + */ + public CubismId getUserDataId(int index) { + return CubismFramework.getIdManager().getId(json.getRoot().get(JsonKey.USER_DATA.key).get(index).get(JsonKey.ID.key).getString()); + } + + /** + * Get the user data string of the specified number. + * + * @param index index + * @return user data + */ + public String getUserDataValue(int index) { + return json.getRoot().get(JsonKey.USER_DATA.key).get(index).get(JsonKey.VALUE.key).getString(); + } + + private enum JsonKey { + META("Meta"), + USER_DATA_COUNT("UserDataCount"), + TOTAL_USER_DATA_SIZE("TotalUserDataSize"), + USER_DATA("UserData"), + TARGET("Target"), + ID("Id"), + VALUE("Value"); + + private final String key; + + JsonKey(String key) { + this.key = key; + } + } + + /** + * JSON data + */ + private final CubismJson json; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismUserModel.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismUserModel.java new file mode 100644 index 0000000..5f223ad --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/CubismUserModel.java @@ -0,0 +1,564 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.model; + +import static com.live2d.sdk.cubism.framework.CubismFramework.VERTEX_OFFSET; +import static com.live2d.sdk.cubism.framework.CubismFramework.VERTEX_STEP; +import static com.live2d.sdk.cubism.framework.utils.CubismDebug.cubismLogError; +import static com.live2d.sdk.cubism.framework.utils.CubismDebug.cubismLogInfo; + +import com.live2d.sdk.cubism.framework.effect.CubismBreath; +import com.live2d.sdk.cubism.framework.effect.CubismEyeBlink; +import com.live2d.sdk.cubism.framework.effect.CubismPose; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismModelMatrix; +import com.live2d.sdk.cubism.framework.math.CubismTargetPoint; +import com.live2d.sdk.cubism.framework.motion.CubismExpressionMotion; +import com.live2d.sdk.cubism.framework.motion.CubismExpressionMotionManager; +import com.live2d.sdk.cubism.framework.motion.CubismMotion; +import com.live2d.sdk.cubism.framework.motion.CubismMotionManager; +import com.live2d.sdk.cubism.framework.motion.CubismMotionQueueManager; +import com.live2d.sdk.cubism.framework.motion.IBeganMotionCallback; +import com.live2d.sdk.cubism.framework.motion.ICubismMotionEventFunction; +import com.live2d.sdk.cubism.framework.motion.IFinishedMotionCallback; +import com.live2d.sdk.cubism.framework.physics.CubismPhysics; +import com.live2d.sdk.cubism.framework.rendering.CubismRenderer; + +/** + * This is the base class of the model that the user actually utilizes. The user defined model class inherits this class. + */ +public abstract class CubismUserModel { + /** + * A callback for registering with CubismMotionQueueManager for an event. + * Call the EventFired which is inherited from CubismUserModel. + * + * @param eventValue the string data of the fired event + * @param model an instance inherited with CubismUserModel + */ + public static void cubismDefaultMotionEventCallback(String eventValue, CubismUserModel model) { + if (model != null) { + model.motionEventFired(eventValue); + } + } + + /** + * Get the collision detection. + *

+ * Get whether the Drawable has been hit at the specified position. + * + * @param drawableId Drawable ID which will be verified. + * @param pointX X-position + * @param pointY Y-position + * @return true If it is hit, return true. + */ + public boolean isHit(CubismId drawableId, float pointX, float pointY) { + final int drawIndex = model.getDrawableIndex(drawableId); + + // If there are no hit Drawable, return false + if (drawIndex < 0) { + return false; + } + + final int count = model.getDrawableVertexCount(drawIndex); + final float[] vertices = model.getDrawableVertices(drawIndex); + + float left = vertices[0]; + float right = vertices[0]; + float top = vertices[1]; + float bottom = vertices[1]; + + + for (int i = 1; i < count; ++i) { + float x = vertices[VERTEX_OFFSET + i * VERTEX_STEP]; + float y = vertices[VERTEX_OFFSET + i * VERTEX_STEP + 1]; + + if (x < left) { + // Min x + left = x; + } + + if (x > right) { + // Max x + right = x; + } + + if (y < top) { + // Min y + top = y; + } + + if (y > bottom) { + // Max y + bottom = y; + } + } + + final float tx = modelMatrix.invertTransformX(pointX); + final float ty = modelMatrix.invertTransformY(pointY); + + return (left <= tx) && (tx <= right) && (top <= ty) && (ty <= bottom); + } + + /** + * 生成されたレンダラーを受け取って初期化する。
+ * このメソッドを使用した場合、クリッピングマスクの描画に使われるバッファのデフォルト枚数は1枚となる。 + * + * @note 引数にnullが与えられた場合`NullPointerException`が投げられる。 + * + * @param renderer CubismRendererを継承したレンダラークラスのインスタンス + */ + public void setupRenderer(CubismRenderer renderer) { + setupRenderer(renderer,1); + } + + /** + * 生成されたレンダラーを受け取って初期化する。
+ * クリッピングマスクの描画に使うバッファの枚数をデフォルトの1枚より増やしたい場合は、このメソッドを使用する。 + * + * @note 第1引数にnullが与えられた場合`NullPointerException`が投げられる。 + * + * @param renderer CubismRendererを継承したレンダラークラスのインスタンス + * @param maskBufferCount 生成したいマスクバッファの枚数 + */ + public void setupRenderer(CubismRenderer renderer, int maskBufferCount) { + this.renderer = renderer; + + // Bind a renderer with a model instance + this.renderer.initialize(model, maskBufferCount); + } + + /** + * Do a standard process at firing the event. + *

+ * This method deals with the case where an Event occurs during the playback process. + * It is basically overrided by inherited class. + * If it is not overrided, output log. + * + * @param eventValue the string data of the fired event + */ + public void motionEventFired(String eventValue) { + cubismLogInfo(eventValue); + } + + /** + * Get initializing status. + * + * @return If this class is initialized, return true. + */ + public boolean isInitialized() { + return isInitialized; + } + + /** + * Set an initializing setting. + * + * @param isInitialized initializing status + */ + public void isInitialized(boolean isInitialized) { + this.isInitialized = isInitialized; + } + + /** + * Get the updating status. + * + * @return If this class is updated, return true. + */ + public boolean isUpdated() { + return isUpdated; + } + + /** + * Set an updating status. + * + * @param isUpdated updating status + */ + public void isUpdated(boolean isUpdated) { + this.isUpdated = isUpdated; + } + + /** + * Set an information of mouse dragging. + * + * @param x X-position of the cursor being dragging + * @param y Y-position of the cursor being dragging + */ + public void setDragging(float x, float y) { + dragManager.set(x, y); + } + + /** + * Set an acceleration information. + * + * @param x Acceleration in X-axis direction + * @param y Acceleration in Y-axis direction + * @param z Acceleration in Z-axis direction + */ + public void setAcceleration(float x, float y, float z) { + accelerationX = x; + accelerationY = y; + accelerationZ = z; + } + + /** + * Get the model matrix. + * This method returns a copy of this _modelMatrix. + * + * @return the model matrix + */ + public CubismModelMatrix getModelMatrix() { + return modelMatrix; + } + + /** + * Get the opacity. + * + * @return the opacity + */ + public float getOpacity() { + return opacity; + } + + /** + * Set an opacity. + * + * @param opacity an opacity + */ + public void setOpacity(float opacity) { + this.opacity = opacity; + } + + /* + * Get the model. + * + * @return the model + */ + public CubismModel getModel() { + return model; + } + + /** + * Get the renderer. This method is the generics. The user have to give the renderer type that they would like to use. + *

+ * (example of use) this{@literal .getRenderer();} + *

+ * + * @param renderer type to use + * @return renderer instance + */ + public T getRenderer() { + return (T) renderer; + } + + /** + * Constructor + */ + protected CubismUserModel() { + // Because this class inherits MotionQueueManager, the usage is the same. + motionManager.setEventCallback(cubismDefaultMotionEventCallback, this); + } + + /** + * モデルデータを読み込む。 + * NOTE: デフォルトではMOC3の整合性をチェックしない。 + * + * @param buffer MOC3ファイルが読み込まれているバイト配列バッファ + */ + protected void loadModel(final byte[] buffer) { + loadModel(buffer, false); + } + + /** + * モデルデータを読み込む。 + * + * @param buffer MOC3ファイルが読み込まれているバイト配列バッファ + */ + protected void loadModel(final byte[] buffer, boolean shouldCheckMocConsistency) { + final CubismMoc moc = CubismMoc.create(buffer, shouldCheckMocConsistency); + + if (moc == null) { + cubismLogError("Failed to create CubismMoc instance."); + return; + } + + this.moc = moc; + final CubismModel model = this.moc.createModel(); + + if (model == null) { + cubismLogError("Failed to create the model."); + return; + } + + this.model = model; + + this.model.saveParameters(); + modelMatrix = CubismModelMatrix.create(this.model.getCanvasWidth(), this.model.getCanvasHeight()); + } + + /** + * Delete Moc and Model instances. + */ + protected void delete() { + if (moc == null || model == null) { + return; + } + moc.deleteModel(model); + + moc.delete(); + model.close(); + renderer.close(); + + moc = null; + model = null; + renderer = null; + } + + /** + * Load a motion data. + * + * @param buffer a buffer where motion3.json file is loaded. + * @param onFinishedMotionHandler the callback method called at finishing motion play. If it is null, callbacking methods is not conducting. + * @param onBeganMotionHandler the callback method called at beginning motion play. If it is null, callbacking methods is not conducting. + * @param shouldCheckMotionConsistency flag to validate the consistency of motion3.json. + * @return motion class + */ + protected CubismMotion loadMotion( + byte[] buffer, + IFinishedMotionCallback onFinishedMotionHandler, + IBeganMotionCallback onBeganMotionHandler, + boolean shouldCheckMotionConsistency + ) { + try { + return CubismMotion.create(buffer, onFinishedMotionHandler, onBeganMotionHandler, shouldCheckMotionConsistency); + } catch (Exception e) { + cubismLogError("Failed to loadMotion(). %s", e.getMessage()); + return null; + } + } + + /** + * Load a motion data. + * This method does not check the consistency of motion3.json. + * To check the consistency of motion3.json, + * use {@link #loadMotion(byte[], IFinishedMotionCallback, IBeganMotionCallback, boolean)} + * and set the fourth argument to `true`. + * + * @param buffer a buffer where motion3.json file is loaded. + * @param onFinishedMotionHandler the callback method called at finishing motion play. If it is null, callbacking methods is not conducting. + * @param onBeganMotionHandler the callback method called at beginning motion play. If it is null, callbacking methods is not conducting. + * @return motion class + */ + protected CubismMotion loadMotion( + byte[] buffer, + IFinishedMotionCallback onFinishedMotionHandler, + IBeganMotionCallback onBeganMotionHandler + ) { + return loadMotion(buffer, onFinishedMotionHandler, onBeganMotionHandler, false); + } + + /** + * Load a motion data. + * This method does not set any callback functions. + * + * @param buffer a buffer where motion3.json file is loaded. + * @param shouldCheckMotionConsistency flag to validate the consistency of motion3.json. + * @return motion class + */ + protected CubismMotion loadMotion(byte[] buffer, boolean shouldCheckMotionConsistency) { + return loadMotion(buffer, null, null, shouldCheckMotionConsistency); + } + + /** + * Load a motion data. + * This method does not check the consistency of motion3.json. + * To check the consistency of motion3.json, + * use {@link #loadMotion(byte[], boolean)} + * and set the second argument to `true`. + * This method does not set any callback functions. + * + * @param buffer a buffer where motion3.json file is loaded. + * @return motion class + */ + protected CubismMotion loadMotion(byte[] buffer) { + return loadMotion(buffer, null, null, false); + } + + /** + * Load a expression data. + * + * @param buffer a buffer where exp3.json is loaded + * @return motion class + */ + protected CubismExpressionMotion loadExpression(final byte[] buffer) { + try { + return CubismExpressionMotion.create(buffer); + } catch (Exception e) { + cubismLogError("Failed to loadExpressionMotion(). %s", e.getMessage()); + return null; + } + } + + /** + * Load pose data. + * + * @param buffer a buffer where pose3.json is loaded. + */ + protected void loadPose(final byte[] buffer) { + try { + pose = CubismPose.create(buffer); + } catch (Exception e) { + cubismLogError("Failed to loadPose(). %s", e.getMessage()); + } + } + + /** + * Load physics data. + * + * @param buffer a buffer where physics3.json is loaded. + */ + protected void loadPhysics(final byte[] buffer) { + try { + physics = CubismPhysics.create(buffer); + } catch (Exception e) { + cubismLogError("Failed to loadPhysics(). %s", e.getMessage()); + } + } + + /** + * Load a user data attached the model. + * + * @param buffer a buffer where userdata3.json is loaded. + */ + protected void loadUserData(final byte[] buffer) { + try { + modelUserData = CubismModelUserData.create(buffer); + } catch (Exception e) { + cubismLogError("Failed to loadUserData(). %s", e.getMessage()); + } + } + + /** + * A Moc data, + */ + protected CubismMoc moc; + /** + * A model instance + */ + protected CubismModel model; + + /** + * A motion manager + */ + protected CubismMotionManager motionManager = new CubismMotionManager(); + /** + * A expression manager + */ + protected CubismExpressionMotionManager expressionManager = new CubismExpressionMotionManager(); + /** + * Auto eye-blink + */ + protected CubismEyeBlink eyeBlink; + /** + * Breathing + */ + protected CubismBreath breath; + /** + * A model matrix + */ + protected CubismModelMatrix modelMatrix; + /** + * m + * Pose manager + */ + protected CubismPose pose; + /** + * A mouse dragging manager + */ + protected CubismTargetPoint dragManager = new CubismTargetPoint(); + /** + * physics + */ + protected CubismPhysics physics; + /** + * A user data + */ + protected CubismModelUserData modelUserData; + + /** + * An initializing status + */ + protected boolean isInitialized; + /** + * An updating status + */ + protected boolean isUpdated; + /** + * Opacity + */ + protected float opacity = 1.0f; + /** + * A lip-sync status + */ + protected boolean lipSync = true; + /** + * A control value of the last lip-sync + */ + protected float lastLipSyncValue; + /** + * An X-position of mouse dragging + */ + protected float dragX; + /** + * An Y-position of mouse dragging + */ + protected float dragY; + /** + * An acceleration in X-axis direction + */ + protected float accelerationX; + /** + * An acceleration in Y-axis direction + */ + protected float accelerationY; + /** + * An acceleration in Z-axis direction + */ + protected float accelerationZ; + /** + * MOC3の整合性を検証するか。検証するならtrue。 + */ + protected boolean mocConsistency; + /** + * motion3.jsonの整合性を検証するか。検証するならtrue。 + */ + protected boolean motionConsistency; + /** + * Whether it is debug mode + */ + protected boolean debugMode; + + /** + * An entity of CubismMotionEventFunction. + */ + private static final ICubismMotionEventFunction cubismDefaultMotionEventCallback = new ICubismMotionEventFunction() { + @Override + public void apply( + CubismMotionQueueManager caller, + String eventValue, + Object customData + ) { + if (customData != null) { + ((CubismUserModel) customData).motionEventFired(eventValue); + } + } + }; + + /** + * A renderer + */ + private CubismRenderer renderer; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/package-info.java new file mode 100644 index 0000000..e5a1f9f --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/model/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide various functions (generate, update, destroy) for handling models. + */ +package com.live2d.sdk.cubism.framework.model; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/ACubismMotion.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/ACubismMotion.java new file mode 100644 index 0000000..ad314df --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/ACubismMotion.java @@ -0,0 +1,403 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismMath; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Abstract base class for motion. + * This class manages motion playback by MotionQueueManager. + */ +public abstract class ACubismMotion { + /** + * Update model's parameters. + * + * @param model target model + * @param motionQueueEntry motion managed by CubismMotionQueueManager + * @param userTimeSeconds total delta time[s] + */ + public void updateParameters( + CubismModel model, + CubismMotionQueueEntry motionQueueEntry, + float userTimeSeconds + ) { + if (!motionQueueEntry.isAvailable() || motionQueueEntry.isFinished()) { + return; + } + + setupMotionQueueEntry(motionQueueEntry, userTimeSeconds); + + float fadeWeight = updateFadeWeight(motionQueueEntry, userTimeSeconds); + + //---- 全てのパラメータIDをループする ---- + doUpdateParameters(model, userTimeSeconds, fadeWeight, motionQueueEntry); + + // 後処理 + // 終了時刻を過ぎたら終了フラグを立てる(CubismMotionQueueManager) + if (motionQueueEntry.getEndTime() > 0.0f && motionQueueEntry.getEndTime() < userTimeSeconds) { + motionQueueEntry.isFinished(true); // 終了 + } + } + + /** + * モーションの再生を開始するためのセットアップを行う。 + * + * @param motionQueueEntry CubismMotionQueueManagerによって管理されるモーション + * @param userTimeSeconds 総再生時間(秒) + */ + public void setupMotionQueueEntry( + CubismMotionQueueEntry motionQueueEntry, + final float userTimeSeconds + ) { + if (!motionQueueEntry.isAvailable() || motionQueueEntry.isFinished()) { + return; + } + + if (motionQueueEntry.isStarted()) { + return; + } + + motionQueueEntry.isStarted(true); + + // Record the start time of the motion. + motionQueueEntry.setStartTime(userTimeSeconds - offsetSeconds); + // Record the start time of fade-in + motionQueueEntry.setFadeInStartTime(userTimeSeconds); + + // Deal with the case where the status is set "end" before it has started. + if (motionQueueEntry.getEndTime() < 0) { + adjustEndTime(motionQueueEntry); + } + } + + /** + * モーションフェードのウェイト値を更新する。 + * + * @param motionQueueEntry CubismMotionQueueManagerで管理されているモーション + * @param userTimeSeconds デルタ時間の積算値[秒] + * @return 更新されたウェイト値 + */ + public float updateFadeWeight(CubismMotionQueueEntry motionQueueEntry, float userTimeSeconds) { + if(motionQueueEntry == null) { + CubismDebug.cubismLogError("motionQueueEntry is null."); + } + + float fadeWeight = weight; // 現在の値と掛け合わせる割合 + + // ---- フェードイン・アウトの処理 ---- + // 単純なサイン関数でイージングする。 + final float fadeIn = fadeInSeconds == 0.0f + ? 1.0f + : CubismMath.getEasingSine((userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / fadeInSeconds); + final float fadeOut = (fadeOutSeconds == 0.0f || motionQueueEntry.getEndTime() < 0.0f) + ? 1.0f + : CubismMath.getEasingSine((motionQueueEntry.getEndTime() - userTimeSeconds) / fadeOutSeconds); + fadeWeight = fadeWeight * fadeIn * fadeOut; + motionQueueEntry.setState(userTimeSeconds, fadeWeight); + + assert (0.0f <= fadeWeight && fadeWeight <= 1.0f); + + return fadeWeight; + } + + + /** + * Set the time it takes to fade in. + * + * @param fadeInSeconds time for fade in [s] + */ + public void setFadeInTime(float fadeInSeconds) { + this.fadeInSeconds = fadeInSeconds; + } + + /** + * Get the time it takes to fade in. + * + * @return time for fade in[s] + */ + public float getFadeInTime() { + return fadeInSeconds; + } + + /** + * Set a time it takes to fade out. + * + * @param fadeOutSeconds time for fade out[s] + */ + public void setFadeOutTime(float fadeOutSeconds) { + this.fadeOutSeconds = fadeOutSeconds; + } + + /** + * Get the time it takes to fade out. + * + * @return time for fade out[s] + */ + public float getFadeOutTime() { + return fadeOutSeconds; + } + + /** + * Set the weight to be applied to the motion. + * + * @param weight weight(0.0 - 1.0) + */ + public void setWeight(float weight) { + this.weight = weight; + } + + /** + * Get the weight to be applied to the motion. + * + * @return weight(0.0 - 1.0) + */ + public float getWeight() { + return weight; + } + + /** + * Get the duration of the motion. + * + * @return duration of motion[s] + * (If it is a loop, "-1". + * Override if it is not a loop. + * If the value is positive, the process ends at the time it is retrieved. + * When the value is "-1", the process will not end unless there is a stop command from outside) + */ + public float getDuration() { + return -1.0f; + } + + /** + * Get the duration of one motion loop. + * + * @return duration of one motion loop[s] + *

+ * (If it does not loop, it returns the same value as GetDuration(). + * Return "-1" in case the duration of one loop cannot be defined (e.g., a subclass that keeps moving programmatically)). + */ + public float getLoopDuration() { + return -1.0f; + } + + /** + * Set the start time for motion playback. + * + * @param offsetSeconds start time for motion playback[s] + */ + public void setOffsetTime(float offsetSeconds) { + this.offsetSeconds = offsetSeconds; + } + + /** + * Sets whether the motion should loop. + * + * @param loop true to set the motion to loop + */ + public void setLoop(boolean loop) { + isLoop = loop; + } + + /** + * Checks whether the motion is set to loop. + * + * @return true if the motion is set to loop; otherwise false. + */ + public boolean getLoop() { + return isLoop; + } + + /** + * Sets whether to perform fade-in for looping motion. + * + * @param loopFadeIn true to perform fade-in for looping motion + */ + public void setLoopFadeIn(boolean loopFadeIn) { + isLoopFadeIn = loopFadeIn; + } + + /** + * Checks the setting for fade-in of looping motion. + * + * @return true if fade-in for looping motion is set; otherwise false. + */ + public boolean getLoopFadeIn() { + return isLoopFadeIn; + } + + /** + * Check for event firing. + * The input time reference is set to zero at the called motion timing. + * + * @param beforeCheckTimeSeconds last event check time [s] + * @param motionTimeSeconds playback time this time [s] + * @return list of events that have fired + */ + public List getFiredEvent(float beforeCheckTimeSeconds, float motionTimeSeconds) { + return Collections.unmodifiableList(firedEventValues); + } + + /** + * Registers a motion playback start callback. + * It is not called in the following states: + * 1. when the currently playing motion is set as "loop" + * 2. when null is registered in the callback + * + * @param onBeganMotionHandler start-of-motion playback callback function + */ + public void setBeganMotionHandler(IBeganMotionCallback onBeganMotionHandler) { + onBeganMotion = onBeganMotionHandler; + } + + /** + * Get the start-of-motion playback callback function. + * + * @return registered start-of-motion playback callback function; if null, no function is registered + */ + public IBeganMotionCallback getBeganMotionCallback() { + return onBeganMotion; + } + + /** + * Registers a motion playback end callback. + * It is called when the isFinished flag is set. + * It is not called in the following states: + * 1. when the currently playing motion is set as "loop" + * 2. when null is registered in the callback + * + * @param onFinishedMotionHandler end-of-motion playback callback function + */ + public void setFinishedMotionHandler(IFinishedMotionCallback onFinishedMotionHandler) { + onFinishedMotion = onFinishedMotionHandler; + } + + /** + * Get the end-of-motion playback callback function. + * + * @return registered end-of-motion playback callback function; if null, no function is registered + */ + public IFinishedMotionCallback getFinishedMotionCallback() { + return onFinishedMotion; + } + + /** + * Check to see if a transparency curve exists. + * + * @return return true if the key exists + */ + public boolean isExistModelOpacity() { + return false; + } + + + /** + * Return the index of the transparency curve. + * + * @return success: index of the transparency curve + */ + public int getModelOpacityIndex() { + return -1; + } + + /** + * Return the ID of the transparency curve. + * + * @return success: atransparency curve + */ + public CubismId getModelOpacityId(int index) { + return null; + } + + /** + * Perform parameter updates for the model. + * + * @param model target model + * @param userTimeSeconds total delta time[s] + * @param weight weight of motion + * @param motionQueueEntry motion managed by CubismMotionQueueManager + */ + protected abstract void doUpdateParameters( + CubismModel model, + float userTimeSeconds, + float weight, + CubismMotionQueueEntry motionQueueEntry + ); + + protected void adjustEndTime(CubismMotionQueueEntry motionQueueEntry) { + final float duration = getDuration(); + + // duration == -1 の場合はループする + final float endTime = (duration <= 0) + ? -1 + : motionQueueEntry.getStartTime() + duration; + + motionQueueEntry.setEndTime(endTime); + } + + /** + * 指定時間の透明度の値を返す。 + * NOTE: 更新後の値を取るには`updateParameters()` の後に呼び出す。 + * + * @return success : モーションの当該時間におけるOpacityの値 + */ + protected float getModelOpacityValue() { + return 1.0f; + } + + /** + * Time for fade-in [s] + */ + protected float fadeInSeconds = -1.0f; + /** + * Time for fade-out[s] + */ + protected float fadeOutSeconds = -1.0f; + /** + * Weight of motion + */ + protected float weight = 1.0f; + /** + * Start time for motion playback[s] + */ + protected float offsetSeconds; + + /** + * Enable/Disable loop + */ + protected boolean isLoop; + /** + * flag whether fade-in is enabled at looping. Default value is true. + */ + protected boolean isLoopFadeIn = true; + + /** + * The previous state of `_isLoop`. + */ + protected boolean previousLoopState = isLoop; + /** + * List of events that have fired + */ + protected List firedEventValues = new ArrayList(); + + /** + * Start-of-motion playback callback function + */ + protected IBeganMotionCallback onBeganMotion; + + /** + * End-of-motion playback callback function + */ + protected IFinishedMotionCallback onFinishedMotion; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismExpressionMotion.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismExpressionMotion.java new file mode 100644 index 0000000..376fc91 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismExpressionMotion.java @@ -0,0 +1,354 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.utils.jsonparser.ACubismJsonValue; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; + +import java.util.ArrayList; +import java.util.List; + +/** + * A motion class for facial expressions. + */ +public class CubismExpressionMotion extends ACubismMotion { + /** + * Calculation method of facial expression parameter values. + */ + public enum ExpressionBlendType { + /** + * Addition + */ + ADD("Add"), + /** + * Multiplication + */ + MULTIPLY("Multiply"), + /** + * Overwriting + */ + OVERWRITE("Overwrite"); + + private final String type; + + ExpressionBlendType(String type) { + this.type = type; + } + } + + /** + * Internal class for expression parameter information. + */ + public static class ExpressionParameter { + public ExpressionParameter(CubismId id, ExpressionBlendType method, float value) { + if (id == null || method == null) { + throw new IllegalArgumentException("id or method is null."); + } + this.parameterId = id; + this.blendType = method; + this.value = value; + } + + /** + * Parameter ID + */ + public final CubismId parameterId; + /** + * Type of parameter calculation + */ + public final ExpressionBlendType blendType; + /** + * Value + */ + public final float value; + } + + /** + * Default fade duration. + */ + public static final float DEFAULT_FADE_TIME = 1.0f; + + /** + * 加算適用の初期値 + */ + public static final float DEFAULT_ADDITIVE_VALUE = 0.0f; + + /** + * 乗算適用の初期値 + */ + public static final float DEFAULT_MULTIPLY_VALUE = 1.0f; + + /** + * Create an ACubismMotion instance. + * + * @param buffer buffer where exp3.json file is loaded + * @return created instance + */ + public static CubismExpressionMotion create(byte[] buffer) { + CubismExpressionMotion expression = new CubismExpressionMotion(); + expression.parse(buffer); + + return expression; + } + + /** + * モデルの表情に関するパラメータを計算する。 + * + * @param model 対象のモデル + * @param userTimeSeconds デルタ時間の積算値[秒] + * @param motionQueueEntry CubismMotionQueueManagerで管理されているモーション + * @param expressionParameterValues モデルに適用する各パラメータの値 + * @param expressionIndex 表情のインデックス + * @param fadeWeight 表情のウェイト + */ + public void calculateExpressionParameters( + CubismModel model, + float userTimeSeconds, + CubismMotionQueueEntry motionQueueEntry, + List expressionParameterValues, + int expressionIndex, + float fadeWeight + ) { + if(motionQueueEntry == null || expressionParameterValues == null) { + return; + } + + if (!motionQueueEntry.isAvailable()) { + return; + } + + // CubismExpressionMotion.fadeWeight は廃止予定です。 + // 互換性のために処理は残りますが、実際には使用しておりません。 + this.fadeWeight = updateFadeWeight(motionQueueEntry, userTimeSeconds); + + // モデルに適用する値を計算 + for (int i = 0; i < expressionParameterValues.size(); i++) { + CubismExpressionMotionManager.ExpressionParameterValue expParamValue = expressionParameterValues.get(i); + + if (expParamValue.parameterId == null) { + continue; + } + + final float currentParameterValue = expParamValue.overwriteValue = model.getParameterValue(expParamValue.parameterId); + + List expressionParameters = getExpressionParameters(); + int parameterIndex = -1; + for (int j = 0; j < expressionParameters.size(); j++) { + if (expParamValue.parameterId != expressionParameters.get(j).parameterId) { + continue; + } + + parameterIndex = j; + break; + } + + // 再生中のExpressionが参照していないパラメータは初期値を適用 + if (parameterIndex < 0) { + if (expressionIndex == 0) { + expParamValue.additiveValue = DEFAULT_ADDITIVE_VALUE; + expParamValue.multiplyValue = DEFAULT_MULTIPLY_VALUE; + expParamValue.overwriteValue = currentParameterValue; + } else { + expParamValue.additiveValue = calculateValue(expParamValue.additiveValue, DEFAULT_ADDITIVE_VALUE, fadeWeight); + expParamValue.multiplyValue = calculateValue(expParamValue.multiplyValue, DEFAULT_MULTIPLY_VALUE, fadeWeight); + expParamValue.overwriteValue = calculateValue(expParamValue.overwriteValue, currentParameterValue, fadeWeight); + } + continue; + } + + // 値を計算 + float value = expressionParameters.get(parameterIndex).value; + float newAdditiveValue, newMultiplyValue, newOverwriteValue; + + switch (expressionParameters.get(parameterIndex).blendType) { + case ADD: + newAdditiveValue = value; + newMultiplyValue = DEFAULT_MULTIPLY_VALUE; + newOverwriteValue = currentParameterValue; + break; + case MULTIPLY: + newAdditiveValue = DEFAULT_ADDITIVE_VALUE; + newMultiplyValue = value; + newOverwriteValue = currentParameterValue; + break; + case OVERWRITE: + newAdditiveValue = DEFAULT_ADDITIVE_VALUE; + newMultiplyValue = DEFAULT_MULTIPLY_VALUE; + newOverwriteValue = value; + break; + default: + return; + } + + if (expressionIndex == 0) { + expParamValue.additiveValue = newAdditiveValue; + expParamValue.multiplyValue = newMultiplyValue; + expParamValue.overwriteValue = newOverwriteValue; + } else { + expParamValue.additiveValue = (expParamValue.additiveValue * (1.0f - fadeWeight)) + newAdditiveValue * fadeWeight; + expParamValue.multiplyValue = (expParamValue.multiplyValue * (1.0f - fadeWeight)) + newMultiplyValue * fadeWeight; + expParamValue.overwriteValue = (expParamValue.overwriteValue * (1.0f - fadeWeight)) + newOverwriteValue * fadeWeight; + } + } + } + + /** + * 表情が参照しているパラメータを取得する。 + * + * @return 表情が参照しているパラメータ + */ + public List getExpressionParameters() { + return parameters; + } + + + /** + * 現在の表情のフェードのウェイト値を取得する。 + * + * @return 表情のフェードのウェイト値 + * + * @deprecated CubismExpressionMotion.fadeWeightが削除予定のため非推奨。 + * CubismExpressionMotionManager.getFadeWeight(int index) を使用してください。 + * @see CubismExpressionMotionManager#getFadeWeight(int index) + */ + @Deprecated + public float getFadeWeight() { + return fadeWeight; + } + + /** + * デフォルトコンストラクタ + */ + protected CubismExpressionMotion() {} + + @Override + protected void doUpdateParameters( + final CubismModel model, + final float userTimeSeconds, + final float weight, + final CubismMotionQueueEntry motionQueueEntry + ) { + for (int i = 0; i < parameters.size(); i++) { + ExpressionParameter parameter = parameters.get(i); + switch (parameter.blendType) { + // Relative change: Addition + case ADD: + model.addParameterValue(parameter.parameterId, parameter.value, weight); + break; + // Relative change: Multiplication + case MULTIPLY: + model.multiplyParameterValue(parameter.parameterId, parameter.value, weight); + break; + // Relatice change: Overwriting + case OVERWRITE: + model.setParameterValue(parameter.parameterId, parameter.value, weight); + break; + default: + // When you set a value that is not in the specification, it is already in the addition mode. + break; + } + } + } + + /** + * exp3.jsonをパースする。 + * + * @param exp3Json exp3.jsonが読み込まれているbyte配列 + */ + protected void parse(byte[] exp3Json) { + CubismJson json = CubismJson.create(exp3Json); + + setFadeInTime(json.getRoot().get(ExpressionKey.FADE_IN.key).toFloat(DEFAULT_FADE_TIME)); + setFadeOutTime(json.getRoot().get(ExpressionKey.FADE_OUT.key).toFloat(DEFAULT_FADE_TIME)); + + ACubismJsonValue jsonParameters = json.getRoot().get(ExpressionKey.PARAMETERS.key); + // Each parameter setting + for (int i = 0; i < jsonParameters.size(); i++) { + final ACubismJsonValue param = jsonParameters.get(i); + + // Parameter ID + final CubismId parameterId = CubismFramework.getIdManager().getId(param.get(ExpressionKey.ID.key).getString()); + // Setting of calculation method. + final ExpressionBlendType blendType = getBlendMethod(param); + // Value + final float value = param.get(ExpressionKey.VALUE.key).toFloat(); + + // Create a configuration object and add it to the list. + ExpressionParameter item = new ExpressionParameter(parameterId, blendType, value); + this.parameters.add(item); + } + } + + /** + * Get the calculation method for the parameter values of expressions set in JSON. + * + * @param parameter JSON parameter value + * @return calculation method set in JSON + */ + private static ExpressionBlendType getBlendMethod(ACubismJsonValue parameter) { + final String method = parameter.get(ExpressionKey.BLEND.key).getString(); + + if (method.equals(ExpressionBlendType.ADD.type)) { + return ExpressionBlendType.ADD; + } else if (method.equals(ExpressionBlendType.MULTIPLY.type)) { + return ExpressionBlendType.MULTIPLY; + } else if (method.equals(ExpressionBlendType.OVERWRITE.type)) { + return ExpressionBlendType.OVERWRITE; + } + // If the value that is not in the specifications is set, it can be recovered by setting addition mode. + else { + return ExpressionBlendType.ADD; + } + } + + /** + * Key of exp3.json. + */ + private enum ExpressionKey { + FADE_IN("FadeInTime"), + FADE_OUT("FadeOutTime"), + PARAMETERS("Parameters"), + ID("Id"), + VALUE("Value"), + BLEND("Blend"); + + private final String key; + + ExpressionKey(String key) { + this.key = key; + } + } + + /** + * 入力された値でブレンド計算をする。 + * + * @param source 現在の値 + * @param destination 適用する値 + * + * @return 計算されたブレンド値 + */ + private float calculateValue(float source, float destination, float fadeWeight) { + return (source * (1.0f - fadeWeight)) + (destination * fadeWeight); + } + + /** + * Parameter information list for facial expressions + */ + private final List parameters = new ArrayList<>(); + + /** + * 表情の現在のウェイト + * + * @deprecated 不具合を引き起こす要因となるため非推奨。 + */ + @Deprecated + private float fadeWeight; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismExpressionMotionManager.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismExpressionMotionManager.java new file mode 100644 index 0000000..133dba6 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismExpressionMotionManager.java @@ -0,0 +1,275 @@ +/** + * 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. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismMath; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class CubismExpressionMotionManager extends CubismMotionQueueManager { + public static class ExpressionParameterValue { + /** + * パラメータID + */ + public CubismId parameterId; + /** + * 加算値 + */ + public float additiveValue; + /** + * 乗算値 + */ + public float multiplyValue; + /** + * 上書き値 + */ + public float overwriteValue; + } + + /** + * 再生中の表情モーションの優先度を取得する。 + * + * @return 表情モーションの優先度 + */ + public int getCurrentPriority() { + return currentPriority; + } + + /** + * 予約中の表情モーションの優先度を取得する。 + * + * @return 表情モーションの優先度 + */ + public int getReservePriority() { + return reservePriority; + } + + /** + * 現在の表情のフェードのウェイト値を取得する。 + * + * @param index 取得する表情モーションのインデックス + * + * @return 表情のフェードのウェイト値 + * + * @throws IllegalArgumentException if an argument is an invalid value. + */ + public float getFadeWeight(int index) { + if(fadeWeights.isEmpty()) { + throw new IllegalArgumentException("No motion during playback."); + } + + if(fadeWeights.size() <= index || index < 0) { + throw new IllegalArgumentException("The index is an invalid value."); + } + + return fadeWeights.get(index); + } + + /** + * 予約中の表情モーションの優先度を設定する。 + * + * @param priority 設定する表情モーションの優先度 + */ + public void setReservePriority(int priority) { + this.reservePriority = priority; + } + + /** + * 優先度を設定して表情モーションを開始する。 + * + * @param motion 開始する表情モーション + * @param priority 優先度 + * @return 開始した表情モーションの識別番号。個別のモーションが終了したか否かを判断するisFinished()の引数で使用する。開始できないときは「-1」を返します。 + */ + public int startMotionPriority(ACubismMotion motion, int priority) { + if (priority == reservePriority) { + reservePriority = 0; // 予約を解除 + } + currentPriority = priority; // 再生中モーションの優先度を設定 + + return startMotion(motion); + } + + /** + * 表情モーションを更新して、モデルにパラメータ値を反映する。 + * + * @param model 対象のモデル + * @param deltaTimeSeconds デルタ時間[秒] + * @return 表情モーションが更新されたかどうか。更新されたならtrue。 + */ + public boolean updateMotion(CubismModel model, float deltaTimeSeconds) { + userTimeSeconds += deltaTimeSeconds; + boolean isUpdated = false; + List motions = getCubismMotionQueueEntries(); + + float expressionWeight = 0.0f; + int expressionIndex = 0; + + // motionQueueEntryの中にあるmotionインスタンスがnullの場合、motionQueueEntryインスタンス自体をnullにする + // for文でnullを順次削除する方式だと例外を出してしまうため。 + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry entry = motions.get(i); + CubismExpressionMotion expressionMotion = (CubismExpressionMotion) entry.getCubismMotion(); + + if (expressionMotion == null) { + motions.set(i, null); + } + } + + // 予めnull要素を全て削除 + motions.removeAll(nullSet); + + while (fadeWeights.size() < motions.size()) { + fadeWeights.add(0.0f); + } + + // ------ 処理を行う ------ + // 既に表情モーションがあれば終了フラグを立てる + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry motionQueueEntry = motions.get(i); + CubismExpressionMotion expressionMotion = (CubismExpressionMotion) motionQueueEntry.getCubismMotion(); + List expressionParameters = expressionMotion.getExpressionParameters(); + + if (motionQueueEntry.isAvailable()) { + // 再生中のExpressionが参照しているパラメータをすべてリストアップ + for (int paramIndex = 0; paramIndex < expressionParameters.size(); paramIndex++) { + if (expressionParameters.get(paramIndex).parameterId == null) { + continue; + } + + int index = -1; + // リストにパラメータIDが存在するか検索 + for (int j = 0; j < expressionParameterValues.size(); j++) { + if (expressionParameterValues.get(j).parameterId != expressionParameters.get(paramIndex).parameterId) { + continue; + } + + index = j; + break; + } + + if (index >= 0) { + continue; + } + + // パラメータがリストに存在しないなら新規追加 + ExpressionParameterValue item = new ExpressionParameterValue(); + item.parameterId = expressionParameters.get(paramIndex).parameterId; + item.additiveValue = CubismExpressionMotion.DEFAULT_ADDITIVE_VALUE; + item.multiplyValue = CubismExpressionMotion.DEFAULT_MULTIPLY_VALUE; + item.overwriteValue = model.getParameterValue(item.parameterId); + expressionParameterValues.add(item); + } + } + + // ------ 値を計算する ------ + expressionMotion.setupMotionQueueEntry(motionQueueEntry, userTimeSeconds); + setFadeWeight(expressionIndex, expressionMotion.updateFadeWeight(motionQueueEntry, userTimeSeconds)); + expressionMotion.calculateExpressionParameters( + model, + userTimeSeconds, + motionQueueEntry, + expressionParameterValues, + expressionIndex, + getFadeWeight(expressionIndex) + ); + + final float easingSine = expressionMotion.getFadeInTime() == 0.0f + ? 1.0f + : CubismMath.getEasingSine((userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / expressionMotion.getFadeInTime()); + expressionWeight += easingSine; + + isUpdated = true; + + if (motionQueueEntry.isTriggeredFadeOut()) { + // フェードアウト開始 + motionQueueEntry.startFadeOut(motionQueueEntry.getFadeOutSeconds(), userTimeSeconds); + } + + expressionIndex++; + } + + // ------ 最新のExpressionのフェードが完了していればそれ以前を削除する ------ + if (motions.size() > 1) { + float latestFadeWeight = getFadeWeight(fadeWeights.size() - 1); + + if (latestFadeWeight >= 1.0f) { + // 配列の最後の要素は削除しない + for (int i = motions.size() - 2; i >= 0; i--) { + // forでremoveすることはできない。nullをセットしておいて後で削除する。 + motions.set(i, null); + + fadeWeights.remove(i); + } + motions.removeAll(nullSet); + } + } + + if (expressionWeight > 1.0f) { + expressionWeight = 1.0f; + } + + // モデルに各値を適用 + for (int i = 0; i < expressionParameterValues.size(); i++) { + ExpressionParameterValue v = expressionParameterValues.get(i); + + model.setParameterValue( + v.parameterId, + (v.overwriteValue + v.additiveValue) * v.multiplyValue, + expressionWeight); + v.additiveValue = CubismExpressionMotion.DEFAULT_ADDITIVE_VALUE; + v.multiplyValue = CubismExpressionMotion.DEFAULT_MULTIPLY_VALUE; + } + + return isUpdated; + } + + /** + * Set the weight of expression fade. + * + * @param index index of the expression motion to be set + * @param expressionFadeWeight weight value of expression fade + */ + private void setFadeWeight(int index, float expressionFadeWeight) { + if (index < 0 || fadeWeights.isEmpty() || fadeWeights.size() <= index) { + CubismDebug.cubismLogWarning("Failed to set the fade weight value. The element at that index does not exist."); + return; + } + fadeWeights.set(index, expressionFadeWeight); + } + + // nullが格納されたSet。null要素だけListから排除する際に使用される。 + private static final Set nullSet = Collections.singleton(null); + + /** + * モデルに適用する各パラメータの値 + */ + private final List expressionParameterValues = new ArrayList<>(); + + /** + * 現在再生中の表情モーションの優先度 + */ + private int currentPriority; + + /** + * 再生予定の表情モーションの優先度。再生中は0になる。 + * 表情モーションファイルを別スレッドで読み込むときの機能。 + */ + private int reservePriority; + + /** + * 再生中の表情モーションのウェイトのリスト + */ + private final List fadeWeights = new ArrayList<>(); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotion.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotion.java new file mode 100644 index 0000000..84f251a --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotion.java @@ -0,0 +1,1209 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismMath; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CsmMotionSegmentEvaluationFunction; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionCurve; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionCurveTarget; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionData; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionEvent; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionPoint; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionSegment; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionSegmentType; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collections; +import java.util.List; + +/** + * Motion class. + */ +public final class CubismMotion extends ACubismMotion { + /** + * Enumerator for version control of Motion Behavior. + * For details, see the SDK Manual. + */ + public enum MotionBehavior { + MOTION_BEHAVIOR_V1, + MOTION_BEHAVIOR_V2, + } + + /** + * Create an instance. + * + * @param buffer buffer where motion3.json is loaded + * @param finishedMotionCallBack callback function called at the end of motion playback, not called if null. + * @param beganMotionCallBack callback function called at the start of motion playback, not called if null. + * @param shouldCheckMotionConsistency flag to validate the consistency of motion3.json. + * @return instance of CubismMotion + */ + public static CubismMotion create( + byte[] buffer, + IFinishedMotionCallback finishedMotionCallBack, + IBeganMotionCallback beganMotionCallBack, + boolean shouldCheckMotionConsistency + ) { + CubismMotion motion = new CubismMotion(); + motion.parse(buffer, shouldCheckMotionConsistency); + + if (motion.motionData != null) { + motion.sourceFrameRate = motion.motionData.fps; + motion.loopDurationSeconds = motion.motionData.duration; + motion.onFinishedMotion = finishedMotionCallBack; + motion.onBeganMotion = beganMotionCallBack; + } else { + motion = null; + } + + // NOTE: Exporting motion with loop is not supported in Editor. + return motion; + } + + /** + * Create an instance. + * This method does not check the consistency of motion3.json. + * To check the consistency of motion3.json, + * use {@link #create(byte[], IFinishedMotionCallback, IBeganMotionCallback, boolean)} + * and set the fourth argument to `true`. + * + * @param buffer buffer where motion3.json is loaded + * @param finishedMotionCallBack callback function called at the end of motion playback, not called if null. + * @param beganMotionCallBack callback function called at the start of motion playback, not called if null. + * @return instance of CubismMotion + */ + public static CubismMotion create( + byte[] buffer, + IFinishedMotionCallback finishedMotionCallBack, + IBeganMotionCallback beganMotionCallBack + ) { + return create(buffer, finishedMotionCallBack, beganMotionCallBack, false); + } + + /** + * Create an instance. + * This method does not set any callback functions. + * + * @param buffer buffer where motion3.json is loaded + * @param shouldCheckMotionConsistency flag to validate the consistency of motion3.json. + * @return instance of CubismMotion + */ + public static CubismMotion create(byte[] buffer, boolean shouldCheckMotionConsistency) { + return create(buffer, null, null, shouldCheckMotionConsistency); + } + + /** + * Create an instance. + * This method does not check the consistency of motion3.json. + * To check the consistency of motion3.json, + * use {@link #create(byte[], boolean)} + * and set the second argument to `true`. + * This method does not set any callback functions. + * + * @param buffer buffer where motion3.json is loaded. + * @return instance of CubismMotion + */ + public static CubismMotion create(byte[] buffer) { + return create(buffer, null, null, false); + } + + /** + * Set loop information. + * + * @param loop loop information + * + * @deprecated Not recommended due to the relocation of isLoop to the base class. + * Use ACubismMotion.setLoop(boolean loop) instead. + **/ + @Deprecated + public void isLooped(boolean loop) { + CubismDebug.cubismLogWarning("isLoop(boolean loop) is a deprecated function. Please use setLoop(boolean loop)."); + super.setLoop(loop); + } + + /** + * Whether the motion loops. + * + * @return If it loops, return true. + * + * @deprecated Not recommended due to the relocation of isLoop to the base class. + * Use ACubismMotion.getLoop() instead. + */ + @Deprecated + public boolean isLooped() { + CubismDebug.cubismLogWarning("isLoop() is a deprecated function. Please use getLoop()."); + return super.getLoop(); + } + + /** + * Set the fade-in information at looping. + * + * @param loopFadeIn fade-in information at looping + * + * @deprecated Not recommended due to the relocation of isLoopFadeIn to the base class. + * Use ACubismMotion.setLoopFadeIn(boolean loopFadeIn) instead. + */ + @Deprecated + public void isLoopFadeIn(boolean loopFadeIn) { + CubismDebug.cubismLogWarning("isLoopFadeIn(boolean loopFadeIn) is a deprecated function. Please use setLoopFadeIn(boolean loopFadeIn)"); + super.setLoopFadeIn(loopFadeIn); + } + + /** + * Whether the motion fade in at looping. + * + * @return If it fades in, return true. + * + * @deprecated Not recommended due to the relocation of isLoopFadeIn to the base class. + * Use ACubismMotion.getLoopFadeIn() instead. + */ + @Deprecated + public boolean isLoopFadeIn() { + CubismDebug.cubismLogWarning("isLoopFadeIn() is a deprecated function. Please use getLoopFadeIn()."); + return super.getLoopFadeIn(); + } + + /** + * Sets the version of the Motion Behavior. + * + * @param motionBehavior the version of the Motion Behavior. + */ + public void setMotionBehavior(MotionBehavior motionBehavior) { + this.motionBehavior = motionBehavior; + } + + /** + * Gets the version of the Motion Behavior. + * + * @return Returns the version of the Motion Behavior. + */ + public MotionBehavior getMotionBehavior() { + return motionBehavior; + } + + /** + * Set the fade-in duration for parameters. + * + * @param parameterId parameter ID + * @param value fade-in duration[s] + */ + public void setParameterFadeInTime(CubismId parameterId, float value) { + for (int i = 0; i < motionData.curves.size(); i++) { + CubismMotionCurve curve = motionData.curves.get(i); + + if (parameterId.equals(curve.id)) { + curve.fadeInTime = value; + return; + } + } + } + + /** + * Get the fade-in duration for parameters. + * + * @param parameterId parameter ID + * @return fade-in duration[s] + */ + public float getParameterFadeInTime(CubismId parameterId) { + for (int i = 0; i < motionData.curves.size(); i++) { + CubismMotionCurve curve = motionData.curves.get(i); + + if (parameterId.equals(curve.id)) { + return curve.fadeInTime; + } + } + return -1; + } + + /** + * Set the fade-out duration for parameters. + * + * @param parameterId parameter ID + * @param value fade-out duration[s] + */ + public void setParameterFadeOutTime(CubismId parameterId, float value) { + for (int i = 0; i < motionData.curves.size(); i++) { + CubismMotionCurve curve = motionData.curves.get(i); + + if (parameterId.equals(curve.id)) { + curve.fadeOutTime = value; + return; + } + } + } + + /** + * Get the fade-out duration for parameters. + * + * @param parameterId parameter ID + * @return fade-out duration[s] + */ + public float getParameterFadeOutTime(CubismId parameterId) { + for (int i = 0; i < motionData.curves.size(); i++) { + CubismMotionCurve curve = motionData.curves.get(i); + + if (parameterId.equals(curve.id)) { + return curve.fadeOutTime; + } + } + return -1; + } + + /** + * Set the parameter ID list to which automatic effects are applied. + * + * @param eyeBlinkParameterIds parameter ID list to which automatic eye blinking is applied + * @param lipSyncParameterIds parameter ID list to which automatic lip-syncing is applied + */ + public void setEffectIds(List eyeBlinkParameterIds, List lipSyncParameterIds) { + this.eyeBlinkParameterIds.clear(); + this.eyeBlinkParameterIds.addAll(eyeBlinkParameterIds); + + this.lipSyncParameterIds.clear(); + this.lipSyncParameterIds.addAll(lipSyncParameterIds); + } + + @Override + public float getDuration() { + return isLoop + ? -1.0f + : loopDurationSeconds; + } + + @Override + public float getLoopDuration() { + return loopDurationSeconds; + } + + @Override + public List getFiredEvent(float beforeCheckTimeSeconds, float motionTimeSeconds) { + firedEventValues.clear(); + + for (int i = 0; i < motionData.events.size(); i++) { + CubismMotionEvent event = motionData.events.get(i); + + if ((event.fireTime > beforeCheckTimeSeconds) && (event.fireTime <= motionTimeSeconds)) { + firedEventValues.add(event.value); + } + } + return Collections.unmodifiableList(firedEventValues); + } + + @Override + public boolean isExistModelOpacity() { + for (int i = 0; i < motionData.curves.size(); i++) { + CubismMotionCurve curve = motionData.curves.get(i); + + if (curve.type != CubismMotionCurveTarget.MODEL) { + continue; + } + if (curve.id.getString().equals(ID_NAME_OPACITY)) { + return true; + } + } + return false; + } + + @Override + public int getModelOpacityIndex() { + if (isExistModelOpacity()) { + for (int i = 0; i < motionData.curves.size(); i++) { + CubismMotionCurve curve = motionData.curves.get(i); + + if (curve.type != CubismMotionCurveTarget.MODEL) { + continue; + } + if (curve.id.getString().equals(ID_NAME_OPACITY)) { + return i; + } + } + } + return -1; + } + + @Override + public CubismId getModelOpacityId(int index) { + if (index == -1) { + return null; + } + + CubismMotionCurve curve = motionData.curves.get(index); + + if (curve.type == CubismMotionCurveTarget.MODEL) { + if (curve.id.getString().equals(ID_NAME_OPACITY)) { + return CubismFramework.getIdManager().getId(curve.id); + } + } + + return null; + } + + @Override + public float getModelOpacityValue() { + return modelOpacity; + } + + /** + * Update parameters of the model. + * + * @param model target model + * @param userTimeSeconds current time[s] + * @param fadeWeight weight of motion + * @param motionQueueEntry motion managed by CubismMotionQueueManager + */ + @Override + protected void doUpdateParameters( + final CubismModel model, + final float userTimeSeconds, + final float fadeWeight, + final CubismMotionQueueEntry motionQueueEntry + ) { + if (modelCurveIdEyeBlink == null) { + modelCurveIdEyeBlink = CubismFramework.getIdManager().getId(EffectName.EYE_BLINK.name); + } + + if (modelCurveIdLipSync == null) { + modelCurveIdLipSync = CubismFramework.getIdManager().getId(EffectName.LIP_SYNC.name); + } + + if (modelCurveIdOpacity == null) { + modelCurveIdOpacity = CubismFramework.getIdManager().getId(ID_NAME_OPACITY); + } + + if (motionBehavior == MotionBehavior.MOTION_BEHAVIOR_V2) { + if (previousLoopState != isLoop) { + // 終了時間を再計算する + adjustEndTime(motionQueueEntry); + previousLoopState = isLoop; + } + } + + float timeOffsetSeconds = userTimeSeconds - motionQueueEntry.getStartTime(); + + + // Error avoidance. + if (timeOffsetSeconds < 0.0f) { + timeOffsetSeconds = 0.0f; + } + + final int MAX_TARGET_SIZE = 64; + + if (eyeBlinkParameterIds.size() > MAX_TARGET_SIZE) { + String message = "too many eye blink targets: " + eyeBlinkParameterIds.size(); + CubismDebug.cubismLogDebug(message); + } + if (lipSyncParameterIds.size() > MAX_TARGET_SIZE) { + String message = "too many lip sync targets: " + lipSyncParameterIds.size(); + CubismDebug.cubismLogDebug(message); + } + + // 'Repeat time as necessary' + float time = timeOffsetSeconds; + float duration = motionData.duration; + boolean isCorrection = motionBehavior == MotionBehavior.MOTION_BEHAVIOR_V2 && isLoop; + + if (isLoop) { + if (motionBehavior == MotionBehavior.MOTION_BEHAVIOR_V2) { + duration += 1.0f / motionData.fps; + } + while (time > duration) { + time -= duration; + } + } + + List curves = motionData.curves; + + float eyeBlinkValue = 0; + float lipSyncValue = 0; + + // A bit flag indicating whether the blink and lip-sync motions have been applied. + boolean isUpdatedEyeBlink = false; + boolean isUpdatedLipSync = false; + + float value; + + // Evaluate model curves + for (int i = 0; i < curves.size(); i++) { + CubismMotionCurve curve = curves.get(i); + + if (curve.type != CubismMotionCurveTarget.MODEL) { + continue; + } + + // Evaluate curve and call handler. + value = evaluateCurve(motionData, i, time, isCorrection, duration); + + if (curve.id.equals(modelCurveIdEyeBlink)) { + eyeBlinkValue = value; + isUpdatedEyeBlink = true; + } else if (curve.id.equals(modelCurveIdLipSync)) { + lipSyncValue = value; + isUpdatedLipSync = true; + } else if (curve.id.equals(modelCurveIdOpacity)){ + modelOpacity = value; + + // 不透明度の値が存在すれば反映する。 + model.setModelOpacity(getModelOpacityValue()); + } + } + + final float tmpFadeIn = (fadeInSeconds <= 0.0f) + ? 1.0f + : CubismMath.getEasingSine((userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / fadeInSeconds); + final float tmpFadeOut = (fadeOutSeconds <= 0.0f || motionQueueEntry.getEndTime() < 0.0f) + ? 1.0f + : CubismMath.getEasingSine((motionQueueEntry.getEndTime() - userTimeSeconds) / fadeOutSeconds); + + for (int i = 0; i < curves.size(); i++) { + CubismMotionCurve curve = curves.get(i); + + if (curve.type != CubismMotionCurveTarget.PARAMETER) { + continue; + } + + // Find parameter index. + final int parameterIndex = model.getParameterIndex(curve.id); + + // Skip curve evaluation if no value. + if (parameterIndex == -1) { + continue; + } + + final float sourceValue = model.getParameterValue(parameterIndex); + + // Evaluate curve and apply value. + value = evaluateCurve(motionData, i, time, isCorrection, duration); + + if (isUpdatedEyeBlink) { + for (int j = 0; j < eyeBlinkParameterIds.size(); j++) { + CubismId id = eyeBlinkParameterIds.get(j); + + if (j == MAX_TARGET_SIZE) { + break; + } + + if (id.equals(curve.id)) { + value *= eyeBlinkValue; + eyeBlinkFlags.set(j); + break; + } + } + } + + if (isUpdatedLipSync) { + for (int j = 0; j < lipSyncParameterIds.size(); j++) { + CubismId id = lipSyncParameterIds.get(j); + + if (j == MAX_TARGET_SIZE) { + break; + } + + if (id.equals(curve.id)) { + value += lipSyncValue; + lipSyncFlags.set(j); + break; + } + } + } + + // Process repeats only for compatibility + if (model.isRepeat(parameterIndex)) { + value = model.getParameterRepeatValue(parameterIndex, value); + } + + float v; + if (existFade(curve)) { + // If the parameter has a fade-in or fade-out setting, apply it. + float fin; + float fout; + + if (existFadeIn(curve)) { + final float easedValue = (userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / curve.fadeInTime; + + fin = curve.fadeInTime == 0.0f + ? 1.0f + : CubismMath.getEasingSine(easedValue); + } else { + fin = tmpFadeIn; + } + + if (existFadeOut(curve)) { + final float easedValue = (motionQueueEntry.getEndTime() - userTimeSeconds) / curve.fadeOutTime; + + fout = (curve.fadeOutTime == 0.0f || motionQueueEntry.getEndTime() < 0.0f) + ? 1.0f + : CubismMath.getEasingSine(easedValue); + } else { + fout = tmpFadeOut; + } + + final float paramWeight = weight * fin * fout; + + // Apply each fading. + v = sourceValue + (value - sourceValue) * paramWeight; + + } else { + // Apply each fading. + v = sourceValue + (value - sourceValue) * fadeWeight; + } + model.setParameterValue(parameterIndex, v); + } + + + if (isUpdatedEyeBlink) { + for (int i = 0; i < eyeBlinkParameterIds.size(); i++) { + CubismId id = eyeBlinkParameterIds.get(i); + + if (i == MAX_TARGET_SIZE) { + break; + } + + // Blink does not apply when there is a motion overriding. + if (eyeBlinkFlags.get(i)) { + continue; + } + + final float sourceValue = model.getParameterValue(id); + final float v = sourceValue + (eyeBlinkValue - sourceValue) * fadeWeight; + + model.setParameterValue(id, v); + } + } + + if (isUpdatedLipSync) { + for (int i = 0; i < lipSyncParameterIds.size(); i++) { + CubismId id = lipSyncParameterIds.get(i); + + if (i == MAX_TARGET_SIZE) { + break; + } + + // Lip-sync does not apply when there is a motion overriding. + if (lipSyncFlags.get(i)) { + continue; + } + + final float sourceValue = model.getParameterValue(id); + + final float v = sourceValue + (lipSyncValue - sourceValue) * fadeWeight; + + model.setParameterValue(id, v); + } + } + + int curveSize = curves.size(); + for (int i = 0; i < curveSize; i++) { + CubismMotionCurve curve = curves.get(i); + + if (curve.type != CubismMotionCurveTarget.PART_OPACITY) { + continue; + } + + // Find parameter index. + final int parameterIndex = model.getParameterIndex(curve.id); + + // Skip curve evaluation if no value. + if (parameterIndex == -1) { + continue; + } + + // Evaluate curve and apply value. + value = evaluateCurve(motionData, i, time, isCorrection, duration); + model.setParameterValue(parameterIndex, value); + } + + if (timeOffsetSeconds >= duration) { + if (isLoop) { + UpdateForNextLoop(motionQueueEntry, userTimeSeconds, time); + } else { + if (onFinishedMotion != null) { + onFinishedMotion.execute(this); + } + motionQueueEntry.isFinished(true); + } + } + lastWeight = fadeWeight; + } + + private void UpdateForNextLoop(CubismMotionQueueEntry motionQueueEntry, float userTimeSeconds, float time) { + switch (motionBehavior) { + case MOTION_BEHAVIOR_V1: + // 旧ループ処理 + motionQueueEntry.setStartTime(userTimeSeconds); //最初の状態へ + if (isLoopFadeIn) { + //ループ中でループ用フェードインが有効のときは、フェードイン設定し直し + motionQueueEntry.setFadeInStartTime(userTimeSeconds); + } + break; + case MOTION_BEHAVIOR_V2: + default: + motionQueueEntry.setStartTime(userTimeSeconds - time); //最初の状態へ + if (isLoopFadeIn) { + //ループ中でループ用フェードインが有効のときは、フェードイン設定し直し + motionQueueEntry.setFadeInStartTime(userTimeSeconds - time); + } + + if (this.onFinishedMotion != null) { + this.onFinishedMotion.execute(this); + } + break; + } + } + + // ID + private static final String ID_NAME_OPACITY = "Opacity"; + + /** + * It is set to "true" to reproduce the motion of Cubism SDK R2 or earlier, or "false" to reproduce the animator's motion correctly. + */ + private static final boolean USE_OLD_BEZIERS_CURVE_MOTION = false; + + + private enum EffectName { + EYE_BLINK("EyeBlink"), + LIP_SYNC("LipSync"); + + private final String name; + + EffectName(String name) { + this.name = name; + } + } + + private enum TargetName { + MODEL("Model"), + PARAMETER("Parameter"), + PART_OPACITY("PartOpacity"); + + private final String name; + + TargetName(String name) { + this.name = name; + } + } + + private static class LinearEvaluator implements CsmMotionSegmentEvaluationFunction { + @Override + public float evaluate(final List points, final float time) { + float t = (time - points.get(0).time) / (points.get(1).time - points.get(0).time); + + if (t < 0.0f) { + t = 0.0f; + } + + return points.get(0).value + ((points.get(1).value - points.get(0).value) * t); + } + } + + private static class BezierEvaluator implements CsmMotionSegmentEvaluationFunction { + @Override + public float evaluate(final List points, final float time) { + float t = (time - points.get(0).time) / (points.get(3).time - points.get(0).time); + + if (t < 0.0f) { + t = 0.0f; + } + + final CubismMotionPoint p01 = lerpPoints(points.get(0), points.get(1), t); + final CubismMotionPoint p12 = lerpPoints(points.get(1), points.get(2), t); + final CubismMotionPoint p23 = lerpPoints(points.get(2), points.get(3), t); + + final CubismMotionPoint p012 = lerpPoints(p01, p12, t); + final CubismMotionPoint p123 = lerpPoints(p12, p23, t); + + return lerpPoints(p012, p123, t).value; + } + } + + private static class BezierEvaluatorCardanoInterpretation implements CsmMotionSegmentEvaluationFunction { + @Override + public float evaluate(final List points, final float time) { + final float x1 = points.get(0).time; + final float x2 = points.get(3).time; + final float cx1 = points.get(1).time; + final float cx2 = points.get(2).time; + + final float a = x2 - 3.0f * cx2 + 3.0f * cx1 - x1; + final float b = 3.0f * cx2 - 6.0f * cx1 + 3.0f * x1; + final float c = 3.0f * cx1 - 3.0f * x1; + final float d = x1 - time; + + final float t = CubismMath.cardanoAlgorithmForBezier(a, b, c, d); + + final CubismMotionPoint p01 = lerpPoints(points.get(0), points.get(1), t); + final CubismMotionPoint p12 = lerpPoints(points.get(1), points.get(2), t); + final CubismMotionPoint p23 = lerpPoints(points.get(2), points.get(3), t); + + final CubismMotionPoint p012 = lerpPoints(p01, p12, t); + final CubismMotionPoint p123 = lerpPoints(p12, p23, t); + + return lerpPoints(p012, p123, t).value; + } + } + + private static class SteppedEvaluator implements CsmMotionSegmentEvaluationFunction { + @Override + public float evaluate(final List points, final float time) { + return points.get(0).value; + } + } + + private static class InverseSteppedEvaluator implements CsmMotionSegmentEvaluationFunction { + @Override + public float evaluate(final List points, final float time) { + return points.get(1).value; + } + } + + // lerp: Linear Interpolate(線形補間の略) + private static CubismMotionPoint lerpPoints( + final CubismMotionPoint a, + final CubismMotionPoint b, + final float t + ) { + CubismMotionPoint result = new CubismMotionPoint(); + + result.time = a.time + ((b.time - a.time) * t); + result.value = a.value + ((b.value - a.value) * t); + + return result; + } + + /** + * Check for the presence of fade-in. + * + * @param curve motion curve instance + * @return If fade-in exists, return true. + */ + private boolean existFadeIn(CubismMotionCurve curve) { + return curve.fadeInTime >= 0.0f; + } + + /** + * Check for the presence of fade-out. + * + * @param curve motion curve instance + * @return If fade-out exists, return true. + */ + private boolean existFadeOut(CubismMotionCurve curve) { + return curve.fadeOutTime >= 0.0f; + } + + /** + * Check for the presence of fading. + * + * @param curve motion curve instance + * @return If fading exists, return true. + */ + private boolean existFade(CubismMotionCurve curve) { + return existFadeIn(curve) || existFadeOut(curve); + } + + /** + * Parse motion3.json. + * + * @param motionJson buffer where motion3.json is loaded + * @param shouldCheckMotionConsistency flag to validate the consistency of motion3.json. + */ + private void parse(byte[] motionJson, boolean shouldCheckMotionConsistency) { + final CubismMotionJson json = new CubismMotionJson(motionJson); + + if (shouldCheckMotionConsistency) { + boolean consistency = json.hasConsistency(); + + if (!consistency) { + // 整合性が確認できなければ処理しない。 + CubismDebug.cubismLogError("Inconsistent motion3.json."); + return; + } + } + + motionData = new CubismMotionData(); + + motionData.duration = json.getMotionDuration(); + motionData.isLooped = json.isMotionLoop(); + motionData.curveCount = json.getMotionCurveCount(); + motionData.fps = json.getMotionFps(); + motionData.eventCount = json.getEventCount(); + + boolean areBeziersRestricted = json.getEvaluationOptionFlag(CubismMotionJson.EvaluationOptionFlag.ARE_BEZIERS_RESTRICTED); + + + if (json.existsMotionFadeInTime()) { + fadeInSeconds = (json.getMotionFadeInTime() < 0.0f) + ? 1.0f + : json.getMotionFadeInTime(); + } else { + fadeInSeconds = 1.0f; + } + + if (json.existsMotionFadeOutTime()) { + fadeOutSeconds = (json.getMotionFadeOutTime() < 0.0f) + ? 1.0f + : json.getMotionFadeOutTime(); + } else { + fadeOutSeconds = 1.0f; + } + + motionData.curves = new ArrayList(motionData.curveCount); + for (int i = 0; i < motionData.curveCount; i++) { + motionData.curves.add(new CubismMotionCurve()); + } + + motionData.segments = new ArrayList(json.getMotionTotalSegmentCount()); + for (int i = 0; i < json.getMotionTotalSegmentCount(); i++) { + motionData.segments.add(new CubismMotionSegment()); + } + + motionData.points = new ArrayList(json.getMotionTotalPointCount()); + for (int i = 0; i < json.getMotionTotalPointCount(); i++) { + motionData.points.add(new CubismMotionPoint()); + } + + motionData.events = new ArrayList(motionData.eventCount); + for (int i = 0; i < motionData.eventCount; i++) { + motionData.events.add(new CubismMotionEvent()); + } + + int totalPointCount = 0; + int totalSegmentCount = 0; + + // Curves + for (int curveCount = 0; curveCount < motionData.curveCount; curveCount++) { + final CubismMotionCurve curve = motionData.curves.get(curveCount); + + // Register target type. + final String targetName = json.getMotionCurveTarget(curveCount); + if (targetName.equals(TargetName.MODEL.name)) { + curve.type = CubismMotionCurveTarget.MODEL; + } else if (targetName.equals(TargetName.PARAMETER.name)) { + curve.type = CubismMotionCurveTarget.PARAMETER; + } else if (targetName.equals(TargetName.PART_OPACITY.name)) { + curve.type = CubismMotionCurveTarget.PART_OPACITY; + } else { + CubismDebug.cubismLogWarning("Warning: Unable to get segment type from Curve! The number of \"CurveCount\" may be incorrect!"); + } + + curve.id = json.getMotionCurveId(curveCount); + curve.baseSegmentIndex = totalSegmentCount; + curve.fadeInTime = + (json.existsMotionCurveFadeInTime(curveCount)) + ? json.getMotionCurveFadeInTime(curveCount) + : -1.0f; + curve.fadeOutTime = + (json.existsMotionCurveFadeOutTime(curveCount)) + ? json.getMotionCurveFadeOutTime(curveCount) + : -1.0f; + + // Segments + for (int segmentPosition = 0; segmentPosition < json.getMotionCurveSegmentCount(curveCount); ) { + if (segmentPosition == 0) { + motionData.segments.get(totalSegmentCount).basePointIndex = totalPointCount; + + motionData.points.get(totalPointCount).time = json.getMotionCurveSegment(curveCount, segmentPosition); + motionData.points.get(totalPointCount).value = json.getMotionCurveSegment(curveCount, segmentPosition + 1); + + totalPointCount += 1; + segmentPosition += 2; + } else { + motionData.segments.get(totalSegmentCount).basePointIndex = totalPointCount - 1; + } + + final CubismMotionSegmentType segmentType = json.getMotionCurveSegmentType(curveCount, segmentPosition); + + switch (segmentType) { + case LINEAR: { + CubismMotionSegment segment = motionData.segments.get(totalSegmentCount); + segment.segmentType = CubismMotionSegmentType.LINEAR; + segment.evaluator = linearEvaluator; + + CubismMotionPoint point = motionData.points.get(totalPointCount); + point.time = json.getMotionCurveSegment(curveCount, segmentPosition + 1); + point.value = json.getMotionCurveSegment(curveCount, segmentPosition + 2); + + totalPointCount += 1; + segmentPosition += 3; + + break; + } + case BEZIER: { + CubismMotionSegment segment = motionData.segments.get(totalSegmentCount); + segment.segmentType = CubismMotionSegmentType.BEZIER; + + if (areBeziersRestricted || USE_OLD_BEZIERS_CURVE_MOTION) { + segment.evaluator = bezierEvaluator; + } else { + segment.evaluator = bezierCardanoInterpretationEvaluator; + } + + motionData.points.get(totalPointCount).time = json.getMotionCurveSegment(curveCount, (segmentPosition + 1)); + motionData.points.get(totalPointCount).value = json.getMotionCurveSegment(curveCount, (segmentPosition + 2)); + + motionData.points.get(totalPointCount + 1).time = json.getMotionCurveSegment(curveCount, (segmentPosition + 3)); + motionData.points.get(totalPointCount + 1).value = json.getMotionCurveSegment(curveCount, (segmentPosition + 4)); + + motionData.points.get(totalPointCount + 2).time = json.getMotionCurveSegment(curveCount, (segmentPosition + 5)); + motionData.points.get(totalPointCount + 2).value = json.getMotionCurveSegment(curveCount, (segmentPosition + 6)); + + totalPointCount += 3; + segmentPosition += 7; + + break; + } + case STEPPED: { + motionData.segments.get(totalSegmentCount).segmentType = CubismMotionSegmentType.STEPPED; + motionData.segments.get(totalSegmentCount).evaluator = steppedEvaluator; + + motionData.points.get(totalPointCount).time = json.getMotionCurveSegment(curveCount, (segmentPosition + 1)); + motionData.points.get(totalPointCount).value = json.getMotionCurveSegment(curveCount, (segmentPosition + 2)); + + totalPointCount += 1; + segmentPosition += 3; + + break; + } + case INVERSESTEPPED: { + motionData.segments.get(totalSegmentCount).segmentType = CubismMotionSegmentType.INVERSESTEPPED; + motionData.segments.get(totalSegmentCount).evaluator = inverseSteppedEvaluator; + + motionData.points.get(totalPointCount).time = json.getMotionCurveSegment(curveCount, (segmentPosition + 1)); + motionData.points.get(totalPointCount).value = json.getMotionCurveSegment(curveCount, (segmentPosition + 2)); + + totalPointCount += 1; + segmentPosition += 3; + + break; + } + default: { + assert (false); + break; + } + } + + ++motionData.curves.get(curveCount).segmentCount; + ++totalSegmentCount; + } + } + + for (int userdatacount = 0; userdatacount < json.getEventCount(); ++userdatacount) { + motionData.events.get(userdatacount).fireTime = json.getEventTime(userdatacount); + motionData.events.get(userdatacount).value = json.getEventValue(userdatacount); + } + } + + private float bezierEvaluateBinarySearch(final CubismMotionPoint[] points, final float time) { + final float x_error = 0.01f; + + float x1 = points[0].time; + float x2 = points[3].time; + float cx1 = points[1].time; + float cx2 = points[2].time; + + float ta = 0.0f; + float tb = 1.0f; + float t = 0.0f; + int i = 0; + + for (boolean var33 = true; i < 20; ++i) { + if (time < x1 + x_error) { + t = ta; + break; + } + + if (x2 - x_error < time) { + t = tb; + break; + } + + float centerx = (cx1 + cx2) * 0.5f; + cx1 = (x1 + cx1) * 0.5f; + cx2 = (x2 + cx2) * 0.5f; + final float ctrlx12 = (cx1 + centerx) * 0.5f; + float ctrlx21 = (cx2 + centerx) * 0.5f; + centerx = (ctrlx12 + ctrlx21) * 0.5f; + if (time < centerx) { + tb = (ta + tb) * 0.5f; + if (centerx - x_error < time) { + t = tb; + break; + } + + x2 = centerx; + cx2 = ctrlx12; + } + else { + ta = (ta + tb) * 0.5f; + if (time < centerx + x_error) { + t = ta; + break; + } + + x1 = centerx; + cx1 = ctrlx21; + } + } + + if (i == 20) { + t = (ta + tb) * 0.5f; + } + + if (t < 0.0f) + { + t = 0.0f; + } + if (t > 1.0f) + { + t = 1.0f; + } + + final CubismMotionPoint p01 = lerpPoints(points[0], points[1], t); + final CubismMotionPoint p12 = lerpPoints(points[1], points[2], t); + final CubismMotionPoint p23 = lerpPoints(points[2], points[3], t); + + final CubismMotionPoint p012 = lerpPoints(p01, p12, t); + final CubismMotionPoint p123 = lerpPoints(p12, p23, t); + + return lerpPoints(p012, p123, t).value; + } + + private float correctEndPoint( + final CubismMotionData motionData, + final int segmentIndex, + final int beginIndex, + final int endIndex, + final float time, + final float endTime + ) { + ArrayList motionPoint = new ArrayList(2); + { + final CubismMotionPoint src = motionData.points.get(endIndex); + motionPoint.add(new CubismMotionPoint(src.time, src.value)); + } + { + final CubismMotionPoint src = motionData.points.get(beginIndex); + motionPoint.add(new CubismMotionPoint(src.time, src.value)); + } + motionPoint.get(1).time = endTime; + + switch (motionData.segments.get(segmentIndex).segmentType) { + case STEPPED: + return steppedEvaluator.evaluate(motionPoint, time); + case INVERSESTEPPED: + return inverseSteppedEvaluator.evaluate(motionPoint, time); + case LINEAR: + case BEZIER: + default: + return linearEvaluator.evaluate(motionPoint, time); + } + } + + private float evaluateCurve(final CubismMotionData motionData, final int index, float time, final boolean isCorrection, final float endTime) { + // Find segment to evaluate. + final CubismMotionCurve curve = motionData.curves.get(index); + + int target = -1; + final int totalSegmentCount = curve.baseSegmentIndex + curve.segmentCount; + int pointPosition = 0; + for (int i = curve.baseSegmentIndex; i < totalSegmentCount; ++i) { + // Get first point of next segment. + pointPosition = motionData.segments.get(i).basePointIndex + + (motionData.segments.get(i).segmentType == CubismMotionSegmentType.BEZIER + ? 3 + : 1); + + // Break if time lies within current segment. + if (motionData.points.get(pointPosition).time > time) { + target = i; + break; + } + } + + if (target == -1) { + if (isCorrection && time < endTime) { + // 終点から始点への補正処理 + return correctEndPoint( + motionData, + totalSegmentCount - 1, + motionData.segments.get(curve.baseSegmentIndex).basePointIndex, + pointPosition, + time, + endTime + ); + } + + return motionData.points.get(pointPosition).value; + } + + final CubismMotionSegment segment = motionData.segments.get(target); + + final List points = motionData.points.subList(segment.basePointIndex, motionData.points.size()); + return segment.evaluator.evaluate(points, time); + } + + /** + * FPS of the loaded file; if not specified, the default value is 30 fps. + */ + private float sourceFrameRate = 30.0f; + /** + * length of the sequence of motions defined in the motion3.json file. + */ + private float loopDurationSeconds = -1.0f; + + private MotionBehavior motionBehavior = MotionBehavior.MOTION_BEHAVIOR_V2; + + /** + * last set weight + */ + private float lastWeight; + /** + * actual motion data itself + */ + private CubismMotionData motionData; + /** + * list of parameter ID handles to which automatic eye blinking is applied. Corresponds to a model (model setting) and a parameter. + */ + private final List eyeBlinkParameterIds = new ArrayList(); + /** + * list of parameter ID handles to which lip-syncing is applied. Corresponds to a model (model setting) and a parameter. + */ + private final List lipSyncParameterIds = new ArrayList(); + + private final BitSet eyeBlinkFlags = new BitSet(eyeBlinkParameterIds.size()); + private final BitSet lipSyncFlags = new BitSet(lipSyncParameterIds.size()); + + /** + * handle to the parameter ID for automatic eye blinking that the model has. Map a model to a motion. + */ + private CubismId modelCurveIdEyeBlink; + /** + * handle to the parameter ID for lip-syncing that the model has. Map a model to a motion. + */ + private CubismId modelCurveIdLipSync; + /** + * handle to the parameter ID for opacity that the moder has. Map a model to a motion. + */ + private CubismId modelCurveIdOpacity; + + /** + * モーションから取得した不透明度 + */ + private float modelOpacity; + + + private final LinearEvaluator linearEvaluator = new LinearEvaluator(); + private final BezierEvaluator bezierEvaluator = new BezierEvaluator(); + private final BezierEvaluatorCardanoInterpretation bezierCardanoInterpretationEvaluator = new BezierEvaluatorCardanoInterpretation(); + private final SteppedEvaluator steppedEvaluator = new SteppedEvaluator(); + private final InverseSteppedEvaluator inverseSteppedEvaluator = new InverseSteppedEvaluator(); +} + diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionInternal.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionInternal.java new file mode 100644 index 0000000..24e03df --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionInternal.java @@ -0,0 +1,190 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.id.CubismId; + +import java.util.ArrayList; +import java.util.List; + +/** + * Internal data used by the CubismMotion class. + */ +class CubismMotionInternal { + /** + * Type of motion curve. + */ + public enum CubismMotionCurveTarget { + /** + * motion curve for the model + */ + MODEL, + /** + * motion curve for parameters + */ + PARAMETER, + /** + * motion curve for part opacity + */ + PART_OPACITY + } + + /** + * Type of motion curve segment. + */ + public enum CubismMotionSegmentType { + /** + * linear + */ + LINEAR, + /** + * bezier curve + */ + BEZIER, + /** + * step + */ + STEPPED, + /** + * inverse step + */ + INVERSESTEPPED + } + + /** + * Motion curve control points. + */ + public static class CubismMotionPoint { + /** + * time[s] + */ + public float time; + /** + * value + */ + public float value; + + public CubismMotionPoint() {} + + public CubismMotionPoint(final float time, final float value) { + this.time = time; + this.value = value; + } + } + + /** + * Segment of motion curve. + */ + public static class CubismMotionSegment { + /** + * used evaluation function + */ + public CsmMotionSegmentEvaluationFunction evaluator; + /** + * index to the first segment + */ + public int basePointIndex; + /** + * type of segment + */ + public CubismMotionSegmentType segmentType = CubismMotionSegmentType.LINEAR; + } + + /** + * Motion curve + */ + public static class CubismMotionCurve { + /** + * type of curve + */ + public CubismMotionCurveTarget type = CubismMotionCurveTarget.MODEL; + /** + * curve ID + */ + public CubismId id; + /** + * number of segments + */ + public int segmentCount; + /** + * index to the first segment + */ + public int baseSegmentIndex; + /** + * time for fade-in[s] + */ + public float fadeInTime; + /** + * time for fade-out[s] + */ + public float fadeOutTime; + } + + /** + * Motion event + */ + public static class CubismMotionEvent { + /** + * duration of event + */ + public float fireTime; + /** + * value + */ + public String value; + } + + /** + * Motion data + */ + public static class CubismMotionData { + /** + * motion duration + */ + public float duration; + /** + * Whether the motion loops + */ + public boolean isLooped; + /** + * number of curves + */ + public int curveCount; + /** + * number of UserData + */ + public int eventCount; + /** + * framerate per second + */ + public float fps; + /** + * list of curves + */ + public List curves = new ArrayList(); + /** + * list of segments + */ + public List segments = new ArrayList(); + /** + * list of points + */ + public List points = new ArrayList(); + /** + * list of events + */ + public List events = new ArrayList(); + } + + /** + * For strategy pattern. + */ + public interface CsmMotionSegmentEvaluationFunction { + float evaluate(final List points, final float time); + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionJson.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionJson.java new file mode 100644 index 0000000..ee84820 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionJson.java @@ -0,0 +1,382 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.motion.CubismMotionInternal.CubismMotionSegmentType; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; + +/** + * Container for motion3.json. + */ +public class CubismMotionJson { + /** + * Flag type of Bezier curve interpretation method + */ + public enum EvaluationOptionFlag { + /** + * Regulatory status of Bezier handle. + */ + ARE_BEZIERS_RESTRICTED + } + + public CubismMotionJson(byte[] buffer) { + CubismJson json; + json = CubismJson.create(buffer); + + this.json = json; + } + + /** + * Get the duration of the motion. + * + * @return motion duration[s] + */ + public float getMotionDuration() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.DURATION.key).toFloat(); + } + + /** + * Whether the motion loops. + * + * @return If the motion loops, return true. + */ + public boolean isMotionLoop() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.LOOP.key).toBoolean(); + } + + /** + * Returns the consistency of the motion3.json file. + * + * @return true if the file is consistent; otherwise returns false. + */ + public boolean hasConsistency() { + boolean result = true; + + final int actualCurveListSize = json.getRoot().get(JsonKey.CURVES.key).getList().size(); + int actualTotalSegmentCount = 0; + int actualTotalPointCount = 0; + + // Counting. + for (int curvePosition = 0; curvePosition < actualCurveListSize; ++curvePosition) { + for (int segmentPosition = 0; segmentPosition < getMotionCurveSegmentCount(curvePosition);) { + + if (segmentPosition == 0) { + actualTotalPointCount += 1; + segmentPosition += 2; + } + + final CubismMotionSegmentType segment = getMotionCurveSegmentType(curvePosition, segmentPosition); + + switch (segment) { + case LINEAR: + actualTotalPointCount += 1; + segmentPosition += 3; + break; + case BEZIER: + actualTotalPointCount += 3; + segmentPosition += 7; + break; + case STEPPED: + actualTotalPointCount += 1; + segmentPosition += 3; + break; + case INVERSESTEPPED: + actualTotalPointCount += 1; + segmentPosition += 3; + break; + default: + assert(false); + break; + } + + ++actualTotalSegmentCount; + } + } + + // Check that the counts match the metadata. + if (actualCurveListSize != getMotionCurveCount()) { + CubismDebug.cubismLogWarning("The number of curves does not match the metadata."); + result = false; + } + if (actualTotalSegmentCount != getMotionTotalSegmentCount()) { + CubismDebug.cubismLogWarning("The number of segment does not match the metadata."); + result = false; + } + if (actualTotalPointCount != getMotionTotalPointCount()) { + CubismDebug.cubismLogWarning("The number of point does not match the metadata."); + result = false; + } + + return result; + } + + /** + * Get the state of the interpretation flag of Bezier curve handles in motion. + * + * @param flagType the flag type specified by EvaluationOptionFlag. + * @return If the flag is present, return true. + */ + public boolean getEvaluationOptionFlag(EvaluationOptionFlag flagType) { + if (EvaluationOptionFlag.ARE_BEZIERS_RESTRICTED == flagType) { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.ARE_BEZIERS_RESTRICTED.key).toBoolean(); + } + return false; + } + + /** + * Get the number of the motion curves. + * + * @return number of motion curve + */ + public int getMotionCurveCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.CURVE_COUNT.key).toInt(); + } + + /** + * Get the framerate of the motion. + * + * @return framerate[FPS] + */ + public float getMotionFps() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.FPS.key).toFloat(); + } + + /** + * Get the total number of motion segments. + * + * @return total number of motion segments + */ + public int getMotionTotalSegmentCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.TOTAL_SEGMENT_COUNT.key).toInt(); + } + + /** + * Get the total number of control points for the curve of the motion. + * + * @return total number of control points for the curve of the motion + */ + public int getMotionTotalPointCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.TOTAL_POINT_COUNT.key).toInt(); + } + + /** + * Whether a fade-in time is set for the motion. + * + * @return If motion fade-in time is set, return true. + */ + public boolean existsMotionFadeInTime() { + return !json.getRoot().get(JsonKey.META.key).get(JsonKey.FADE_IN_TIME.key).isNull(); + } + + /** + * Whether a fade-out time is set for the motion. + * + * @return If motion fade-out time is set, return true. + */ + public boolean existsMotionFadeOutTime() { + return !json.getRoot().get(JsonKey.META.key).get(JsonKey.FADE_OUT_TIME.key).isNull(); + } + + /** + * Get the motion fade-in duration. + * + * @return fade-in duration[s] + */ + public float getMotionFadeInTime() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.FADE_IN_TIME.key).toFloat(); + } + + /** + * Get the motion fade-out duration. + * + * @return fade-out duration[s] + */ + public float getMotionFadeOutTime() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.FADE_OUT_TIME.key).toFloat(); + } + + /** + * Get the type of motion curve. + * + * @param curveIndex index of curve + * @return type of motion curve + */ + public String getMotionCurveTarget(int curveIndex) { + return json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.TARGET.key).getString(); + } + + /** + * Get ID of motion curve. + * + * @param curveIndex index of curve + * @return curve ID + */ + public CubismId getMotionCurveId(int curveIndex) { + return CubismFramework.getIdManager().getId(json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.ID.key).getString()); + } + + /** + * Whether the fade-in duration is set for the motion's curve. + * + * @param curveIndex index of curve + * @return If fade-in duration is set, return true. + */ + public boolean existsMotionCurveFadeInTime(int curveIndex) { + return !json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.FADE_IN_TIME.key).isNull(); + } + + /** + * Whether the fade-out duration is set for the motion's curve. + * + * @param curveIndex index of curve + * @return If fade-out duration is set, return true. + */ + public boolean existsMotionCurveFadeOutTime(int curveIndex) { + return !json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.FADE_OUT_TIME.key).isNull(); + } + + /** + * Get the fade-in duration of the motion curve. + * + * @param curveIndex index of curve + * @return fade-in duration[s] + */ + public float getMotionCurveFadeInTime(int curveIndex) { + return json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.FADE_IN_TIME.key).toFloat(); + } + + /** + * Get the fade-out duration of the motion curve. + * + * @param curveIndex index of curve + * @return fade-out duration[s] + */ + public float getMotionCurveFadeOutTime(int curveIndex) { + return json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.FADE_OUT_TIME.key).toFloat(); + } + + /** + * Get the number of segments in the curve of the motion. + * + * @param curveIndex index of curve + * @return number of segments in the curve of the motion + */ + public int getMotionCurveSegmentCount(int curveIndex) { + return json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.SEGMENTS.key).getList().size(); + } + + /** + * Get the value of a segment of a motion curve. + * + * @param curveIndex index of curve + * @param segmentIndex index of segment + * @return value of segment + */ + public float getMotionCurveSegment(int curveIndex, int segmentIndex) { + return json.getRoot().get(JsonKey.CURVES.key).get(curveIndex).get(JsonKey.SEGMENTS.key).get(segmentIndex).toFloat(); + } + + /** + * Get the type of a segment of a motion curve. + * + * @param curveIndex index of curve + * @param segmentIndex index of segment + * @return the type of segment + */ + public CubismMotionSegmentType getMotionCurveSegmentType(final int curveIndex, final int segmentIndex) { + final int segmentTypeValue = (int) (getMotionCurveSegment(curveIndex, segmentIndex)); + + switch (segmentTypeValue) { + case 0: + return CubismMotionSegmentType.LINEAR; + case 1: + return CubismMotionSegmentType.BEZIER; + case 2: + return CubismMotionSegmentType.STEPPED; + case 3: + return CubismMotionSegmentType.INVERSESTEPPED; + default: + assert (false); + return null; + } + } + + /** + * Get the number of events. + * + * @return number of events + */ + public int getEventCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.USER_DATA_COUNT.key).toInt(); + } + + /** + * Get the total number of characters in the event. + * + * @return total number of characters in the event + */ + public int getTotalEventValueSize() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.TOTAL_USER_DATA_SIZE.key).toInt(); + } + + /** + * Get the event duration. + * + * @param userDataIndex index of events + * @return event duration[s] + */ + public float getEventTime(int userDataIndex) { + return json.getRoot().get(JsonKey.USER_DATA.key).get(userDataIndex).get(JsonKey.TIME.key).toFloat(); + } + + /** + * Get the event string. + * + * @param userDataIndex index of event + * @return event strings + */ + public String getEventValue(int userDataIndex) { + return json.getRoot().get(JsonKey.USER_DATA.key).get(userDataIndex).get(JsonKey.VALUE.key).getString(); + } + + private enum JsonKey { + META("Meta"), + DURATION("Duration"), + LOOP("Loop"), + ARE_BEZIERS_RESTRICTED("AreBeziersRestricted"), + CURVE_COUNT("CurveCount"), + FPS("Fps"), + TOTAL_SEGMENT_COUNT("TotalSegmentCount"), + TOTAL_POINT_COUNT("TotalPointCount"), + CURVES("Curves"), + TARGET("Target"), + ID("Id"), + FADE_IN_TIME("FadeInTime"), + FADE_OUT_TIME("FadeOutTime"), + SEGMENTS("Segments"), + USER_DATA("UserData"), + USER_DATA_COUNT("UserDataCount"), + TOTAL_USER_DATA_SIZE("TotalUserDataSize"), + TIME("Time"), + VALUE("Value"); + + private final String key; + + JsonKey(String key) { + this.key = key; + } + } + + /** + * motion3.json data + */ + private final CubismJson json; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionManager.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionManager.java new file mode 100644 index 0000000..ac34fb4 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionManager.java @@ -0,0 +1,107 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.model.CubismModel; + +/** + * Class for managing motion playback, used to play ACubismMotion subclasses such as CubismMotion motion. + * * If another motion do startMotion() during playback, it will smoothly change to the new motion and the old motion will be suspended. + * * Use multiple CubismMotionManager instances to play multiple motions at the same time, such as when motions for facial expressions and body motions are made separately. + */ +public class CubismMotionManager extends CubismMotionQueueManager { + /** + * Set a priority and start the motion. + * + * @param motion motion instance + * @param priority priority of motion + * @return Returns the identification number(OptionalInt) of the motion that has started. Used as an argument for isFinished(), which judges whether an individual motion has been completed. When it cannot be started, it returns an empty OptionalInt. + */ + public int startMotionPriority(ACubismMotion motion, int priority) { + if (priority == reservationPriority) { + reservationPriority = 0; // Cancel the reservation. + } + + // Set priority of the motion during playback. + currentPriority = priority; + + return startMotion(motion); + } + + /** + * Update the motion and reflect the parameter values to the model. + * + * @param model target model + * @param deltaTimeSeconds delta time[s] + * @return If it is updated, return true. + */ + public boolean updateMotion(CubismModel model, float deltaTimeSeconds) { + userTimeSeconds += deltaTimeSeconds; + + final boolean isUpdated = doUpdateMotion(model, userTimeSeconds); + + if (isFinished()) { + currentPriority = 0; // 再生中モーションの優先度を解除 + } + return isUpdated; + } + + /** + * Get the priority of the motion being played now. + * + * @return priority of the motion + */ + public int getCurrentPriority() { + return currentPriority; + } + + /** + * Get the priority of the reserved motion. + * + * @return priority of the motion + */ + public int getReservationPriority() { + return reservationPriority; + } + + /** + * Set the priority to the reserved motion. + * + * @param priority motion's priority + */ + public void setReservationPriority(int priority) { + reservationPriority = priority; + } + + /** + * Reserve motion with a priority. + *

+ * If the given priority is lower than the already existing reserved priority and the priority of the current motion, it is not reserved and "false" is returned. + *

+ * + * @param priority motion's priority + * @return If reserving the motion is successful, return true. + */ + public boolean reserveMotion(int priority) { + if (priority <= reservationPriority || priority <= currentPriority) { + return false; + } + reservationPriority = priority; + + return true; + } + + /** + * Priority of the currently playing motion. + */ + private int currentPriority; + /** + * Priority of the motion to be played. The value becomes 0 during playback. This is function for loading motion files in a separate thread. + */ + private int reservationPriority; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionQueueEntry.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionQueueEntry.java new file mode 100644 index 0000000..8d1d1e6 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionQueueEntry.java @@ -0,0 +1,288 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +/** + * Manager class for each motion being played by CubismMotionQueueManager. + */ +public class CubismMotionQueueEntry { + /** + * Get the motion. + * + * @return motion instance + */ + public ACubismMotion getMotion() { + return motion; + } + + /** + * Set a motion instance. + * + * @param motion motion instance + */ + public void setMotion(ACubismMotion motion) { + this.motion = motion; + } + + + /** + * Set the fade-out to the start state. + * + * @param fadeOutSeconds time it takes to fade out[s] + */ + public void setFadeOut(float fadeOutSeconds) { + this.fadeOutSeconds = fadeOutSeconds; + isTriggeredFadeOut = true; + } + + /** + * Start fade-out. + * + * @param fadeOutSeconds time it takes to fade out[s] + * @param userTimeSeconds total delta time[s] + */ + public void startFadeOut(float fadeOutSeconds, float userTimeSeconds) { + final float newEndTimeSeconds = userTimeSeconds + fadeOutSeconds; + isTriggeredFadeOut = true; + + if (endTimeSeconds < 0.0f || newEndTimeSeconds < endTimeSeconds) { + endTimeSeconds = newEndTimeSeconds; + } + } + + /** + * Get the start time of the motion. + * + * @return start time of the motion[s] + */ + public float getStartTime() { + return startTimeSeconds; + } + + /** + * Set the start time of the motion. + * + * @param startTime start time of the motion[s] + */ + public void setStartTime(float startTime) { + startTimeSeconds = startTime; + } + + /** + * Get the start time of the fade-in. + * + * @return start time of the fade-in[s] + */ + public float getFadeInStartTime() { + return fadeInStartTimeSeconds; + } + + /** + * Set the start time of fade-in. + * + * @param startTime start time of fade-in[s] + */ + public void setFadeInStartTime(float startTime) { + fadeInStartTimeSeconds = startTime; + } + + /** + * Get the end time of the fade-in. + * + * @return end time of the fade-in + */ + public float getEndTime() { + return endTimeSeconds; + } + + /** + * Set end time of the motion. + * + * @param endTime end time of the motion[s] + */ + public void setEndTime(float endTime) { + endTimeSeconds = endTime; + } + + /** + * Whether the motion is finished. + * + * @return If the motion is finished, return true. + */ + public boolean isFinished() { + return finished; + } + + /** + * Set end state of the motion. + * + * @param isMotionFinished If true, set the motion to the end state. + */ + public void isFinished(boolean isMotionFinished) { + finished = isMotionFinished; + } + + /** + * Whether the motion is started. + * + * @return If the motion is started, return true. + */ + public boolean isStarted() { + return started; + } + + /** + * Set start state of the motion. + * + * @param isMotionStarted If true, set the motion to the start state. + */ + public void isStarted(boolean isMotionStarted) { + started = isMotionStarted; + } + + /** + * Get the status of the motion.(Enable/Disable) + * + * @return If the motion is valid, return true. + */ + public boolean isAvailable() { + return available; + } + + /** + * Set the status of the motion.(Enable/Disable) + * + * @param isMotionAvailable If it is true, the motion is enabled. + */ + public void isAvailable(boolean isMotionAvailable) { + available = isMotionAvailable; + } + + /** + * Set the state of the motion. + * + * @param timeSeconds current time[s] + * @param weight weight of motion + */ + public void setState(float timeSeconds, float weight) { + stateTimeSeconds = timeSeconds; + stateWeight = weight; + } + + /** + * Get the current time of the motion. + * + * @return current time of the motion. + */ + public float getStateTime() { + return stateTimeSeconds; + } + + /** + * Get the weight of the motion. + * + * @return weight of the motion + */ + public float getStateWeight() { + return stateWeight; + } + + /** + * Get the time when the last event firing was checked. + * + * @return time when the last event firing was checked[s] + */ + public float getLastCheckEventTime() { + return lastEventCheckSeconds; + } + + /** + * Set the time when the last event firing was checked. + * + * @param checkTime time when the last event firing was checked[s] + */ + public void setLastCheckEventTime(float checkTime) { + lastEventCheckSeconds = checkTime; + } + + /** + * Get the starting status of the fade-out. + * + * @return Whether fade out is started + */ + public boolean isTriggeredFadeOut() { + return isTriggeredFadeOut; + } + + /** + * Get fade-out duration. + * + * @return fade-out duration + */ + public float getFadeOutSeconds() { + return fadeOutSeconds; + } + + /** + * ACubismMotionを継承したクラスのインスタンスを取得する。 + * + * @return モーションのインスタンス + */ + public ACubismMotion getCubismMotion() { + return motion; + } + + /** + * motion + */ + private ACubismMotion motion; + /** + * Enable flag + */ + private boolean available = true; + /** + * finished flag + */ + private boolean finished; + /** + * start flag(0.9.00 or later) + */ + private boolean started; + /** + * Motion playback start time[s] + */ + private float startTimeSeconds = -1.0f; + /** + * Fade-in start time[s] (When in a loop, only the first time.) + */ + private float fadeInStartTimeSeconds; + /** + * Scheduled end time[s] + */ + private float endTimeSeconds = -1.0f; + /** + * state of time[s] + */ + private float stateTimeSeconds; + /** + * state of weight + */ + private float stateWeight; + /** + * last event check time + */ + private float lastEventCheckSeconds; + /** + * fade-out duration of the motion[s] + */ + private float fadeOutSeconds; + /** + * Whether the motion fade-out is started + */ + private boolean isTriggeredFadeOut; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionQueueManager.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionQueueManager.java new file mode 100644 index 0000000..92af666 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/CubismMotionQueueManager.java @@ -0,0 +1,259 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +import com.live2d.sdk.cubism.framework.model.CubismModel; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * The manager class for playing motions. This is used to play ACubismMotion's subclasses such as CubismMotion's motion. + *

+ * If another motion is done "StartMotion()" during playback, the motion changes smoothly to the new motion and the old motion is interrupted. When multiple motions are played back simultaneously (For example, separate motions for facial expressions, body motions, etc.), multiple CubismMotionQueueManager instances are used. + */ +public class CubismMotionQueueManager { + /** + * 引数で指定したモーションを再生する。同じタイプのモーションが既にある場合は、既存のモーションに終了フラグを立て、フェードアウトを開始する。 + * + * @param motion 開始するモーション + * @return 開始したモーションの識別番号を返す。個別のモーションが終了したか否かを判定するisFinished()の引数として使用する。開始できない場合は「-1」を返す。 + */ + public int startMotion(ACubismMotion motion) { + if (motion == null) { + return -1; + } + + // 既にモーションがあれば終了フラグを立てる。 + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry entry = motions.get(i); + + if (entry == null) { + continue; + } + entry.setFadeOut(entry.getMotion().getFadeOutTime()); + } + + CubismMotionQueueEntry motionQueueEntry = new CubismMotionQueueEntry(); + motionQueueEntry.setMotion(motion); + + motions.add(motionQueueEntry); + + if (motion.onBeganMotion != null) { + motion.onBeganMotion.execute(motion); + } + + return System.identityHashCode(motionQueueEntry); + } + + /** + * Start the specified motion. If there is already a motion of the same type, set the end flag for the existing motion and start fading out. + * + * @param motion motion to start + * @param userTimeSeconds total user time[s] + * @return Returns the identification number(OptionalInt) of the motion that has started. Used as an argument for isFinished(), which judges whether an individual motion has been completed. When it cannot be started, it returns an empty OptionalInt. + * + * @deprecated 第2引数userTimeSecondsを関数内で使用していないため非推奨。startMotion(ACubismMotion motion)を使用してください。 + * @see #startMotion(ACubismMotion) + */ + @Deprecated + public int startMotion(ACubismMotion motion, float userTimeSeconds) { + if (motion == null) { + return -1; + } + + // If there is already motion, flag it as finished. + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry entry = motions.get(i); + + if (entry == null) { + continue; + } + entry.setFadeOut(entry.getMotion().getFadeOutTime()); + } + + CubismMotionQueueEntry motionQueueEntry = new CubismMotionQueueEntry(); + motionQueueEntry.setMotion(motion); + + motions.add(motionQueueEntry); + + return System.identityHashCode(motionQueueEntry); + } + + public boolean isFinished() { + // ---- Do processing ---- + // If there is already a motion, flag it as finished. + + // At first, remove the null elements from motions list. + motions.removeAll(nullSet); + + // motionがnullならば要素をnullとする + // 後でnull要素を全て削除する。 + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry motionQueueEntry = motions.get(i); + ACubismMotion motion = motionQueueEntry.getMotion(); + + if (motion == null) { + motions.set(i, null); + continue; + } + + if (!motionQueueEntry.isFinished()) { + return false; + } + } + + motions.removeAll(nullSet); + + return true; + } + + public boolean isFinished(int motionQueueEntryNumber) { + // ---- Do processing ---- + // If there is already a motion, flag it as finished. + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry motionQueueEntry = motions.get(i); + + if (motionQueueEntry == null) { + continue; + } + + if (System.identityHashCode(motionQueueEntry) == motionQueueEntryNumber && !motionQueueEntry.isFinished()) { + return false; + } + } + return true; + } + + /** + * Stop all motions. + */ + public void stopAllMotions() { + motions.clear(); + } + + /** + * Get the specified CubismMotionQueueEntry instance. + * + * @param motionQueueEntryNumber identification number of the motion + * @return specified CubismMotionQueueEntry object. If not found, empty Optional is returned. + */ + public CubismMotionQueueEntry getCubismMotionQueueEntry(int motionQueueEntryNumber) { + // ---- Do processing ---- + // If there is already a motion, flag it as finished. + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry motionQueueEntry = motions.get(i); + + if (motionQueueEntry == null) { + continue; + } + + if (System.identityHashCode(motionQueueEntry) == motionQueueEntryNumber) { + return motionQueueEntry; + } + } + return null; + } + + /** + * CubismMotionQueueEntryのリストを取得する。 + * + * @return CubismMotionQueueEntryのリスト + */ + public List getCubismMotionQueueEntries() { + return motions; + } + + /** + * Register the callback function to receive events. + * + * @param callback callback function + * @param customData data to be given to callback + */ + public void setEventCallback(ICubismMotionEventFunction callback, Object customData) { + eventCallback = callback; + eventCustomData = customData; + } + + /** + * Update the motion and reflect the parameter values to the model. + * + * @param model target model + * @param userTimeSeconds total delta time[s] + * @return If reflecting the parameter value to the model(the motion is changed.) is successed, return true. + */ + protected boolean doUpdateMotion(CubismModel model, float userTimeSeconds) { + boolean isUpdated = false; + + // ---- Do processing ---- + // If there is already a motion, flag it as finished. + + // At first, remove the null elements from motions list. + motions.removeAll(nullSet); + + for (int i = 0; i < motions.size(); i++) { + CubismMotionQueueEntry motionQueueEntry = motions.get(i); + ACubismMotion motion = motionQueueEntry.getMotion(); + + if (motion == null) { + motions.set(i, null); + continue; + } + + motion.updateParameters(model, motionQueueEntry, userTimeSeconds); + isUpdated = true; + + // Inspect user-triggered events. + final List firedList = motion.getFiredEvent( + motionQueueEntry.getLastCheckEventTime() - motionQueueEntry.getStartTime(), + userTimeSeconds - motionQueueEntry.getStartTime()); + + for (int j = 0; j < firedList.size(); j++) { + String event = firedList.get(j); + eventCallback.apply(this, event, eventCustomData); + } + motionQueueEntry.setLastCheckEventTime(userTimeSeconds); + + // If any processes have already been finished, delete them. + if (motionQueueEntry.isFinished()) { + motions.set(i, null); + } else { + if (motionQueueEntry.isTriggeredFadeOut()) { + motionQueueEntry.startFadeOut(motionQueueEntry.getFadeOutSeconds(), userTimeSeconds); + } + } + } + + motions.removeAll(nullSet); + + return isUpdated; + } + + /** + * total delta time[s] + */ + protected float userTimeSeconds; + + /** + * List of motions + */ + private final List motions = new ArrayList(); + /** + * Callback function + */ + private ICubismMotionEventFunction eventCallback; + /** + * Data to be given to the callback + */ + private Object eventCustomData; + + // nullが格納されたSet. null要素だけListから排除する際に使用される。 + private final Set nullSet = Collections.singleton(null); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/IBeganMotionCallback.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/IBeganMotionCallback.java new file mode 100644 index 0000000..7afe600 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/IBeganMotionCallback.java @@ -0,0 +1,15 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +/** + * モーション再生開始コールバック + */ +public interface IBeganMotionCallback { + void execute(ACubismMotion motion); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/ICubismMotionEventFunction.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/ICubismMotionEventFunction.java new file mode 100644 index 0000000..6dedd6a --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/ICubismMotionEventFunction.java @@ -0,0 +1,16 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +public interface ICubismMotionEventFunction { + void apply( + CubismMotionQueueManager caller, + String eventValue, + Object customData + ); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/IFinishedMotionCallback.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/IFinishedMotionCallback.java new file mode 100644 index 0000000..9c6056f --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/IFinishedMotionCallback.java @@ -0,0 +1,15 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.motion; + +/** + * モーション再生終了コールバック + */ +public interface IFinishedMotionCallback { + void execute(ACubismMotion motion); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/package-info.java new file mode 100644 index 0000000..1a24bf3 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/motion/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide various functions (motion playback, parameter blending) for applying motion data to models. + */ +package com.live2d.sdk.cubism.framework.motion; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysics.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysics.java new file mode 100644 index 0000000..e743b2b --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysics.java @@ -0,0 +1,1012 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.physics; + +import com.live2d.sdk.cubism.framework.math.CubismMath; +import com.live2d.sdk.cubism.framework.math.CubismVector2; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.physics.CubismPhysicsFunctions.*; +import com.live2d.sdk.cubism.framework.physics.CubismPhysicsInternal.*; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Physics operation class. + */ +public class CubismPhysics { + /** + * Options of physics operation + */ + public static class Options { + /** + * Constructor + */ + public Options() { + gravity = new CubismVector2(); + wind = new CubismVector2(); + } + + /** + * Copy constructor. + * + * @param options Options instace + */ + public Options(Options options) { + this.gravity = new CubismVector2(options.gravity); + this.wind = new CubismVector2(options.wind); + } + + /** + * Gravity + */ + public final CubismVector2 gravity; + /** + * Wind + */ + public final CubismVector2 wind; + } + + /** + * Output result of physics operations before applying to parameters + */ + public static class PhysicsOutput { + float[] outputs; + } + + /** + * Create an CubismPhysics instance. + * + * @param buffer the buffer where physics3.json is loaded. + * @return the created instance + */ + public static CubismPhysics create(byte[] buffer) { + final CubismPhysics physics = new CubismPhysics(); + physics.parse(buffer); + physics.physicsRig.gravity.y = 0; + + return physics; + } + + /** + * Reset parameters. + */ + public void reset() { + options.gravity.set(0.0f, -1.0f); + options.wind.setZero(); + + physicsRig.gravity.setZero(); + physicsRig.wind.setZero(); + + initialize(); + } + + /** + * 現在のパラメータ値で物理演算が安定化する状態を演算する。 + * + * @param model 物理演算の結果を適用するモデル + */ + public void stabilization(CubismModel model) { + float[] totalAngle = new float[1]; + float weight; + float radAngle; + float outputValue; + CubismVector2 totalTranslation = new CubismVector2(); + int i, settingIndex, particleIndex; + CubismPhysicsSubRig currentSetting; + + float[] parameterValues = model.getModel().getParameters().getValues(); + float[] parameterMaximumValues = model.getModel().getParameters().getMaximumValues(); + float[] parameterMinimumValues = model.getModel().getParameters().getMinimumValues(); + float[] parameterDefaultValues = model.getModel().getParameters().getDefaultValues(); + + if (parameterCaches.length < model.getParameterCount()) { + parameterCaches = new float[model.getParameterCount()]; + } + if (parameterInputCaches.length < model.getParameterCount()) { + parameterInputCaches = new float[model.getParameterCount()]; + } + + for (int j = 0; j < model.getParameterCount(); j++) { + parameterCaches[j] = parameterValues[j]; + parameterInputCaches[j] = parameterValues[j]; + } + + for (settingIndex = 0; settingIndex < physicsRig.subRigCount; settingIndex++) { + totalAngle[0] = 0.0f; + totalTranslation.setZero(); + + currentSetting = physicsRig.settings.get(settingIndex); + int baseInputIndex = currentSetting.baseInputIndex; + int baseOutputIndex = currentSetting.baseOutputIndex; + int baseParticleIndex = currentSetting.baseParticleIndex; + + // Load input parameters. + for (i = 0; i < currentSetting.inputCount; i++) { + CubismPhysicsInput currentInput = physicsRig.inputs.get(baseInputIndex + i); + + weight = currentInput.weight / MAXIMUM_WEIGHT; + + if (currentInput.sourceParameterIndex == -1) { + currentInput.sourceParameterIndex = model.getParameterIndex(currentInput.source.Id); + } + + currentInput.getNormalizedParameterValue.getNormalizedParameterValue( + totalTranslation, + totalAngle, + parameterValues[currentInput.sourceParameterIndex], + parameterMinimumValues[currentInput.sourceParameterIndex], + parameterMaximumValues[currentInput.sourceParameterIndex], + parameterDefaultValues[currentInput.sourceParameterIndex], + currentSetting.normalizationPosition, + currentSetting.normalizationAngle, + currentInput.reflect, + weight + ); + + parameterCaches[currentInput.sourceParameterIndex] = parameterValues[currentInput.sourceParameterIndex]; + } + + radAngle = CubismMath.degreesToRadian(-totalAngle[0]); + + totalTranslation.x = (totalTranslation.x * CubismMath.cosF(radAngle) - totalTranslation.y * CubismMath.sinF(radAngle)); + totalTranslation.y = (totalTranslation.x * CubismMath.sinF(radAngle) + totalTranslation.y * CubismMath.cosF(radAngle)); + + // Calculate particles position. + updateParticlesForStabilization( + physicsRig.particles, + baseParticleIndex, + currentSetting.particleCount, + totalTranslation, + totalAngle[0], + options.wind, + MOVEMENT_THRESHOLD * currentSetting.normalizationPosition.maximumValue + ); + + // Update output parameters. + for (i = 0; i < currentSetting.outputCount; i++) { + CubismPhysicsOutput currentOutput = physicsRig.outputs.get(baseOutputIndex + i); + + particleIndex = currentOutput.vertexIndex; + + if (currentOutput.destinationParameterIndex == -1) { + currentOutput.destinationParameterIndex = model.getParameterIndex(currentOutput.destination.Id); + } + + if (particleIndex < 1 || particleIndex >= currentSetting.particleCount) { + continue; + } + + CubismVector2 translation = new CubismVector2(); + CubismVector2.subtract(physicsRig.particles.get(baseParticleIndex + particleIndex).position, physicsRig.particles.get(baseParticleIndex + particleIndex - 1).position, translation); + + outputValue = currentOutput.getValue.getValue( + translation, + physicsRig.particles, + physicsRig.settings.get(i).baseParticleIndex, + particleIndex, + currentOutput.reflect, + options.gravity + ); + + currentRigOutputs.get(settingIndex).outputs[i] = outputValue; + previousRigOutputs.get(settingIndex).outputs[i] = outputValue; + + updateOutputParameterValue( + parameterValues, + currentOutput.destinationParameterIndex, + parameterMinimumValues[currentOutput.destinationParameterIndex], + parameterMaximumValues[currentOutput.destinationParameterIndex], + outputValue, + currentOutput + ); + + parameterCaches[currentOutput.destinationParameterIndex] = parameterValues[currentOutput.destinationParameterIndex]; + } + } + } + + /** + * Evaluate a physics operation. + *

+ * Pendulum interpolation weights + *

+ * 振り子の計算結果は保存され、パラメータへの出力は保存された前回の結果で補間されます。 + * The result of the pendulum calculation is saved and + * the output to the parameters is interpolated with the saved previous result of the pendulum calculation. + *

+ * 図で示すと[1]と[2]で補間されます。 + * The figure shows the interpolation between [1] and [2]. + *

+ * 補間の重みは最新の振り子計算タイミングと次回のタイミングの間で見た現在時間で決定する。 + * The weight of the interpolation are determined by the current time seen between + * the latest pendulum calculation timing and the next timing. + *

+ * 図で示すと[2]と[4]の間でみた(3)の位置の重みになる。 + * Figure shows the weight of position (3) as seen between [2] and [4]. + *

+ * 解釈として振り子計算のタイミングと重み計算のタイミングがズレる。 + * As an interpretation, the pendulum calculation and weights are misaligned. + *

+ * physics3.jsonにFPS情報が存在しない場合は常に前の振り子状態で設定される。 + * If there is no FPS information in physics3.json, it is always set in the previous pendulum state. + *

+ * この仕様は補間範囲を逸脱したことが原因の震えたような見た目を回避を目的にしている。 + * The purpose of this specification is to avoid the quivering appearance caused by deviations from the interpolation range. + *

+ * {@literal ------------ time -------------->} + *

+ * {@literal         |+++++|------| <- weight} + * ==[1]====#=====[2]---(3)----(4) + * ^ output contents + *

+ * 1:_previousRigOutputs + * 2:_currentRigOutputs + * 3:_currentRemainTime (now rendering) + * 4:next particles timing + * + * @param model Model to which the results of physics operation are applied + * @param deltaTimeSeconds rendering delta time[s] + */ + public void evaluate(CubismModel model, float deltaTimeSeconds) { + float weight; + float radAngle; + float outputValue; + int i, settingIndex, particleIndex; + List inputs = physicsRig.inputs; + List outputs = physicsRig.outputs; + + if (0.0f >= deltaTimeSeconds) { + return; + } + + float physicsDeltaTime; + currentRemainTime += deltaTimeSeconds; + if (currentRemainTime > MAX_DELTA_TIME) { + currentRemainTime = 0.0f; + } + + float[] parameterValues = model.getModel().getParameters().getValues(); + final float[] parameterMaximumValues = model.getModel().getParameters().getMaximumValues(); + final float[] parameterMinimumValues = model.getModel().getParameters().getMinimumValues(); + final float[] parameterDefaultValues = model.getModel().getParameters().getDefaultValues(); + + if (parameterCaches.length < model.getParameterCount()) { + parameterCaches = new float[model.getParameterCount()]; + } + + if (parameterInputCaches.length < model.getParameterCount()) { + parameterInputCaches = new float[model.getParameterCount()]; + if (model.getParameterCount() >= 0) + System.arraycopy(parameterValues, 0, parameterInputCaches, 0, model.getParameterCount()); + } + + if (physicsRig.fps > 0.0f) { + physicsDeltaTime = 1.0f / physicsRig.fps; + } else { + physicsDeltaTime = deltaTimeSeconds; + } + + CubismPhysicsSubRig currentSetting; + CubismPhysicsInput currentInput; + CubismPhysicsOutput currentOutput; + CubismPhysicsParticle currentParticle; + + while (currentRemainTime >= physicsDeltaTime) { + // copy RigOutputs: _currentRigOutputs to _previousRigOutputs + for (settingIndex = 0; settingIndex < physicsRig.subRigCount; settingIndex++) { + currentSetting = physicsRig.settings.get(settingIndex); + + for (i = 0; i < currentSetting.outputCount; i++) { + previousRigOutputs.get(settingIndex).outputs[i] = currentRigOutputs.get(settingIndex).outputs[i]; + } + } + + // 入力キャッシュとパラメータで線形補間してUpdateParticlesするタイミングでの入力を計算する。 + // Calculate the input at the timing to UpdateParticles by linear interpolation with the _parameterInputCaches and parameterValues. + // _parameterCachesはグループ間での値の伝搬の役割があるので_parameterInputCachesとの分離が必要。 + // _parameterCaches needs to be separated from _parameterInputCaches because of its role in propagating values between groups. + float inputWeight = physicsDeltaTime / currentRemainTime; + for (int j = 0; j < model.getParameterCount(); j++) { + parameterCaches[j] = parameterInputCaches[j] * (1.0f - inputWeight) + parameterValues[j] * inputWeight; + parameterInputCaches[j] = parameterCaches[j]; + } + + for (settingIndex = 0; settingIndex < physicsRig.subRigCount; settingIndex++) { + totalAngle[0] = 0.0f; + totalTranslation.setZero(); + + currentSetting = physicsRig.settings.get(settingIndex); + List particles = physicsRig.particles; + + int baseInputIndex = currentSetting.baseInputIndex; + int baseOutputIndex = currentSetting.baseOutputIndex; + int baseParticleIndex = currentSetting.baseParticleIndex; + + // Load input parameters. + for (i = 0; i < currentSetting.inputCount; i++) { + currentInput = inputs.get(baseInputIndex + i); + weight = currentInput.weight / MAXIMUM_WEIGHT; + + if (currentInput.sourceParameterIndex == -1) { + currentInput.sourceParameterIndex = model.getParameterIndex(currentInput.source.Id); + } + + currentInput.getNormalizedParameterValue.getNormalizedParameterValue( + totalTranslation, + totalAngle, + parameterCaches[currentInput.sourceParameterIndex], + parameterMinimumValues[currentInput.sourceParameterIndex], + parameterMaximumValues[currentInput.sourceParameterIndex], + parameterDefaultValues[currentInput.sourceParameterIndex], + currentSetting.normalizationPosition, + currentSetting.normalizationAngle, + currentInput.reflect, + weight + ); + + } + + radAngle = CubismMath.degreesToRadian(-totalAngle[0]); + + totalTranslation.x = (totalTranslation.x * CubismMath.cosF(radAngle) - totalTranslation.y * CubismMath.sinF(radAngle)); + totalTranslation.y = (totalTranslation.x * CubismMath.sinF(radAngle) + totalTranslation.y * CubismMath.cosF(radAngle)); + + + // Calculate particles position. + updateParticles( + particles, + baseParticleIndex, + currentSetting.particleCount, + totalTranslation, + totalAngle[0], + options.wind, + MOVEMENT_THRESHOLD * currentSetting.normalizationPosition.maximumValue, + physicsDeltaTime, + AIR_RESISTANCE + ); + + // Update output parameters. + for (i = 0; i < currentSetting.outputCount; i++) { + currentOutput = outputs.get(baseOutputIndex + i); + particleIndex = currentOutput.vertexIndex; + + + if (currentOutput.destinationParameterIndex == -1) { + currentOutput.destinationParameterIndex = model.getParameterIndex(currentOutput.destination.Id); + } + + if (particleIndex < 1 || particleIndex >= currentSetting.particleCount) { + continue; + } + + currentParticle = particles.get(baseParticleIndex + particleIndex); + CubismPhysicsParticle previousParticle = particles.get(baseParticleIndex + particleIndex - 1); + CubismVector2.subtract(currentParticle.position, previousParticle.position, translation); + + outputValue = currentOutput.getValue.getValue( + translation, + particles, + baseParticleIndex, + particleIndex, + currentOutput.reflect, + options.gravity + ); + + currentRigOutputs.get(settingIndex).outputs[i] = outputValue; + + cache[0] = parameterCaches[currentOutput.destinationParameterIndex]; + + updateOutputParameterValue( + cache, + 0, + parameterMinimumValues[currentOutput.destinationParameterIndex], + parameterMaximumValues[currentOutput.destinationParameterIndex], + outputValue, + currentOutput + ); + parameterCaches[currentOutput.destinationParameterIndex] = cache[0]; + + } + } + currentRemainTime -= physicsDeltaTime; + } + + final float alpha = currentRemainTime / physicsDeltaTime; + interpolate(model, alpha); + } + + // There are only used by 'evaluate' method. + // Avoid creating a new float array and CubismVector2 instance. + private final float[] totalAngle = new float[1]; + private final float[] cache = new float[1]; + private final CubismVector2 totalTranslation = new CubismVector2(); + private final CubismVector2 translation = new CubismVector2(); + + /** + * Set an option. + * + * @param options a physics operation of option + */ + public void setOptions(Options options) { + if (options == null) { + return; + } + this.options = options; + } + + /** + * Get the physics operation of option. + * + * @return the physics operation of option + */ + public Options getOptions() { + return options; + } + + /** + * 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 + */ + private static void updateParticles( + List strand, + int baseParticleIndex, + int strandCount, + CubismVector2 totalTranslation, + float totalAngle, + CubismVector2 windDirection, + float thresholdValue, + float deltaTimeSeconds, + float airResistance + ) { + float totalRadian; + float delay; + float radian; + + strand.get(baseParticleIndex).position.set(totalTranslation.x, totalTranslation.y); + + totalRadian = CubismMath.degreesToRadian(totalAngle); + CubismMath.radianToDirection(totalRadian, currentGravity).normalize(); + + for (int i = 1; i < strandCount; i++) { + final CubismPhysicsParticle currentParticle = strand.get(baseParticleIndex + i); + final CubismPhysicsParticle previousParticle = strand.get(baseParticleIndex + i - 1); + + currentParticle.lastPosition.set(currentParticle.position.x, currentParticle.position.y); + + { + CubismVector2.multiply(currentGravity, currentParticle.acceleration, currentParticle.force).add(windDirection); + + delay = currentParticle.delay * deltaTimeSeconds * 30.0f; + CubismVector2.subtract(currentParticle.position, previousParticle.position, direction); + } + { + radian = CubismMath.directionToRadian(currentParticle.lastGravity, currentGravity) / airResistance; + + direction.x = ((CubismMath.cosF(radian) * direction.x) - (CubismMath.sinF(radian) * direction.y)); + direction.y = ((CubismMath.sinF(radian) * direction.x) + (direction.y * CubismMath.cosF(radian))); + } + { + CubismVector2.add(previousParticle.position, direction, currentParticle.position); + CubismVector2.multiply(currentParticle.velocity, delay, velocity); + CubismVector2.multiply(currentParticle.force, delay, force).multiply(delay); + + currentParticle.position.add(velocity).add(force); + } + { + float newDirectionX = currentParticle.position.x - previousParticle.position.x; + float newDirectionY = currentParticle.position.y - previousParticle.position.y; + float length = (float) (Math.pow((newDirectionX * newDirectionX) + (newDirectionY * newDirectionY), 0.5f)); + newDirectionX /= length; + newDirectionY /= length; + + currentParticle.position.x = previousParticle.position.x + (newDirectionX * currentParticle.radius); + currentParticle.position.y = previousParticle.position.y + (newDirectionY * currentParticle.radius); + } + + if (CubismMath.absF(currentParticle.position.x) < thresholdValue) { + currentParticle.position.x = 0.0f; + } + + if (delay != 0.0f) { + CubismVector2.subtract(currentParticle.position, currentParticle.lastPosition, currentParticle.velocity); + + currentParticle.velocity.divide(delay); + currentParticle.velocity.multiply(currentParticle.mobility); + + } + currentParticle.force.setZero(); + currentParticle.lastGravity.set(currentGravity.x, currentGravity.y); + } + } + + // There are only used by 'updateParticles' method. + // Avoid creating a new CubismVector2 instance. + private static final CubismVector2 direction = new CubismVector2(); + private static final CubismVector2 velocity = new CubismVector2(); + private static final CubismVector2 force = new CubismVector2(); + private static final CubismVector2 currentGravity = new CubismVector2(); + + private static void updateParticlesForStabilization( + List strand, + int baseParticleIndex, + int strandCount, + CubismVector2 totalTranslation, + float totalAngle, + CubismVector2 windDirection, + float thresholdValue + ) { + int i; + float totalRadian; + + strand.get(baseParticleIndex).position.set(totalTranslation.x, totalTranslation.y); + + totalRadian = CubismMath.degreesToRadian(totalAngle); + CubismMath.radianToDirection(totalRadian, currentGravityForStablization).normalize(); + + for (i = 1; i < strandCount; i++) { + CubismPhysicsParticle particle = strand.get(baseParticleIndex + i); + CubismVector2.multiply(currentGravityForStablization, particle.acceleration, particle.force).add(windDirection); + + particle.lastPosition.set(particle.position.x, particle.position.y); + particle.velocity.setZero(); + + forceForStabilization.set(particle.force.x, particle.force.y); + forceForStabilization.normalize(); + + forceForStabilization.multiply(particle.radius); + CubismVector2.add(strand.get(baseParticleIndex + i - 1).position, forceForStabilization, particle.position); + + if (CubismMath.absF(particle.position.x) < thresholdValue) { + particle.position.x = 0.0f; + } + + particle.force.setZero(); + particle.lastGravity.set(currentGravityForStablization.x, currentGravityForStablization.y); + } + } + + // updateParticlesForStabilization関数内でのみ使われるキャッシュ変数 + private static final CubismVector2 currentGravityForStablization = new CubismVector2(); + private static final CubismVector2 forceForStabilization = new CubismVector2(); + + private static void updateOutputParameterValue( + float[] parameterValue, + int destinationParameterIndex, + float parameterValueMinimum, + float parameterValueMaximum, + float translation, + CubismPhysicsOutput output + ) { + float outputScale; + float value; + float weight; + + outputScale = output.getScale.getScale( + output.transitionScale, + 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 / MAXIMUM_WEIGHT; + + if (!(weight >= 1.0f)) { + value = (parameterValue[destinationParameterIndex] * (1.0f - weight)) + (value * weight); + } + parameterValue[destinationParameterIndex] = value; + } + + /** + * Constant of air resistance + */ + private static final float AIR_RESISTANCE = 5.0f; + + /** + * Constant of maximum weight of input and output ratio + */ + private static final float MAXIMUM_WEIGHT = 100.0f; + + /** + * Constant of threshold of movement + */ + private static final float MOVEMENT_THRESHOLD = 0.001f; + /** + * Constant of maximum allowed delta time + */ + private static final float MAX_DELTA_TIME = 5.0f; + + // -----private constants----- +// Physics types tags + private enum PhysicsTypeTag { + X("X"), + Y("Y"), + ANGLE("Angle"); + + private final String tag; + + PhysicsTypeTag(String tag) { + this.tag = tag; + } + } + + /** + * Private constructor + */ + private CubismPhysics() { + options.gravity.set(0.0f, -1.0f); + options.wind.setZero(); + } + + /** + * Parse a physics3.json data. + * + * @param physicsJson a buffer where physics3.json is loaded. + */ + private void parse(final byte[] physicsJson) { + physicsRig = new CubismPhysicsRig(); + + CubismPhysicsJson json; + json = new CubismPhysicsJson(physicsJson); + + physicsRig.gravity = json.getGravity(); + physicsRig.wind = json.getWind(); + physicsRig.subRigCount = json.getSubRigCount(); + + physicsRig.fps = json.getFps(); + + physicsRig.settings = new ArrayList(physicsRig.subRigCount); + + physicsRig.inputs = new ArrayList(json.getTotalInputCount()); + + physicsRig.outputs = new ArrayList(json.getTotalOutputCount()); + + physicsRig.particles = new ArrayList(json.getVertexCount()); + + currentRigOutputs.clear(); + previousRigOutputs.clear(); + + int inputIndex = 0; + int outputIndex = 0; + int particleIndex = 0; + + for (int i = 0; i < physicsRig.subRigCount; i++) { + final CubismPhysicsSubRig setting = new CubismPhysicsSubRig(); + + // Setting + setting.baseInputIndex = inputIndex; + setting.baseOutputIndex = outputIndex; + setting.baseParticleIndex = particleIndex; + parseSetting(json, setting, i); + + // Input + parseInputs(json, i, setting.inputCount); + inputIndex += setting.inputCount; + + // Output + parseOutputs(json, i, setting.outputCount); + outputIndex += setting.outputCount; + + // Particle + parseParticles(json, i, setting.particleCount); + particleIndex += setting.particleCount; + } + initialize(); + } + + /** + * Parse setting parameters. + * + * @param json physics3.json data + * @param setting current physics setting + * @param settingIndex current setting index + */ + private void parseSetting(final CubismPhysicsJson json, final CubismPhysicsSubRig setting, final int settingIndex) { + setting.normalizationPosition.minimumValue = json.getNormalizationPositionMinimumValue(settingIndex); + setting.normalizationPosition.maximumValue = json.getNormalizationPositionMaximumValue(settingIndex); + setting.normalizationPosition.defaultValue = json.getNormalizationPositionDefaultValue(settingIndex); + + setting.normalizationAngle.minimumValue = json.getNormalizationAngleMinimumValue(settingIndex); + setting.normalizationAngle.maximumValue = json.getNormalizationAngleMaximumValue(settingIndex); + setting.normalizationAngle.defaultValue = json.getNormalizationAngleDefaultValue(settingIndex); + + setting.inputCount = json.getInputCount(settingIndex); + setting.outputCount = json.getOutputCount(settingIndex); + setting.particleCount = json.getParticleCount(settingIndex); + + physicsRig.settings.add(setting); + } + + /** + * Parse inputs parameters. + * (Used for only the parse() method.) + * + * @param json physics3.json data. + * @param settingIndex current setting index + * @param inputCount number of the current input + */ + private void parseInputs(final CubismPhysicsJson json, final int settingIndex, final int inputCount) { + for (int inputIndex = 0; inputIndex < inputCount; inputIndex++) { + final CubismPhysicsInput input = new CubismPhysicsInput(); + + input.sourceParameterIndex = -1; + input.weight = json.getInputWeight(settingIndex, inputIndex); + input.reflect = json.getInputReflect(settingIndex, inputIndex); + + final String tag = json.getInputType(settingIndex, inputIndex); + + if (tag.equals(PhysicsTypeTag.X.tag)) { + input.type = CubismPhysicsSource.X; + input.getNormalizedParameterValue = new GetInputTranslationXFromNormalizedParameterValue(); + } else if (tag.equals(PhysicsTypeTag.Y.tag)) { + input.type = CubismPhysicsSource.Y; + input.getNormalizedParameterValue = new GetInputTranslationYFromNormalizedParameterValue(); + } else if (tag.equals(PhysicsTypeTag.ANGLE.tag)) { + input.type = CubismPhysicsSource.ANGLE; + input.getNormalizedParameterValue = new GetInputAngleFromNormalizedParameterValue(); + } + + input.source.targetType = CubismPhysicsTargetType.PARAMETER; + input.source.Id = json.getInputSourceId(settingIndex, inputIndex); + + physicsRig.inputs.add(input); + } + } + + /** + * Parse outputs parameters. + * (Used for only the parse() method.) + * + * @param json physics3.json data + * @param settingIndex current setting index + * @param outputCount number of the current input + */ + private void parseOutputs(final CubismPhysicsJson json, final int settingIndex, final int outputCount) { + final int count = physicsRig.settings.get(settingIndex).outputCount; + + PhysicsOutput currentRigOutput = new PhysicsOutput(); + currentRigOutput.outputs = new float[count]; + currentRigOutputs.add(currentRigOutput); + + PhysicsOutput previousRigOutput = new PhysicsOutput(); + previousRigOutput.outputs = new float[count]; + previousRigOutputs.add(previousRigOutput); + + for (int outputIndex = 0; outputIndex < outputCount; outputIndex++) { + final CubismPhysicsOutput output = new CubismPhysicsOutput(); + + output.destinationParameterIndex = -1; + output.vertexIndex = json.getOutputVertexIndex(settingIndex, outputIndex); + output.angleScale = json.getOutputAngleScale(settingIndex, outputIndex); + output.weight = json.getOutputWeight(settingIndex, outputIndex); + output.destination.targetType = CubismPhysicsTargetType.PARAMETER; + + output.destination.Id = json.getOutputsDestinationId(settingIndex, outputIndex); + + final String tag = json.getOutputType(settingIndex, outputIndex); + if (tag.equals(PhysicsTypeTag.X.tag)) { + output.type = CubismPhysicsSource.X; + output.getValue = new GetOutputTranslationX(); + output.getScale = new GetOutputScaleTranslationX(); + } else if (tag.equals(PhysicsTypeTag.Y.tag)) { + output.type = CubismPhysicsSource.Y; + output.getValue = new GetOutputTranslationY(); + output.getScale = new GetOutputScaleTranslationY(); + } else if (tag.equals(PhysicsTypeTag.ANGLE.tag)) { + output.type = CubismPhysicsSource.ANGLE; + output.getValue = new GetOutputAngle(); + output.getScale = new GetOutputScaleAngle(); + } + + output.reflect = json.getOutputReflect(settingIndex, outputIndex); + + physicsRig.outputs.add(output); + } + } + + /** + * Parse particles parameters. + * (Used for only the parse() method) + * + * @param json physics3.json data + * @param settingIndex current setting index + * @param particleCount number of the current particle + */ + private void parseParticles(final CubismPhysicsJson json, final int settingIndex, final int particleCount) { + for (int particleIndex = 0; particleIndex < particleCount; particleIndex++) { + final CubismPhysicsParticle particle = new CubismPhysicsParticle(); + + particle.mobility = json.getParticleMobility(settingIndex, particleIndex); + particle.delay = json.getParticleDelay(settingIndex, particleIndex); + particle.acceleration = json.getParticleAcceleration(settingIndex, particleIndex); + particle.radius = json.getParticleRadius(settingIndex, particleIndex); + particle.position = json.getParticlePosition(settingIndex, particleIndex); + + physicsRig.particles.add(particle); + } + } + + /** + * Initializes physics + */ + private void initialize() { + for (int settingIndex = 0; settingIndex < physicsRig.subRigCount; settingIndex++) { + final CubismPhysicsSubRig currentSetting = physicsRig.settings.get(settingIndex); + + final int baseIndex = currentSetting.baseParticleIndex; + final CubismPhysicsParticle baseParticle = physicsRig.particles.get(baseIndex); + + // Initialize the top of particle + baseParticle.initialPosition = new CubismVector2(); + baseParticle.lastPosition = new CubismVector2(baseParticle.initialPosition); + baseParticle.lastGravity = new CubismVector2(0.0f, 1.0f); + baseParticle.velocity = new CubismVector2(); + baseParticle.force = new CubismVector2(); + + // Initialize particles + for (int i = 1; i < currentSetting.particleCount; i++) { + final CubismPhysicsParticle currentParticle = physicsRig.particles.get(baseIndex + i); + + final CubismVector2 radius = new CubismVector2(0.0f, currentParticle.radius); + + final CubismVector2 previousPosition = new CubismVector2(physicsRig.particles.get(baseIndex + i - 1).initialPosition); + currentParticle.initialPosition = previousPosition.add(radius); + + currentParticle.position = new CubismVector2(currentParticle.initialPosition); + currentParticle.lastPosition = new CubismVector2(currentParticle.initialPosition); + currentParticle.lastGravity = new CubismVector2(0.0f, 1.0f); + currentParticle.velocity = new CubismVector2(); + currentParticle.force = new CubismVector2(); + } + } + } + + /** + * 引数で与えられたモデルに、振り子演算の最新の結果とその1つ前の結果、及び与えられた重みから算出された物理演算の結果を適用する。 + * Apply the result of the physics operation calculated from the latest result of the pendulum operation, the previous one, and the given weights, to the model given in the argument. + * + * @param model model applied the result of physics operation + * @param weight weight of the latest result + */ + private void interpolate(CubismModel model, float weight) { + for (int settingIndex = 0; settingIndex < physicsRig.subRigCount; settingIndex++) { + CubismPhysicsSubRig currentSetting = physicsRig.settings.get(settingIndex); + List outputs = physicsRig.outputs; + int baseOutputIndex = currentSetting.baseOutputIndex; + + float[] parameterValues = model.getModel().getParameters().getValues(); + float[] parameterMaximumValues = model.getModel().getParameters().getMaximumValues(); + float[] parameterMinimumValues = model.getModel().getParameters().getMinimumValues(); + + tmpValue[0] = 0.0f; + + for (int i = 0; i < currentSetting.outputCount; i++) { + CubismPhysicsOutput currentOutput = outputs.get(baseOutputIndex + i); + + if (currentOutput.destinationParameterIndex == -1) { + continue; + } + + tmpValue[0] = parameterValues[currentOutput.destinationParameterIndex]; + + updateOutputParameterValue( + tmpValue, + 0, + parameterMinimumValues[currentOutput.destinationParameterIndex], + parameterMaximumValues[currentOutput.destinationParameterIndex], + previousRigOutputs.get(settingIndex).outputs[i] * (1 - weight) + currentRigOutputs.get(settingIndex).outputs[i] * weight, + currentOutput + ); + parameterValues[currentOutput.destinationParameterIndex] = tmpValue[0]; + } + } + } + + // This is only used by 'interpolate' method. + // Avoid creating a new float array instance. + private final float[] tmpValue = new float[1]; + + /** + * Load input parameters. + * (Used for only evaluate() method.) + * + * @param model model instance + * @param transition total amount of model's transition + * @param settingIndex index of setting + * @return total amount of model's angle + */ + private float loadInputParameters(final CubismModel model, final CubismVector2 transition, final int settingIndex) { + CubismPhysicsSubRig currentSetting = physicsRig.settings.get(settingIndex); + + final float[] totalAngle = new float[1]; + + for (int i = 0; i < currentSetting.inputCount; i++) { + final CubismPhysicsInput currentInput = physicsRig.inputs.get(currentSetting.baseInputIndex + i); + final float weight = currentInput.weight / MAXIMUM_WEIGHT; + + if (currentInput.sourceParameterIndex == -1) { + currentInput.sourceParameterIndex = model.getParameterIndex(currentInput.source.Id); + } + + final float parameterValue = model.getParameterValue(currentInput.sourceParameterIndex); + final float parameterMaximumValue = model.getParameterMaximumValue(currentInput.sourceParameterIndex); + final float parameterMinimumValue = model.getParameterMinimumValue(currentInput.sourceParameterIndex); + final float parameterDefaultValue = model.getParameterDefaultValue(currentInput.sourceParameterIndex); + + currentInput.getNormalizedParameterValue.getNormalizedParameterValue( + transition, + totalAngle, + parameterValue, + parameterMinimumValue, + parameterMaximumValue, + parameterDefaultValue, + currentSetting.normalizationPosition, + currentSetting.normalizationAngle, + currentInput.reflect, + weight + ); + } + return totalAngle[0]; + } + + + /** + * Physics operation data + */ + private CubismPhysicsRig physicsRig; + /** + * Options of physics operation + */ + private Options options = new Options(); + + /** + * Result of the latest pendulum calculation + */ + private final List currentRigOutputs = new ArrayList(); + /** + * Result of one previous pendulum calculation + */ + private final List previousRigOutputs = new ArrayList(); + + /** + * Time not processed by physics + */ + private float currentRemainTime; + + /** + * Cache of parameter used in 'Evaluate' method + */ + private float[] parameterCaches = new float[1]; + /** + * Cache of parameter input in 'UpdateParticles' method + */ + private float[] parameterInputCaches = new float[1]; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsFunctions.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsFunctions.java new file mode 100644 index 0000000..b7576f2 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsFunctions.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + * + */ + +package com.live2d.sdk.cubism.framework.physics; + +import com.live2d.sdk.cubism.framework.math.CubismMath; +import com.live2d.sdk.cubism.framework.math.CubismVector2; +import com.live2d.sdk.cubism.framework.physics.CubismPhysicsInternal.NormalizedPhysicsParameterValueGetter; +import com.live2d.sdk.cubism.framework.physics.CubismPhysicsInternal.PhysicsScaleGetter; +import com.live2d.sdk.cubism.framework.physics.CubismPhysicsInternal.PhysicsValueGetter; + +import java.util.List; + +/** + * This is the set of algorithms used in CubismPhysics class. + *

+ * In Cubism SDK for Java Framework's CubismPhysics, employs a design pattern called the "Strategy Pattern". This class is a collection of those 'strategies'. + */ +class CubismPhysicsFunctions { + public static class GetInputTranslationXFromNormalizedParameterValue implements NormalizedPhysicsParameterValueGetter { + @Override + public void getNormalizedParameterValue( + CubismVector2 targetTranslation, + float[] targetAngle, + float value, + float parameterMinimumValue, + float parameterMaximumValue, + float parameterDefaultValue, + CubismPhysicsInternal.CubismPhysicsNormalization normalizationPosition, + CubismPhysicsInternal.CubismPhysicsNormalization normalizationAngle, + boolean isInverted, + float weight + ) { + targetTranslation.x += normalizeParameterValue( + value, + parameterMinimumValue, + parameterMaximumValue, + parameterDefaultValue, + normalizationPosition.minimumValue, + normalizationPosition.maximumValue, + normalizationPosition.defaultValue, + isInverted + ) * weight; + } + } + + public static class GetInputTranslationYFromNormalizedParameterValue implements NormalizedPhysicsParameterValueGetter { + @Override + public void getNormalizedParameterValue( + CubismVector2 targetTranslation, + float[] targetAngle, + float value, + float parameterMinimumValue, + float parameterMaximumValue, + float parameterDefaultValue, + CubismPhysicsInternal.CubismPhysicsNormalization normalizationPosition, + CubismPhysicsInternal.CubismPhysicsNormalization normalizationAngle, + boolean isInverted, + float weight + ) { + targetTranslation.y += normalizeParameterValue( + value, + parameterMinimumValue, + parameterMaximumValue, + parameterDefaultValue, + normalizationPosition.minimumValue, + normalizationPosition.maximumValue, + normalizationPosition.defaultValue, + isInverted + ) * weight; + } + } + + public static class GetInputAngleFromNormalizedParameterValue implements NormalizedPhysicsParameterValueGetter { + @Override + public void getNormalizedParameterValue( + CubismVector2 targetTranslation, + float[] targetAngle, + float value, + float parameterMinimumValue, + float parameterMaximumValue, + float parameterDefaultValue, + CubismPhysicsInternal.CubismPhysicsNormalization normalizationPosition, + CubismPhysicsInternal.CubismPhysicsNormalization normalizationAngle, + boolean isInverted, + float weight + ) { + targetAngle[0] += normalizeParameterValue( + value, + parameterMinimumValue, + parameterMaximumValue, + parameterDefaultValue, + normalizationAngle.minimumValue, + normalizationAngle.maximumValue, + normalizationAngle.defaultValue, + isInverted + ) * weight; + } + } + + public static class GetOutputTranslationX implements PhysicsValueGetter { + @Override + public float getValue( + CubismVector2 translation, + List particles, + int baseParticleIndex, + int particleIndex, + boolean isInverted, + CubismVector2 parentGravity + ) { + float outputValue = translation.x; + + if (isInverted) { + outputValue *= -1.0f; + } + + return outputValue; + } + } + + public static class GetOutputTranslationY implements PhysicsValueGetter { + @Override + public float getValue( + CubismVector2 translation, + List particles, + int baseParticleIndex, + int particleIndex, + boolean isInverted, + CubismVector2 parentGravity + ) { + float outputValue = translation.y; + + if (isInverted) { + outputValue *= -1.0f; + } + + return outputValue; + } + } + + public static class GetOutputAngle implements PhysicsValueGetter { + @Override + public float getValue( + CubismVector2 translation, + List particles, + int baseParticleIndex, + int particleIndex, + boolean isInverted, + CubismVector2 parentGravity + ) { + float outputValue; + tmpGravity.x = parentGravity.x; + tmpGravity.y = parentGravity.y; + + if (particleIndex >= 2) { + tmpGravity.x = particles.get(baseParticleIndex + particleIndex - 1).position.x - particles.get(baseParticleIndex + particleIndex - 2).position.x; + tmpGravity.y = particles.get(baseParticleIndex + particleIndex - 1).position.y - particles.get(baseParticleIndex + particleIndex - 2).position.y; + + } else { + tmpGravity.multiply(-1.0f); + } + + outputValue = CubismMath.directionToRadian(tmpGravity, translation); + + if (isInverted) { + outputValue *= -1.0f; + } + + return outputValue; + } + } + + private static final CubismVector2 tmpGravity = new CubismVector2(); + + public static class GetOutputScaleTranslationX implements PhysicsScaleGetter { + @Override + public float getScale(CubismVector2 translationScale, float angleScale) { + return translationScale.x; + } + } + + public static class GetOutputScaleTranslationY implements PhysicsScaleGetter { + @Override + public float getScale(CubismVector2 translationScale, float angleScale) { + return translationScale.y; + } + } + + public static class GetOutputScaleAngle implements PhysicsScaleGetter { + @Override + public float getScale(CubismVector2 translationScale, float angleScale) { + return angleScale; + } + } + + private static float normalizeParameterValue( + float value, + float parameterMinimum, + float parameterMaximum, + float parameterDefault, + float normalizedMinimum, + float normalizedMaximum, + float normalizedDefault, + boolean isInverted + ) { + float result = 0.0f; + + final float maxValue = Math.max(parameterMaximum, parameterMinimum); + + if (maxValue < value) { + value = maxValue; + } + + final float minValue = Math.min(parameterMaximum, parameterMinimum); + + if (minValue > value) { + value = minValue; + } + + final float minNormValue = Math.min(normalizedMinimum, normalizedMaximum); + final float maxNormValue = Math.max(normalizedMinimum, normalizedMaximum); + final float middleNormValue = normalizedDefault; + + final float middleValue = getDefaultValue(minValue, maxValue); + final float paramValue = value - middleValue; + + + switch ((int) Math.signum(paramValue)) { + case 1: { + final float nLength = maxNormValue - middleNormValue; + final float pLength = maxValue - middleValue; + + if (pLength != 0.0f) { + result = paramValue * (nLength / pLength); + result += middleNormValue; + } + break; + } + case -1: { + final float nLength = minNormValue - middleNormValue; + final float pLength = minValue - middleValue; + + if (pLength != 0.0f) { + result = paramValue * (nLength / pLength); + result += middleNormValue; + } + break; + } + case 0: { + result = middleNormValue; + break; + } + default: { + break; + } + } + return (isInverted) ? result + : (result * (-1.0f)); + } + + private static float getRangeValue(float min, float max) { + float maxValue = Math.max(min, max); + float minValue = Math.min(min, max); + + return CubismMath.absF(maxValue - minValue); + } + + private static float getDefaultValue(float min, float max) { + float minValue = Math.min(min, max); + return minValue + (getRangeValue(min, max) / 2.0f); + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsInternal.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsInternal.java new file mode 100644 index 0000000..18532d9 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsInternal.java @@ -0,0 +1,370 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.physics; + +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismVector2; + +import java.util.ArrayList; +import java.util.List; + +/** + * Internal data of CubismPhysics. + */ +public class CubismPhysicsInternal { + /** + * Types of physics operations to be applied. + */ + public enum CubismPhysicsTargetType { + /** + * Apply physics operation to parameters + */ + PARAMETER + } + + /** + * Types of input for physics operations. + */ + public enum CubismPhysicsSource { + /** + * From X-axis + */ + X, + /** + * From Y-axis + */ + Y, + /** + * From angle + */ + ANGLE + } + + /** + * External forces used in physics operations. + */ + public static class PhysicsJsonEffectiveForces { + /** + * Gravity + */ + public CubismVector2 gravity; + /** + * Wind + */ + public CubismVector2 wind; + } + + /** + * Parameter information for physics operations. + */ + public static class CubismPhysicsParameter { + /** + * Parameter ID + */ + public CubismId Id; + /** + * Type of destination + */ + public CubismPhysicsTargetType targetType; + } + + /** + * Normalization information for physics operations. + */ + public static class CubismPhysicsNormalization { + /** + * Minimum value + */ + public float minimumValue; + /** + * Maximum value + */ + public float maximumValue; + /** + * Default value + */ + public float defaultValue; + } + + /** + * Information on a particle used for physics operations. + */ + public static class CubismPhysicsParticle { + /** + * Initial position + */ + public CubismVector2 initialPosition = new CubismVector2(); + /** + * Mobility + */ + public float mobility; + /** + * Delay + */ + public float delay; + /** + * Acceleration + */ + public float acceleration; + /** + * Distance + */ + public float radius; + /** + * Current position + */ + public CubismVector2 position = new CubismVector2(); + /** + * Last position + */ + public CubismVector2 lastPosition = new CubismVector2(); + /** + * Last gravity + */ + public CubismVector2 lastGravity = new CubismVector2(); + /** + * Current force + */ + public CubismVector2 force = new CubismVector2(); + /** + * Current velocity + */ + public CubismVector2 velocity = new CubismVector2(); + } + + /** + * Manager of phycal points in physics operations. + */ + public static class CubismPhysicsSubRig { + /** + * number of inputs + */ + public int inputCount; + /** + * number of outputs + */ + public int outputCount; + /** + * number of particles + */ + public int particleCount; + /** + * First index of inputs + */ + public int baseInputIndex; + /** + * First index of outputs + */ + public int baseOutputIndex; + /** + * First index of particles + */ + public int baseParticleIndex; + /** + * Normalized position + */ + public CubismPhysicsNormalization normalizationPosition = new CubismPhysicsNormalization(); + /** + * Normalized angle + */ + public CubismPhysicsNormalization normalizationAngle = new CubismPhysicsNormalization(); + } + + /** + * Input information for physics operations. + */ + public static class CubismPhysicsInput { + /** + * Input source parameter + */ + public CubismPhysicsParameter source = new CubismPhysicsParameter(); + /** + * Index of input source parameter + */ + public int sourceParameterIndex; + /** + * Weight + */ + public float weight; + /** + * Type of input + */ + public CubismPhysicsSource type; + /** + * Whether the value is inverted. + */ + public boolean reflect; + /** + * Function to get normalized parameter values + */ + public NormalizedPhysicsParameterValueGetter getNormalizedParameterValue; + } + + /** + * Output information for physics operations. + */ + public static class CubismPhysicsOutput { + /** + * Output destination parameter + */ + public CubismPhysicsParameter destination = new CubismPhysicsParameter(); + /** + * Index of output destination parameter + */ + public int destinationParameterIndex; + /** + * Pendulum index + */ + public int vertexIndex; + /** + * transition scale + */ + public CubismVector2 transitionScale = new CubismVector2(); + /** + * Angle scale + */ + public float angleScale; + /** + * Weight + */ + public float weight; + /** + * Type of output + */ + public CubismPhysicsSource type; + /** + * Whether the value is inverted + */ + public boolean reflect; + /** + * Value when the value is below the minimum value + */ + public float valueBelowMinimum; + /** + * Value when the maximum value is exceeded. + */ + public float valueExceededMaximum; + /** + * Function to get the value for physics operation. + */ + public PhysicsValueGetter getValue; + /** + * Function to get the scale value for physics operation + */ + public PhysicsScaleGetter getScale; + } + + /** + * Physics operation data + */ + public static class CubismPhysicsRig { + /** + * Number of physics point for physics operation + */ + public int subRigCount; + /** + * List of physics point management for physics operation + */ + public List settings = new ArrayList(); + /** + * List of inputs for physics operation + */ + public List inputs = new ArrayList(); + /** + * List of outputs for physics operation + */ + public List outputs = new ArrayList(); + /** + * List of particles for physics operation + */ + public List particles = new ArrayList(); + /** + * Gravity + */ + public CubismVector2 gravity = new CubismVector2(); + /** + * Wind + */ + public CubismVector2 wind = new CubismVector2(); + /** + * Physics operation FPS + */ + public float fps; + } + + /** + * Functional interface with a function which gets normalized parameters. + */ + public interface NormalizedPhysicsParameterValueGetter { + /** + * Get normalized parameters. + * + * @param targetTransition the move value of the calculation result + * @param targetAngle the angle of the calculation result + * @param value the value of the parameter + * @param parameterMinimumValue the minimum value of the parameter + * @param parameterMaximumValue the maximum value of the parameter + * @param parameterDefaultValue the default value of the parameter + * @param normalizationPosition the normalized position + * @param normalizationAngle the normalized angle + * @param isInverted Whether the value is inverted + * @param weight a weight + */ + void getNormalizedParameterValue( + CubismVector2 targetTransition, + float[] targetAngle, + float value, + float parameterMinimumValue, + float parameterMaximumValue, + float parameterDefaultValue, + CubismPhysicsNormalization normalizationPosition, + CubismPhysicsNormalization normalizationAngle, + boolean isInverted, + float weight + ); + } + + /** + * Functional interface with a function for getting values of physics operations. + */ + public interface PhysicsValueGetter { + /** + * Get values of physics operations. + * + * @param transition a transition value + * @param particles a particles list + * @param particleIndex a particle index + * @param isInverted Whether the value is inverted + * @param parentGravity a gravity + * @return the value + */ + float getValue( + CubismVector2 transition, + List particles, + int baseParticleIndex, + int particleIndex, + boolean isInverted, + CubismVector2 parentGravity + ); + } + + /** + * Functional interface with a function for getting the scale of physics operations. + */ + public interface PhysicsScaleGetter { + /** + * Get a scale of physics operations. + * + * @param transitionScale transition scale + * @param angleScale angle scale + * @return scale value + */ + float getScale(CubismVector2 transitionScale, float angleScale); + } + +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsJson.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsJson.java new file mode 100644 index 0000000..01f00eb --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/CubismPhysicsJson.java @@ -0,0 +1,424 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.physics; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.id.CubismId; +import com.live2d.sdk.cubism.framework.math.CubismVector2; +import com.live2d.sdk.cubism.framework.utils.jsonparser.CubismJson; + +/** + * A manager of physics3.json. + */ +public class CubismPhysicsJson { + /** + * Constructor + * + * @param buffer a buffer where physics3.json is loaded. + */ + public CubismPhysicsJson(final byte[] buffer) { + json = CubismJson.create(buffer); + } + + /** + * Get the gravity vector. + * + * @return gravity vector + */ + public CubismVector2 getGravity() { + CubismVector2 gravity = new CubismVector2(); + + gravity.x = json.getRoot().get(JsonKey.META.key).get(JsonKey.EFFECTIVE_FORCES.key).get(JsonKey.GRAVITY.key).get(JsonKey.X.key).toFloat(); + gravity.y = json.getRoot().get(JsonKey.META.key).get(JsonKey.EFFECTIVE_FORCES.key).get(JsonKey.GRAVITY.key).get(JsonKey.Y.key).toFloat(); + + return gravity; + } + + /** + * Get the wind vector. + * + * @return wind vector + */ + public CubismVector2 getWind() { + CubismVector2 wind = new CubismVector2(); + + wind.x = json.getRoot().get(JsonKey.META.key).get(JsonKey.EFFECTIVE_FORCES.key).get(JsonKey.WIND.key).get(JsonKey.X.key).toFloat(); + wind.y = json.getRoot().get(JsonKey.META.key).get(JsonKey.EFFECTIVE_FORCES.key).get(JsonKey.WIND.key).get(JsonKey.Y.key).toFloat(); + + return wind; + } + + /** + * Get the assumed FPS of physics operations. + * If there is no FPS information in physics3.json, return 0.0f. + * + * @return physics operation FPS + */ + public float getFps() { + // If FPS information does not exist in physics3.json, 0.0f is returned. + return json.getRoot().get(JsonKey.META.key).get(JsonKey.FPS.key).toFloat(0.0f); + } + + /** + * Get the number of physics settings. + * + * @return the number of physics settings. + */ + public int getSubRigCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.PHYSICS_SETTING_COUNT.key).toInt(); + } + + /** + * Get the total number of inputs. + * + * @return total number of inputs + */ + public int getTotalInputCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.TOTAL_INPUT_COUNT.key).toInt(); + } + + /** + * Get the total number of outputs. + * + * @return the total number of outputs + */ + public int getTotalOutputCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.TOTAL_OUTPUT_COUNT.key).toInt(); + } + + /** + * Get the number of vertices. + * + * @return the number of vertices + */ + public int getVertexCount() { + return json.getRoot().get(JsonKey.META.key).get(JsonKey.VERTEX_COUNT.key).toInt(); + } + + /** + * Get the minimum value of normalized position. + * + * @param physicsSettingIndex physics setting index + * @return the minimum value of normalized position + */ + public float getNormalizationPositionMinimumValue(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.NORMALIZATION.key).get(JsonKey.POSITION.key).get(JsonKey.MINIMUM.key).toFloat(); + } + + /** + * Get the maximum value of normalized position. + * + * @param physicsSettingIndex physics setting index + * @return the maximum value of normalized position + */ + public float getNormalizationPositionMaximumValue(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.NORMALIZATION.key).get(JsonKey.POSITION.key).get(JsonKey.MAXIMUM.key).toFloat(); + } + + /** + * Get the default value of normalized position. + * + * @param physicsSettingIndex physics setting index + * @return the maximum value of normalized position + */ + public float getNormalizationPositionDefaultValue(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.NORMALIZATION.key).get(JsonKey.POSITION.key).get(JsonKey.DEFAULT.key).toFloat(); + } + + /** + * Get the minimum value of normalized angle. + * + * @param physicsSettingIndex physics setting index + * @return the minimum value of normalized angle + */ + public float getNormalizationAngleMinimumValue(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.NORMALIZATION.key).get(JsonKey.ANGLE.key).get(JsonKey.MINIMUM.key).toFloat(); + } + + /** + * Get the maximum value of normalized angle. + * + * @param physicsSettingIndex physics setting index + * @return the maximum value of normalized angle + */ + public float getNormalizationAngleMaximumValue(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.NORMALIZATION.key).get(JsonKey.ANGLE.key).get(JsonKey.MAXIMUM.key).toFloat(); + } + + /** + * Get the default value of normalized angle. + * + * @param physicsSettingIndex physics setting index + * @return the default value of normalized angle + */ + public float getNormalizationAngleDefaultValue(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.NORMALIZATION.key).get(JsonKey.ANGLE.key).get(JsonKey.DEFAULT.key).toFloat(); + } + + /** + * Get the number of the input. + * + * @param physicsSettingIndex physics setting index + * @return the number of inputs + */ + public int getInputCount(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.INPUT.key).getList().size(); + } + + /** + * Get the weight of the input. + * + * @param physicsSettingIndex physics setting index + * @param inputIndex an input index + * @return the weight of inputs + */ + public float getInputWeight(int physicsSettingIndex, int inputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.INPUT.key).get(inputIndex).get(JsonKey.WEIGHT.key).toFloat(); + } + + /** + * Get the inversion of the input. + * + * @param physicsSettingIndex physics setting index + * @param inputIndex an input index + * @return the inversion of the input + */ + public boolean getInputReflect(int physicsSettingIndex, int inputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.INPUT.key).get(inputIndex).get(JsonKey.REFLECT.key).toBoolean(); + } + + /** + * Get the kind of the input. + * + * @param physicsSettingIndex physics setting index + * @param inputIndex an input index + * @return 入力の種類 the kind of the input + */ + public String getInputType(int physicsSettingIndex, int inputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.INPUT.key).get(inputIndex).get(JsonKey.TYPE.key).getString(); + + } + + /** + * Get the ID of the input destination. + * + * @param physicsSettingIndex physics setting index + * @param inputIndex an input index + * @return the input destination ID + */ + public CubismId getInputSourceId(int physicsSettingIndex, int inputIndex) { + return CubismFramework.getIdManager().getId(json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.INPUT.key).get(inputIndex).get(JsonKey.SOURCE.key).get(JsonKey.ID.key).getString()); + } + + /** + * Get the number of outputs. + * + * @param physicsSettingIndex physics setting index + * @return the number of outputs + */ + public int getOutputCount(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).getList().size(); + } + + /** + * Get the index of output vertices. + * + * @param physicsSettingIndex physics setting index + * @param outputIndex an output index + * @return the index of output vertices + */ + public int getOutputVertexIndex(int physicsSettingIndex, int outputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).get(outputIndex).get(JsonKey.VERTEX_INDEX.key).toInt(); + } + + /** + * Get the scale of output angle. + * + * @param physicsSettingIndex physics setting index + * @param outputIndex output index + * @return the scale of output angle + */ + public float getOutputAngleScale(int physicsSettingIndex, int outputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).get(outputIndex).get(JsonKey.SCALE.key).toFloat(); + } + + /** + * Get the weight of the output. + * + * @param physicsSettingIndex physics setting index + * @param outputIndex an output index + * @return the weight of the output + */ + public float getOutputWeight(int physicsSettingIndex, int outputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).get(outputIndex).get(JsonKey.WEIGHT.key).toFloat(); + } + + /** + * Get the ID of the output destination. + * + * @param physicsSettingIndex physics setting index + * @param outputIndex an output index + * @return the output destination ID + */ + public CubismId getOutputsDestinationId(int physicsSettingIndex, int outputIndex) { + return CubismFramework.getIdManager().getId(json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).get(outputIndex).get(JsonKey.DESTINATION.key).get(JsonKey.ID.key).getString()); + } + + /** + * Get the kind of the output. + * + * @param physicsSettingIndex physics setting index + * @param outputIndex output index + * @return the kind of the output + */ + public String getOutputType(int physicsSettingIndex, int outputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).get(outputIndex).get(JsonKey.TYPE.key).getString(); + } + + /** + * Get the inversion of the output. + * + * @param physicsSettingIndex physics setting index + * @param outputIndex output index + * @return the inversion of the output + */ + public boolean getOutputReflect(int physicsSettingIndex, int outputIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.OUTPUT.key).get(outputIndex).get(JsonKey.REFLECT.key).toBoolean(); + } + + /** + * Get the number of particles. + * + * @param physicsSettingIndex physics setting index + * @return the number of particles + */ + public int getParticleCount(int physicsSettingIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).getList().size(); + } + + /** + * Get the mobility of the particles. + * + * @param physicsSettingIndex physics setting index + * @param vertexIndex the vertex index + * @return the mobility of the particles + */ + public float getParticleMobility(int physicsSettingIndex, int vertexIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).get(vertexIndex).get(JsonKey.MOBILITY.key).toFloat(); + } + + /** + * Get the delay of the particle. + * + * @param physicsSettingIndex physics setting index + * @param vertexIndex the vertex index + * @return the delay of the particle + */ + public float getParticleDelay(int physicsSettingIndex, int vertexIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).get(vertexIndex).get(JsonKey.DELAY.key).toFloat(); + } + + /** + * Get the acceleration of the particle. + * + * @param physicsSettingIndex physics setting index + * @param vertexIndex vertex index + * @return the acceleration of the particle. + */ + public float getParticleAcceleration(int physicsSettingIndex, int vertexIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).get(vertexIndex).get(JsonKey.ACCELERATION.key).toFloat(); + } + + /** + * Get the distance of the particle. + * + * @param physicsSettingIndex physics setting index + * @param vertexIndex vertex index + * @return the distance of the particle + */ + public float getParticleRadius(int physicsSettingIndex, int vertexIndex) { + return json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).get(vertexIndex).get(JsonKey.RADIUS.key).toFloat(); + } + + /** + * Get the position of the particle. + * + * @param physicsSettingIndex physics setting index + * @param vertexIndex vertex index + * @return the position of the particle + */ + public CubismVector2 getParticlePosition(int physicsSettingIndex, int vertexIndex) { + float x = json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).get(vertexIndex).get(JsonKey.POSITION.key).get(JsonKey.X.key).toFloat(); + float y = json.getRoot().get(JsonKey.PHYSICS_SETTINGS.key).get(physicsSettingIndex).get(JsonKey.VERTICES.key).get(vertexIndex).get(JsonKey.POSITION.key).get(JsonKey.Y.key).toFloat(); + + return new CubismVector2(x, y); + } + + + //----- private constants ----- + private enum JsonKey { + POSITION("Position"), + X("X"), + Y("Y"), + ANGLE("Angle"), + TYPE("Type"), + ID("Id"), + + // Meta + META("Meta"), + EFFECTIVE_FORCES("EffectiveForces"), + TOTAL_INPUT_COUNT("TotalInputCount"), + TOTAL_OUTPUT_COUNT("TotalOutputCount"), + PHYSICS_SETTING_COUNT("PhysicsSettingCount"), + GRAVITY("Gravity"), + WIND("Wind"), + VERTEX_COUNT("VertexCount"), + FPS("Fps"), + + // Physics Settings + PHYSICS_SETTINGS("PhysicsSettings"), + NORMALIZATION("Normalization"), + MINIMUM("Minimum"), + MAXIMUM("Maximum"), + DEFAULT("Default"), + REFLECT("Reflect"), + WEIGHT("Weight"), + + // Input + INPUT("Input"), + SOURCE("Source"), + + // Output + OUTPUT("Output"), + SCALE("Scale"), + VERTEX_INDEX("VertexIndex"), + DESTINATION("Destination"), + + // Particle + VERTICES("Vertices"), + MOBILITY("Mobility"), + DELAY("Delay"), + RADIUS("Radius"), + ACCELERATION("Acceleration"); + + private final String key; + + JsonKey(String key) { + this.key = key; + } + } + + private CubismPhysicsJson(CubismJson json) { + this.json = json; + } + + /** + * physics3.json data + */ + private final CubismJson json; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/package-info.java new file mode 100644 index 0000000..d9b38bb --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/physics/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide functions for applying physics-based deformation operations to models. + */ +package com.live2d.sdk.cubism.framework.physics; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ACubismClippingContext.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ACubismClippingContext.java new file mode 100644 index 0000000..bf9f461 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ACubismClippingContext.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering; + +import com.live2d.sdk.cubism.framework.math.CubismMatrix44; +import com.live2d.sdk.cubism.framework.rendering.android.CubismClippingContextAndroid; +import com.live2d.sdk.cubism.framework.type.csmRectF; + +import java.util.ArrayList; +import java.util.List; + +/** + * クリッピングについての設定を保持するクラス + * サブクラスに環境依存のフィールドを保持する。 + */ +public abstract class ACubismClippingContext { + /** + * 渡されたレンダラーの種類に基づき、適切なクリッピングコンテキストを生成する。 + * + * @param type 生成するレンダラーの種類 + * @param manager このクリッピングコンテキストを保持するマネージャーのインスタンス + * @param clippingDrawableIndices クリッピングマスクのIDの配列 + * @param clipCount クリッピングマスクの数 + * + * @return 生成したクリッピングコンテキストのインスタンス + */ + public static ACubismClippingContext createClippingContext( + CubismRenderer.RendererType type, + ICubismClippingManager manager, + int[] clippingDrawableIndices, + int clipCount + ) { + switch (type) { + case ANDROID: + return new CubismClippingContextAndroid(manager, clippingDrawableIndices, clipCount); + case UNKNOWN: + default: + throw new IllegalArgumentException("Failed to create a clipping context. The specified renderer type may be incorrect."); + } + } + + /** + * コンストラクタ + * + * @param manager このクリッピングコンテキストを保持するマネージャーのインスタンス + * @param clippingDrawableIndices クリッピングマスクのIDの配列 + * @param clipCount クリッピングマスクの数 + */ + public ACubismClippingContext( + ICubismClippingManager manager, + int[] clippingDrawableIndices, + int clipCount + ) { + if (clippingDrawableIndices == null || manager == null) { + throw new IllegalArgumentException("The argument is null."); + } + + // クリップしている(=マスク用の)Drawableのインデックスリスト + clippingIdList = clippingDrawableIndices; + // マスクの数 + clippingIdCount = clipCount; + // このコンテキストを保持するマネージャー + owner = manager; + } + + /** + * このマスクにクリップされる描画オブジェクトを追加する + * + * @param drawableIndex クリッピング対象に追加する描画オブジェクトのインデックス + */ + public void addClippedDrawable(int drawableIndex) { + clippedDrawableIndexList.add(drawableIndex); + } + + /** + * このマスクを管理するマネージャのインスタンスを取得する。 + * + * @return クリッピングマネージャのインスタンス + */ + public abstract ICubismClippingManager getClippingManager(); + + /** + * 現在の描画状態でマスクの準備が必要ならtrue + */ + public boolean isUsing; + + /** + * クリッピングマスクのIDの配列 + */ + public final int[] clippingIdList; + + /** + * クリッピングマスクの数 + */ + public final int clippingIdCount; + + /** + * RGBAのいずれのチャンネルにこのクリップを配置するか(0:R, 1:G, 2:B, 3:A) + */ + public int layoutChannelIndex; + + /** + * マスク用チャンネルのどの領域にマスクを入れるか(View座標-1..1, UVは0..1に直す) + */ + public final csmRectF layoutBounds = csmRectF.create(); + /** + * このクリッピングで、クリッピングされる全ての描画オブジェクトの囲み矩形(毎回更新) + */ + public final csmRectF allClippedDrawRect = csmRectF.create(); + /** + * マスクの位置計算結果を保持する行列 + */ + public final CubismMatrix44 matrixForMask = CubismMatrix44.create(); + /** + * 描画オブジェクトの位置計算結果を保持する行列 + */ + public final CubismMatrix44 matrixForDraw = CubismMatrix44.create(); + /** + * このマスクにクリップされる描画オブジェクトのリスト + */ + public final List clippedDrawableIndexList = new ArrayList<>(); + /** + * このマスクが割り当てられるレンダーテクスチャ(フレームバッファ)やカラーバッファのインデックス + */ + public int bufferIndex; + + /** + * このマスクを管理しているマネージャーのインスタンス + */ + protected ICubismClippingManager owner; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ACubismClippingManager.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ACubismClippingManager.java new file mode 100644 index 0000000..6ef9c72 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ACubismClippingManager.java @@ -0,0 +1,584 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering; + +import static com.live2d.sdk.cubism.framework.CubismFramework.VERTEX_OFFSET; +import static com.live2d.sdk.cubism.framework.CubismFramework.VERTEX_STEP; +import static com.live2d.sdk.cubism.framework.utils.CubismDebug.cubismLogError; + +import com.live2d.sdk.cubism.framework.math.CubismMatrix44; +import com.live2d.sdk.cubism.framework.math.CubismVector2; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.type.csmRectF; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.List; + +/** + * クリッピングマネージャーの抽象骨格クラス + * + * @param ACubismClippingContextを継承した型 + * @param CubismOffscreenSurface型 + */ +public abstract class ACubismClippingManager< + T_ClippingContext extends ACubismClippingContext, + T_OffscreenSurface + > implements Closeable, ICubismClippingManager { + /** + * コンストラクタ + */ + public ACubismClippingManager() { + CubismRenderer.CubismTextureColor tmp = new CubismRenderer.CubismTextureColor(); + tmp.r = 1.0f; + tmp.g = 0.0f; + tmp.b = 0.0f; + tmp.a = 0.0f; + channelColors.add(tmp); + + tmp = new CubismRenderer.CubismTextureColor(); + tmp.r = 0.0f; + tmp.g = 1.0f; + tmp.b = 0.0f; + tmp.a = 0.0f; + channelColors.add(tmp); + + tmp = new CubismRenderer.CubismTextureColor(); + tmp.r = 0.0f; + tmp.g = 0.0f; + tmp.b = 1.0f; + tmp.a = 0.0f; + channelColors.add(tmp); + + tmp = new CubismRenderer.CubismTextureColor(); + tmp.r = 0.0f; + tmp.g = 0.0f; + tmp.b = 0.0f; + tmp.a = 1.0f; + channelColors.add(tmp); + } + + @Override + public void close() { + clippingContextListForMask.clear(); + clippingContextListForDraw.clear(); + + channelColors.clear(); + + if (clearedMaskBufferFlags != null) { + clearedMaskBufferFlags = null; + } + } + + @Override + public void initialize( + CubismRenderer.RendererType type, + CubismModel model, + int maskBufferCount + ) { + renderTextureCount = maskBufferCount; + + // レンダーテクスチャのクリアフラグの配列の初期化 + clearedMaskBufferFlags = new boolean[renderTextureCount]; + + final int drawableCount = model.getDrawableCount(); // 描画オブジェクトの数 + final int[][] drawableMasks = model.getDrawableMasks(); // 描画オブジェクトをマスクする描画オブジェクトのインデックスのリスト + final int[] drawableMaskCounts = model.getDrawableMaskCounts(); // 描画オブジェクトをマスクする描画オブジェクトの数 + + // クリッピングマスクを使う描画オブジェクトを全て登録する。 + // クリッピングマスクは、通常数個程度に限定して使うものとする。 + for (int i = 0; i < drawableCount; i++) { + if (drawableMaskCounts[i] <= 0) { + // クリッピングマスクが使用されていないアートメッシュ(多くの場合使用しない) + clippingContextListForDraw.add(null); + continue; + } + + // 既にあるClipContextと同じかチェックする。 + T_ClippingContext cc = findSameClip(drawableMasks[i], drawableMaskCounts[i]); + if (cc == null) { + // 同一のマスクが存在していない場合は生成する。 + cc = (T_ClippingContext) ACubismClippingContext.createClippingContext( + type, + this, + drawableMasks[i], + drawableMaskCounts[i] + ); + + clippingContextListForMask.add(cc); + } + + cc.addClippedDrawable(i); + clippingContextListForDraw.add(cc); + } + } + + @Override + public void setupMatrixForHighPrecision(CubismModel model, boolean isRightHanded) { + // 全てのクリッピングを用意する。 + // 同じクリップ(複数の場合はまとめて1つのクリップ)を使う場合は1度だけ設定する。 + int usingClipCount = 0; + for (int clipIndex = 0; clipIndex < clippingContextListForMask.size(); clipIndex++) { + // 1つのクリッピングマスクに関して + T_ClippingContext cc = clippingContextListForMask.get(clipIndex); + + // このクリップを利用する描画オブジェクト群全体を囲む矩形を計算 + calcClippedDrawTotalBounds(model, cc); + + if (cc.isUsing) { + usingClipCount++; // 使用中としてカウント + } + } + + // マスク行列作成処理 + if (usingClipCount <= 0) { + return; // クリッピングマスクが存在しない場合何もしない。 + } + + setupLayoutBounds(0); + + // サイズがレンダーテクスチャの枚数と合わない場合は合わせる。 + if (clearedMaskBufferFlags.length != renderTextureCount) { + clearedMaskBufferFlags = new boolean[renderTextureCount]; + } + // マスクのクリアフラグを毎フレーム開始時に初期化する。 + else { + for (int i = 0; i < renderTextureCount; i++) { + clearedMaskBufferFlags[i] = false; + } + } + + // 実際にマスクを生成する。 + // 全てのマスクをどのようにレイアウトして描くかを決定し、ClipContext, ClippedDrawContextに記憶する。 + for (int clipIndex = 0; clipIndex < clippingContextListForMask.size(); clipIndex++) { + // ---- 実際に1つのマスクを描く ---- + T_ClippingContext clipContext = clippingContextListForMask.get(clipIndex); + csmRectF allClippedDrawRect = clipContext.allClippedDrawRect; // このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形 + csmRectF layoutBoundsOnTex01 = clipContext.layoutBounds; // このマスクを収める + + final float margin = 0.05f; + float scaleX, scaleY; + final float ppu = model.getPixelPerUnit(); + final float maskPixelWidth = clipContext.getClippingManager().getClippingMaskBufferSize().x; + final float maskPixelHeight = clipContext.getClippingManager().getClippingMaskBufferSize().y; + final float physicalMaskWidth = layoutBoundsOnTex01.getWidth() * maskPixelWidth; + final float physicalMaskHeight = layoutBoundsOnTex01.getHeight() * maskPixelHeight; + + tmpBoundsOnModel.setRect(allClippedDrawRect); + + if (tmpBoundsOnModel.getWidth() * ppu > physicalMaskWidth) { + tmpBoundsOnModel.expand(allClippedDrawRect.getWidth() * margin, 0.0f); + scaleX = layoutBoundsOnTex01.getWidth() / tmpBoundsOnModel.getWidth(); + } else { + scaleX = ppu / physicalMaskWidth; + } + + if (tmpBoundsOnModel.getHeight() * ppu > physicalMaskHeight) { + tmpBoundsOnModel.expand(0.0f, allClippedDrawRect.getHeight() * margin); + scaleY = layoutBoundsOnTex01.getHeight() / tmpBoundsOnModel.getHeight(); + } else { + scaleY = ppu / physicalMaskHeight; + } + + // マスク生成時に使う行列を求める。 + createMatrixForMask(isRightHanded, layoutBoundsOnTex01, scaleX, scaleY); + + clipContext.matrixForMask.setMatrix(tmpMatrixForMask.getArray()); + clipContext.matrixForDraw.setMatrix(tmpMatrixForDraw.getArray()); + } + } + + @Override + public void createMatrixForMask( + boolean isRightHanded, + csmRectF layoutBoundsOnTex01, + float scaleX, + float scaleY + ) { + // マスク作成用の行列の計算 + tmpMatrix.loadIdentity(); + { + // Layout0..1を、-1..1に変換 + tmpMatrix.translateRelative(-1.0f, -1.0f); + tmpMatrix.scaleRelative(2.0f, 2.0f); + + // view to Layout0..1 + tmpMatrix.translateRelative( + layoutBoundsOnTex01.getX(), + layoutBoundsOnTex01.getY() + ); + tmpMatrix.scaleRelative(scaleX, scaleY); + tmpMatrix.translateRelative( + -tmpBoundsOnModel.getX(), + -tmpBoundsOnModel.getY() + ); + } + tmpMatrixForMask.setMatrix(tmpMatrix); + + // 描画用の行列の計算 + tmpMatrix.loadIdentity(); + { + tmpMatrix.translateRelative( + layoutBoundsOnTex01.getX(), + layoutBoundsOnTex01.getY() * ((isRightHanded) ? -1.0f : 1.0f) + ); + tmpMatrix.scaleRelative(scaleX, scaleY * ((isRightHanded) ? -1.0f : 1.0f)); + tmpMatrix.translateRelative( + -tmpBoundsOnModel.getX(), + -tmpBoundsOnModel.getY() + ); + } + tmpMatrixForDraw.setMatrix(tmpMatrix); + } + + @Override + public void setupLayoutBounds(int usingClipCount) { + final int useClippingMaskMaxCount = renderTextureCount <= 1 + ? CLIPPING_MASK_MAX_COUNT_ON_DEFAULT + : CLIPPING_MASK_MAX_COUNT_ON_MULTI_RENDER_TEXTURE * renderTextureCount; + + if (usingClipCount <= 0 || usingClipCount > useClippingMaskMaxCount) { + if (usingClipCount > useClippingMaskMaxCount) { + // マスクの制限数の警告を出す + int count = usingClipCount - useClippingMaskMaxCount; + cubismLogError( + "not supported mask count : %d\n[Details] render texture count: %d\n, mask count : %d", + count, + renderTextureCount, + usingClipCount + ); + } + // この場合は一つのマスクターゲットを毎回クリアして使用する + for (int index = 0; index < clippingContextListForMask.size(); index++) { + T_ClippingContext cc = clippingContextListForMask.get(index); + + cc.layoutChannelIndex = 0; // どうせ毎回消すので固定で良い + cc.layoutBounds.setX(0.0f); + cc.layoutBounds.setY(0.0f); + cc.layoutBounds.setWidth(1.0f); + cc.layoutBounds.setHeight(1.0f); + cc.bufferIndex = 0; + } + return; + } + + // レンダーテクスチャが1枚なら9分割する(最大36枚) + final int layoutCountMaxValue = renderTextureCount <= 1 ? 9 : 8; + + // ひとつのRenderTextureを極力いっぱいに使ってマスクをレイアウトする。 + // マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する。 + // NOTE: 1枚に割り当てるマスクの分割数を取りたいため、小数点は切り上げる。 + final int countPerSheetDiv = (usingClipCount + renderTextureCount - 1) / renderTextureCount; // レンダーテクスチャ1枚あたり何枚割り当てるか + final int reduceLayoutTextureCount = usingClipCount % renderTextureCount; // レイアウトの数を1枚減らすレンダーテクスチャの数(この数だけのレンダーテクスチャが対象)。 + + // RGBAを順番に使っていく。 + final int divCount = countPerSheetDiv / COLOR_CHANNEL_COUNT; // 1チャンネルに配置する基本のマスク個数 + final int modCount = countPerSheetDiv % COLOR_CHANNEL_COUNT; // 余り、この番号のチャンネルまでに1つずつ配分する(インデックスではない) + + // RGBAそれぞれのチャンネルを用意していく(0:R , 1:G , 2:B, 3:A, ) + int curClipIndex = 0; // 順番に設定していく + + for (int renderTextureIndex = 0; renderTextureIndex < renderTextureCount; renderTextureIndex++) { + for (int channelIndex = 0; channelIndex < COLOR_CHANNEL_COUNT; channelIndex++) { + // このチャンネルにレイアウトする数 + // NOTE: レイアウト数 = 1チャンネルに配置する基本のマスク + 余りのマスクを置くチャンネルなら1つ追加 + int layoutCount = divCount + (channelIndex < modCount ? 1 : 0); + + // レイアウトの数を1枚減らす場合にそれを行うチャンネルを決定 + // divが0の時は正常なインデックスの範囲になるように調整 + final int checkChannelIndex = modCount + (divCount < 1 ? -1 : 0); + + // 今回が対象のチャンネルかつ、レイアウトの数を1枚減らすレンダーテクスチャが存在する場合 + if (channelIndex == checkChannelIndex && reduceLayoutTextureCount > 0) { + // 現在のレンダーテクスチャが、対象のレンダーテクスチャであればレイアウトの数を1枚減らす。 + layoutCount -= !(renderTextureIndex < reduceLayoutTextureCount) ? 1 : 0; + } + + // 分割方法を決定する。 + if (layoutCount == 0) { + // 何もしない。 + } else if (layoutCount == 1) { + // 全てをそのまま使う。 + T_ClippingContext cc = clippingContextListForMask.get(curClipIndex++); + cc.layoutChannelIndex = channelIndex; + csmRectF bounds = cc.layoutBounds; + + bounds.setX(0.0f); + bounds.setY(0.0f); + bounds.setWidth(1.0f); + bounds.setHeight(1.0f); + + cc.bufferIndex = renderTextureIndex; + } else if (layoutCount == 2) { + for (int i = 0; i < layoutCount; i++) { + final int xpos = i % 2; + + T_ClippingContext cc = clippingContextListForMask.get(curClipIndex++); + cc.layoutChannelIndex = channelIndex; + csmRectF bounds = cc.layoutBounds; + + // UVを2つに分解して使う + bounds.setX(xpos * 0.5f); + bounds.setY(0.0f); + bounds.setWidth(0.5f); + bounds.setHeight(1.0f); + + cc.bufferIndex = renderTextureIndex; + } + } else if (layoutCount <= 4) { + // 4分割して使う + for (int i = 0; i < layoutCount; i++) { + final int xpos = i % 2; + final int ypos = i / 2; + + T_ClippingContext cc = clippingContextListForMask.get(curClipIndex++); + cc.layoutChannelIndex = channelIndex; + csmRectF bounds = cc.layoutBounds; + + bounds.setX(xpos * 0.5f); + bounds.setY(ypos * 0.5f); + bounds.setWidth(0.5f); + bounds.setHeight(0.5f); + + cc.bufferIndex = renderTextureIndex; + } + } else if (layoutCount <= layoutCountMaxValue) { + // 9分割して使う + for (int i = 0; i < layoutCount; i++) { + final int xpos = i % 3; + final int ypos = i / 3; + + T_ClippingContext cc = clippingContextListForMask.get(curClipIndex++); + cc.layoutChannelIndex = channelIndex; + csmRectF bounds = cc.layoutBounds; + + bounds.setX(xpos / 3.0f); + bounds.setY(ypos / 3.0f); + bounds.setWidth(1.0f / 3.0f); + bounds.setHeight(1.0f / 3.0f); + + cc.bufferIndex = renderTextureIndex; + } + } + // マスクの制限枚数を超えた場合の処理 + else { + int count = usingClipCount - useClippingMaskMaxCount; + cubismLogError( + "not supported mask count : %d\n[Details] render texture count: %d\n, mask count : %d", + count, + renderTextureCount, + usingClipCount + ); + + // 開発モードの場合は停止させる。 + assert false; + + // 引き続き実行する場合、 SetupShaderProgramでオーバーアクセスが発生するので仕方なく適当に入れておく。 + // もちろん描画結果はろくなことにならない。 + for (int i = 0; i < layoutCount; i++) { + T_ClippingContext cc = clippingContextListForMask.get(curClipIndex++); + cc.layoutChannelIndex = 0; + + csmRectF bounds = cc.layoutBounds; + bounds.setX(0.0f); + bounds.setY(0.0f); + bounds.setWidth(1.0f); + bounds.setHeight(1.0f); + + cc.bufferIndex = 0; + } + } + } + } + } + + @Override + public CubismVector2 getClippingMaskBufferSize() { + return clippingMaskBufferSize; + } + + @Override + public void setClippingMaskBufferSize(float width, float height) { + clippingMaskBufferSize.set(width, height); + } + + @Override + public int getRenderTextureCount() { + return renderTextureCount; + } + + @Override + public CubismRenderer.CubismTextureColor getChannelFlagAsColor(int channelIndex) { + return channelColors.get(channelIndex); + } + + /** + * 既にマスクを作っているかを確認する。 + * 作っているようであれば該当するクリッピングマスクのインスタンスを返す。 + * 作っていなければnullを返す。 + * + * @param drawableMasks 描画オブジェクトをマスクする描画オブジェクトのリスト + * @param drawableMaskCounts 描画オブジェクトをマスクする描画オブジェクトの数 + * @return 該当するクリッピングマスクが存在すればインスタンスを返し、なければnullを返す。 + */ + public T_ClippingContext findSameClip(int[] drawableMasks, int drawableMaskCounts) { + // 作成済みClippingContextと一致するか確認 + for (int i = 0; i < clippingContextListForMask.size(); i++) { + T_ClippingContext clipContext = clippingContextListForMask.get(i); + + final int count = clipContext.clippingIdCount; + if (count != drawableMaskCounts) { + // 個数が違う場合は別物 + continue; + } + int sameCount = 0; + + // 同じIDを持つか確認。配列の数が同じなので、一致した個数が同じなら同じ物を持つとする。 + for (int j = 0; j < count; j++) { + final int clipId = clipContext.clippingIdList[j]; + for (int k = 0; k < count; k++) { + if (drawableMasks[k] == clipId) { + sameCount++; + break; + } + } + } + if (sameCount == count) { + return clipContext; + } + } + + return null; // 見つからなかった。 + } + + /** + * マスクされる描画オブジェクト群全体を囲む矩形(モデル座標系)を計算する。 + * + * @param model モデルのインスタンス + * @param clippingContext クリッピングマスクのコンテキスト + */ + public void calcClippedDrawTotalBounds(CubismModel model, T_ClippingContext clippingContext) { + // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 + float clippedDrawTotalMinX = Float.MAX_VALUE; + float clippedDrawTotalMinY = Float.MAX_VALUE; + float clippedDrawTotalMaxX = -Float.MAX_VALUE; + float clippedDrawTotalMaxY = -Float.MAX_VALUE; + + // このマスクが実際に必要か判定する。 + // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある。 + final int clippedDrawCount = clippingContext.clippedDrawableIndexList.size(); + for (int clippedDrawableIndex = 0; clippedDrawableIndex < clippedDrawCount; clippedDrawableIndex++) { + // マスクを使用する描画オブジェクトの描画される矩形を求める。 + final int drawableIndex = clippingContext.clippedDrawableIndexList.get(clippedDrawableIndex); + + final int drawableVertexCount = model.getDrawableVertexCount(drawableIndex); + float[] drawableVertices = model.getDrawableVertices(drawableIndex); + + float minX = Float.MAX_VALUE; + float minY = Float.MAX_VALUE; + float maxX = -Float.MAX_VALUE; + float maxY = -Float.MAX_VALUE; + + int loop = drawableVertexCount * VERTEX_STEP; + for (int pi = VERTEX_OFFSET; pi < loop; pi += VERTEX_STEP) { + float x = drawableVertices[pi]; + float y = drawableVertices[pi + 1]; + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + + if (minX == Float.MAX_VALUE) { + continue; // 有効な点が1つも取れなかったのでスキップする + } + + // 全体の矩形に反映 + if (minX < clippedDrawTotalMinX) clippedDrawTotalMinX = minX; + if (maxX > clippedDrawTotalMaxX) clippedDrawTotalMaxX = maxX; + if (minY < clippedDrawTotalMinY) clippedDrawTotalMinY = minY; + if (maxY > clippedDrawTotalMaxY) clippedDrawTotalMaxY = maxY; + } + + if (clippedDrawTotalMinX == Float.MAX_VALUE) { + clippingContext.isUsing = false; + + csmRectF clippedDrawRect = clippingContext.allClippedDrawRect; + clippedDrawRect.setX(0.0f); + clippedDrawRect.setY(0.0f); + clippedDrawRect.setWidth(0.0f); + clippedDrawRect.setHeight(0.0f); + } else { + clippingContext.isUsing = true; + float w = clippedDrawTotalMaxX - clippedDrawTotalMinX; + float h = clippedDrawTotalMaxY - clippedDrawTotalMinY; + + csmRectF clippedDrawRect = clippingContext.allClippedDrawRect; + clippedDrawRect.setX(clippedDrawTotalMinX); + clippedDrawRect.setY(clippedDrawTotalMinY); + clippedDrawRect.setWidth(w); + clippedDrawRect.setHeight(h); + } + } + + /** + * 画面描画に使用するクリッピングマスクのリストを取得する。 + * + * @return 画面描画に使用するクリッピングマスクのリスト + */ + public List getClippingContextListForDraw() { + return clippingContextListForDraw; + } + + /** + * オフスクリーンフレームのインスタンス + */ + protected T_OffscreenSurface currentMaskBuffer; + /** + * マスクのクリアフラグの配列 + */ + protected boolean[] clearedMaskBufferFlags; + + /** + * カラーチャンネル(RGBA)のフラグのリスト(0:R, 1:G, 2:B, 3:A) + */ + protected final List channelColors = new ArrayList<>(); + /** + * マスク用クリッピングコンテキストのリスト + */ + protected final List clippingContextListForMask = new ArrayList<>(); + /** + * 描画用クリッピングコンテキストのリスト + */ + protected final List clippingContextListForDraw = new ArrayList<>(); + /** + * クリッピングマスクのバッファサイズ(初期値:256) + */ + protected final CubismVector2 clippingMaskBufferSize = new CubismVector2(256, 256); + /** + * 生成するレンダーテクスチャの枚数 + */ + protected int renderTextureCount; + + /** + * 一時計算用行列 + */ + protected CubismMatrix44 tmpMatrix = CubismMatrix44.create(); + /** + * マスク計算のための一時計算用行列 + */ + protected CubismMatrix44 tmpMatrixForMask = CubismMatrix44.create(); + /** + * 描画用の一時計算用行列 + */ + protected CubismMatrix44 tmpMatrixForDraw = CubismMatrix44.create(); + /** + * マスク配置計算用の一時計算用矩形 + */ + protected csmRectF tmpBoundsOnModel = csmRectF.create(); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/CubismRenderer.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/CubismRenderer.java new file mode 100644 index 0000000..3224c4c --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/CubismRenderer.java @@ -0,0 +1,385 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering; + +import com.live2d.sdk.cubism.framework.math.CubismMatrix44; +import com.live2d.sdk.cubism.framework.model.CubismModel; + +/** + * A renderer which processes drawing models. + *

+ * Environment-dependent drawing instructions are written in subclasses that inherit from this class. + */ +public abstract class CubismRenderer { + /** + * レンダラーの種類 + */ + public enum RendererType { + ANDROID, + UNKNOWN // 不明・未定義なレンダラー + } + + /** + * Color blending mode + */ + public enum CubismBlendMode { + NORMAL, // 通常 + ADDITIVE, // 加算 + MULTIPLICATIVE, // 乗算 + MASK // マスク + } + + /** + * Data class for handling texture colors in RGBA. + */ + public static class CubismTextureColor { + public CubismTextureColor() {} + + public CubismTextureColor( + float r, + float g, + float b, + float a + ) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismTextureColor that = (CubismTextureColor) o; + + if (Float.compare(that.r, r) != 0) return false; + if (Float.compare(that.g, g) != 0) return false; + if (Float.compare(that.b, b) != 0) return false; + return Float.compare(that.a, a) == 0; + } + + @Override + public int hashCode() { + int result = (r != 0.0f ? Float.floatToIntBits(r) : 0); + result = 31 * result + (g != 0.0f ? Float.floatToIntBits(g) : 0); + result = 31 * result + (b != 0.0f ? Float.floatToIntBits(b) : 0); + result = 31 * result + (a != 0.0f ? Float.floatToIntBits(a) : 0); + return result; + } + + /** + * Red channel + */ + public float r = 1.0f; + /** + * Green channel + */ + public float g = 1.0f; + /** + * Blue channel + */ + public float b = 1.0f; + /** + * Alpha channel + */ + public float a = 1.0f; + } + + public static void delete() { + + } + + public static void staticRelease() { + + } + + /** + * Initialize this renderer. + * A model instance has the information which is required to initialize the renderer. + * + * @param model model instance + */ + public void initialize(CubismModel model) { + this.model = model; + } + + /** + * レンダラーの初期化処理を実行する。
+ * マスクバッファを2つ以上作成する場合はこのメソッドを使用する。第2引数に何も入れない場合のデフォルト値は1となる。 + * + * @param model モデルのインスタンス + * @param maskBufferCount バッファの生成数 + */ + abstract public void initialize(CubismModel model, int maskBufferCount); + + public void close() { + model.close(); + } + + /** + * Draw the model. + *

+ * Calling following methods before and after DoDrawModel() method is required. + * ・saveProfile() + * ・restoreProfile() + * These methods return the state of the renderer to the state before drawing the model. + */ + public void drawModel() { + if (getModel() == null) { + return; + } + + /* + * Call the following methods before and after DoDrawModel() method. + * ・saveProfile() + * ・restoreProfile() + * These methods save and restore the renderer's drawing settings to the state immediately before the model is drawn. + */ + saveProfile(); + doDrawModel(); + restoreProfile(); + } + + + /** + * Get the Model-View-Projection Matrix. + * + * @return Model-View-Projection Matrix + */ + public CubismMatrix44 getMvpMatrix() { + return mvpMatrix44; + } + + /** + * Set the Model-View-Projection Matrix + * + * @param matrix4x4 Model-View-Projection Matrix + */ + public void setMvpMatrix(final CubismMatrix44 matrix4x4) { + mvpMatrix44.setMatrix(matrix4x4); + } + + /** + * Set colors of a model. + * Each color is specified in the range 0.0~1.0. (1.0 is standard value) + * + * @param red value of red channel + * @param green value of green channel + * @param blue value of blue channel + * @param alpha value of alpha channel + */ + public void setModelColor(float red, float green, float blue, float alpha) { + modelColor.r = constrain(red); + modelColor.g = constrain(green); + modelColor.b = constrain(blue); + modelColor.a = constrain(alpha); + } + + /** + * Set colors of a model. + * + * @param color CubismTextureColor instance + */ + public void setModelColor(CubismTextureColor color) { + modelColor.r = color.r; + modelColor.g = color.g; + modelColor.b = color.b; + modelColor.a = color.a; + } + + /** + * Get the model's colors. + * Each color is specified in the range 0.0~1.0. (1.0 is standard value) + * + * @return the color information of RGBA. + */ + public CubismTextureColor getModelColor() { + return modelColor; + } + + /** + * 透明度を考慮したモデルの色を計算する。 + * + * @param opacity 透明度 + * @return RGBAのカラー情報 + */ + public CubismTextureColor getModelColorWithOpacity(float opacity) { + tmpModelColor.r = modelColor.r; + tmpModelColor.g = modelColor.g; + tmpModelColor.b = modelColor.b; + tmpModelColor.a = modelColor.a; + + tmpModelColor.a *= opacity; + + if (isPremultipliedAlpha()) { + tmpModelColor.r *= tmpModelColor.a; + tmpModelColor.g *= tmpModelColor.a; + tmpModelColor.b *= tmpModelColor.a; + } + + return tmpModelColor; + } + + /** + * Get the validity or invalidity of multiplied alpha. + * + * @return If multiplied alpha is valid, return true. + */ + public boolean isPremultipliedAlpha() { + return isPremultipliedAlpha; + } + + /** + * Set the validity or invalidity of multiplied alpha. + * + * @param enable a state of premultiplied alpha. + */ + public void isPremultipliedAlpha(boolean enable) { + isPremultipliedAlpha = enable; + } + + /** + * Get the validity or invalid of culling. + * + * @return If culling is valid, return true. + */ + public boolean isCulling() { + return isCulling; + } + + /** + * Set the validity or invalidity of culling. + * + * @param enable a state of culling. + */ + public void isCulling(boolean enable) { + isCulling = enable; + } + + /** + * Get the parameters for anisotropic filtering of textures. + * + * @return the parameters for anisotropic filtering of textures + */ + public float getAnisotropy() { + return anisotropy; + } + + /** + * Set the parameters for anisotropic filtering of textures. + * The influence of parameter values depends on the implementation of the renderer. + * + * @param value parameter value + */ + public void setAnisotropy(float value) { + anisotropy = value; + } + + /** + * Get the rendered model. + * + * @return the rendered model + */ + public CubismModel getModel() { + return model; + } + + /** + * Change the mask rendering method. + * In the case of false, the mask is divided into a single texture and rendered(default is this). + * This method is high speed, but the upper limit of the number of masks is limited to 36 and the quality is also rough. + * In the case of true, the necessary mask is redrawn before drawing parts. + * The rendering quality is high, but the drawing processing load increase. + * + * @param isHigh rendering quality + */ + public void isUsingHighPrecisionMask(boolean isHigh) { + useHighPrecisionMask = isHigh; + } + + /** + * Get the mask rendering method. + * + * @return the mask rendering method + */ + public boolean isUsingHighPrecisionMask() { + return useHighPrecisionMask; + } + + /** + * Constructor + */ + protected CubismRenderer() { + mvpMatrix44 = CubismMatrix44.create(); + mvpMatrix44.loadIdentity(); + } + + /** + * the model drawing inplementation. + */ + protected abstract void doDrawModel(); + + /** + * Save the state of the renderer just before drawing the model. + */ + protected abstract void saveProfile(); + + /** + * Restore the state of the renderer just before drawing the model. + */ + protected abstract void restoreProfile(); + + /** + * Limit a value to a range of 0.0 to 1.0. + * + * @param target value to limit + * @return value after limit processing + */ + private float constrain(float target) { + if (target < 0.0f) { + return 0.0f; + } else return Math.min(target, 1.0f); + } + + + /** + * Model-View-Projection Matrix + */ + private final CubismMatrix44 mvpMatrix44; + /** + * the color which model has.(RGBA) + */ + private final CubismTextureColor modelColor = new CubismTextureColor(); + /** + * whether culling is valid + */ + private boolean isCulling; + /** + * whether premultiplied alpha is valid + */ + private boolean isPremultipliedAlpha; + /** + * parameters for anisotropic filtering of textures + */ + private float anisotropy; + /** + * the model to be rendered + */ + private CubismModel model; + /** + * If this is false, the masks are drawn together. If this is true, the masks are redrawn for each part drawing. + */ + private boolean useHighPrecisionMask; + + /** + * 計算用の色格納用インスタンス + */ + private final CubismTextureColor tmpModelColor = new CubismTextureColor(); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ICubismClippingManager.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ICubismClippingManager.java new file mode 100644 index 0000000..7829f2a --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/ICubismClippingManager.java @@ -0,0 +1,103 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering; + +import com.live2d.sdk.cubism.framework.math.CubismVector2; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.type.csmRectF; + +public interface ICubismClippingManager { + /** + * 実験時に1チャンネルの場合は1、RGBだけの場合は3、アルファも含める場合は4 + */ + int COLOR_CHANNEL_COUNT = 4; + /** + * 通常のフレームバッファ1枚あたりのマスク最大数 + */ + int CLIPPING_MASK_MAX_COUNT_ON_DEFAULT = 36; + /** + * フレームバッファが2枚以上ある場合のフレームバッファ1枚あたりのマスク最大数 + */ + int CLIPPING_MASK_MAX_COUNT_ON_MULTI_RENDER_TEXTURE = 32; + + /** + * マネージャーの初期化処理 + * クリッピングマスクを使う描画オブジェクトの登録を行う。 + * + * @param type レンダラーの種類 + * @param model モデルのインスタンス + * @param maskBufferCount バッファの生成数 + */ + void initialize( + CubismRenderer.RendererType type, + CubismModel model, + int maskBufferCount + ); + + /** + * 高精細マスク処理用の行列を計算する。 + * + * @param model モデルのインスタンス + * @param isRightHanded 処理が右手系かどうか。右手系ならtrue + */ + void setupMatrixForHighPrecision(CubismModel model, boolean isRightHanded); + + /** + * マスク作成・描画用の行列を作成する。 + * + * @param isRightHanded 座標を右手系として扱うかどうか。右手系として扱うならtrue + * @param layoutBoundsOnTex01 マスクを収める領域 + * @param scaleX 描画オブジェクトのX方向への伸縮率 + * @param scaleY 描画オブジェクトのY方向への伸縮率 + */ + void createMatrixForMask( + boolean isRightHanded, + csmRectF layoutBoundsOnTex01, + float scaleX, + float scaleY + ); + + /** + * クリッピングコンテキストを配置するレイアウト。 + * 1つのレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトする。 + * マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2, 2, 1, 1と配置する。 + * + * @param usingClipCount 配置するクリッピングコンテキストの数 + */ + void setupLayoutBounds(int usingClipCount); + + /** + * クリッピングマスクバッファのサイズを取得する。 + * + * @return クリッピングマスクバッファのサイズ + */ + CubismVector2 getClippingMaskBufferSize(); + + /** + * クリッピングマスクバッファのサイズを設定する。 + * + * @param width クリッピングマスクバッファの幅 + * @param height クリッピングマスクバッファの高さ + */ + void setClippingMaskBufferSize(float width, float height); + + /** + * このバッファのレンダーテクスチャの枚数を取得する。 + * + * @return このバッファのレンダーテクスチャの枚数 + */ + int getRenderTextureCount(); + + /** + * カラーチャンネル(RGBA)のフラグを取得する。 + * + * @param channelIndex カラーチャンネル(RGBA)の番号(0:R, 1:G, 2:B, 3:A) + * @return カラーチャンネルのフラグ + */ + CubismRenderer.CubismTextureColor getChannelFlagAsColor(int channelIndex); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismClippingContextAndroid.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismClippingContextAndroid.java new file mode 100644 index 0000000..3e03456 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismClippingContextAndroid.java @@ -0,0 +1,43 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +import com.live2d.sdk.cubism.framework.rendering.ACubismClippingContext; +import com.live2d.sdk.cubism.framework.rendering.ICubismClippingManager; + +/** + * Context of Clipping Mask + */ +public class CubismClippingContextAndroid extends ACubismClippingContext { + /** + * コンストラクタ + * + * @param manager このクリッピングコンテキストを保持するマネージャーのインスタンス + * @param clipingDrawableIndices クリッピングマスクのIDの配列 + * @param clipCount クリッピングマスクの数 + */ + public CubismClippingContextAndroid( + ICubismClippingManager manager, + int[] clipingDrawableIndices, + int clipCount + ) { + super(manager, clipingDrawableIndices, clipCount); + } + + /** + * このマスクを管理するマネージャーのインスタンスを返す。 + * + * @return クリッピングマネージャーのインスタンス。 + * @throws ClassCastException 具象クラスへのキャストに失敗しました。 + */ + @Override + public CubismClippingManagerAndroid getClippingManager() { + // キャストに失敗する可能性があります。その場合は内部でClassCastExceptionが送出されます。 + return (CubismClippingManagerAndroid) owner; + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismClippingManagerAndroid.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismClippingManagerAndroid.java new file mode 100644 index 0000000..84189ff --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismClippingManagerAndroid.java @@ -0,0 +1,175 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.rendering.ACubismClippingManager; +import com.live2d.sdk.cubism.framework.type.csmRectF; + +import java.io.Closeable; + +import static android.opengl.GLES20.*; + +/** + * クリッピングマスクの処理を実行するクラス + */ +class CubismClippingManagerAndroid extends ACubismClippingManager< + CubismClippingContextAndroid, + CubismOffscreenSurfaceAndroid + > implements Closeable { + /** + * コンストラクタ + */ + public CubismClippingManagerAndroid() { + super(); + } + + /** + * クリッピングコンテキストを作成する。モデル描画時に実行する。 + * + * @param model モデルのインスタンス + * @param renderer レンダラーのインスタンス + * @param lastFBO フレームバッファ + * @param lastViewport ビューポート + */ + public void setupClippingContext(CubismModel model, CubismRendererAndroid renderer, int[] lastFBO, int[] lastViewport) { + // Prepare all clipping. + // Set only once when using the same clip (or a group of clips if there are multiple clips). + int usingClipCount = 0; + for (int i = 0; i < clippingContextListForMask.size(); i++) { + CubismClippingContextAndroid clipContext = clippingContextListForMask.get(i); + + // Calculate the rectangle that encloses the entire group of drawing objects that use this clip. + calcClippedDrawTotalBounds(model, clipContext); + + if (clipContext.isUsing) { + // Count as in use. + usingClipCount++; + } + } + + if (!(usingClipCount > 0)) { + return; + } + + // Process of creating mask. + // Set up a viewport with the same size as the generated MaskBuffer. + glViewport(0, 0, (int) clippingMaskBufferSize.x, (int) clippingMaskBufferSize.y); + + // 後の計算のためにインデックスの最初をセットする。 + currentMaskBuffer = renderer.getMaskBuffer(0); + + // マスク描画処理 + currentMaskBuffer.beginDraw(lastFBO); + + // バッファをクリアする + renderer.preDraw(); + + // Determine the layout of each mask. + setupLayoutBounds(usingClipCount); + + // サイズがレンダーテクスチャの枚数と合わない場合は合わせる。 + if (clearedMaskBufferFlags.length != renderTextureCount) { + clearedMaskBufferFlags = new boolean[renderTextureCount]; + } + // マスクのクリアフラグを毎フレーム開始時に初期化する。 + else { + for (int i = 0; i < renderTextureCount; i++) { + clearedMaskBufferFlags[i] = false; + } + } + + // ---------- Mask Drawing Process ----------- + // Actually generate the masks. + // Determine how to layout and draw all the masks, and store them in ClipContext and ClippedDrawContext. + for (int j = 0; j < clippingContextListForMask.size(); j++) { + CubismClippingContextAndroid clipContext = clippingContextListForMask.get(j); + + // The enclosing rectangle in logical coordinates of all drawing objects that use this mask. + csmRectF allClippedDrawRect = clipContext.allClippedDrawRect; + // Fit the mask in here. + csmRectF layoutBoundsOnTex01 = clipContext.layoutBounds; + + final float margin = 0.05f; + + // clipContextに設定したオフスクリーンサーフェスをインデックスで取得 + final CubismOffscreenSurfaceAndroid clipContextOffscreenSurface = renderer.getMaskBuffer(clipContext.bufferIndex); + + // 現在のオフスクリーンサーフェスがclipContextのものと異なる場合 + if (currentMaskBuffer != clipContextOffscreenSurface) { + currentMaskBuffer.endDraw(); + currentMaskBuffer = clipContextOffscreenSurface; + + // マスク用RenderTextureをactiveにセット。 + currentMaskBuffer.beginDraw(lastFBO); + + // バッファをクリアする。 + renderer.preDraw(); + } + + + // Use a rectangle on the model coordinates with margins as appropriate. + tmpBoundsOnModel.setRect(allClippedDrawRect); + + tmpBoundsOnModel.expand( + allClippedDrawRect.getWidth() * margin, + allClippedDrawRect.getHeight() * margin + ); + + // ######## It is best to keep the size to a minimum, rather than using the entire allocated space. + // Find the formula for the shader. If rotation is not taken into account, the formula is as follows. + // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] + float scaleX = layoutBoundsOnTex01.getWidth() / tmpBoundsOnModel.getWidth(); + float scaleY = layoutBoundsOnTex01.getHeight() / tmpBoundsOnModel.getHeight(); + + // Calculate the matrix to be used for mask generation. + createMatrixForMask(false, layoutBoundsOnTex01, scaleX, scaleY); + + clipContext.matrixForMask.setMatrix(tmpMatrixForMask); + clipContext.matrixForDraw.setMatrix(tmpMatrixForDraw); + + // 実際の描画を行う。 + final int clipDrawCount = clipContext.clippingIdCount; + for (int i = 0; i < clipDrawCount; i++) { + final int clipDrawIndex = clipContext.clippingIdList[i]; + + // If vertex information is not updated and reliable, pass drawing. + if (!model.getDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex)) { + continue; + } + + renderer.isCulling(model.getDrawableCulling(clipDrawIndex)); + + // マスクがクリアされていないなら処理する。 + if (!clearedMaskBufferFlags[clipContext.bufferIndex]) { + // マスクをクリアする。 + // (仮仕様) 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダーCd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない) + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + clearedMaskBufferFlags[clipContext.bufferIndex] = true; + } + + // Apply this special transformation to draw it. + // Switching channel is also needed.(A,R,G,B) + renderer.setClippingContextBufferForMask(clipContext); + + renderer.drawMeshAndroid( + model, + clipDrawIndex + ); + } + } + + // --- Post Processing --- + // Return the drawing target + currentMaskBuffer.endDraw(); + renderer.setClippingContextBufferForMask(null); + + glViewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3]); + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismDrawableInfoCachesHolder.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismDrawableInfoCachesHolder.java new file mode 100644 index 0000000..18ffd47 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismDrawableInfoCachesHolder.java @@ -0,0 +1,123 @@ +package com.live2d.sdk.cubism.framework.rendering.android; + +import com.live2d.sdk.cubism.framework.model.CubismModel; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; + +/** + * Drawableの情報を格納するバッファをキャッシュし保持するクラス。 + */ +class CubismDrawableInfoCachesHolder { + public CubismDrawableInfoCachesHolder(CubismModel model) { + final int drawableCount = model.getDrawableCount(); + final int[] renderOrder = model.getDrawableRenderOrders(); + final int[] sortedDrawableIndexList = new int[drawableCount]; + + // Sort the index by drawing order + for (int i = 0; i < drawableCount; i++) { + final int order = renderOrder[i]; + sortedDrawableIndexList[order] = i; + } + vertexArrayCaches = new FloatBuffer[drawableCount]; + uvArrayCaches = new FloatBuffer[drawableCount]; + indexArrayCaches = new ShortBuffer[drawableCount]; + + for (int i = 0; i < drawableCount; i++) { + final int drawableIndex = sortedDrawableIndexList[i]; + + // Vertex Array + { + float[] vertexArray = model.getDrawableVertices(drawableIndex); + + ByteBuffer bb = ByteBuffer.allocateDirect(vertexArray.length * 4); + bb.order(ByteOrder.nativeOrder()); + FloatBuffer buffer = bb.asFloatBuffer(); + vertexArrayCaches[drawableIndex] = buffer; + } + + // UV Array + { + float[] uvArray = model.getDrawableVertexUvs(drawableIndex); + + ByteBuffer bb = ByteBuffer.allocateDirect(uvArray.length * 4); + bb.order(ByteOrder.nativeOrder()); + FloatBuffer buffer = bb.asFloatBuffer(); + uvArrayCaches[drawableIndex] = buffer; + } + + // Index Array + { + short[] indexArray = model.getDrawableVertexIndices(drawableIndex); + + ByteBuffer bb = ByteBuffer.allocateDirect(indexArray.length * 4); + bb.order(ByteOrder.nativeOrder()); + ShortBuffer buffer = bb.asShortBuffer(); + indexArrayCaches[drawableIndex] = buffer; + } + } + } + + /** + * Drawableの頂点をキャッシュされたバッファに入れて返す。 + * + * @param drawableIndex 取得したいDrawableのインデックス + * @param drawableVertices Drawableの頂点が格納された配列 + * @return 頂点バッファ + */ + public FloatBuffer setUpVertexArray(int drawableIndex, float[] drawableVertices) { + FloatBuffer vertexArray = vertexArrayCaches[drawableIndex]; + vertexArray.clear(); + vertexArray.put(drawableVertices); + vertexArray.position(0); + + return vertexArray; + } + + /** + * DrawableのUV情報をキャッシュされたバッファに入れて返す。 + * + * @param drawableIndex 取得したいDrawableのインデックス + * @param drawableVertexUvs DrawableのUV情報が入った配列 + * @return UV情報バッファ + */ + public FloatBuffer setUpUvArray(int drawableIndex, float[] drawableVertexUvs) { + FloatBuffer uvArray = uvArrayCaches[drawableIndex]; + uvArray.clear(); + uvArray.put(drawableVertexUvs); + uvArray.position(0); + + return uvArray; + } + + /** + * Drawableの頂点に対するポリゴンの対応番号をキャッシュされたバッファに入れて返す。 + * + * @param drawableIndex 取得したいDrawableのインデックス + * @param drawableIndices Drawableの頂点に対するポリゴンの対応番号の配列 + * @return 頂点に対するポリゴンの対応番号のバッファ + */ + public ShortBuffer setUpIndexArray(int drawableIndex, short[] drawableIndices) { + ShortBuffer indexArray = indexArrayCaches[drawableIndex]; + indexArray.clear(); + indexArray.put(drawableIndices); + indexArray.position(0); + + return indexArray; + } + + /** + * Drawableの頂点のキャッシュ配列 + */ + private final FloatBuffer[] vertexArrayCaches; + /** + * DrawableのUV情報のキャッシュ配列 + */ + private final FloatBuffer[] uvArrayCaches; + /** + * Drawableの頂点に対するポリゴンの対応番号のキャッシュ配列 + */ + private final ShortBuffer[] indexArrayCaches; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismOffscreenSurfaceAndroid.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismOffscreenSurfaceAndroid.java new file mode 100644 index 0000000..ba652ff --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismOffscreenSurfaceAndroid.java @@ -0,0 +1,311 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +import com.live2d.sdk.cubism.framework.math.CubismVector2; + +import java.nio.IntBuffer; +import java.util.Arrays; + +import static android.opengl.GLES20.*; + +/** + * This class is for drawing offscreen. + **/ +public class CubismOffscreenSurfaceAndroid { + /** + * Constructor + */ + public CubismOffscreenSurfaceAndroid() {} + + /** + * Copy constructor + * + * @param offscreenSurface offscreen surface buffer + */ + public CubismOffscreenSurfaceAndroid(CubismOffscreenSurfaceAndroid offscreenSurface) { + renderTexture = Arrays.copyOf(offscreenSurface.renderTexture, offscreenSurface.renderTexture.length); + colorBuffer = Arrays.copyOf(offscreenSurface.colorBuffer, offscreenSurface.colorBuffer.length); + oldFBO = Arrays.copyOf(offscreenSurface.oldFBO, offscreenSurface.oldFBO.length); + + bufferWidth = offscreenSurface.bufferWidth; + bufferHeight = offscreenSurface.bufferHeight; + isColorBufferInherited = offscreenSurface.isColorBufferInherited; + } + + /** + * Begin drawing to the specific drawing target. + * + * @param restoreFBO If it is not "null", EndDraw will run glBindFrameBuffer this value. + **/ + public void beginDraw(int[] restoreFBO) { + if (renderTexture == null) { + return; + } + + // Remember the back buffer surface. + if (restoreFBO == null) { + glGetIntegerv(GL_FRAMEBUFFER_BINDING, IntBuffer.wrap(oldFBO)); + } else { + oldFBO = restoreFBO; + } + + // Set the RenderTexture for the mask to active. + glBindFramebuffer(GL_FRAMEBUFFER, renderTexture[0]); + } + + /** + * Begin drawing to the specific drawing target. + *

+ * This method reproduces default argument of C++. The users can use this method instead of specifying null as an argument. + *

+ */ + public void beginDraw() { + beginDraw(null); + } + + /** + * Finish drawing. + **/ + public void endDraw() { + if (renderTexture == null) { + return; + } + + // Return the drawing target. + glBindFramebuffer(GL_FRAMEBUFFER, oldFBO[0]); + } + + /** + * Clear the rendering target. + * Note: Call this after BeginDraw(). + * + * @param r red(0.0~1.0) + * @param g green(0.0~1.0) + * @param b blue(0.0~1.0) + * @param a α(0.0~1.0) + */ + public void clear(final float r, final float g, final float b, final float a) { + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + } + + /** + * Create CubismOffscreenSurface. + *

+ * This method reproduces default argument of C++. The users can use this method instead of specifying null as colorBuffer(2rd) argument. + *

+ * + * @param displayBufferSize buffer size(Vector type) + */ + public void createOffscreenSurface(CubismVector2 displayBufferSize) { + createOffscreenSurface((int) displayBufferSize.x, (int) displayBufferSize.y, null); + } + + /** + * Create CubismOffscreenSurface. + * + * @param displayBufferSize buffer size + * @param colorBuffer if non-zero, use colorBuffer as pixel storage area. + */ + public void createOffscreenSurface(final CubismVector2 displayBufferSize, final int[] colorBuffer) { + createOffscreenSurface((int) displayBufferSize.x, (int) displayBufferSize.y, colorBuffer); + } + + /** + * Create CubismOffscreenSurface. + *

+ * This method reproduces default argument of C++. The users can use this method instead of specifying null as colorBuffer(3rd) argument. + *

+ * + * @param displayBufferWidth buffer width + * @param displayBufferHeight buffer height + */ + public void createOffscreenSurface(int displayBufferWidth, int displayBufferHeight) { + createOffscreenSurface(displayBufferWidth, displayBufferHeight, null); + } + + /** + * Create CubismOffscreenSurface. + * + * @param displayBufferWidth buffer width + * @param displayBufferHeight buffer height + * @param colorBuffer if non-zero, use colorBuffer as pixel storage area. + */ + public void createOffscreenSurface(final int displayBufferWidth, final int displayBufferHeight, final int[] colorBuffer) { + // いったん削除 + destroyOffscreenSurface(); + + int[] ret = new int[1]; + + // Create new offscreen surface + if (colorBuffer == null) { + this.colorBuffer = new int[1]; + glGenTextures(1, this.colorBuffer, 0); + + glBindTexture(GL_TEXTURE_2D, this.colorBuffer[0]); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + displayBufferWidth, + displayBufferHeight, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + null); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + isColorBufferInherited = false; + } + // Use the designated color buffer. + else { + this.colorBuffer = colorBuffer; + isColorBufferInherited = true; + } + + int[] tmpFBO = new int[1]; + + glGetIntegerv(GL_FRAMEBUFFER_BINDING, tmpFBO, 0); + + glGenFramebuffers(1, ret, 0); + glBindFramebuffer(GL_FRAMEBUFFER, ret[0]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this.colorBuffer[0], 0); + glBindFramebuffer(GL_FRAMEBUFFER, tmpFBO[0]); + + this.renderTexture = new int[1]; + this.renderTexture[0] = ret[0]; + bufferWidth = displayBufferWidth; + bufferHeight = displayBufferHeight; + } + + /** + * Destroy CubismOffscreenSurface + */ + public void destroyOffscreenSurface() { + if (!isColorBufferInherited && (colorBuffer != null)) { + glDeleteTextures(1, colorBuffer, 0); + colorBuffer = null; + } + + if (renderTexture != null) { + glDeleteFramebuffers(1, renderTexture, 0); + renderTexture = null; + } + } + + /** + * レンダーテクスチャのアドレス(intの配列型)を取得する。 + * + * @return レンダーテクスチャのアドレス + */ + public int[] getRenderTexture() { + return renderTexture; + } + + + /** + * Get color buffer. + * + * @return color buffer + */ + + public int[] getColorBuffer() { + return colorBuffer; + } + + + /** + * Get buffer width + * + * @return buffer width + */ + public int getBufferWidth() { + return bufferWidth; + } + + + /** + * Get buffer height. + * + * @return buffer height + */ + public int getBufferHeight() { + return bufferHeight; + } + + + /** + * Whether render texture is valid. + * + * @return If it is valid, return true + */ + + public boolean isValid() { + return renderTexture != null; + } + + /** + * Whether buffer size is the same. + * + * @param bufferSize buffer size + * @return Whether buffer size is the same + */ + public boolean isSameSize(final CubismVector2 bufferSize) { + int width = (int) bufferSize.x; + int height = (int) bufferSize.y; + + return (width == bufferWidth && height == bufferHeight); + } + + /** + * Whether buffer size is the same. + * + * @param width buffer width + * @param height buffer height + * @return Whether buffer size is the same + */ + public boolean isSameSize(final int width, final int height) { + return (width == bufferWidth && height == bufferHeight); + } + + + /** + * texture as rendering target. It is called frame buffer. + */ + private int[] renderTexture; + + /** + * color buffer + */ + private int[] colorBuffer = new int[1]; + + /** + * old frame buffer + */ + private int[] oldFBO = new int[1]; + + /** + * width specified at Create() method + */ + private int bufferWidth; + + /** + * height specified at Create() method + */ + private int bufferHeight; + + /** + * Whether the color buffer is the one set by the argument + */ + private boolean isColorBufferInherited; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismRendererAndroid.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismRendererAndroid.java new file mode 100644 index 0000000..2a1173e --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismRendererAndroid.java @@ -0,0 +1,520 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +import android.opengl.GLES11Ext; + +import com.live2d.sdk.cubism.framework.math.CubismVector2; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.rendering.CubismRenderer; +import com.live2d.sdk.cubism.framework.utils.CubismDebug; + +import java.nio.ShortBuffer; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static android.opengl.GLES20.*; +import static com.live2d.sdk.cubism.framework.CubismFrameworkConfig.CSM_DEBUG; + +/** + * The class that implements drawing instructions for Android. + */ +public class CubismRendererAndroid extends CubismRenderer { + /** + * Create the renderer instance for Android platform. + * + * @return renderer instance + */ + public static CubismRenderer create() { + return new CubismRendererAndroid(); + } + + /** + * Release static resources that this renderer keeps. + */ + public static void staticRelease() { + CubismRendererAndroid.doStaticRelease(); + } + + /** + * Tegra processor support. + * Enable/Disable drawing by extension method. + * + * @param extMode Whether to draw using the extended method + * @param extPAMode Whether to enable the PA setting for the extended method + */ + public static void setExtShaderMode(boolean extMode, boolean extPAMode) { + CubismShaderAndroid.setExtShaderMode(extMode, extPAMode); + CubismShaderAndroid.deleteInstance(); + } + + /** + * Android-Tegra support. Reload shader programs. + */ + public static void reloadShader() { + CubismShaderAndroid.deleteInstance(); + } + + @Override + public void initialize(CubismModel model) { + initialize(model, 1); + } + + @Override + public void initialize(CubismModel model, int maskBufferCount) { + // 頂点情報をキャッシュする。 + drawableInfoCachesHolder = new CubismDrawableInfoCachesHolder(model); + + if (model.isUsingMasking()) { + // マスクバッファの枚数として、0または負の値が指定されている場合は強制的に1枚と設定し、警告ログを出力する。 + // Webと違いCubismOffscreenSurfaceの配列を作成するため、こちらで不正値を検知し修正する。 + if (maskBufferCount < 1) { + maskBufferCount = 1; + CubismDebug.cubismLogWarning("The number of render textures must be an integer greater than or equal to 1. Set the number of render textures to 1."); + } + + // Initialize clipping mask and buffer preprocessing method + clippingManager = new CubismClippingManagerAndroid(); + clippingManager.initialize( + RendererType.ANDROID, + model, + maskBufferCount + ); + + offscreenSurfaces = new CubismOffscreenSurfaceAndroid[maskBufferCount]; + + for (int i = 0; i < maskBufferCount; i++) { + CubismOffscreenSurfaceAndroid offscreenSurface = new CubismOffscreenSurfaceAndroid(); + offscreenSurface.createOffscreenSurface(clippingManager.getClippingMaskBufferSize(), null); + + offscreenSurfaces[i] = offscreenSurface; + } + } + + sortedDrawableIndexList = new int[model.getDrawableCount()]; + super.initialize(model); + } + + @Override + public void close() { + super.close(); + + if (clippingManager != null) { + clippingManager.close(); + } + + if (offscreenSurfaces != null) { + for (int i = 0; i < offscreenSurfaces.length; i++) { + if (offscreenSurfaces[i].isValid()) { + offscreenSurfaces[i].destroyOffscreenSurface(); + } + } + } + + drawableInfoCachesHolder = null; + } + + /** + * Bind processing of OpenGL textures. + * + * @param modelTextureIndex number of the model texture to set + * @param glTextureIndex number of the OpenGL texture to bind + */ + public void bindTexture(int modelTextureIndex, int glTextureIndex) { + textures.put(modelTextureIndex, glTextureIndex); + areTexturesChanged = true; + } + + /** + * Get textures list bound to OpenGL. + * + * @return textures list + */ + public Map getBoundTextures() { + if (areTexturesChanged) { + cachedImmutableTextures = Collections.unmodifiableMap(textures); + areTexturesChanged = false; + } + return cachedImmutableTextures; + } + + /** + * Get the size of clipping mask buffer. + * + * @return size of clipping mask buffer + */ + private CubismVector2 getClippingMaskBufferSize() { + return clippingManager.getClippingMaskBufferSize(); + } + + /** + * Set the size of clipping mask buffer. + * This method's processing cost is high because the MaskBuffer for the mask is destroyed and recreated. + * + * @param width width of MaskBufferSize + * @param height height of MaskBufferSize + */ + public void setClippingMaskBufferSize(final float width, final float height) { + if (clippingManager == null) { + return; + } + + // インスタンス破棄前にレンダーテクスチャの数を保存 + final int renderTextureCount = this.clippingManager.getRenderTextureCount(); + + // Destroy and recreate instances to change the size of MaskBuffer + clippingManager = new CubismClippingManagerAndroid(); + clippingManager.setClippingMaskBufferSize(width, height); + + CubismModel model = getModel(); + clippingManager.initialize( + RendererType.ANDROID, + model, + renderTextureCount + ); + } + + /** + * レンダーテクスチャの枚数を取得する。 + * + * @return レンダーテクスチャの枚数 + */ + public int getRenderTextureCount() { + return clippingManager.getRenderTextureCount(); + } + + /** + * Draw the drawing objects (ArtMesh).
+ * Both polygon mesh and the texture number is given to this method. + * + * @param model number of the drawed texture + * @param index index of the drawing object + */ + protected void drawMeshAndroid( + final CubismModel model, + final int index + ) { + if (!CSM_DEBUG) { + // If the texture referenced by the model is not bound, skip drawing. + if (textures.get(model.getDrawableTextureIndex(index)) == null) { + return; + } + } + + // Enabling/disabling culling + if (isCulling()) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } + + // In Cubism3 OpenGL, CCW becomes surface for both masks and art meshes. + glFrontFace(GL_CCW); + + // マスク生成時 + if (isGeneratingMask()) { + CubismShaderAndroid.getInstance().setupShaderProgramForMask(this, model, index); + } else { + CubismShaderAndroid.getInstance().setupShaderProgramForDraw(this, model, index); + } + + // Draw the prygon mesh + final int indexCount = model.getDrawableVertexIndexCount(index); + final ShortBuffer indexArrayBuffer = drawableInfoCachesHolder.setUpIndexArray( + index, + model.getDrawableVertexIndices(index) + ); + glDrawElements( + GL_TRIANGLES, + indexCount, + GL_UNSIGNED_SHORT, + indexArrayBuffer + ); + + // post-processing + glUseProgram(0); + setClippingContextBufferForDraw(null); + setClippingContextBufferForMask(null); + } + + // This is only used by 'drawMeshAndroid' method. + // Avoid creating a new CubismTextureColor instance. + private final CubismTextureColor modelColorRGBA = new CubismTextureColor(); + + @Override + protected void doDrawModel() { + final CubismModel model = getModel(); + + // In the case of clipping mask and buffer preprocessing method + if (clippingManager != null) { + preDraw(); + + // If offscreen frame buffer size is different from clipping mask buffer size, recreate it. + for (int i = 0; i < clippingManager.getRenderTextureCount(); i++) { + CubismOffscreenSurfaceAndroid offscreenSurface = offscreenSurfaces[i]; + + if (!offscreenSurface.isSameSize(clippingManager.getClippingMaskBufferSize())) { + offscreenSurface.createOffscreenSurface(clippingManager.getClippingMaskBufferSize(), null); + } + } + + if (isUsingHighPrecisionMask()) { + clippingManager.setupMatrixForHighPrecision(getModel(), false); + } else { + clippingManager.setupClippingContext( + getModel(), + this, + rendererProfile.lastFBO, + rendererProfile.lastViewport + ); + } + } + + // preDraw() method is called twice. + preDraw(); + + final int drawableCount = model.getDrawableCount(); + final int[] renderOrder = model.getDrawableRenderOrders(); + + // Sort the index by drawing order + for (int i = 0; i < drawableCount; i++) { + final int order = renderOrder[i]; + sortedDrawableIndexList[order] = i; + } + + // Draw process + for (int i = 0; i < drawableCount; i++) { + final int drawableIndex = sortedDrawableIndexList[i]; + + // If Drawable is not in the display state, the process is passed. + if (!model.getDrawableDynamicFlagIsVisible(drawableIndex)) { + continue; + } + + // Set clipping mask + CubismClippingContextAndroid clipContext = (clippingManager != null) + ? clippingManager.getClippingContextListForDraw().get(drawableIndex) + : null; + + // マスクを描く必要がある + if (clipContext != null && isUsingHighPrecisionMask()) { + // 描くことになっていた + if (clipContext.isUsing) { + // 生成したOffscreenSurfaceと同じサイズでビューポートを設定 + glViewport(0, 0, (int) clippingManager.getClippingMaskBufferSize().x, (int) clippingManager.getClippingMaskBufferSize().y); + + // バッファをクリアする + preDraw(); + + // マスク描画処理 + // マスク用RenderTextureをactiveにセット + getMaskBuffer(clipContext.bufferIndex).beginDraw(rendererProfile.lastFBO); + + // マスクをクリアする。 + // 1が無効(描かれない領域)、0が有効(描かれる)領域。(シェーダーでCd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない。) + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + + final int clipDrawCount = clipContext.clippingIdCount; + for (int index = 0; index < clipDrawCount; index++) { + final int clipDrawIndex = clipContext.clippingIdList[index]; + + // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする + if (!getModel().getDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex)) { + continue; + } + + isCulling(getModel().getDrawableCulling(clipDrawIndex)); + + // 今回専用の変換を適用して描く + // チャンネルも切り替える必要がある(A,R,G,B) + setClippingContextBufferForMask(clipContext); + + drawMeshAndroid(model, clipDrawIndex); + } + // --- 後処理 --- + for (int j = 0; j < clippingManager.getRenderTextureCount(); j++) { + offscreenSurfaces[j].endDraw(); + setClippingContextBufferForMask(null); + glViewport( + rendererProfile.lastViewport[0], + rendererProfile.lastViewport[1], + rendererProfile.lastViewport[2], + rendererProfile.lastViewport[3] + ); + } + } + // クリッピングマスクをセットする + setClippingContextBufferForDraw(clipContext); + + isCulling(model.getDrawableCulling(drawableIndex)); + + drawMeshAndroid(model, drawableIndex); + } + postDraw(); + } + + @Override + protected void saveProfile() { + rendererProfile.save(); + } + + @Override + protected void restoreProfile() { + rendererProfile.restore(); + } + + /** + * Release OpenGLES2 static shader programs. + */ + static void doStaticRelease() { + CubismShaderAndroid.deleteInstance(); + } + + /** + * Get the clipping context to draw to the mask texture + * + * @return the clipping context to draw to the mask texture + */ + CubismClippingContextAndroid getClippingContextBufferForMask() { + return clippingContextBufferForMask; + } + + /** + * Set the clipping context to draw to the mask texture + * + * @param clip clipping context to draw to the mask texture + */ + void setClippingContextBufferForMask(CubismClippingContextAndroid clip) { + clippingContextBufferForMask = clip; + } + + /** + * Get the clipping context to draw on display + * + * @return the clipping context to draw on display + */ + CubismClippingContextAndroid getClippingContextBufferForDraw() { + return clippingContextBufferForDraw; + } + + /** + * Set the clipping context to draw on display + * + * @param clip the clipping context to draw on display + */ + void setClippingContextBufferForDraw(CubismClippingContextAndroid clip) { + clippingContextBufferForDraw = clip; + } + + /** + * Get the offscreen frame buffer + * + * @return the offscreen frame buffer + */ + CubismOffscreenSurfaceAndroid getMaskBuffer(int index) { + return offscreenSurfaces[index]; + } + + CubismDrawableInfoCachesHolder getDrawableInfoCachesHolder() { + return drawableInfoCachesHolder; + } + + /** + * Additional proccesing at the start of drawing + * This method implements the necessary processing for the clipping mask before drawing the model + */ + void preDraw() { + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + + glEnable(GL_BLEND); + glColorMask(true, true, true, true); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + // If the buffer has been bound before, it needs to be destroyed + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // Anisotropic filtering. If it is not supported, do not set it + if (getAnisotropy() >= 1.0f) { + for (Map.Entry entry : textures.entrySet()) { + glBindTexture(GL_TEXTURE_2D, entry.getValue()); + glTexParameterf(GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_MAX_ANISOTROPY_EXT, getAnisotropy()); + } + } + } + + /** + * Additinal processing after drawing is completed. + */ + void postDraw() { + } + + /** + * テクスチャマップにバインドされたテクスチャIDを取得する。 + * バインドされていなければダミーとして-1を返します。 + * + * @param textureId テクスチャID + * @return バインドされたテクスチャID + */ + int getBoundTextureId(int textureId) { + Integer boundTextureId = textures.get(textureId); + return boundTextureId == null ? -1 : boundTextureId; + } + + /** + * Frame buffer for drawing mask + */ + CubismOffscreenSurfaceAndroid[] offscreenSurfaces; + + /** + * マスク生成時かどうかを判定する。 + * + * @return マスク生成時かどうか。生成時ならtrue。 + */ + private boolean isGeneratingMask() { + return getClippingContextBufferForMask() != null; + } + + /** + * Map between the textures referenced by the model and the textures bound by the renderer + */ + private final Map textures = new HashMap(32); + + private boolean areTexturesChanged = true; + + private Map cachedImmutableTextures; + /** + * A list of drawing object indices arranged in drawing order + */ + private int[] sortedDrawableIndexList; + /** + * the object which keeps the OpenGL state + */ + private final CubismRendererProfileAndroid rendererProfile = new CubismRendererProfileAndroid(); + /** + * Clipping mask management object + */ + private CubismClippingManagerAndroid clippingManager; + /** + * Clippping context for drawing on mask texture + */ + private CubismClippingContextAndroid clippingContextBufferForMask; + /** + * Clipping context for drawing on the screen + */ + private CubismClippingContextAndroid clippingContextBufferForDraw; + + /** + * Drawable情報のキャッシュ変数 + */ + private CubismDrawableInfoCachesHolder drawableInfoCachesHolder; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismRendererProfileAndroid.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismRendererProfileAndroid.java new file mode 100644 index 0000000..3b4068a --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismRendererProfileAndroid.java @@ -0,0 +1,222 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +import static android.opengl.GLES20.*; + +/** + * Class that saves and restores the OpenGL ES 2.0 state just before drawing the Cubism model. + */ +class CubismRendererProfileAndroid { + /** + * Save OpenGL ES 2.0 state. + */ + public void save() { + //-- push state -- + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, lastArrayBufferBinding, 0); + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, lastElementArrayBufferBinding, 0); + glGetIntegerv(GL_CURRENT_PROGRAM, lastProgram, 0); + + glGetIntegerv(GL_ACTIVE_TEXTURE, lastActiveTexture, 0); + + // Activate Texture Unit1 (It is the target to be set thereafter) + glActiveTexture(GL_TEXTURE1); + glGetIntegerv(GL_TEXTURE_BINDING_2D, lastTexture1Binding2D, 0); + + // Activate Texture Unit0 (It is the target to be set thereafter) + glActiveTexture(GL_TEXTURE0); + glGetIntegerv(GL_TEXTURE_BINDING_2D, lastTexture0Binding2D, 0); + + glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, lastVertexAttribArrayEnabled[0], 0); + glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, lastVertexAttribArrayEnabled[1], 0); + glGetVertexAttribiv(2, GL_VERTEX_ATTRIB_ARRAY_ENABLED, lastVertexAttribArrayEnabled[2], 0); + glGetVertexAttribiv(3, GL_VERTEX_ATTRIB_ARRAY_ENABLED, lastVertexAttribArrayEnabled[3], 0); + + lastScissorTest = glIsEnabled(GL_SCISSOR_TEST); + lastStencilTest = glIsEnabled(GL_STENCIL_TEST); + lastDepthTest = glIsEnabled(GL_DEPTH_TEST); + lastCullFace = glIsEnabled(GL_CULL_FACE); + lastBlend = glIsEnabled(GL_BLEND); + + glGetIntegerv(GL_FRONT_FACE, lastFrontFace, 0); + + glGetBooleanv(GL_COLOR_WRITEMASK, lastColorMask, 0); + + // backup blending + glGetIntegerv(GL_BLEND_SRC_RGB, lastBlendingSrcRGB, 0); + glGetIntegerv(GL_BLEND_DST_RGB, lastBlendingDstRGB, 0); + glGetIntegerv(GL_BLEND_SRC_ALPHA, lastBlendingSrcAlpha, 0); + glGetIntegerv(GL_BLEND_DST_ALPHA, lastBlendingDstAlpha, 0); + + // Save the FBO and viewport just before drawing the model. + glGetIntegerv(GL_FRAMEBUFFER_BINDING, lastFBO, 0); + glGetIntegerv(GL_VIEWPORT, lastViewport, 0); + } + + /** + * Restore OpenGL ES 2.0 state which is saved. + */ + public void restore() { + glUseProgram(lastProgram[0]); + + setGlEnableVertexAttribArray(0, lastVertexAttribArrayEnabled[0][0]); + setGlEnableVertexAttribArray(1, lastVertexAttribArrayEnabled[1][0]); + setGlEnableVertexAttribArray(2, lastVertexAttribArrayEnabled[2][0]); + setGlEnableVertexAttribArray(3, lastVertexAttribArrayEnabled[3][0]); + + setGlEnable(GL_SCISSOR_TEST, lastScissorTest); + setGlEnable(GL_STENCIL_TEST, lastStencilTest); + setGlEnable(GL_DEPTH_TEST, lastDepthTest); + setGlEnable(GL_CULL_FACE, lastCullFace); + setGlEnable(GL_BLEND, lastBlend); + + glFrontFace(lastFrontFace[0]); + + glColorMask( + lastColorMask[0], + lastColorMask[1], + lastColorMask[2], + lastColorMask[3] + ); + + // If the buffer was bound before, it needs to be destroyed. + glBindBuffer(GL_ARRAY_BUFFER, lastArrayBufferBinding[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lastElementArrayBufferBinding[0]); + + // Restore Texture Unit1. + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, lastTexture1Binding2D[0]); + + // Restore Texture Unit0. + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, lastTexture0Binding2D[0]); + + glActiveTexture(lastActiveTexture[0]); + + // restore blending + glBlendFuncSeparate( + lastBlendingSrcRGB[0], + lastBlendingDstRGB[0], + lastBlendingSrcAlpha[0], + lastBlendingDstAlpha[0] + ); + } + + /** + * FBO just before model drawing + */ + public final int[] lastFBO = new int[1]; + /** + * Viewport just before drawing the model + */ + public final int[] lastViewport = new int[4]; + + /** + * Set enable/disable of OpenGL ES 2.0 features. + * + * @param index index of function to enable/disable + * @param enabled If true, enable it. + */ + private void setGlEnable(int index, boolean enabled) { + if (enabled) { + glEnable(index); + } else { + glDisable(index); + } + } + + /** + * Set enable/disable for Vertex Attribute Array feature in OpenGL ES 2.0. + * + * @param index index of function to enable/disable + * @param isEnabled If true, enable it. + */ + private void setGlEnableVertexAttribArray(int index, int isEnabled) { + // It true + if (isEnabled != 0) { + glEnableVertexAttribArray(index); + } + // If false + else { + glDisableVertexAttribArray(index); + } + } + + /** + * Vertex buffer just before drawing the model + */ + private final int[] lastArrayBufferBinding = new int[1]; + /** + * Element buffer just before drawing the model + */ + private final int[] lastElementArrayBufferBinding = new int[1]; + /** + * Shader program buffer just before drawing the model + */ + private final int[] lastProgram = new int[1]; + /** + * The active texture just before drawing the model + */ + private final int[] lastActiveTexture = new int[1]; + /** + * Texture unit0 just before model drawing + */ + private final int[] lastTexture0Binding2D = new int[1]; + /** + * Texture unit1 just before model drawing + */ + private final int[] lastTexture1Binding2D = new int[1]; + /** + * GL_VERTEX_ATTRIB_ARRAY_ENABLED parameter just before model drawing + */ + private final int[][] lastVertexAttribArrayEnabled = new int[4][1]; + /** + * GL_SCISSOR_TEST parameter just before drawing the model + */ + private boolean lastScissorTest; + /** + * GL_BLEND parameter just before model drawing + */ + private boolean lastBlend; + /** + * GL_STENCIL_TEST parameter just before drawing the model + */ + private boolean lastStencilTest; + /** + * GL_DEPTH_TEST parameter just before drawing the model + */ + private boolean lastDepthTest; + /** + * GL_CULL_FACE parameter just before drawing the model + */ + private boolean lastCullFace; + /** + * GL_FRONT_FACE parameter just before model drawing + */ + private final int[] lastFrontFace = new int[1]; + /** + * GL_COLOR_WRITEMASK parameter just before model drawing + */ + private final boolean[] lastColorMask = new boolean[4]; + /** + * GL_BLEND_SRC_RGB parameter just before model drawing + */ + private final int[] lastBlendingSrcRGB = new int[1]; + /** + * GL_BLEND_DST_RGB parameter just before model drawing + */ + private final int[] lastBlendingDstRGB = new int[1]; + /** + * GL_BLEND_SRC_ALPHA parameter just before model drawing + */ + private final int[] lastBlendingSrcAlpha = new int[1]; + /** + * GL_BLEND_DST_ALPHA parameter just before model drawing + */ + private final int[] lastBlendingDstAlpha = new int[1]; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismShaderAndroid.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismShaderAndroid.java new file mode 100644 index 0000000..2f7d719 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismShaderAndroid.java @@ -0,0 +1,878 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +import com.live2d.sdk.cubism.framework.math.CubismMatrix44; +import com.live2d.sdk.cubism.framework.model.CubismModel; +import com.live2d.sdk.cubism.framework.rendering.CubismRenderer; +import com.live2d.sdk.cubism.framework.type.csmRectF; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; + +import static android.opengl.GLES20.*; +import static com.live2d.sdk.cubism.framework.rendering.android.CubismShaderPrograms.*; +import static com.live2d.sdk.cubism.framework.utils.CubismDebug.cubismLogError; + +/** + * This class manage a shader program for Android(OpenGL ES 2.0). This is singleton. + */ +class CubismShaderAndroid { + /** + * Tegra processor support. Enable/Disable drawing by extension method. + * + * @param extMode Whether to draw using the extended method. + * @param extPAMode Enables/disables the PA setting for the extension method. + */ + public static void setExtShaderMode(boolean extMode, boolean extPAMode) { + CubismShaderAndroid.EXT_MODE = extMode; + CubismShaderAndroid.EXT_PA_MODE = extPAMode; + } + + /** + * Get this singleton instance. + * + * @return singleton instance + */ + public static CubismShaderAndroid getInstance() { + if (s_instance == null) { + s_instance = new CubismShaderAndroid(); + } + + return s_instance; + } + + /** + * Delete this singleton instance. + */ + public static void deleteInstance() { + s_instance = null; + } + + /** + * Setup shader program. + * + * @param renderer renderer instance + * @param model rendered model + * @param index target artmesh index + */ + public void setupShaderProgramForDraw( + CubismRendererAndroid renderer, + CubismModel model, + int index + ) { + if (shaderSets.isEmpty()) { + generateShaders(); + } + + // Blending + int srcColor; + int dstColor; + int srcAlpha; + int dstAlpha; + + // shaderSets用のオフセット計算 + final boolean isMasked = renderer.getClippingContextBufferForDraw() != null; // この描画オブジェクトはマスク対象か? + final boolean isInvertedMask = model.getDrawableInvertedMask(index); + final boolean isPremultipliedAlpha = renderer.isPremultipliedAlpha(); + + final int offset = (isMasked ? (isInvertedMask ? 2 : 1) : 0) + (isPremultipliedAlpha ? 3 : 0); + + // シェーダーセット + CubismShaderSet shaderSet; + switch (model.getDrawableBlendMode(index)) { + case NORMAL: + default: + shaderSet = this.shaderSets.get(ShaderNames.NORMAL.getId() + offset); + srcColor = GL_ONE; + dstColor = GL_ONE_MINUS_SRC_ALPHA; + srcAlpha = GL_ONE; + dstAlpha = GL_ONE_MINUS_SRC_ALPHA; + break; + case ADDITIVE: + shaderSet = shaderSets.get(ShaderNames.ADD.getId() + offset); + srcColor = GL_ONE; + dstColor = GL_ONE; + srcAlpha = GL_ZERO; + dstAlpha = GL_ONE; + break; + case MULTIPLICATIVE: + shaderSet = shaderSets.get(ShaderNames.MULT.getId() + offset); + srcColor = GL_DST_COLOR; + dstColor = GL_ONE_MINUS_SRC_ALPHA; + srcAlpha = GL_ZERO; + dstAlpha = GL_ONE; + break; + } + + glUseProgram(shaderSet.shaderProgram); + + // キャッシュされたバッファを取得し、実際のデータを格納する。 + CubismDrawableInfoCachesHolder drawableInfoCachesHolder = renderer.getDrawableInfoCachesHolder(); + // vertex array + FloatBuffer vertexArrayBuffer = drawableInfoCachesHolder.setUpVertexArray( + index, + model.getDrawableVertices(index) + ); + // uv array + FloatBuffer uvArrayBuffer = drawableInfoCachesHolder.setUpUvArray( + index, + model.getDrawableVertexUvs(index) + ); + + // setting of vertex array + glEnableVertexAttribArray(shaderSet.attributePositionLocation); + glVertexAttribPointer( + shaderSet.attributePositionLocation, + 2, + GL_FLOAT, + false, + Float.SIZE / Byte.SIZE * 2, + vertexArrayBuffer + ); + + // setting of texture vertex + glEnableVertexAttribArray(shaderSet.attributeTexCoordLocation); + glVertexAttribPointer( + shaderSet.attributeTexCoordLocation, + 2, + GL_FLOAT, + false, + Float.SIZE / Byte.SIZE * 2, + uvArrayBuffer + ); + + if (isMasked) { + glActiveTexture(GL_TEXTURE1); + + // OffscreenSurfaceに描かれたテクスチャ + int tex = renderer.getMaskBuffer(renderer.getClippingContextBufferForDraw().bufferIndex).getColorBuffer()[0]; + glBindTexture(GL_TEXTURE_2D, tex); + glUniform1i(shaderSet.samplerTexture1Location, 1); + + // set up a matrix to convert View-coordinates to ClippingContext coordinates + glUniformMatrix4fv( + shaderSet.uniformClipMatrixLocation, + 1, + false, + renderer.getClippingContextBufferForDraw().matrixForDraw.getArray(), + 0 + ); + + // Set used color channel. + final int channelIndex = renderer.getClippingContextBufferForDraw().layoutChannelIndex; + CubismRenderer.CubismTextureColor colorChannel = renderer + .getClippingContextBufferForDraw() + .getClippingManager() + .getChannelFlagAsColor(channelIndex); + glUniform4f( + shaderSet.uniformChannelFlagLocation, + colorChannel.r, + colorChannel.g, + colorChannel.b, + colorChannel.a + ); + } + + // texture setting + int textureId = renderer.getBoundTextureId( + model.getDrawableTextureIndex(index) + ); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureId); + glUniform1i(shaderSet.samplerTexture0Location, 0); + + // coordinate transformation + CubismMatrix44 matrix44 = renderer.getMvpMatrix(); + glUniformMatrix4fv( + shaderSet.uniformMatrixLocation, + 1, + false, + matrix44.getArray(), + 0 + ); + + // ベース色の取得 + CubismRenderer.CubismTextureColor baseColor = renderer.getModelColorWithOpacity( + model.getDrawableOpacity(index) + ); + CubismRenderer.CubismTextureColor multiplyColor = model.getMultiplyColor(index); + CubismRenderer.CubismTextureColor screenColor = model.getScreenColor(index); + glUniform4f( + shaderSet.uniformBaseColorLocation, + baseColor.r, + baseColor.g, + baseColor.b, + baseColor.a + ); + glUniform4f( + shaderSet.uniformMultiplyColorLocation, + multiplyColor.r, + multiplyColor.g, + multiplyColor.b, + multiplyColor.a + ); + glUniform4f( + shaderSet.uniformScreenColorLocation, + screenColor.r, + screenColor.g, + screenColor.b, + screenColor.a + ); + + glBlendFuncSeparate(srcColor, dstColor, srcAlpha, dstAlpha); + } + + public void setupShaderProgramForMask( + CubismRendererAndroid renderer, + CubismModel model, + int index + ) { + if (shaderSets.isEmpty()) { + generateShaders(); + } + + // Blending + int srcColor; + int dstColor; + int srcAlpha; + int dstAlpha; + + CubismShaderSet shaderSet = shaderSets.get(ShaderNames.SETUP_MASK.id); + glUseProgram(shaderSet.shaderProgram); + + // texture setting + int textureId = renderer.getBoundTextureId(model.getDrawableTextureIndex(index)); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureId); + glUniform1i(shaderSet.samplerTexture0Location, 0); + + // キャッシュされたバッファを取得し、実際のデータを格納する。 + CubismDrawableInfoCachesHolder drawableInfoCachesHolder = renderer.getDrawableInfoCachesHolder(); + // vertex array + FloatBuffer vertexArrayBuffer = drawableInfoCachesHolder.setUpVertexArray( + index, + model.getDrawableVertices(index) + ); + // uv array + FloatBuffer uvArrayBuffer = drawableInfoCachesHolder.setUpUvArray( + index, + model.getDrawableVertexUvs(index) + ); + + // setting of vertex array + glEnableVertexAttribArray(shaderSet.attributePositionLocation); + glVertexAttribPointer( + shaderSet.attributePositionLocation, + 2, + GL_FLOAT, + false, + Float.SIZE / Byte.SIZE * 2, + vertexArrayBuffer + ); + + // setting of texture vertex + glEnableVertexAttribArray(shaderSet.attributeTexCoordLocation); + glVertexAttribPointer( + shaderSet.attributeTexCoordLocation, + 2, + GL_FLOAT, + false, + Float.SIZE / Byte.SIZE * 2, + uvArrayBuffer + ); + + // channels + final int channelIndex = renderer.getClippingContextBufferForMask().layoutChannelIndex; + CubismRenderer.CubismTextureColor colorChannel = renderer + .getClippingContextBufferForMask() + .getClippingManager() + .getChannelFlagAsColor(channelIndex); + + glUniform4f( + shaderSet.uniformChannelFlagLocation, + colorChannel.r, + colorChannel.g, + colorChannel.b, + colorChannel.a + ); + + glUniformMatrix4fv( + shaderSet.uniformClipMatrixLocation, + 1, + false, + renderer.getClippingContextBufferForMask().matrixForMask.getArray(), + 0 + ); + + csmRectF rect = renderer.getClippingContextBufferForMask().layoutBounds; + + glUniform4f( + shaderSet.uniformBaseColorLocation, + rect.getX() * 2.0f - 1.0f, + rect.getY() * 2.0f - 1.0f, + rect.getRight() * 2.0f - 1.0f, + rect.getBottom() * 2.0f - 1.0f + ); + + CubismRenderer.CubismTextureColor multiplyColor = model.getMultiplyColor(index); + CubismRenderer.CubismTextureColor screenColor = model.getScreenColor(index); + glUniform4f( + shaderSet.uniformMultiplyColorLocation, + multiplyColor.r, + multiplyColor.g, + multiplyColor.b, + multiplyColor.a + ); + glUniform4f( + shaderSet.uniformScreenColorLocation, + screenColor.r, + screenColor.g, + screenColor.b, + screenColor.a + ); + + srcColor = GL_ZERO; + dstColor = GL_ONE_MINUS_SRC_COLOR; + srcAlpha = GL_ZERO; + dstAlpha = GL_ONE_MINUS_SRC_ALPHA; + + glBlendFuncSeparate(srcColor, dstColor, srcAlpha, dstAlpha); + } + + /** + * Singleton instance. + */ + private static CubismShaderAndroid s_instance; + + /** + * Tegra support. Drawing with Extended Method. + */ + private static boolean EXT_MODE; + /** + * Variable for setting the PA of the extension method. + */ + private static boolean EXT_PA_MODE; + + /** + * Shader names + */ + private enum ShaderNames { + // Setup Mask + SETUP_MASK(0), + + // Normal + NORMAL(1), + NORMAL_MASKED(2), + NORMAL_MASKED_INVERTED(3), + NORMAL_PREMULTIPLIED_ALPHA(4), + NORMAL_MASKED_PREMULTIPLIED_ALPHA(5), + NORMAL_MASKED_INVERTED_PREMULTIPLIED_ALPHA(6), + + // Add + ADD(7), + ADD_MASKED(8), + ADD_MASKED_INVERTED(9), + ADD_PREMULTIPLIED_ALPHA(10), + ADD_MASKED_PREMULTIPLIED_ALPHA(11), + ADD_MASKED_PREMULTIPLIED_ALPHA_INVERTED(12), + + // Multi + MULT(13), + MULT_MASKED(14), + MULT_MASKED_INVERTED(15), + MULT_PREMULTIPLIED_ALPHA(16), + MULT_MASKED_PREMULTIPLIED_ALPHA(17), + MULT_MASKED_PREMULTIPLIED_ALPHA_INVERTED(18); + + private final int id; + + ShaderNames(int id) { + this.id = id; + } + + private int getId() { + return id; + } + } + + /** + * Data class that holds the addresses of shader programs and shader variables + */ + private static class CubismShaderSet { + /** + * address of shader program. + */ + int shaderProgram; + /** + * Address of the variable to be passed to the shader program (Position) + */ + int attributePositionLocation; + /** + * Address of the variable to be passed to the shader program (TexCoord) + */ + int attributeTexCoordLocation; + /** + * Address of the variable to be passed to the shader program (Matrix) + */ + int uniformMatrixLocation; + /** + * Address of the variable to be passed to the shader program (ClipMatrix) + */ + int uniformClipMatrixLocation; + /** + * Address of the variable to be passed to the shader program (Texture0) + */ + int samplerTexture0Location; + /** + * Address of the variable to be passed to the shader program (Texture1) + */ + int samplerTexture1Location; + /** + * Address of the variable to be passed to the shader program (BaseColor) + */ + int uniformBaseColorLocation; + /** + * Address of the variable to be passed to the shader program (MultiplyColor) + */ + int uniformMultiplyColorLocation; + /** + * Address of the variable to be passed to the shader program (ScreenColor) + */ + int uniformScreenColorLocation; + /** + * Address of the variable to be passed to the shader program (ChannelFlag) + */ + int uniformChannelFlagLocation; + } + + /** + * private constructor. + */ + private CubismShaderAndroid() { + } + + /** + * Release shader programs. + */ + private void releaseShaderProgram() { + for (CubismShaderSet shaderSet : shaderSets) { + glDeleteProgram(shaderSet.shaderProgram); + shaderSet.shaderProgram = 0; + } + shaderSets.clear(); + } + + /** + * Initialize and generate shader programs. + */ + private void generateShaders() { + for (int i = 0; i < SHADER_COUNT; i++) { + shaderSets.add(new CubismShaderSet()); + } + + if (EXT_MODE) { + shaderSets.get(0).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_SETUP_MASK, FRAG_SHADER_SRC_SETUP_MASK_TEGRA); + shaderSets.get(1).shaderProgram = loadShaderProgram(VERT_SHADER_SRC, FRAG_SHADER_SRC_TEGRA); + shaderSets.get(2).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_TEGRA); + shaderSets.get(3).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_INVERTED_TEGRA); + shaderSets.get(4).shaderProgram = loadShaderProgram(VERT_SHADER_SRC, FRAG_SHADER_SRC_PREMULTIPLIED_ALPHA_TEGRA); + shaderSets.get(5).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_PREMULTIPLIED_ALPHA_TEGRA); + shaderSets.get(6).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_INVERTED_PREMULTIPLIED_ALPHA_TEGRA); + } else { + shaderSets.get(0).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_SETUP_MASK, FRAG_SHADER_SRC_SETUP_MASK); + shaderSets.get(1).shaderProgram = loadShaderProgram(VERT_SHADER_SRC, FRAG_SHADER_SRC); + shaderSets.get(2).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK); + shaderSets.get(3).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_INVERTED); + shaderSets.get(4).shaderProgram = loadShaderProgram(VERT_SHADER_SRC, FRAG_SHADER_SRC_PREMULTIPLIED_ALPHA); + shaderSets.get(5).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_PREMULTIPLIED_ALPHA); + shaderSets.get(6).shaderProgram = loadShaderProgram(VERT_SHADER_SRC_MASKED, FRAG_SHADER_SRC_MASK_INVERTED_PREMULTIPLIED_ALPHA); + } + + // 加算も通常と同じシェーダーを利用する + shaderSets.get(7).shaderProgram = shaderSets.get(1).shaderProgram; + shaderSets.get(8).shaderProgram = shaderSets.get(2).shaderProgram; + shaderSets.get(9).shaderProgram = shaderSets.get(3).shaderProgram; + shaderSets.get(10).shaderProgram = shaderSets.get(4).shaderProgram; + shaderSets.get(11).shaderProgram = shaderSets.get(5).shaderProgram; + shaderSets.get(12).shaderProgram = shaderSets.get(6).shaderProgram; + + // 乗算も通常と同じシェーダーを利用する + shaderSets.get(13).shaderProgram = shaderSets.get(1).shaderProgram; + shaderSets.get(14).shaderProgram = shaderSets.get(2).shaderProgram; + shaderSets.get(15).shaderProgram = shaderSets.get(3).shaderProgram; + shaderSets.get(16).shaderProgram = shaderSets.get(4).shaderProgram; + shaderSets.get(17).shaderProgram = shaderSets.get(5).shaderProgram; + shaderSets.get(18).shaderProgram = shaderSets.get(6).shaderProgram; + + // Setup mask + shaderSets.get(0).attributePositionLocation = glGetAttribLocation(shaderSets.get(0).shaderProgram, "a_position"); + shaderSets.get(0).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(0).shaderProgram, "a_texCoord"); + shaderSets.get(0).samplerTexture0Location = glGetUniformLocation(shaderSets.get(0).shaderProgram, "s_texture0"); + shaderSets.get(0).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(0).shaderProgram, "u_clipMatrix"); + shaderSets.get(0).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(0).shaderProgram, "u_channelFlag"); + shaderSets.get(0).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(0).shaderProgram, "u_baseColor"); + shaderSets.get(0).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(0).shaderProgram, "u_multiplyColor"); + shaderSets.get(0).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(0).shaderProgram, "u_screenColor"); + + // 通常 + shaderSets.get(1).attributePositionLocation = glGetAttribLocation(shaderSets.get(1).shaderProgram, "a_position"); + shaderSets.get(1).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(1).shaderProgram, "a_texCoord"); + shaderSets.get(1).samplerTexture0Location = glGetUniformLocation(shaderSets.get(1).shaderProgram, "s_texture0"); + shaderSets.get(1).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(1).shaderProgram, "u_matrix"); + shaderSets.get(1).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(1).shaderProgram, "u_baseColor"); + shaderSets.get(1).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(1).shaderProgram, "u_multiplyColor"); + shaderSets.get(1).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(1).shaderProgram, "u_screenColor"); + + // 通常(クリッピング) + shaderSets.get(2).attributePositionLocation = glGetAttribLocation(shaderSets.get(2).shaderProgram, "a_position"); + shaderSets.get(2).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(2).shaderProgram, "a_texCoord"); + shaderSets.get(2).samplerTexture0Location = glGetUniformLocation(shaderSets.get(2).shaderProgram, "s_texture0"); + shaderSets.get(2).samplerTexture1Location = glGetUniformLocation(shaderSets.get(2).shaderProgram, "s_texture1"); + shaderSets.get(2).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(2).shaderProgram, "u_matrix"); + shaderSets.get(2).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(2).shaderProgram, "u_clipMatrix"); + shaderSets.get(2).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(2).shaderProgram, "u_channelFlag"); + shaderSets.get(2).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(2).shaderProgram, "u_baseColor"); + shaderSets.get(2).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(2).shaderProgram, "u_multiplyColor"); + shaderSets.get(2).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(2).shaderProgram, "u_screenColor"); + + // 通常(クリッピング・反転) + shaderSets.get(3).attributePositionLocation = glGetAttribLocation(shaderSets.get(3).shaderProgram, "a_position"); + shaderSets.get(3).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(3).shaderProgram, "a_texCoord"); + shaderSets.get(3).samplerTexture0Location = glGetUniformLocation(shaderSets.get(3).shaderProgram, "s_texture0"); + shaderSets.get(3).samplerTexture1Location = glGetUniformLocation(shaderSets.get(3).shaderProgram, "s_texture1"); + shaderSets.get(3).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(3).shaderProgram, "u_matrix"); + shaderSets.get(3).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(3).shaderProgram, "u_clipMatrix"); + shaderSets.get(3).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(3).shaderProgram, "u_channelFlag"); + shaderSets.get(3).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(3).shaderProgram, "u_baseColor"); + shaderSets.get(3).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(3).shaderProgram, "u_multiplyColor"); + shaderSets.get(3).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(3).shaderProgram, "u_screenColor"); + + // 通常(PremultipliedAlpha) + shaderSets.get(4).attributePositionLocation = glGetAttribLocation(shaderSets.get(4).shaderProgram, "a_position"); + shaderSets.get(4).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(4).shaderProgram, "a_texCoord"); + shaderSets.get(4).samplerTexture0Location = glGetUniformLocation(shaderSets.get(4).shaderProgram, "s_texture0"); + shaderSets.get(4).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(4).shaderProgram, "u_matrix"); + shaderSets.get(4).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(4).shaderProgram, "u_baseColor"); + shaderSets.get(4).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(4).shaderProgram, "u_multiplyColor"); + shaderSets.get(4).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(4).shaderProgram, "u_screenColor"); + + // 通常(クリッピング、PremultipliedAlpha) + shaderSets.get(5).attributePositionLocation = glGetAttribLocation(shaderSets.get(5).shaderProgram, "a_position"); + shaderSets.get(5).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(5).shaderProgram, "a_texCoord"); + shaderSets.get(5).samplerTexture0Location = glGetUniformLocation(shaderSets.get(5).shaderProgram, "s_texture0"); + shaderSets.get(5).samplerTexture1Location = glGetUniformLocation(shaderSets.get(5).shaderProgram, "s_texture1"); + shaderSets.get(5).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(5).shaderProgram, "u_matrix"); + shaderSets.get(5).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(5).shaderProgram, "u_clipMatrix"); + shaderSets.get(5).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(5).shaderProgram, "u_channelFlag"); + shaderSets.get(5).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(5).shaderProgram, "u_baseColor"); + shaderSets.get(5).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(5).shaderProgram, "u_multiplyColor"); + shaderSets.get(5).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(5).shaderProgram, "u_screenColor"); + + // 通常(クリッピング・反転、PremultipliedAlpha) + shaderSets.get(6).attributePositionLocation = glGetAttribLocation(shaderSets.get(6).shaderProgram, "a_position"); + shaderSets.get(6).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(6).shaderProgram, "a_texCoord"); + shaderSets.get(6).samplerTexture0Location = glGetUniformLocation(shaderSets.get(6).shaderProgram, "s_texture0"); + shaderSets.get(6).samplerTexture1Location = glGetUniformLocation(shaderSets.get(6).shaderProgram, "s_texture1"); + shaderSets.get(6).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(6).shaderProgram, "u_matrix"); + shaderSets.get(6).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(6).shaderProgram, "u_clipMatrix"); + shaderSets.get(6).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(6).shaderProgram, "u_channelFlag"); + shaderSets.get(6).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(6).shaderProgram, "u_baseColor"); + shaderSets.get(6).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(6).shaderProgram, "u_multiplyColor"); + shaderSets.get(6).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(6).shaderProgram, "u_screenColor"); + + // 加算 + shaderSets.get(7).attributePositionLocation = glGetAttribLocation(shaderSets.get(7).shaderProgram, "a_position"); + shaderSets.get(7).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(7).shaderProgram, "a_texCoord"); + shaderSets.get(7).samplerTexture0Location = glGetUniformLocation(shaderSets.get(7).shaderProgram, "s_texture0"); + shaderSets.get(7).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(7).shaderProgram, "u_matrix"); + shaderSets.get(7).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(7).shaderProgram, "u_baseColor"); + shaderSets.get(7).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(7).shaderProgram, "u_multiplyColor"); + shaderSets.get(7).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(7).shaderProgram, "u_screenColor"); + + // 加算(クリッピング) + shaderSets.get(8).attributePositionLocation = glGetAttribLocation(shaderSets.get(8).shaderProgram, "a_position"); + shaderSets.get(8).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(8).shaderProgram, "a_texCoord"); + shaderSets.get(8).samplerTexture0Location = glGetUniformLocation(shaderSets.get(8).shaderProgram, "s_texture0"); + shaderSets.get(8).samplerTexture1Location = glGetUniformLocation(shaderSets.get(8).shaderProgram, "s_texture1"); + shaderSets.get(8).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(8).shaderProgram, "u_matrix"); + shaderSets.get(8).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(8).shaderProgram, "u_clipMatrix"); + shaderSets.get(8).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(8).shaderProgram, "u_channelFlag"); + shaderSets.get(8).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(8).shaderProgram, "u_baseColor"); + shaderSets.get(8).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(8).shaderProgram, "u_multiplyColor"); + shaderSets.get(8).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(8).shaderProgram, "u_screenColor"); + + // 加算(クリッピング・反転) + shaderSets.get(9).attributePositionLocation = glGetAttribLocation(shaderSets.get(9).shaderProgram, "a_position"); + shaderSets.get(9).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(9).shaderProgram, "a_texCoord"); + shaderSets.get(9).samplerTexture0Location = glGetUniformLocation(shaderSets.get(9).shaderProgram, "s_texture0"); + shaderSets.get(9).samplerTexture1Location = glGetUniformLocation(shaderSets.get(9).shaderProgram, "s_texture1"); + shaderSets.get(9).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(9).shaderProgram, "u_matrix"); + shaderSets.get(9).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(9).shaderProgram, "u_clipMatrix"); + shaderSets.get(9).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(9).shaderProgram, "u_channelFlag"); + shaderSets.get(9).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(9).shaderProgram, "u_baseColor"); + shaderSets.get(9).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(9).shaderProgram, "u_multiplyColor"); + shaderSets.get(9).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(9).shaderProgram, "u_screenColor"); + + // 加算(PremultipliedAlpha) + shaderSets.get(10).attributePositionLocation = glGetAttribLocation(shaderSets.get(10).shaderProgram, "a_position"); + shaderSets.get(10).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(10).shaderProgram, "a_texCoord"); + shaderSets.get(10).samplerTexture0Location = glGetUniformLocation(shaderSets.get(10).shaderProgram, "s_texture0"); + shaderSets.get(10).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(10).shaderProgram, "u_matrix"); + shaderSets.get(10).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(10).shaderProgram, "u_baseColor"); + shaderSets.get(10).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(10).shaderProgram, "u_multiplyColor"); + shaderSets.get(10).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(10).shaderProgram, "u_screenColor"); + + // 加算(クリッピング、PremultipliedAlpha) + shaderSets.get(11).attributePositionLocation = glGetAttribLocation(shaderSets.get(11).shaderProgram, "a_position"); + shaderSets.get(11).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(11).shaderProgram, "a_texCoord"); + shaderSets.get(11).samplerTexture0Location = glGetUniformLocation(shaderSets.get(11).shaderProgram, "s_texture0"); + shaderSets.get(11).samplerTexture1Location = glGetUniformLocation(shaderSets.get(11).shaderProgram, "s_texture1"); + shaderSets.get(11).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(11).shaderProgram, "u_matrix"); + shaderSets.get(11).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(11).shaderProgram, "u_clipMatrix"); + shaderSets.get(11).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(11).shaderProgram, "u_channelFlag"); + shaderSets.get(11).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(11).shaderProgram, "u_baseColor"); + shaderSets.get(11).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(11).shaderProgram, "u_multiplyColor"); + shaderSets.get(11).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(11).shaderProgram, "u_screenColor"); + + // 加算(クリッピング・反転、PremultipliedAlpha) + shaderSets.get(12).attributePositionLocation = glGetAttribLocation(shaderSets.get(12).shaderProgram, "a_position"); + shaderSets.get(12).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(12).shaderProgram, "a_texCoord"); + shaderSets.get(12).samplerTexture0Location = glGetUniformLocation(shaderSets.get(12).shaderProgram, "s_texture0"); + shaderSets.get(12).samplerTexture1Location = glGetUniformLocation(shaderSets.get(12).shaderProgram, "s_texture1"); + shaderSets.get(12).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(12).shaderProgram, "u_matrix"); + shaderSets.get(12).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(12).shaderProgram, "u_clipMatrix"); + shaderSets.get(12).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(12).shaderProgram, "u_channelFlag"); + shaderSets.get(12).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(12).shaderProgram, "u_baseColor"); + shaderSets.get(12).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(12).shaderProgram, "u_multiplyColor"); + shaderSets.get(12).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(12).shaderProgram, "u_screenColor"); + + // 乗算 + shaderSets.get(13).attributePositionLocation = glGetAttribLocation(shaderSets.get(13).shaderProgram, "a_position"); + shaderSets.get(13).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(13).shaderProgram, "a_texCoord"); + shaderSets.get(13).samplerTexture0Location = glGetUniformLocation(shaderSets.get(13).shaderProgram, "s_texture0"); + shaderSets.get(13).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(13).shaderProgram, "u_matrix"); + shaderSets.get(13).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(13).shaderProgram, "u_baseColor"); + shaderSets.get(13).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(13).shaderProgram, "u_multiplyColor"); + shaderSets.get(13).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(13).shaderProgram, "u_screenColor"); + + // 乗算(クリッピング) + shaderSets.get(14).attributePositionLocation = glGetAttribLocation(shaderSets.get(14).shaderProgram, "a_position"); + shaderSets.get(14).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(14).shaderProgram, "a_texCoord"); + shaderSets.get(14).samplerTexture0Location = glGetUniformLocation(shaderSets.get(14).shaderProgram, "s_texture0"); + shaderSets.get(14).samplerTexture1Location = glGetUniformLocation(shaderSets.get(14).shaderProgram, "s_texture1"); + shaderSets.get(14).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(14).shaderProgram, "u_matrix"); + shaderSets.get(14).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(14).shaderProgram, "u_clipMatrix"); + shaderSets.get(14).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(14).shaderProgram, "u_channelFlag"); + shaderSets.get(14).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(14).shaderProgram, "u_baseColor"); + shaderSets.get(14).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(14).shaderProgram, "u_multiplyColor"); + shaderSets.get(14).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(14).shaderProgram, "u_screenColor"); + + // 乗算(クリッピング・反転) + shaderSets.get(15).attributePositionLocation = glGetAttribLocation(shaderSets.get(15).shaderProgram, "a_position"); + shaderSets.get(15).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(15).shaderProgram, "a_texCoord"); + shaderSets.get(15).samplerTexture0Location = glGetUniformLocation(shaderSets.get(15).shaderProgram, "s_texture0"); + shaderSets.get(15).samplerTexture1Location = glGetUniformLocation(shaderSets.get(15).shaderProgram, "s_texture1"); + shaderSets.get(15).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(15).shaderProgram, "u_matrix"); + shaderSets.get(15).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(15).shaderProgram, "u_clipMatrix"); + shaderSets.get(15).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(15).shaderProgram, "u_channelFlag"); + shaderSets.get(15).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(15).shaderProgram, "u_baseColor"); + shaderSets.get(15).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(15).shaderProgram, "u_multiplyColor"); + shaderSets.get(15).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(15).shaderProgram, "u_screenColor"); + + // 乗算(PremultipliedAlpha) + shaderSets.get(16).attributePositionLocation = glGetAttribLocation(shaderSets.get(16).shaderProgram, "a_position"); + shaderSets.get(16).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(16).shaderProgram, "a_texCoord"); + shaderSets.get(16).samplerTexture0Location = glGetUniformLocation(shaderSets.get(16).shaderProgram, "s_texture0"); + shaderSets.get(16).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(16).shaderProgram, "u_matrix"); + shaderSets.get(16).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(16).shaderProgram, "u_baseColor"); + shaderSets.get(16).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(16).shaderProgram, "u_multiplyColor"); + shaderSets.get(16).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(16).shaderProgram, "u_screenColor"); + + // 乗算(クリッピング、PremultipliedAlpha) + shaderSets.get(17).attributePositionLocation = glGetAttribLocation(shaderSets.get(17).shaderProgram, "a_position"); + shaderSets.get(17).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(17).shaderProgram, "a_texCoord"); + shaderSets.get(17).samplerTexture0Location = glGetUniformLocation(shaderSets.get(17).shaderProgram, "s_texture0"); + shaderSets.get(17).samplerTexture1Location = glGetUniformLocation(shaderSets.get(17).shaderProgram, "s_texture1"); + shaderSets.get(17).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(17).shaderProgram, "u_matrix"); + shaderSets.get(17).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(17).shaderProgram, "u_clipMatrix"); + shaderSets.get(17).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(17).shaderProgram, "u_channelFlag"); + shaderSets.get(17).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(17).shaderProgram, "u_baseColor"); + shaderSets.get(17).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(17).shaderProgram, "u_multiplyColor"); + shaderSets.get(17).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(17).shaderProgram, "u_screenColor"); + + // 乗算(クリッピング・反転、PremultipliedAlpha) + shaderSets.get(18).attributePositionLocation = glGetAttribLocation(shaderSets.get(18).shaderProgram, "a_position"); + shaderSets.get(18).attributeTexCoordLocation = glGetAttribLocation(shaderSets.get(18).shaderProgram, "a_texCoord"); + shaderSets.get(18).samplerTexture0Location = glGetUniformLocation(shaderSets.get(18).shaderProgram, "s_texture0"); + shaderSets.get(18).samplerTexture1Location = glGetUniformLocation(shaderSets.get(18).shaderProgram, "s_texture1"); + shaderSets.get(18).uniformMatrixLocation = glGetUniformLocation(shaderSets.get(18).shaderProgram, "u_matrix"); + shaderSets.get(18).uniformClipMatrixLocation = glGetUniformLocation(shaderSets.get(18).shaderProgram, "u_clipMatrix"); + shaderSets.get(18).uniformChannelFlagLocation = glGetUniformLocation(shaderSets.get(18).shaderProgram, "u_channelFlag"); + shaderSets.get(18).uniformBaseColorLocation = glGetUniformLocation(shaderSets.get(18).shaderProgram, "u_baseColor"); + shaderSets.get(18).uniformMultiplyColorLocation = glGetUniformLocation(shaderSets.get(18).shaderProgram, "u_multiplyColor"); + shaderSets.get(18).uniformScreenColorLocation = glGetUniformLocation(shaderSets.get(18).shaderProgram, "u_screenColor"); + } + + private void setAttribLocation(final int shaderIndex) { + CubismShaderSet shader = shaderSets.get(shaderIndex); + + shader.attributePositionLocation = glGetAttribLocation(shader.shaderProgram, "a_position"); + shader.attributeTexCoordLocation = glGetAttribLocation(shader.shaderProgram, "a_texCoord"); + shader.samplerTexture0Location = glGetUniformLocation(shader.shaderProgram, "s_texture0"); + shader.uniformMatrixLocation = glGetUniformLocation(shader.shaderProgram, "u_matrix"); + shader.uniformBaseColorLocation = glGetUniformLocation(shader.shaderProgram, "u_baseColor"); + } + + private void setAttribLocationClipping(final int shaderIndex) { + CubismShaderSet shader = shaderSets.get(shaderIndex); + + shader.attributePositionLocation = glGetAttribLocation(shader.shaderProgram, "a_position"); + shader.attributeTexCoordLocation = glGetAttribLocation(shader.shaderProgram, "a_texCoord"); + shader.samplerTexture0Location = glGetUniformLocation(shader.shaderProgram, "s_texture0"); + shader.samplerTexture1Location = glGetUniformLocation(shader.shaderProgram, "s_texture1"); + shader.uniformMatrixLocation = glGetUniformLocation(shader.shaderProgram, "u_matrix"); + shader.uniformClipMatrixLocation = glGetUniformLocation(shader.shaderProgram, "u_clipMatrix"); + shader.uniformChannelFlagLocation = glGetUniformLocation(shader.shaderProgram, "u_channelFlag"); + shader.uniformBaseColorLocation = glGetUniformLocation(shader.shaderProgram, "u_baseColor"); + } + + /** + * Load shader program. + * + * @param vertShaderSrc source of vertex shader + * @param fragShaderSrc source of fragment shader + * @return reference value to the shader program + */ + private int loadShaderProgram(final String vertShaderSrc, final String fragShaderSrc) { + int[] vertShader = new int[1]; + int[] fragShader = new int[1]; + + // Create shader program. + int shaderProgram = glCreateProgram(); + + if (!compileShaderSource(vertShader, GL_VERTEX_SHADER, vertShaderSrc)) { + cubismLogError("Vertex shader compile error!"); + return 0; + } + + // Create and compile fragment shader. + if (!compileShaderSource(fragShader, GL_FRAGMENT_SHADER, fragShaderSrc)) { + cubismLogError("Fragment shader compile error!"); + return 0; + } + + // Attach vertex shader to program. + glAttachShader(shaderProgram, vertShader[0]); + // Attach fragment shader to program. + glAttachShader(shaderProgram, fragShader[0]); + + // Link program. + if (!linkProgram(shaderProgram)) { + cubismLogError("Failed to link program: " + shaderProgram); + + glDeleteShader(vertShader[0]); + glDeleteShader(fragShader[0]); + glDeleteProgram(shaderProgram); + + return 0; + } + + // Release vertex and fragment shaders. + glDetachShader(shaderProgram, vertShader[0]); + glDeleteShader(vertShader[0]); + + glDetachShader(shaderProgram, fragShader[0]); + glDeleteShader(fragShader[0]); + + return shaderProgram; + } + + /** + * Compile shader program. + * + * @param shader reference value to compiled shader program + * @param shaderType shader type(Vertex/Fragment) + * @param shaderSource source of shader program + * @return If compilling succeeds, return true + */ + private boolean compileShaderSource(int[] shader, int shaderType, final String shaderSource) { + if (shader == null || shader.length == 0) { + return false; + } + + shader[0] = glCreateShader(shaderType); + + glShaderSource(shader[0], shaderSource); + glCompileShader(shader[0]); + + int[] logLength = new int[1]; + glGetShaderiv(shader[0], GL_INFO_LOG_LENGTH, IntBuffer.wrap(logLength)); + if (logLength[0] > 0) { + String log = glGetShaderInfoLog(shader[0]); + cubismLogError("Shader compile log: " + log); + } + + int[] status = new int[1]; + glGetShaderiv(shader[0], GL_COMPILE_STATUS, IntBuffer.wrap(status)); + if (status[0] == GL_FALSE) { + glDeleteShader(shader[0]); + return false; + } + return true; + } + + /** + * Link shader program. + * + * @param shaderProgram reference value to a shader program to link + * @return If linking succeeds, return true + */ + private boolean linkProgram(int shaderProgram) { + glLinkProgram(shaderProgram); + + int[] logLength = new int[1]; + glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, IntBuffer.wrap(logLength)); + if (logLength[0] > 0) { + String log = glGetProgramInfoLog(shaderProgram); + cubismLogError("Program link log: " + log); + } + + int[] status = new int[1]; + glGetProgramiv(shaderProgram, GL_LINK_STATUS, IntBuffer.wrap(status)); + return status[0] != GL_FALSE; + } + + /** + * Validate shader program. + * + * @param shaderProgram reference value to shader program to be validated + * @return If there is no problem, return true + */ + private boolean validateProgram(int shaderProgram) { + glValidateProgram(shaderProgram); + + int[] logLength = new int[1]; + glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, IntBuffer.wrap(logLength)); + if (logLength[0] > 0) { + String log = glGetProgramInfoLog(shaderProgram); + cubismLogError("Validate program log: " + log); + } + + int[] status = new int[1]; + glGetProgramiv(shaderProgram, GL_VALIDATE_STATUS, IntBuffer.wrap(status)); + return status[0] != GL_FALSE; + } + + /** + * Variable that holds the loaded shader program. + */ + private final List shaderSets = new ArrayList(); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismShaderPrograms.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismShaderPrograms.java new file mode 100644 index 0000000..422fbaf --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/CubismShaderPrograms.java @@ -0,0 +1,428 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.rendering.android; + +/** + * This class has raw GLSL codes. + * Number of shaders = for generating mask + (normal + adding + premultiplication) * (without mask + with mask + with mask inverted + without mask for premultiplied alpha + with mask for premultiplied alpha + with mask inverted for premultiplied alpha) + */ +class CubismShaderPrograms { + /** + * The enum class that represents the precision of floating point numbers used in GLSL. + */ + public enum CsmFragmentShaderFpPrecision { + HIGH("highp"), + MID("mediump"), + LOW("lowp"); + + private final String value; + + CsmFragmentShaderFpPrecision(String value) { + this.value = value; + } + } + + /** + * Number of GLSL codes. + *

+ * Number of the shaders = for generating masks + (Normal + Add + Multiply) * (No mask + mask + inverted mask + no mask for premultiplied alpha + mask for premultiplied alpha + inverted mask for premultiplied alpha) + *

+ */ + public static final int SHADER_COUNT = 19; + + /** + * Floating point number's precision used in GLSL. (Default value: "highp") + */ + private static CsmFragmentShaderFpPrecision precision = CsmFragmentShaderFpPrecision.HIGH; + + /** + * Vertex shader code for setting up mask. + */ + public static final String VERT_SHADER_SRC_SETUP_MASK = + "#version 100\n" + + "attribute vec4 a_position;\n" + + "attribute vec2 a_texCoord;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_myPos;\n" + + "uniform mat4 u_clipMatrix;\n" + + "void main()\n" + + "{\n" + + "gl_Position = u_clipMatrix * a_position;\n" + + "v_myPos = u_clipMatrix * a_position;\n" + + "v_texCoord = a_texCoord;\n" + + "v_texCoord.y = 1.0 - v_texCoord.y;\n" + + "}"; + /** + * Fragment shader code for setting up mask. + */ + public static final String FRAG_SHADER_SRC_SETUP_MASK = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_myPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "void main()\n" + + "{\n" + + "float isInside = " + + "step(u_baseColor.x, v_myPos.x/v_myPos.w)" + + "* step(u_baseColor.y, v_myPos.y/v_myPos.w)" + + "* step(v_myPos.x/v_myPos.w, u_baseColor.z)" + + "* step(v_myPos.y/v_myPos.w, u_baseColor.w);\n" + + "gl_FragColor = u_channelFlag * texture2D(s_texture0 , v_texCoord).a * isInside;\n" + + "}"; + /** + * Fragment shader code for setting up mask for Tegra + */ + public static final String FRAG_SHADER_SRC_SETUP_MASK_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_myPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "void main()\n" + + "{\n" + + "float isInside = " + + "step(u_baseColor.x, v_myPos.x/v_myPos.w)" + + "* step(u_baseColor.y, v_myPos.y/v_myPos.w)" + + "* step(v_myPos.x/v_myPos.w, u_baseColor.z)" + + "* step(v_myPos.y/v_myPos.w, u_baseColor.w);\n" + + + "gl_FragColor = u_channelFlag * texture2D(s_texture0 , v_texCoord).a * isInside;\n" + + "}"; + + //----- Vertex Shader Programs ----- + // Normal & Add & Multi common part + /** + * Vertex shader code. + */ + public static final String VERT_SHADER_SRC = + "#version 100\n" + + "attribute vec4 a_position;\n" // v.vertex + + "attribute vec2 a_texCoord;\n" // v.texcoord + + "varying vec2 v_texCoord;\n" // v2f.texcoord + + "uniform mat4 u_matrix;\n" + + "void main()\n" + + "{\n" + + "gl_Position = u_matrix * a_position;\n" + + "v_texCoord = a_texCoord;\n" + + "v_texCoord.y = 1.0 - v_texCoord.y;\n" + + "}"; + + /** + * Vertex shader code for masked things. + */ + public static final String VERT_SHADER_SRC_MASKED = + "#version 100\n" + + "attribute vec4 a_position;\n" + + "attribute vec2 a_texCoord;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform mat4 u_matrix;\n" + + "uniform mat4 u_clipMatrix;\n" + + "void main()\n" + + "{\n" + + "gl_Position = u_matrix * a_position;\n" + + "v_clipPos = u_clipMatrix * a_position;\n" + + "v_texCoord = a_texCoord;\n" + + "v_texCoord.y = 1.0 - v_texCoord.y;\n" + + "}"; + + //----- Fragment Shader Programs ----- + // Normal & Add & Mult common part + /** + * Fragment shader code. + */ + public static final String FRAG_SHADER_SRC = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" // v2f.texcoord + + "uniform sampler2D s_texture0;\n" // _MainTex + + "uniform vec4 u_baseColor;\n" // v2f.color + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = texColor.rgb + u_screenColor.rgb - (texColor.rgb * u_screenColor.rgb);\n" + + "vec4 color = texColor * u_baseColor;\n" + + "gl_FragColor = vec4(color.rgb * color.a, color.a);\n" + + "}"; + /** + * Fragment shader code for Tegra. + */ + public static final String FRAG_SHADER_SRC_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" //v2f.texcoord + + "uniform sampler2D s_texture0;\n" //_MainTex + + "uniform vec4 u_baseColor;\n" //v2f.color + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = texColor.rgb + u_screenColor.rgb - (texColor.rgb * u_screenColor.rgb);\n" + + "vec4 color = texColor * u_baseColor;\n" + + "gl_FragColor = vec4(color.rgb * color.a, color.a);\n" + + "}"; + + // Normal & Add & Mult common (PremultipliedAlpha) + /** + * Fragment shader code for premultipiled alpha. + */ + public static final String FRAG_SHADER_SRC_PREMULTIPLIED_ALPHA = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" // v2f.texcoord + + "uniform sampler2D s_texture0;\n" // _MainTex + + "uniform vec4 u_baseColor;\n" // v2f.color + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);\n" + + "gl_FragColor = texColor * u_baseColor;\n" + + "}"; + /** + * Fragment shader code for premultiplied alpha for Tegra. + */ + public static final String FRAG_SHADER_SRC_PREMULTIPLIED_ALPHA_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" //v2f.texcoord + + "uniform sampler2D s_texture0;\n" //_MainTex + + "uniform vec4 u_baseColor;\n" //v2f.color + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);\n" + + "gl_FragColor = texColor * u_baseColor;\n" + + "}"; + + // Normal & Add & Mult common(for drawing the clipped thing) + /** + * Fragment shader code for masked things. + */ + public static final String FRAG_SHADER_SRC_MASK = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = texColor.rgb + u_screenColor.rgb - (texColor.rgb * u_screenColor.rgb);\n" + + "vec4 col_formask = texColor * u_baseColor;\n" + + "col_formask.rgb = col_formask.rgb * col_formask.a;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * maskVal;\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + /** + * Fragment shader code for masked things. (for Tegra) + */ + public static final String FRAG_SHADER_SRC_MASK_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "void main()\n" + + "{\n" + + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;\n" + + "col_formask.rgb = col_formask.rgb * col_formask.a;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * maskVal;\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + // Normal & Add & Mult common (For clipped and reversed use drawing) + /** + * Fragment shader code for inverted mask. + */ + public static final String FRAG_SHADER_SRC_MASK_INVERTED = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = texColor.rgb + u_screenColor.rgb - (texColor.rgb * u_screenColor.rgb);\n" + + "vec4 col_formask = texColor * u_baseColor;\n" + + "col_formask.rgb = col_formask.rgb * col_formask.a;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * (1.0 - maskVal);\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + /** + * Fragment shader code for inverted mask. (for Tegra) + */ + public static final String FRAG_SHADER_SRC_MASK_INVERTED_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "void main()\n" + + "{\n" + + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;\n" + + "col_formask.rgb = col_formask.rgb * col_formask.a;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * (1.0 - maskVal);\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + /** + * Fragment shader code for the masked things at premultiplied alpha. + */ + public static final String FRAG_SHADER_SRC_MASK_PREMULTIPLIED_ALPHA = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);\n" + + "vec4 col_formask = texColor * u_baseColor;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * maskVal;\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + /** + * Fragment shader code for the masked things at premultiplied alpha. (for Tegra) + */ + public static final String FRAG_SHADER_SRC_MASK_PREMULTIPLIED_ALPHA_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "void main()\n" + + "{\n" + + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * maskVal;\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + // Normal & Add & Mult common (For clipped and reversed use drawing, in the case of PremultipliedAlpha) + /** + * Fragment shader code for inverted mask at premultiplied alpha. + */ + public static final String FRAG_SHADER_SRC_MASK_INVERTED_PREMULTIPLIED_ALPHA = + "#version 100\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "uniform vec4 u_multiplyColor;\n" + + "uniform vec4 u_screenColor;\n" + + "void main()\n" + + "{\n" + + "vec4 texColor = texture2D(s_texture0, v_texCoord);\n" + + "texColor.rgb = texColor.rgb * u_multiplyColor.rgb;\n" + + "texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);\n" + + "vec4 col_formask = texColor * u_baseColor;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * (1.0 - maskVal);\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + /** + * Fragment shader code for inverted mask at premultiplied alpha(for Tegra) + */ + public static final String FRAG_SHADER_SRC_MASK_INVERTED_PREMULTIPLIED_ALPHA_TEGRA = + "#version 100\n" + + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + + "precision " + precision.value + " float;\n" + + "varying vec2 v_texCoord;\n" + + "varying vec4 v_clipPos;\n" + + "uniform sampler2D s_texture0;\n" + + "uniform sampler2D s_texture1;\n" + + "uniform vec4 u_channelFlag;\n" + + "uniform vec4 u_baseColor;\n" + + "void main()\n" + + "{\n" + + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;\n" + + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;\n" + + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;\n" + + "col_formask = col_formask * (1.0 - maskVal);\n" + + "gl_FragColor = col_formask;\n" + + "}"; + + /** + * Set the floating point number's precision used in GLSL. + * + * @param p precision + */ + public void setFragmentShaderFpPrecision(CubismShaderPrograms.CsmFragmentShaderFpPrecision p) { + precision = p; + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/package-info.java new file mode 100644 index 0000000..beba545 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/android/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide the renderer that implemetns graphics instructions for rendering models on the Android platform. + */ +package com.live2d.sdk.cubism.framework.rendering.android; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/package-info.java new file mode 100644 index 0000000..9da3807 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/rendering/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide the renderer that implements graphics instructions for rendering models on various platforms. + */ +package com.live2d.sdk.cubism.framework.rendering; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/type/csmRectF.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/type/csmRectF.java new file mode 100644 index 0000000..08a701c --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/type/csmRectF.java @@ -0,0 +1,230 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + + +package com.live2d.sdk.cubism.framework.type; + +/** + * This class defines a rectangle form(a coordinate and a length is float value) + */ +public class csmRectF { + /** + * Create the new CubismRectangle instance. + * + * @return CubismRectangle instance + */ + public static csmRectF create() { + return new csmRectF(); + } + + /** + * Create the new CubismRectangle instance with each parameter. + * + * @param x x-coordinate + * @param y y-coordinate + * @param w width + * @param h height + * @return CubismRectangle instance + */ + public static csmRectF create( + float x, + float y, + float w, + float h + ) { + return new csmRectF(x, y, w, h); + } + + /** + * Create the new CubismRectangle instance. + * This method works the same way as a copy constructor. + * + * @param r CubismRectangle instance to be copied + * @return CubismRectangle instance + */ + public static csmRectF create(csmRectF r) { + return new csmRectF(r); + } + + + /** + * Get the x-coordinate at center of this rectangle. + * + * @return the x-coord at center of this rect. + */ + public float getCenterX() { + return x + 0.5f * width; + } + + /** + * Get the y-coordinate at center of this rectangle. + * + * @return the y-coord at center of this rect + */ + public float getCenterY() { + return y + 0.5f * height; + } + + /** + * Get the x-coordinate at right end of this rectangle. + * + * @return x-coord at right end + */ + public float getRight() { + return x + width; + } + + /** + * Get the y-coordinate at bottom of this rectangle. + * + * @return y-coord at bottom + */ + public float getBottom() { + return y + height; + } + + /** + * Set a value to this rectangle. + */ + public void setRect(csmRectF r) { + x = r.getX(); + y = r.getY(); + width = r.getWidth(); + height = r.getHeight(); + } + + /** + * Scale width and height with the center of this rectangle as axis. + * + * @param w the amount of scaling into width + * @param h the amount of scaling into height + */ + public void expand(final float w, final float h) { + x -= w; + y -= h; + width += w * 2.0f; + height += h * 2.0f; + } + + /** + * Get this x-coordinate + * + * @return x-coord + */ + public float getX() { + return x; + } + + /** + * Set x-coordinate to this one. + * + * @param x x-coord + */ + public void setX(float x) { + this.x = x; + } + + /** + * Get this y-coordinate + * + * @return y-coord + */ + public float getY() { + return y; + } + + /** + * Set y-coordinate to this one. + * + * @param y y-coord + */ + public void setY(float y) { + this.y = y; + } + + /** + * Get the width of this. + * + * @return width + */ + public float getWidth() { + return width; + } + + /** + * Set the width to this one. + * + * @param width width set to this + */ + public void setWidth(float width) { + this.width = width; + } + + /** + * Get the height of this. + * + * @return height + */ + public float getHeight() { + return height; + } + + /** + * Set the height to this one. + * + * @param height height set to this + */ + public void setHeight(float height) { + this.height = height; + } + + /** + * Constructor + */ + private csmRectF() {} + + /** + * Constructor with each value. + * + * @param x left end x-coord + * @param y top end y-coord + * @param w width + * @param h height + */ + private csmRectF( + final float x, + final float y, + final float w, + final float h + ) { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + } + + private csmRectF(csmRectF r) { + setRect(r); + } + + /** + * Left end x-coordinate + */ + private float x; + /** + * Top end y-coordinate + */ + private float y; + /** + * Width + */ + private float width; + /** + * Height + */ + private float height; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/CubismDebug.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/CubismDebug.java new file mode 100644 index 0000000..b53bd6e --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/CubismDebug.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils; + +import com.live2d.sdk.cubism.framework.CubismFramework; +import com.live2d.sdk.cubism.framework.CubismFrameworkConfig.LogLevel; + +import static com.live2d.sdk.cubism.framework.CubismFrameworkConfig.CSM_LOG_LEVEL; + +/** + * A utility class for debugging. + *

+ * Log output, dump byte, and so on. + */ +public class CubismDebug { + /** + * Output log. Set log level to 1st argument. + * At using {@link CubismFramework#initialize()} function, if the log level is lower than set log output level, log output is not executed. + * + * @param logLevel log level setting + * @param message format string + * @param args variadic arguments + */ + public static void print(final LogLevel logLevel, final String message, Object... args) { + // If the log level is lower than set log output level in Option class, log outputting is not executed. + if (logLevel.getId() < CubismFramework.getLoggingLevel().getId()) { + return; + } + + String format = String.format(message, args); + CubismFramework.coreLogFunction(format); + } + + /** + * Dump out a specified length of data. + *

+ * If the log output level is below the level set in the option at {@link CubismFramework#initialize()}, it will not be logged. + * + * @param logLevel setting of log level + * @param data data to dump + * @param length length of dumping + */ + public static void dumpBytes(final LogLevel logLevel, final byte[] data, int length) { + for (int i = 0; i < length; i++) { + if (i % 16 == 0 && i > 0) { + print(logLevel, "\n"); + } else if (i % 8 == 0 && i > 0) { + print(logLevel, " "); + } + print(logLevel, "%02X", (data[i] & 0xFF)); + } + } + + /** + * Display the normal message. + * + * @param message message + */ + public static void cubismLogPrint(LogLevel logLevel, String message, Object... args) { + print(logLevel, "[CSM]" + message, args); + } + + /** + * Display a newline message. + * + * @param message message + */ + public static void cubismLogPrintln(LogLevel logLevel, String message, Object... args) { + cubismLogPrint(logLevel, message + "\n", args); + } + + /** + * Show detailed message. + * + * @param message message + */ + public static void cubismLogVerbose(String message, Object... args) { + if (CSM_LOG_LEVEL.getId() <= LogLevel.VERBOSE.getId()) { + cubismLogPrintln(LogLevel.VERBOSE, "[V]" + message, args); + } + } + + /** + * Display the debug message. + * + * @param message message + */ + public static void cubismLogDebug(String message, Object... args) { + if (CSM_LOG_LEVEL.getId() <= LogLevel.DEBUG.getId()) { + cubismLogPrintln(LogLevel.DEBUG, "[D]" + message, args); + } + } + + /** + * Display informational messages. + * + * @param message message + */ + public static void cubismLogInfo(String message, Object... args) { + if (CSM_LOG_LEVEL.getId() <= LogLevel.INFO.getId()) { + cubismLogPrintln(LogLevel.INFO, "[I]" + message, args); + } + } + + /** + * Display a warning message. + * + * @param message message + */ + public static void cubismLogWarning(String message, Object... args) { + if (CSM_LOG_LEVEL.getId() <= LogLevel.WARNING.getId()) { + cubismLogPrintln(LogLevel.WARNING, "[W]" + message, args); + } + } + + /** + * Display a error message. + * + * @param message message. + */ + public static void cubismLogError(String message, Object... args) { + if (CSM_LOG_LEVEL.getId() <= LogLevel.ERROR.getId()) { + cubismLogPrintln(LogLevel.ERROR, "[E]" + message, args); + } + } + + /** + * Private constructor + */ + private CubismDebug() {} +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/ACubismJsonValue.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/ACubismJsonValue.java new file mode 100644 index 0000000..0ef7fe2 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/ACubismJsonValue.java @@ -0,0 +1,228 @@ +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public abstract class ACubismJsonValue { + /** + * If the class implemented this interface is {@code CubismJsonObject}, returns the value corresponding to the key. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @param key the key of the JSON Object + * @return the value of the JSON Object + */ + public ACubismJsonValue get(String key) { + ACubismJsonValue nullValue = new CubismJsonNullValue(); + nullValue.setErrorNotForClientCall(JsonError.TYPE_MISMATCH.message); + + return nullValue; + } + + /** + * If the class implemented this interface is {@code CubismJsonArray}, returns the value corresponding to the index of the argument. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @param index index of the element to return + * @return the value corresponding to the index + */ + public ACubismJsonValue get(int index) { + ACubismJsonValue errorValue = new CubismJsonErrorValue(); + errorValue.setErrorNotForClientCall(JsonError.TYPE_MISMATCH.message); + + return errorValue; + } + + /** + * Returns the JSON Value's string expression. + * + * @return the JSON Value's string expression + */ + public abstract String getString(String defaultValue, String indent); + + public String getString(String defaultValue) { + return getString(defaultValue, ""); + } + + public String getString() { + return getString("", ""); + } + + /** + * If the class implemented this interface is {@code CubismJsonObject}, returns the map of {@code CubismJsonString} and {@code ICubismJsonValue}. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the map of strings and values + */ + public Map getMap() { + return null; + } + + /** + * もしこのインターフェースが実装されているクラスが{@code CubismJsonObject}ならば、{@code CubismJsonString}と{@code ACubismJsonValue}をペアにしたMapを返す。
+ * もし他の具象クラスに実装されていた場合は、{@code null}を返す。 + * + * @param defaultValue デフォルト値 + * @return デフォルト値 + */ + public Map getMap(Map defaultValue) { + return defaultValue; + } + + /** + * If the class implemented this interface is {@code CubismJsonArray}, returns the list of {@code ICubismJsonValue}. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the list of {@code ICubismJsonValue} + */ + public List getList() { + return new ArrayList(); + } + + /** + * もしこのインターフェースが実装されているクラスが{@code CubismJsonArray}ならば、{@code ACubismJsonValue}のListを返す。
+ * もし他の具象クラスに実装されていた場合は、{@code null}を返す。 + * + * @param defaultValue デフォルト値 + * @return デフォルト値 + */ + public List getList(List defaultValue) { + return defaultValue; + } + + /** + * If the class implemented this interface is {@code CubismJsonObject}, returns the set of the keys({@code CubismJsonString}). + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the set of the keys({@code CubismJsonString}) + */ + public List getKeys() { + return Collections.emptyList(); + } + + /** + * If the class implemented this interface is {@code CubismJsonObject} and {@code CubismJsonArray}, returns the number of JSON Value that they hold. + *

+ * If this is implemented in {@code CubismJsonString}, returns the length of the string. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the number of JSON Value that they hold or the length of the string + */ + public int size() { + return 0; + } + + /** + * If the class implemented this interface is {@code CubismJsonNumber}, returns the value cast to an integer value. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the value cast to an integer value + */ + public int toInt() { + return 0; + } + + public int toInt(int defaultValue) { + return defaultValue; + } + + /** + * If the class implemented this interface is {@code CubismJsonNumber}, returns the value cast to a float value. + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the value cast to an float value + */ + public float toFloat() { + return 0.0f; + } + + public float toFloat(float defaultValue) { + return defaultValue; + } + + /** + * If the class implemented this interface is {@code CubismJsonBoolean}, returns the boolean value it holds + *

+ * If this is implemented in other concrete class, {@code UnsupportedOperationException} is thrown. + * + * @return the boolean value that the class has + */ + public boolean toBoolean() { + return false; + } + + public boolean toBoolean(boolean defaultValue) { + return defaultValue; + } + + public boolean isError() { + return false; + } + + /** + * If the class implemented this interface is {@code CubismJsonNullValue}, returns {@code true}. + *

+ * If this is implemented in other concrete class, returns {@code false}. + * + * @return If this JSON Value is Null Value, returns true + */ + public boolean isNull() { + return false; + } + + public boolean isBoolean() { + return false; + } + + public boolean isNumber() { + return false; + } + + public boolean isString() { + return false; + } + + public boolean isArray() { + return false; + } + + public boolean isObject() { + return false; + } + + /** + * Valueにエラー値をセットする。 + * + * @param errorMsg エラーメッセージ + * @return JSON Null Value + */ + public ACubismJsonValue setErrorNotForClientCall(String errorMsg) { + stringBuffer = errorMsg; + return new CubismJsonNullValue(); + } + + /** + * エラーメッセージ定義 + */ + protected enum JsonError { + TYPE_MISMATCH("Error: type mismatch"), + INDEX_OUT_OF_BOUNDS("Error: index out of bounds"); + + public final String message; + + JsonError(String message) { + this.message = message; + } + } + + protected String stringBuffer; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJson.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJson.java new file mode 100644 index 0000000..68009bc --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJson.java @@ -0,0 +1,251 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +import com.live2d.sdk.cubism.framework.exception.CubismJsonParseException; +import com.live2d.sdk.cubism.framework.exception.CubismJsonSyntaxErrorException; + +import java.io.IOException; + +/** + * This class has some functions related to JSON. + */ +public class CubismJson { + /** + * Creates the JSON object. + * + * @param buffer byte data of the JSON + * @return JSON object + * + * @throws IllegalArgumentException If the argument is null + */ + public static CubismJson create(byte[] buffer) { + if (buffer == null || buffer.length == 0) { + throw new IllegalArgumentException("Parsed JSON data is empty."); + } + + CubismJson json = new CubismJson(); + json.parse(buffer); + + return json; + } + + /** + * Get a root of a parsed JSON. + * + * @return JSON root + */ + public ACubismJsonValue getRoot() { + return root; + } + + /** + * Private constructor + */ + private CubismJson() {} + + /** + * Parse JSON string. + * + * @param buffer JSON byte data + */ + private void parse(byte[] buffer) { + try { + String json = new String(buffer, "UTF-8"); + lexer = new CubismJsonLexer(json); + + token = lexer.getNextToken(); + root = createValue(); + } catch (IOException e) { + throw new CubismJsonParseException("It seems that an error has occured in the input/output processing", e); + } + } + + /** + * Construct a JSON value. + * + * @return JSON Value + */ + private ACubismJsonValue createValue() throws CubismJsonParseException, IOException { + // JSON Object + if (token.getTokenType() == CubismJsonToken.TokenType.LBRACE) { + objectNestingLevel++; + CubismJsonObject object = createObject(); + + // If parsing is midway, the next token is read. + if (objectNestingLevel != 0 || arrayNestingLevel != 0) { + token = lexer.getNextToken(); + } + return object; + } + // JSON Array + else if (token.getTokenType() == CubismJsonToken.TokenType.LSQUARE_BRACKET) { + arrayNestingLevel++; + CubismJsonArray array = createArray(); + + // If parsing is midway, the next token is read. + if (objectNestingLevel != 0 || arrayNestingLevel != 0) { + token = lexer.getNextToken(); + } + return array; + } + // JSON Number + else if (token.getTokenType() == CubismJsonToken.TokenType.NUMBER) { + CubismJsonNumber number = CubismJsonNumber.valueOf(token.getNumberValue()); + + if (objectNestingLevel != 0 || arrayNestingLevel != 0) { + token = lexer.getNextToken(); + } + return number; + } + // JSON String + else if (token.getTokenType() == CubismJsonToken.TokenType.STRING) { + CubismJsonString string = CubismJsonString.valueOf(token.getStringValue()); + + if (objectNestingLevel != 0 || arrayNestingLevel != 0) { + token = lexer.getNextToken(); + } + return string; + } + // JSON Boolean(true or false) + else if (token.getTokenType() == CubismJsonToken.TokenType.BOOLEAN) { + CubismJsonBoolean bool = CubismJsonBoolean.valueOf(token.getBooleanValue()); + + if (objectNestingLevel != 0 || arrayNestingLevel != 0) { + token = lexer.getNextToken(); + } + return bool; + } + // JSON null value + else if (token.getTokenType() == CubismJsonToken.TokenType.NULL) { + CubismJsonNullValue nullValue = new CubismJsonNullValue(); + + if (objectNestingLevel != 0 || arrayNestingLevel != 0) { + token = lexer.getNextToken(); + } + return nullValue; + } else { + throw new CubismJsonSyntaxErrorException("Incorrect JSON format.", lexer.getCurrentLineNumber() - 1); + } + } + + /** + * Construct a JSON object + * + * @return JSON Object + */ + private CubismJsonObject createObject() throws CubismJsonParseException, IOException { + CubismJsonObject object = new CubismJsonObject(); + + token = lexer.getNextToken(); + + // If the next token is braces, this object is regarded as empty object + if (token.getTokenType() == CubismJsonToken.TokenType.RBRACE) { + objectNestingLevel--; + return object; + } else { + // Continue reading until closed by '}' + // If the format is not "string : value (, string : value, ...)", an exception is thrown. + while (true) { + CubismJsonString string; + ACubismJsonValue value; + + // Construct a string value + if (token.getTokenType() == CubismJsonToken.TokenType.STRING) { + string = CubismJsonString.valueOf(token.getStringValue()); + } else { + throw new CubismJsonSyntaxErrorException("JSON Object's format is incorrect.", lexer.getCurrentLineNumber()); + } + + token = lexer.getNextToken(); + + // If it is not divided by colon, an exception is thrown. + if (token.getTokenType() != CubismJsonToken.TokenType.COLON) { + throw new CubismJsonSyntaxErrorException("JSON Object's format is incorrect.", lexer.getCurrentLineNumber()); + } + + token = lexer.getNextToken(); + value = createValue(); + + // Put a pair of string and value into object + object.putPair(string, value); + + // If the next token is comma, reading is continued. If the next token is '}', it is done to "break". + if (token.getTokenType() == CubismJsonToken.TokenType.RBRACE) { + objectNestingLevel--; + break; + } else if (token.getTokenType() == CubismJsonToken.TokenType.COMMA) { + token = lexer.getNextToken(); + } else { + throw new CubismJsonSyntaxErrorException("JSON Object's format is incorrect.", lexer.getCurrentLineNumber() - 1); + } + } + } + return object; + } + + /** + * Construct a JSON array. + * + * @return JSON Array + * + * @throws CubismJsonParseException an exception related to parsing + */ + private CubismJsonArray createArray() throws CubismJsonParseException, IOException { + CubismJsonArray array = new CubismJsonArray(); + + token = lexer.getNextToken(); + + // If the next token is square brackets, this array is regarded as empty array. + if (token.getTokenType() == CubismJsonToken.TokenType.RSQUARE_BRACKET) { + arrayNestingLevel--; + return array; + } else { + // Continue reading until closed by ']' + // If the format is not "value (, value, ...)", an exception is thrown. + while (true) { + ACubismJsonValue value; + + // Construct a value + value = createValue(); + // Put the value into array + array.putValue(value); + + // If the next token is comma, reading is continued. If the next token is ']', it is done to "break". + if (token.getTokenType() == CubismJsonToken.TokenType.RSQUARE_BRACKET) { + arrayNestingLevel--; + break; + } else if (token.getTokenType() == CubismJsonToken.TokenType.COMMA) { + token = lexer.getNextToken(); + } else { + throw new CubismJsonSyntaxErrorException("JSON Array's format is incorrect.", lexer.getCurrentLineNumber() - 1); + } + } + } + return array; + } + + /** + * JSON root + */ + private ACubismJsonValue root; + /** + * JSON lexer + */ + private CubismJsonLexer lexer; + /** + * JSON token + */ + private CubismJsonToken token; + /** + * A nest level of JSON object. If left brace is appeared, nest level increases by 1, and if right brace is done, it decreases by 1. + */ + private int objectNestingLevel; + + private int arrayNestingLevel; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonArray.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonArray.java new file mode 100644 index 0000000..79a2086 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonArray.java @@ -0,0 +1,112 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class expresses JSON Array + */ +class CubismJsonArray extends ACubismJsonValue { + /** + * Add a JSON Value. + * + * @param value JSON value + */ + public void putValue(ACubismJsonValue value) { + this.value.add(value); + } + + @Override + public ACubismJsonValue get(String key) { + return new CubismJsonErrorValue().setErrorNotForClientCall(JsonError.TYPE_MISMATCH.message); + } + + @Override + public ACubismJsonValue get(int index) { + if (index < 0 || value.size() <= index) { + return new CubismJsonErrorValue().setErrorNotForClientCall(JsonError.INDEX_OUT_OF_BOUNDS.message); + } + + ACubismJsonValue value = this.value.get(index); + + if (value == null) { + return new CubismJsonNullValue(); + } + + return value; + } + + @Override + public String getString(String defaultValue, String indent) { + // バッファに格納されている文字列を空にする + bufferForGetString.delete(0, bufferForGetString.length()); + + bufferForGetString.append(indent); + bufferForGetString.append("[\n"); + + for (int i = 0; i < value.size(); i++) { + bufferForGetString.append(indent); + bufferForGetString.append(" "); + bufferForGetString.append(value.get(i).getString(indent + " ")); + bufferForGetString.append("\n"); + } + + bufferForGetString.append(indent); + bufferForGetString.append("]\n"); + + stringBuffer = bufferForGetString.toString(); + return stringBuffer; + } + + @Override + public List getList() { + return value; + } + + @Override + public int size() { + return value.size(); + } + + @Override + public boolean isArray() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismJsonArray that = (CubismJsonArray) o; + + return value.equals(that.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + /** + * {@code getString}メソッドで使われる一時的な文字列バッファの最小容量。 + */ + private static final int MINIMUM_CAPACITY = 128; + + /** + * JSON Array value + */ + private final List value = new ArrayList(); + + /** + * {@code getString}で使用される文字列バッファ + */ + private final StringBuffer bufferForGetString = new StringBuffer(MINIMUM_CAPACITY); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonBoolean.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonBoolean.java new file mode 100644 index 0000000..e230be6 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonBoolean.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +/** + * This class expresses a boolean value. + */ +class CubismJsonBoolean extends ACubismJsonValue { + /** + * Get a boolean instance + * + * @param value a boolean value + * @return a JSON boolean value + */ + public static CubismJsonBoolean valueOf(final boolean value) { + return new CubismJsonBoolean(value); + } + + @Override + public String getString(String defaultValue, String indent) { + return stringBuffer; + } + + @Override + public boolean toBoolean() { + return value; + } + + @Override + public boolean toBoolean(boolean defaultValue) { + return value; + } + + @Override + public boolean isBoolean() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismJsonBoolean that = (CubismJsonBoolean) o; + + return value == that.value; + } + + @Override + public int hashCode() { + return (value ? 1 : 0); + } + + /** + * Private constructor + * + * @param value a boolean value + */ + private CubismJsonBoolean(boolean value) { + this.value = value; + stringBuffer = String.valueOf(value); + } + + /** + * A boolean value + */ + private final boolean value; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonErrorValue.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonErrorValue.java new file mode 100644 index 0000000..9d95903 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonErrorValue.java @@ -0,0 +1,28 @@ +/* + * + * * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + * + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +class CubismJsonErrorValue extends ACubismJsonValue { + @Override + public String getString(String defaultValue, String indent) { + return stringBuffer; + } + + @Override + public boolean isError() { + return true; + } + + @Override + public ACubismJsonValue setErrorNotForClientCall(String s) { + this.stringBuffer = s; + return this; + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonLexer.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonLexer.java new file mode 100644 index 0000000..0245bde --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonLexer.java @@ -0,0 +1,458 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +import com.live2d.sdk.cubism.framework.exception.CubismJsonParseException; + +import java.io.IOException; +import java.util.Arrays; + +/** + * This class offers a function of JSON lexer. + */ +class CubismJsonLexer { + /** + * Package-private constructor + * + * @param json string of JSON + */ + public CubismJsonLexer(String json) { + // 上位層で、nullだったら例外を出しているため、 + // 引数がnullであることは考えられない + assert json != null; + + // char配列に変換する + jsonChars = json.toCharArray(); + jsonCharsLength = jsonChars.length; + + // トークン解析用のバッファを初期化 + // 初期容量は128。128文字を超えるトークンが出現するならばその都度拡張する。 + parsedTokonBuffer = new char[MINIMUM_CAPACITY]; + } + + /** + * Get a next token. + */ + public CubismJsonToken getNextToken() throws CubismJsonParseException, IOException { + // Skip blank characters + while (isWhiteSpaceChar(nextChar)) { + updateNextChar(); + } + + // null文字で埋める + Arrays.fill(parsedTokonBuffer, 0, bufferIndex, '\0'); + bufferIndex = 0; + + // A Number token + // A process when beginning at minus sign + if (nextChar == '-') { + append('-'); + updateNextChar(); + + if (Character.isDigit(nextChar)) { + buildNumber(); + String numberStr = String.copyValueOf(parsedTokonBuffer, 0, bufferIndex); + NUMBER.setNumberValue(Double.parseDouble(numberStr)); + + return NUMBER; + } else { + throw new CubismJsonParseException("Number's format is incorrect.", lineNumber); + } + } + // A process when beginning at a number except 0. + else if (Character.isDigit(nextChar)) { + buildNumber(); + String numberStr = String.copyValueOf(parsedTokonBuffer, 0, bufferIndex); + NUMBER.setNumberValue(Double.parseDouble(numberStr)); + + return NUMBER; + } + // true + else if (nextChar == 't') { + append(nextChar); + updateNextChar(); + + for (int i = 0; i < 3; i++) { + append(nextChar); + updateNextChar(); + } + + // If "value" does not create true value, send an exception. + String trueString = String.copyValueOf(parsedTokonBuffer, 0, bufferIndex); + if (!trueString.equals("true")) { + throw new CubismJsonParseException("Boolean's format or spell is incorrect.", lineNumber); + } + return TRUE; + } + // false + else if (nextChar == 'f') { + append(nextChar); + updateNextChar(); + + for (int i = 0; i < 4; i++) { + append(nextChar); + updateNextChar(); + } + + // If the value does not equals to "false" value, send the exception. + String falseString = String.copyValueOf(parsedTokonBuffer, 0, bufferIndex); + if (!falseString.equals("false")) { + throw new CubismJsonParseException("Boolean's format or spell is incorrect.", lineNumber); + } + return FALSE; + } + // null + else if (nextChar == 'n') { + append(nextChar); + updateNextChar(); + + for (int i = 0; i < 3; i++) { + append(nextChar); + updateNextChar(); + } + + // If the JSON value does not equal to the "null" value, send an exception. + String nullString = String.copyValueOf(parsedTokonBuffer, 0, bufferIndex); + if (!nullString.equals("null")) { + throw new CubismJsonParseException("JSON Null's format or spell is incorrect.", lineNumber); + } + return NULL; + } else if (nextChar == '{') { + updateNextChar(); + return LBRACE; + } else if (nextChar == '}') { + updateNextChar(); + return RBRACE; + } else if (nextChar == '[') { + updateNextChar(); + return LSQUARE_BRACKET; + } else if (nextChar == ']') { + updateNextChar(); + return RSQUARE_BRACKET; + } + // If next character is double quote, string token is created. + else if (nextChar == '"') { + updateNextChar(); + + // Until closing by double quote("), it is continued to read. + while (nextChar != '"') { + // Consider a escape sequence. + if (nextChar == '\\') { + updateNextChar(); + buildEscapedString(); + } else { + append(nextChar); + } + updateNextChar(); + } + updateNextChar(); + STRING.setStringValue(String.valueOf(parsedTokonBuffer, 0, bufferIndex)); + + return STRING; + } + // Colon(:) + else if (nextChar == ':') { + updateNextChar(); + return COLON; + } + // Comma(,) + else if (nextChar == ',') { + updateNextChar(); + return COMMA; + } + throw new CubismJsonParseException("The JSON is not closed properly, or there is some other malformed form.", lineNumber); + } + + /** + * Return current line number. + * + * @return current line number + */ + public int getCurrentLineNumber() { + return lineNumber; + } + + /** + * Build number string. + * + * @throws CubismJsonParseException the exception at failing to parse + */ + private void buildNumber() throws CubismJsonParseException { + if (nextChar == '0') { + append(nextChar); + updateNextChar(); + buildDoubleOrExpNumber(); + } else { + append(nextChar); + updateNextChar(); + + // Repeat processes until appearing a character except dot, exponential expression or number. + while (Character.isDigit(nextChar)) { + append(nextChar); + updateNextChar(); + } + buildDoubleOrExpNumber(); + } + } + + /** + * Build double or exponential number. + * + * @throws CubismJsonParseException the exception at failing to parse + */ + private void buildDoubleOrExpNumber() throws CubismJsonParseException { + // If the next character is dot, floating point number is created. + if (nextChar == '.') { + buildDoubleNumber(); + } + // If there is an e or E, it is considered an exponential expression. + if (nextChar == 'e' || nextChar == 'E') { + buildExponents(); + } + } + + /** + * Return floating point number as strings(StringBuilder). + * + * @throws CubismJsonParseException the exception at failing to parse + */ + private void buildDoubleNumber() throws CubismJsonParseException { + append('.'); + updateNextChar(); + + // If the character following dot sign is not a number, an exception is thrown. + if (!Character.isDigit(nextChar)) { + throw new CubismJsonParseException("Number's format is incorrect.", lineNumber); + } + do { + append(nextChar); + updateNextChar(); + } while (Character.isDigit(nextChar)); + } + + /** + * Build a number string used an exponential expression. + * + * @throws CubismJsonParseException the exception at failing to parse + */ + private void buildExponents() throws CubismJsonParseException { + append(nextChar); + updateNextChar(); + + // Handle cases where a number is preceded by a sign. + if (nextChar == '+') { + append(nextChar); + updateNextChar(); + } else if (nextChar == '-') { + append(nextChar); + updateNextChar(); + } + // If the character is not a number or a sign, an exception is thrown. + if (!Character.isDigit(nextChar)) { + throw new CubismJsonParseException(String.copyValueOf(parsedTokonBuffer, 0, bufferIndex) + "\n: " + "Exponent value's format is incorrect.", lineNumber); + } + + do { + append(nextChar); + updateNextChar(); + } while (Character.isDigit(nextChar)); + } + + /** + * Build a string used an escape sequence. + * + * @throws CubismJsonParseException the exception at failing to parse + */ + private void buildEscapedString() throws CubismJsonParseException { + switch (nextChar) { + case '"': + case '\\': + case '/': + append(nextChar); + break; + case 'b': + append('\b'); + break; + case 'f': + append('\f'); + break; + case 'n': + append('\n'); + break; + case 'r': + append('\r'); + break; + case 't': + append('\t'); + break; + case 'u': { + // バッファをクリアする + bufferForHexadecimalString.delete(0, 16); + + bufferForHexadecimalString.append('\\'); + bufferForHexadecimalString.append('u'); + for (int i = 0; i < 4; i++) { + updateNextChar(); + bufferForHexadecimalString.append(nextChar); + } + // Check whether it is hex number. If there is a problem, an exception is thrown. + String tmp = bufferForHexadecimalString.toString(); + if (!tmp.matches("\\\\u[a-fA-F0-9]{4}")) { + throw new CubismJsonParseException(bufferForHexadecimalString + "\n: " + "The unicode notation is incorrect.", lineNumber); + } + + for (int i = 0; i < tmp.length(); i++) { + append(tmp.charAt(i)); + } + break; + } + } + } + + /** + * {@code buildEscapedString}の16進数の文字コードをパースする箇所で使用されるバッファ。 + */ + private static final StringBuffer bufferForHexadecimalString = new StringBuffer(); + + /** + * Whether a character is white space character. + * + * @param c checked character + * @return If the character is white space character, return true + */ + private boolean isWhiteSpaceChar(char c) { + return (c == ' ' || c == '\r' || c == '\n' || c == '\t'); + } + + /** + * Read a next character + */ + private void updateNextChar() { + // 文字を全部読んだら、次の文字をnull文字にセットしてreturnする + if (charIndex >= jsonCharsLength) { + nextChar = '\0'; + return; + } + + nextChar = jsonChars[charIndex]; + charIndex++; + + // 改行コードがあれば行数をインクリメントする + if (nextChar == '\n') { + lineNumber++; + } + } + + /** + * Tokonのパース用の文字列バッファに、引数で指定された文字リテラルを追加する。 + * + * @param c 追加する文字リテラル + */ + private void append(char c) { + // Tokenをパースするためのバッファがいっぱいになったら、バッファサイズを2倍にする + if (bufferLength == bufferIndex) { + bufferLength *= 2; + char[] tmp = new char[bufferLength]; + System.arraycopy(parsedTokonBuffer, 0, tmp, 0, bufferIndex); + + parsedTokonBuffer = tmp; + } + parsedTokonBuffer[bufferIndex] = c; + bufferIndex++; + } + + // Tokenを都度生成せずに定数として保持する + /** + * 左波カッコ'{'のトークン + */ + private static final CubismJsonToken LBRACE = new CubismJsonToken(CubismJsonToken.TokenType.LBRACE); + /** + * 右波カッコ'}'のトークン + */ + private static final CubismJsonToken RBRACE = new CubismJsonToken(CubismJsonToken.TokenType.RBRACE); + /** + * 左角カッコ'['のトークン + */ + private static final CubismJsonToken LSQUARE_BRACKET = new CubismJsonToken(CubismJsonToken.TokenType.LSQUARE_BRACKET); + /** + * 左角カッコ'['のトークン + */ + private static final CubismJsonToken RSQUARE_BRACKET = new CubismJsonToken(CubismJsonToken.TokenType.RSQUARE_BRACKET); + /** + * コロン':'のトークン + */ + private static final CubismJsonToken COLON = new CubismJsonToken(CubismJsonToken.TokenType.COLON); + /** + * カンマ','のトークン + */ + private static final CubismJsonToken COMMA = new CubismJsonToken(CubismJsonToken.TokenType.COMMA); + /** + * 真偽値'true'のトークン + */ + private static final CubismJsonToken TRUE = new CubismJsonToken(true); + /** + * 真偽値'false'のトークン + */ + private static final CubismJsonToken FALSE = new CubismJsonToken(false); + /** + * 'null'のトークン + */ + private static final CubismJsonToken NULL = new CubismJsonToken(); + + // 中の値を書き換えて使用する + /** + * 文字列のトークン + */ + private static final CubismJsonToken STRING = new CubismJsonToken(""); + /** + * 数値のトークン + */ + private static final CubismJsonToken NUMBER = new CubismJsonToken(0.0); + + /** + * jsonChars配列の初期サイズ。 + * これを超えるトークンが出現した場合はサイズを2倍に拡張する。 + */ + private static final int MINIMUM_CAPACITY = 128; + + /** + * パースするJSON文字列 + */ + private final char[] jsonChars; + /** + * 現在読んでいる文字のインデックス + */ + private int charIndex; + /** + * パースするJSON文字列の文字数 + */ + private final int jsonCharsLength; + /** + * 行数。改行文字が出てくるたびにインクリメントされる。 + */ + private int lineNumber = 1; + + /** + * the next character + */ + private char nextChar = ' '; + + /** + * トークンのパース時に使用されるバッファ + */ + private char[] parsedTokonBuffer; + /** + * {@code parsedTokonBuffer}の最後尾のインデックス + */ + private int bufferIndex; + /** + * {@code parsedTokonBuffer}の容量 + */ + private int bufferLength = MINIMUM_CAPACITY; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonNullValue.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonNullValue.java new file mode 100644 index 0000000..34cd7b6 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonNullValue.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +/** + * This class expresses a JSON null Value. + * It has no fields and methods. + */ +class CubismJsonNullValue extends ACubismJsonValue { + public CubismJsonNullValue() { + stringBuffer = "NullValue"; + } + + @Override + public String getString(String defaultValue, String indent) { + return stringBuffer; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismJsonNullValue that = (CubismJsonNullValue) o; + + return stringBuffer != null ? stringBuffer.equals(that.stringBuffer) : that.stringBuffer == null; + } + + @Override + public int hashCode() { + return stringBuffer != null ? stringBuffer.hashCode() : 0; + } + + +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonNumber.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonNumber.java new file mode 100644 index 0000000..85aafff --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonNumber.java @@ -0,0 +1,86 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +/** + * This class expresses a number value. + * It has double type number. + */ +class CubismJsonNumber extends ACubismJsonValue { + /** + * Get an instance of number type. + * + * @param value number value + * @return an instance of number type + */ + public static CubismJsonNumber valueOf(double value) { + return new CubismJsonNumber(value); + } + + @Override + public String getString(String defaultValue, String indent) { + return stringBuffer; + } + + + @Override + public int toInt() { + return (int) value; + } + + @Override + public int toInt(int defaultValue) { + return (int) value; + } + + @Override + public float toFloat() { + return (float) value; + } + + @Override + public float toFloat(float defaultValue) { + return (float) value; + } + + @Override + public boolean isNumber() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismJsonNumber that = (CubismJsonNumber) o; + + return Float.compare((float) that.value, (float) value) == 0; + } + + @Override + public int hashCode() { + long temp = Float.floatToIntBits((float) value); + return (int) (temp ^ (temp >>> 32)); + } + + /** + * private constructor + * + * @param value number value + */ + private CubismJsonNumber(double value) { + this.value = value; + stringBuffer = String.valueOf(value); + } + + /** + * number value + */ + private final double value; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonObject.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonObject.java new file mode 100644 index 0000000..80e9681 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonObject.java @@ -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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class expresses JSON Object. + * If duplicate key is put, an error is not returned. However, the value corresponding duplicate key is overridden with the value corresponding the key which is defined later. + */ +class CubismJsonObject extends ACubismJsonValue { + /** + * Put a pair of string and value + * + * @param string key(string) + * @param value value + */ + public void putPair(CubismJsonString string, ACubismJsonValue value) { + this.value.put(string, value); + + // Add to key list + keys.add(string); + } + + @Override + public ACubismJsonValue get(String key) { + CubismJsonString str = CubismJsonString.valueOf(key); + ACubismJsonValue value = this.value.get(str); + + if (value == null) { + return new CubismJsonNullValue(); + } + + return value; + } + + @Override + public ACubismJsonValue get(int index) { + return new CubismJsonErrorValue().setErrorNotForClientCall(JsonError.TYPE_MISMATCH.message); + } + + @Override + public String getString(String defaultValue, String indent) { + // バッファをクリアする + bufferForGetString.delete(0, bufferForGetString.length()); + + bufferForGetString.append(indent); + bufferForGetString.append("{\n"); + + for (int i = 0; i < keys.size(); i++) { + CubismJsonString key = keys.get(i); + ACubismJsonValue value = this.value.get(key); + + assert value != null; + + bufferForGetString.append(indent); + bufferForGetString.append(" "); + bufferForGetString.append(key); + bufferForGetString.append(" : "); + bufferForGetString.append(value.getString(indent + " ")); + bufferForGetString.append("\n"); + } + + bufferForGetString.append(indent); + bufferForGetString.append("}\n"); + + stringBuffer = bufferForGetString.toString(); + return stringBuffer; + } + + + @Override + public Map getMap() { + return value; + } + + @Override + public List getKeys() { + return keys; + } + + @Override + public int size() { + return value.size(); + } + + @Override + public boolean isObject() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CubismJsonObject)) return false; + + CubismJsonObject that = (CubismJsonObject) o; + + if (!value.equals(that.value)) return false; + return keys.equals(that.keys); + } + + @Override + public int hashCode() { + int result = value.hashCode(); + result = 31 * result + keys.hashCode(); + return result; + } + + /** + * {@code getString}メソッドで使われる一時的な文字列バッファの最小容量。 + */ + private static final int MINIMUM_CAPACITY = 128; + + /** + * JSON Object value(map of JSON String and JSON Value) + */ + private final Map value = new HashMap(); + /** + * List of keys to speed up access to the specified index + */ + private final List keys = new ArrayList(); + + /** + * {@code getString}で使用される文字列バッファ + */ + private final StringBuffer bufferForGetString = new StringBuffer(MINIMUM_CAPACITY); +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonString.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonString.java new file mode 100644 index 0000000..4664087 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonString.java @@ -0,0 +1,54 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +public class CubismJsonString extends ACubismJsonValue { + /** + * stringのインスタンスを得る + * + * @return stringのインスタンス + * + * @throws IllegalArgumentException If the given value is 'null'. + */ + public static CubismJsonString valueOf(String value) { + if (value == null) { + throw new IllegalArgumentException("The value is null."); + } + return new CubismJsonString(value); + } + + @Override + public String getString(String defaultValue, String indent) { + return stringBuffer; + } + + @Override + public boolean isString() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CubismJsonString that = (CubismJsonString) o; + + return stringBuffer != null ? stringBuffer.equals(that.stringBuffer) : that.stringBuffer == null; + } + + @Override + public int hashCode() { + return stringBuffer != null ? stringBuffer.hashCode() : 0; + } + + private CubismJsonString(String value) { + stringBuffer = value; + } +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonToken.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonToken.java new file mode 100644 index 0000000..582c8fe --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/CubismJsonToken.java @@ -0,0 +1,137 @@ +/* + * 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 http://live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +package com.live2d.sdk.cubism.framework.utils.jsonparser; + +/** + * This class expresses JSON Tokens. + */ +class CubismJsonToken { + /** + * Token types + */ + public enum TokenType { + NUMBER, // ex) 0, 1.0, -1.2e+3 + STRING, // ex) "test" + BOOLEAN, // 'true' or 'false' + LBRACE, // '{' + RBRACE, // '}' + LSQUARE_BRACKET, // '[' + RSQUARE_BRACKET, // ']' + COMMA, + COLON, + NULL, // JSON null value + } + + /** + * Construct a CubismJsonToken by specifying only the token type. + * + * @param type token type + */ + public CubismJsonToken(TokenType type) { + tokenType = type; + } + + /** + * Construct a string token. + * + * @param value string value + */ + public CubismJsonToken(String value) { + tokenType = TokenType.STRING; + stringValue = value; + } + + /** + * Construct a number token. + * + * @param value number value + */ + public CubismJsonToken(double value) { + tokenType = TokenType.NUMBER; + numberValue = value; + } + + + /** + * Construct a boolean token. + * + * @param value boolean value + */ + public CubismJsonToken(boolean value) { + tokenType = TokenType.BOOLEAN; + booleanValue = value; + } + + /** + * Construct a null token. + */ + public CubismJsonToken() { + tokenType = TokenType.NULL; + } + + /** + * Get the type of token. + * + * @return token type + */ + public TokenType getTokenType() { + return tokenType; + } + + /** + * Get string value. + * + * @return string value + */ + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + /** + * Get number value. + * + * @return number value + */ + public double getNumberValue() { + return numberValue; + } + + public void setNumberValue(double numberValue) { + this.numberValue = numberValue; + } + + /** + * Get boolean value. + * + * @return boolean value + */ + public boolean getBooleanValue() { + return booleanValue; + } + + /** + * Token type + */ + private final TokenType tokenType; + /** + * String value + */ + private String stringValue; + /** + * Number value + */ + private double numberValue; + /** + * Boolean value + */ + private boolean booleanValue; +} diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/package-info.java new file mode 100644 index 0000000..62d3a19 --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/jsonparser/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide a function of JSON parser. + */ +package com.live2d.sdk.cubism.framework.utils.jsonparser; diff --git a/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/package-info.java b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/package-info.java new file mode 100644 index 0000000..7fccf8a --- /dev/null +++ b/Live2DFramework/framework/src/main/java/com/live2d/sdk/cubism/framework/utils/package-info.java @@ -0,0 +1,4 @@ +/** + * Provide utility functions such as a JSON parser and log output. + */ +package com.live2d.sdk.cubism.framework.utils; diff --git a/Live2DFramework/gradle.properties b/Live2DFramework/gradle.properties new file mode 100644 index 0000000..0529722 --- /dev/null +++ b/Live2DFramework/gradle.properties @@ -0,0 +1,25 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Android SDK version that will be used as the compiled project +PROP_COMPILE_SDK_VERSION=35 +# Android SDK version that will be used as the earliest version of android this application can run on +PROP_MIN_SDK_VERSION=21 +# Android SDK version that will be used as the latest version of android this application has been tested on +PROP_TARGET_SDK_VERSION=35 diff --git a/Live2DFramework/gradle/wrapper/gradle-wrapper.jar b/Live2DFramework/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/Live2DFramework/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Live2DFramework/gradle/wrapper/gradle-wrapper.properties b/Live2DFramework/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bc23f3d --- /dev/null +++ b/Live2DFramework/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jul 11 18:25:17 JST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/Live2DFramework/gradlew b/Live2DFramework/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/Live2DFramework/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/Live2DFramework/gradlew.bat b/Live2DFramework/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/Live2DFramework/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Live2DFramework/settings.gradle b/Live2DFramework/settings.gradle new file mode 100644 index 0000000..5d0b081 --- /dev/null +++ b/Live2DFramework/settings.gradle @@ -0,0 +1,13 @@ +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Framework" +include ':framework' diff --git a/app/build.gradle b/app/build.gradle index 3ca1143..33e8a66 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,6 +40,7 @@ android { buildConfigField "String", "LLM_API_URL", "\"${(project.findProperty('LLM_API_URL') ?: 'https://ark.cn-beijing.volces.com/api/v3/chat/completions').toString()}\"" buildConfigField "String", "LLM_API_KEY", "\"${(project.findProperty('LLM_API_KEY') ?: '').toString()}\"" buildConfigField "String", "LLM_MODEL", "\"${(project.findProperty('LLM_MODEL') ?: 'doubao-1-5-pro-32k-character-250228').toString()}\"" + buildConfigField "boolean", "USE_LIVE2D", "${(project.findProperty('USE_LIVE2D') ?: 'false').toString()}" ndk { abiFilters "arm64-v8a" @@ -72,4 +73,6 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // ExoPlayer for video playback (used to show silent / speaking videos) implementation 'com.google.android.exoplayer:exoplayer:2.18.6' + implementation project(':framework') + implementation files('../Live2DFramework/Core/android/Live2DCubismCore.aar') } diff --git a/app/note/design_doc b/app/note/design_doc new file mode 100644 index 0000000..152740b --- /dev/null +++ b/app/note/design_doc @@ -0,0 +1,57 @@ +1. ## 🎯 当前使用的ASR模型 + ### 模型名称:SenseVoice (RKNN版本) + ### 模型架构: + - 编码器 : sense-voice-encoder.rknn - RKNN格式的神经网络模型 + - 嵌入层 : embedding.npy - 词嵌入矩阵 + - 分词器 : chn_jpn_yue_eng_ko_spectok.bpe.model - BPE分词模型 + ### 模型特点: + 1. 多语言支持 - 支持中文、日文、粤语、英文、韩文 + 2. RKNN加速 - 针对RK3588等Rockchip芯片优化 + 3. ITN支持 - 启用了逆文本归一化(Inverse Text Normalization),提高数字/日期识别准确性 + +2. ## TTS模型信息 + ### 模型名称 + Sherpa-ONNX VITS - 中文版本(sherpa-onnx-vits-zh-ll) + + ### 模型文件 + 位于 app/src/main/assets/tts_model/sherpa-onnx-vits-zh-ll/ 目录: + + - model.onnx - ONNX格式的声学模型 + - tokens.txt - 音素/字符映射表 + - lexicon.txt - 发音词典 + - phone.fst - 音素转换规则 + - date.fst - 日期归一化规则 + - number.fst - 数字归一化规则 + - new_heteronym.fst - 多音字处理规则 + +3. ## VAD模型信息 + ### 模型名称 + Silero VAD (Voice Activity Detection) + + ### 模型文件 + - 文件路径: assets/vad_model/silero_vad.onnx + - 格式:ONNX格式 + +4. 模型部署对比 +模型 类型 格式 RKNN加速 推理设备 配置 +ASR SenseVoice .rknn ✅ 是 NPU RKNN Runtime +VAD Silero VAD .onnx ❌ 否 CPU provider="cpu" +TTS Sherpa-ONNX VITS .onnx ❌ 否 CPU ONNX Runtime + +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ AudioProcessor │────▶│ VadManager │────▶│ ASR Queue │ +│ (录音+增益) │ │ (语音活动检测) │ │ (Channel队列) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ + ┌─────────────────────────┘ + ▼ + ┌─────────────────┐ + │ runAsrWorker │ + │ (协程工作器) │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ SenseVoice │ + │ (RKNN推理) │ + └─────────────────┘ \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e32b052..a7fa46d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,13 +11,15 @@ android:theme="@style/Theme.DigitalPerson"> + + diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.2048/texture_00.png b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.2048/texture_00.png new file mode 100644 index 0000000..881ad67 Binary files /dev/null and b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.2048/texture_00.png differ diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.2048/texture_01.png b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.2048/texture_01.png new file mode 100644 index 0000000..9caa21e Binary files /dev/null and b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.2048/texture_01.png differ diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.cdi3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.cdi3.json new file mode 100644 index 0000000..f252a17 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.cdi3.json @@ -0,0 +1,348 @@ +{ + "Version": 3, + "Parameters": [ + { + "Id": "ParamAngleX", + "GroupId": "ParamGroupFace", + "Name": "角度 X" + }, + { + "Id": "ParamAngleY", + "GroupId": "ParamGroupFace", + "Name": "角度 Y" + }, + { + "Id": "ParamAngleZ", + "GroupId": "ParamGroupFace", + "Name": "角度 Z" + }, + { + "Id": "ParamTere", + "GroupId": "ParamGroupFace", + "Name": "照れ" + }, + { + "Id": "ParamFaceForm", + "GroupId": "ParamGroupFace", + "Name": "顔の拡縮" + }, + { + "Id": "ParamEyeLOpen", + "GroupId": "ParamGroupEyes", + "Name": "左目 開閉" + }, + { + "Id": "ParamEyeLSmile", + "GroupId": "ParamGroupEyes", + "Name": "左目 笑顔" + }, + { + "Id": "ParamEyeROpen", + "GroupId": "ParamGroupEyes", + "Name": "右目 開閉" + }, + { + "Id": "ParamEyeRSmile", + "GroupId": "ParamGroupEyes", + "Name": "右目 笑顔" + }, + { + "Id": "ParamEyeForm", + "GroupId": "ParamGroupEyes", + "Name": "眼 変形" + }, + { + "Id": "ParamEyeBallForm", + "GroupId": "ParamGroupEyes", + "Name": "目玉 収縮" + }, + { + "Id": "ParamTear", + "GroupId": "ParamGroupEyes", + "Name": "涙" + }, + { + "Id": "ParamEyeBallX", + "GroupId": "ParamGroupEyes", + "Name": "目玉 X" + }, + { + "Id": "ParamEyeBallY", + "GroupId": "ParamGroupEyes", + "Name": "目玉 Y" + }, + { + "Id": "ParamBrowLY", + "GroupId": "ParamGroup", + "Name": "左眉 上下" + }, + { + "Id": "ParamBrowRY", + "GroupId": "ParamGroup", + "Name": "右眉 上下" + }, + { + "Id": "ParamBrowLX", + "GroupId": "ParamGroup", + "Name": "左眉 左右" + }, + { + "Id": "ParamBrowRX", + "GroupId": "ParamGroup", + "Name": "右眉 左右" + }, + { + "Id": "ParamBrowLAngle", + "GroupId": "ParamGroup", + "Name": "左眉 角度" + }, + { + "Id": "ParamBrowRAngle", + "GroupId": "ParamGroup", + "Name": "右眉 角度" + }, + { + "Id": "ParamBrowLForm", + "GroupId": "ParamGroup", + "Name": "左眉 変形" + }, + { + "Id": "ParamBrowRForm", + "GroupId": "ParamGroup", + "Name": "右眉 変形" + }, + { + "Id": "ParamMouthForm", + "GroupId": "ParamGroupMouth", + "Name": "口 変形" + }, + { + "Id": "ParamMouthOpenY", + "GroupId": "ParamGroupMouth", + "Name": "口 開閉" + }, + { + "Id": "ParamScarf", + "GroupId": "ParamGroup2", + "Name": "スカーフ揺れ" + }, + { + "Id": "ParamBodyAngleX", + "GroupId": "ParamGroup2", + "Name": "体の回転 X" + }, + { + "Id": "ParamBodyAngleY", + "GroupId": "ParamGroup2", + "Name": "体の回転 Y" + }, + { + "Id": "ParamBodyAngleZ", + "GroupId": "ParamGroup2", + "Name": "体の回転 Z" + }, + { + "Id": "ParamBodyUpper", + "GroupId": "ParamGroup2", + "Name": "上体" + }, + { + "Id": "ParamBreath", + "GroupId": "ParamGroup2", + "Name": "呼吸" + }, + { + "Id": "ParamBustY", + "GroupId": "ParamGroup2", + "Name": "胸 揺れ" + }, + { + "Id": "ParamArmLA", + "GroupId": "ParamGroupArms", + "Name": "左腕 A" + }, + { + "Id": "ParamArmRA", + "GroupId": "ParamGroupArms", + "Name": "右腕 A" + }, + { + "Id": "ParamArmLB", + "GroupId": "ParamGroupArms", + "Name": "右腕 B" + }, + { + "Id": "ParamArmRB", + "GroupId": "ParamGroupArms", + "Name": "左腕 B" + }, + { + "Id": "ParamHandChangeR", + "GroupId": "ParamGroupArms", + "Name": "右手切替" + }, + { + "Id": "ParamHandAngleR", + "GroupId": "ParamGroupArms", + "Name": "右手首角度" + }, + { + "Id": "ParamHandDhangeL", + "GroupId": "ParamGroupArms", + "Name": "左手切替" + }, + { + "Id": "ParamHandAngleL", + "GroupId": "ParamGroupArms", + "Name": "左手首角度" + }, + { + "Id": "ParamHairFront", + "GroupId": "ParamGroup3", + "Name": "髪揺れ 前" + }, + { + "Id": "ParamHairSide", + "GroupId": "ParamGroup3", + "Name": "髪揺れ 横" + }, + { + "Id": "ParamHairBack", + "GroupId": "ParamGroup3", + "Name": "髪揺れ 後" + } + ], + "ParameterGroups": [ + { + "Id": "ParamGroupFace", + "GroupId": "", + "Name": "顔" + }, + { + "Id": "ParamGroupEyes", + "GroupId": "", + "Name": "目" + }, + { + "Id": "ParamGroup", + "GroupId": "", + "Name": "眉毛" + }, + { + "Id": "ParamGroupMouth", + "GroupId": "", + "Name": "口" + }, + { + "Id": "ParamGroup2", + "GroupId": "", + "Name": "胴体" + }, + { + "Id": "ParamGroupArms", + "GroupId": "", + "Name": "腕" + }, + { + "Id": "ParamGroup3", + "GroupId": "", + "Name": "髪揺れ" + } + ], + "Parts": [ + { + "Id": "Part01Core", + "Name": "コアパーツ" + }, + { + "Id": "Part01Hoho001", + "Name": "頬" + }, + { + "Id": "Part01Brow001", + "Name": "まゆ毛" + }, + { + "Id": "Part01Tear", + "Name": "涙" + }, + { + "Id": "Part01EyeBall001", + "Name": "目玉" + }, + { + "Id": "Part01Eye001", + "Name": "目" + }, + { + "Id": "Part01Nose001", + "Name": "鼻" + }, + { + "Id": "Part01Mouth001", + "Name": "口" + }, + { + "Id": "Part01Face001", + "Name": "顔" + }, + { + "Id": "Part01Ear001", + "Name": "耳" + }, + { + "Id": "Part01Neck001", + "Name": "首" + }, + { + "Id": "Part01HairFront001", + "Name": "前髪" + }, + { + "Id": "Part01HairSide001", + "Name": "横髪" + }, + { + "Id": "Part01HairBack001", + "Name": "後ろ髪" + }, + { + "Id": "Part01ArmRB001", + "Name": "左腕 B" + }, + { + "Id": "Part01ArmLB001", + "Name": "右腕 B" + }, + { + "Id": "Part01ArmRA001", + "Name": "右腕 A" + }, + { + "Id": "Part01ArmLA001", + "Name": "左腕 A" + }, + { + "Id": "Part01Body001", + "Name": "制服" + }, + { + "Id": "Part01Sketch", + "Name": "[ 下絵 ]" + } + ], + "CombinedParameters": [ + [ + "ParamAngleX", + "ParamAngleY" + ], + [ + "ParamEyeBallX", + "ParamEyeBallY" + ], + [ + "ParamMouthForm", + "ParamMouthOpenY" + ] + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.moc3 b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.moc3 new file mode 100644 index 0000000..0dc7d4b Binary files /dev/null and b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.moc3 differ diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.model3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.model3.json new file mode 100644 index 0000000..5948a9a --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.model3.json @@ -0,0 +1,125 @@ +{ + "Version": 3, + "FileReferences": { + "Moc": "haru_greeter_t05.moc3", + "Textures": [ + "haru_greeter_t05.2048/texture_00.png", + "haru_greeter_t05.2048/texture_01.png" + ], + "Physics": "haru_greeter_t05.physics3.json", + "Pose": "haru_greeter_t05.pose3.json", + "DisplayInfo": "haru_greeter_t05.cdi3.json", + "Motions": { + "": [ + { + "File": "motion/haru_g_idle.motion3.json" + }, + { + "File": "motion/haru_g_m01.motion3.json" + }, + { + "File": "motion/haru_g_m02.motion3.json" + }, + { + "File": "motion/haru_g_m03.motion3.json" + }, + { + "File": "motion/haru_g_m04.motion3.json" + }, + { + "File": "motion/haru_g_m05.motion3.json" + }, + { + "File": "motion/haru_g_m06.motion3.json" + }, + { + "File": "motion/haru_g_m07.motion3.json" + }, + { + "File": "motion/haru_g_m08.motion3.json" + }, + { + "File": "motion/haru_g_m09.motion3.json" + }, + { + "File": "motion/haru_g_m10.motion3.json" + }, + { + "File": "motion/haru_g_m11.motion3.json" + }, + { + "File": "motion/haru_g_m12.motion3.json" + }, + { + "File": "motion/haru_g_m13.motion3.json" + }, + { + "File": "motion/haru_g_m14.motion3.json" + }, + { + "File": "motion/haru_g_m15.motion3.json" + }, + { + "File": "motion/haru_g_m16.motion3.json" + }, + { + "File": "motion/haru_g_m17.motion3.json" + }, + { + "File": "motion/haru_g_m18.motion3.json" + }, + { + "File": "motion/haru_g_m19.motion3.json" + }, + { + "File": "motion/haru_g_m20.motion3.json" + }, + { + "File": "motion/haru_g_m21.motion3.json" + }, + { + "File": "motion/haru_g_m22.motion3.json" + }, + { + "File": "motion/haru_g_m23.motion3.json" + }, + { + "File": "motion/haru_g_m24.motion3.json" + }, + { + "File": "motion/haru_g_m25.motion3.json" + }, + { + "File": "motion/haru_g_m26.motion3.json" + } + ] + } + }, + "Groups": [ + { + "Target": "Parameter", + "Name": "EyeBlink", + "Ids": [ + "ParamEyeLOpen", + "ParamEyeROpen" + ] + }, + { + "Target": "Parameter", + "Name": "LipSync", + "Ids": [ + "ParamMouthOpenY" + ] + } + ], + "HitAreas": [ + { + "Id": "HitArea", + "Name": "" + }, + { + "Id": "HitArea2", + "Name": "" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.physics3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.physics3.json new file mode 100644 index 0000000..3f14797 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.physics3.json @@ -0,0 +1,373 @@ +{ + "Version": 3, + "Meta": { + "PhysicsSettingCount": 4, + "TotalInputCount": 14, + "TotalOutputCount": 4, + "VertexCount": 8, + "EffectiveForces": { + "Gravity": { + "X": 0, + "Y": -1 + }, + "Wind": { + "X": 0, + "Y": 0 + } + }, + "PhysicsDictionary": [ + { + "Id": "PhysicsSetting1", + "Name": "前髪" + }, + { + "Id": "PhysicsSetting2", + "Name": "横髪" + }, + { + "Id": "PhysicsSetting3", + "Name": "後ろ髪" + }, + { + "Id": "PhysicsSetting4", + "Name": "スカーフ" + } + ] + }, + "PhysicsSettings": [ + { + "Id": "PhysicsSetting1", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairFront" + }, + "VertexIndex": 1, + "Scale": 1.821, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 8 + }, + "Mobility": 0.95, + "Delay": 0.8, + "Acceleration": 1.5, + "Radius": 8 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting2", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairSide" + }, + "VertexIndex": 1, + "Scale": 1.593, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 8 + }, + "Mobility": 0.95, + "Delay": 0.8, + "Acceleration": 1, + "Radius": 8 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting3", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairBack" + }, + "VertexIndex": 1, + "Scale": 1.943, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 8 + }, + "Mobility": 0.95, + "Delay": 0.8, + "Acceleration": 1.5, + "Radius": 8 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting4", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 100, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamScarf" + }, + "VertexIndex": 1, + "Scale": 0.873, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 10 + }, + "Mobility": 0.9, + "Delay": 0.6, + "Acceleration": 1.5, + "Radius": 10 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.pose3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.pose3.json new file mode 100644 index 0000000..06bda9e --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/haru_greeter_t05.pose3.json @@ -0,0 +1,25 @@ +{ + "Type": "Live2D Pose", + "Groups": [ + [ + { + "Id": "Part01ArmRB001", + "Link": [] + }, + { + "Id": "Part01ArmRA001", + "Link": [] + } + ], + [ + { + "Id": "Part01ArmLB001", + "Link": [] + }, + { + "Id": "Part01ArmLA001", + "Link": [] + } + ] + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_idle.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_idle.motion3.json new file mode 100644 index 0000000..f28938b --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_idle.motion3.json @@ -0,0 +1,2260 @@ +{ + "Version": 3, + "Meta": { + "Duration": 10, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 296, + "TotalPointCount": 785, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 3.32, + 1, + 6.64, + 1, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + -4, + 0.533, + -4, + 1, + 0.989, + -4, + 1.444, + -4, + 1.9, + -4, + 1, + 2.378, + -4, + 2.856, + 0, + 3.333, + 0, + 1, + 3.444, + 0, + 3.556, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.433, + 0, + 6.967, + 14, + 7.5, + 14, + 1, + 7.833, + 14, + 8.167, + 14, + 8.5, + 14, + 1, + 8.989, + 14, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + -6, + 0.533, + -6, + 1, + 0.989, + -6, + 1.444, + -6, + 1.9, + -6, + 1, + 2.378, + -6, + 2.856, + 0, + 3.333, + 0, + 1, + 3.444, + 0, + 3.556, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.211, + 0, + 6.522, + 5, + 6.833, + 5, + 1, + 7.056, + 5, + 7.278, + -6, + 7.5, + -6, + 1, + 7.833, + -6, + 8.167, + -6, + 8.5, + -6, + 1, + 8.989, + -6, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + -6, + 0.533, + -6, + 1, + 0.733, + -6, + 0.933, + 1.432, + 1.133, + 5, + 1, + 1.389, + 9.559, + 1.644, + 10, + 1.9, + 10, + 1, + 2.378, + 10, + 2.856, + -6, + 3.333, + -6, + 1, + 3.444, + -6, + 3.556, + -6, + 3.667, + -6, + 1, + 4.156, + -6, + 4.644, + 6, + 5.133, + 6, + 1, + 5.389, + 6, + 5.644, + 6, + 5.9, + 6, + 1, + 6.211, + 6, + 6.522, + 12, + 6.833, + 12, + 1, + 7.389, + 12, + 7.944, + -6, + 8.5, + -6, + 1, + 8.989, + -6, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.633, + 1, + 1.267, + 1, + 1.9, + 1, + 1, + 2, + 1, + 2.1, + 1, + 2.2, + 1, + 1, + 2.244, + 1, + 2.289, + 0, + 2.333, + 0, + 1, + 2.356, + 0, + 2.378, + 0, + 2.4, + 0, + 1, + 2.456, + 0, + 2.511, + 1, + 2.567, + 1, + 1, + 2.933, + 1, + 3.3, + 1, + 3.667, + 1, + 1, + 3.711, + 1, + 3.756, + 0, + 3.8, + 0, + 1, + 3.822, + 0, + 3.844, + 0, + 3.867, + 0, + 1, + 3.922, + 0, + 3.978, + 1, + 4.033, + 1, + 1, + 4.656, + 1, + 5.278, + 1, + 5.9, + 1, + 1, + 6.433, + 1, + 6.967, + 1, + 7.5, + 1, + 1, + 7.544, + 1, + 7.589, + 0, + 7.633, + 0, + 1, + 7.656, + 0, + 7.678, + 0, + 7.7, + 0, + 1, + 7.756, + 0, + 7.811, + 1, + 7.867, + 1, + 1, + 8.078, + 1, + 8.289, + 1, + 8.5, + 1, + 1, + 8.989, + 1, + 9.478, + 1, + 9.967, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.633, + 1, + 1.267, + 1, + 1.9, + 1, + 1, + 2, + 1, + 2.1, + 1, + 2.2, + 1, + 1, + 2.244, + 1, + 2.289, + 0, + 2.333, + 0, + 1, + 2.356, + 0, + 2.378, + 0, + 2.4, + 0, + 1, + 2.456, + 0, + 2.511, + 1, + 2.567, + 1, + 1, + 2.933, + 1, + 3.3, + 1, + 3.667, + 1, + 1, + 3.711, + 1, + 3.756, + 0, + 3.8, + 0, + 1, + 3.822, + 0, + 3.844, + 0, + 3.867, + 0, + 1, + 3.922, + 0, + 3.978, + 1, + 4.033, + 1, + 1, + 4.656, + 1, + 5.278, + 1, + 5.9, + 1, + 1, + 6.433, + 1, + 6.967, + 1, + 7.5, + 1, + 1, + 7.544, + 1, + 7.589, + 0, + 7.633, + 0, + 1, + 7.656, + 0, + 7.678, + 0, + 7.7, + 0, + 1, + 7.756, + 0, + 7.811, + 1, + 7.867, + 1, + 1, + 8.078, + 1, + 8.289, + 1, + 8.5, + 1, + 1, + 8.989, + 1, + 9.478, + 1, + 9.967, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + 0.23, + 0.533, + 0.23, + 1, + 0.989, + 0.23, + 1.444, + 0.23, + 1.9, + 0.23, + 1, + 2.611, + 0.23, + 3.322, + 0, + 4.033, + 0, + 1, + 4.656, + 0, + 5.278, + 0, + 5.9, + 0, + 1, + 6.211, + 0, + 6.522, + -0.198, + 6.833, + -0.3, + 1, + 7.056, + -0.373, + 7.278, + -0.398, + 7.5, + -0.43, + 1, + 7.833, + -0.477, + 8.167, + -0.49, + 8.5, + -0.49, + 1, + 8.989, + -0.49, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + 0.25, + 0.533, + 0.25, + 1, + 0.989, + 0.25, + 1.444, + 0.25, + 1.9, + 0.25, + 1, + 2.611, + 0.25, + 3.322, + 0, + 4.033, + 0, + 1, + 4.656, + 0, + 5.278, + 0, + 5.9, + 0, + 1, + 6.211, + 0, + 6.522, + -0.17, + 6.833, + -0.17, + 1, + 7.056, + -0.17, + 7.278, + 0.29, + 7.5, + 0.29, + 1, + 7.833, + 0.29, + 8.167, + 0.282, + 8.5, + 0.21, + 1, + 8.989, + 0.104, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 3.322, + 1, + 6.644, + 1, + 9.967, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + -3, + 0.533, + -3, + 1, + 0.989, + -3, + 1.444, + -3, + 1.9, + -3, + 1, + 1.989, + -3, + 2.078, + -3, + 2.167, + -3, + 1, + 2.556, + -3, + 2.944, + 0, + 3.333, + 0, + 1, + 3.444, + 0, + 3.556, + 0, + 3.667, + 0, + 1, + 3.722, + 0, + 3.778, + 0, + 3.833, + 0, + 1, + 4.267, + 0, + 4.7, + 4, + 5.133, + 4, + 1, + 5.389, + 4, + 5.644, + 4, + 5.9, + 4, + 1, + 6, + 4, + 6.1, + 4, + 6.2, + 4, + 1, + 6.411, + 4, + 6.622, + 4.702, + 6.833, + 6, + 1, + 7.056, + 7.367, + 7.278, + 8, + 7.5, + 8, + 1, + 7.833, + 8, + 8.167, + 8, + 8.5, + 8, + 1, + 8.6, + 8, + 8.7, + 8, + 8.8, + 8, + 1, + 9.189, + 8, + 9.578, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 1.989, + 0, + 2.078, + 0, + 2.167, + 0, + 1, + 2.667, + 0, + 3.167, + 0, + 3.667, + 0, + 1, + 3.722, + 0, + 3.778, + 0, + 3.833, + 0, + 1, + 4.522, + 0, + 5.211, + 0, + 5.9, + 0, + 1, + 6, + 0, + 6.1, + 0, + 6.2, + 0, + 1, + 6.967, + 0, + 7.733, + 0, + 8.5, + 0, + 1, + 8.6, + 0, + 8.7, + 0, + 8.8, + 0, + 1, + 9.189, + 0, + 9.578, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 3.788, + 0.733, + 4.987, + 1, + 0.956, + 6.077, + 1.178, + 5.954, + 1.4, + 5.954, + 1, + 1.778, + 5.954, + 2.156, + 5.242, + 2.533, + 2.985, + 1, + 2.8, + 1.393, + 3.067, + 0, + 3.333, + 0, + 1, + 3.444, + 0, + 3.556, + 0, + 3.667, + 0, + 1, + 3.722, + 0, + 3.778, + 0, + 3.833, + 0, + 1, + 4.267, + 0, + 4.7, + -2, + 5.133, + -2, + 1, + 5.389, + -2, + 5.644, + -2, + 5.9, + -2, + 1, + 6, + -2, + 6.1, + -2, + 6.2, + -2, + 1, + 6.411, + -2, + 6.622, + -4, + 6.833, + -4, + 1, + 7.056, + -4, + 7.278, + -2, + 7.5, + -2, + 1, + 7.833, + -2, + 8.167, + -5, + 8.5, + -5, + 1, + 8.6, + -5, + 8.7, + -5, + 8.8, + -5, + 1, + 9.189, + -5, + 9.578, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 3.322, + 1, + 6.644, + 1, + 9.967, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 3.322, + 1, + 6.644, + 1, + 9.967, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + -0.1, + 1, + 3.322, + -0.1, + 6.644, + -0.1, + 9.967, + -0.1, + 0, + 10, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0.1, + 1, + 3.322, + 0.1, + 6.644, + 0.1, + 9.967, + 0.1, + 0, + 10, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 3.322, + 0, + 6.644, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.633, + 0, + 1.267, + 0, + 1.9, + 0, + 1, + 2.489, + 0, + 3.078, + 0, + 3.667, + 0, + 1, + 4.411, + 0, + 5.156, + 0, + 5.9, + 0, + 1, + 6.767, + 0, + 7.633, + 0, + 8.5, + 0, + 1, + 8.989, + 0, + 9.478, + 0, + 9.967, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 9.97, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 9.97, + 0, + 0, + 10, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 9.97, + 1, + 0, + 10, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 9.97, + 0, + 0, + 10, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m01.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m01.motion3.json new file mode 100644 index 0000000..115419e --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m01.motion3.json @@ -0,0 +1,1189 @@ +{ + "Version": 3, + "Meta": { + "Duration": 2.9, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 143, + "TotalPointCount": 326, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 0.96, + 1, + 1.91, + 1, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.2, + 0, + 1.3, + -8, + 1.4, + -8, + 1, + 1.456, + -8, + 1.511, + -5.237, + 1.567, + 0, + 1, + 1.667, + 9.427, + 1.767, + 14, + 1.867, + 14, + 1, + 1.989, + 14, + 2.111, + -16, + 2.233, + -16, + 1, + 2.389, + -16, + 2.544, + 0, + 2.7, + 0, + 1, + 2.756, + 0, + 2.811, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.667, + 1, + 1.333, + 1, + 2, + 1, + 1, + 2.044, + 1, + 2.089, + 0, + 2.133, + 0, + 1, + 2.2, + 0, + 2.267, + 0, + 2.333, + 0, + 1, + 2.389, + 0, + 2.444, + 1, + 2.5, + 1, + 1, + 2.622, + 1, + 2.744, + 1, + 2.867, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.667, + 1, + 1.333, + 1, + 2, + 1, + 1, + 2.044, + 1, + 2.089, + 0, + 2.133, + 0, + 1, + 2.2, + 0, + 2.267, + 0, + 2.333, + 0, + 1, + 2.389, + 0, + 2.444, + 1, + 2.5, + 1, + 1, + 2.622, + 1, + 2.744, + 1, + 2.867, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.956, + 1, + 1.911, + 1, + 2.867, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.489, + 0, + 0.978, + 0, + 1.467, + 0, + 1, + 1.622, + 0, + 1.778, + 2, + 1.933, + 2, + 1, + 2.056, + 2, + 2.178, + 0, + 2.3, + 0, + 1, + 2.489, + 0, + 2.678, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.956, + 1, + 1.911, + 1, + 2.867, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.956, + 1, + 1.911, + 1, + 2.867, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.956, + 5, + 1.911, + 5, + 2.867, + 5, + 0, + 2.9, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.19, + 1, + 0.956, + 0.19, + 1.911, + 0.19, + 2.867, + 0.19, + 0, + 2.9, + 0.19 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.17, + 1, + 0.956, + -0.17, + 1.911, + -0.17, + 2.867, + -0.17, + 0, + 2.9, + -0.17 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 2.87, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 2.87, + 0, + 0, + 2.9, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 0, + 2.9, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2.87, + 0, + 0, + 2.9, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m02.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m02.motion3.json new file mode 100644 index 0000000..d0dd0f2 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m02.motion3.json @@ -0,0 +1,1214 @@ +{ + "Version": 3, + "Meta": { + "Duration": 2.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 146, + "TotalPointCount": 337, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 0.67, + 1, + 1.33, + 1, + 2, + 1, + 1, + 2.01, + 1, + 2.02, + 1, + 2.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + 0, + 0.233, + 0, + 1, + 0.411, + 0, + 0.589, + 0, + 0.767, + 0, + 1, + 1.178, + 0, + 1.589, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + 0, + 0.233, + 0, + 1, + 0.411, + 0, + 0.589, + 14, + 0.767, + 14, + 1, + 0.889, + 14, + 1.011, + -11, + 1.133, + -11, + 1, + 1.3, + -11, + 1.467, + 0, + 1.633, + 0, + 1, + 1.756, + 0, + 1.878, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.511, + 1, + 1.022, + 1, + 1.533, + 1, + 1, + 1.689, + 1, + 1.844, + 1, + 2, + 1, + 0, + 2.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.511, + 1, + 1.022, + 1, + 1.533, + 1, + 1, + 1.689, + 1, + 1.844, + 1, + 2, + 1, + 0, + 2.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.511, + 0, + 1.022, + 0, + 1.533, + 0, + 1, + 1.689, + 0, + 1.844, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.511, + 0, + 1.022, + 0, + 1.533, + 0, + 1, + 1.689, + 0, + 1.844, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.511, + 0, + 1.022, + 0, + 1.533, + 0, + 1, + 1.689, + 0, + 1.844, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.667, + 1, + 1.333, + 1, + 2, + 1, + 0, + 2.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + 0, + 0.267, + 0, + 1, + 0.456, + 0, + 0.644, + 5, + 0.833, + 5, + 1, + 0.956, + 5, + 1.078, + 0, + 1.2, + 0, + 1, + 1.467, + 0, + 1.733, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 6, + 1, + 0.667, + 6, + 1.333, + 6, + 2, + 6, + 0, + 2.033, + 6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + -1, + 1, + 0.156, + -1, + 0.311, + -1, + 0.467, + -1, + 1, + 0.611, + -1, + 0.756, + -0.89, + 0.9, + -0.89, + 1, + 1.022, + -0.89, + 1.144, + -1, + 1.267, + -1, + 1, + 1.511, + -1, + 1.756, + -1, + 2, + -1, + 0, + 2.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + -1, + 1, + 0.156, + -1, + 0.311, + -1, + 0.467, + -1, + 1, + 0.611, + -1, + 0.756, + -0.89, + 0.9, + -0.89, + 1, + 1.022, + -0.89, + 1.144, + -1, + 1.267, + -1, + 1, + 1.511, + -1, + 1.756, + -1, + 2, + -1, + 0, + 2.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 2, + 0, + 2, + 2.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 2, + 0, + 2, + 2.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 2, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2, + 0, + 2, + 2.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m03.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m03.motion3.json new file mode 100644 index 0000000..5c5775a --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m03.motion3.json @@ -0,0 +1,1735 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.63, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 221, + "TotalPointCount": 560, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.53, + 1, + 3.07, + 1, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.344, + 0, + 0.689, + 0, + 1.033, + 0, + 1, + 1.089, + 0, + 1.144, + 0, + 1.2, + 0, + 1, + 1.622, + 0, + 2.044, + 0, + 2.467, + 0, + 1, + 2.578, + 0, + 2.689, + 0, + 2.8, + 0, + 1, + 2.911, + 0, + 3.022, + 0, + 3.133, + 0, + 1, + 3.233, + 0, + 3.333, + 0, + 3.433, + 0, + 1, + 3.544, + 0, + 3.656, + 0, + 3.767, + 0, + 1, + 3.856, + 0, + 3.944, + 0, + 4.033, + 0, + 1, + 4.222, + 0, + 4.411, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.344, + 0, + 0.689, + 0, + 1.033, + 0, + 1, + 1.089, + 0, + 1.144, + 0, + 1.2, + 0, + 1, + 1.622, + 0, + 2.044, + 0, + 2.467, + 0, + 1, + 2.578, + 0, + 2.689, + 13, + 2.8, + 13, + 1, + 2.911, + 13, + 3.022, + -13, + 3.133, + -13, + 1, + 3.233, + -13, + 3.333, + 0, + 3.433, + 0, + 1, + 3.544, + 0, + 3.656, + -13, + 3.767, + -13, + 1, + 3.856, + -13, + 3.944, + 0, + 4.033, + 0, + 1, + 4.222, + 0, + 4.411, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 0.8, + 1, + 0.133, + 0.8, + 0.267, + 0.8, + 0.4, + 0.8, + 1, + 0.578, + 0.8, + 0.756, + 0.9, + 0.933, + 0.9, + 1, + 1.067, + 0.9, + 1.2, + 0.8, + 1.333, + 0.8, + 1, + 1.422, + 0.8, + 1.511, + 0.8, + 1.6, + 0.8, + 1, + 1.678, + 0.8, + 1.756, + 1, + 1.833, + 1, + 1, + 1.889, + 1, + 1.944, + 0, + 2, + 0, + 1, + 2.056, + 0, + 2.111, + 0, + 2.167, + 0, + 1, + 2.256, + 0, + 2.344, + 1, + 2.433, + 1, + 1, + 2.589, + 1, + 2.744, + 1, + 2.9, + 1, + 1, + 2.956, + 1, + 3.011, + 0, + 3.067, + 0, + 1, + 3.4, + 0, + 3.733, + 0, + 4.067, + 0, + 1, + 4.2, + 0, + 4.333, + 0.8, + 4.467, + 0.8, + 1, + 4.511, + 0.8, + 4.556, + 0.8, + 4.6, + 0.8, + 0, + 4.633, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 0.8, + 1, + 0.133, + 0.8, + 0.267, + 0.8, + 0.4, + 0.8, + 1, + 0.567, + 0.8, + 0.733, + 0.9, + 0.9, + 0.9, + 1, + 1.044, + 0.9, + 1.189, + 0.8, + 1.333, + 0.8, + 1, + 1.422, + 0.8, + 1.511, + 0.8, + 1.6, + 0.8, + 1, + 1.678, + 0.8, + 1.756, + 1, + 1.833, + 1, + 1, + 1.889, + 1, + 1.944, + 0, + 2, + 0, + 1, + 2.056, + 0, + 2.111, + 0, + 2.167, + 0, + 1, + 2.256, + 0, + 2.344, + 1, + 2.433, + 1, + 1, + 2.589, + 1, + 2.744, + 1, + 2.9, + 1, + 1, + 2.956, + 1, + 3.011, + 0, + 3.067, + 0, + 1, + 3.4, + 0, + 3.733, + 0, + 4.067, + 0, + 1, + 4.2, + 0, + 4.333, + 0.8, + 4.467, + 0.8, + 1, + 4.511, + 0.8, + 4.556, + 0.8, + 4.6, + 0.8, + 0, + 4.633, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.467, + 0, + 0.933, + 0, + 1.4, + 0, + 1, + 1.522, + 0, + 1.644, + -0.1, + 1.767, + -0.1, + 1, + 1.889, + -0.1, + 2.011, + 0, + 2.133, + 0, + 1, + 2.956, + 0, + 3.778, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.467, + 0, + 0.933, + 0, + 1.4, + 0, + 1, + 1.522, + 0, + 1.644, + -0.38, + 1.767, + -0.38, + 1, + 1.889, + -0.38, + 2.011, + 0, + 2.133, + 0, + 1, + 2.956, + 0, + 3.778, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 2.133, + 0, + 3.367, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 2.133, + 0, + 3.367, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 2.133, + 0, + 3.367, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 2.133, + 0, + 3.367, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 1.044, + 0, + 1.189, + 0.01, + 1.333, + 0.01, + 1, + 2.211, + 0.01, + 3.089, + 0.01, + 3.967, + 0.01, + 1, + 4.178, + 0.01, + 4.389, + 0.01, + 4.6, + 0.01, + 0, + 4.633, + 0.01 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 1.044, + 0, + 1.189, + 0, + 1.333, + 0, + 1, + 2.211, + 0, + 3.089, + 0, + 3.967, + 0, + 1, + 4.178, + 0, + 4.389, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + -0.35, + 1, + 0.3, + -0.35, + 0.6, + -0.35, + 0.9, + -0.35, + 1, + 1.044, + -0.35, + 1.189, + -0.66, + 1.333, + -0.66, + 1, + 2.211, + -0.66, + 3.089, + -0.66, + 3.967, + -0.66, + 1, + 4.178, + -0.66, + 4.389, + -0.39, + 4.6, + -0.39, + 0, + 4.633, + -0.39 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + -0.35, + 1, + 0.3, + -0.35, + 0.6, + -0.35, + 0.9, + -0.35, + 1, + 1.044, + -0.35, + 1.189, + -0.65, + 1.333, + -0.65, + 1, + 2.211, + -0.65, + 3.089, + -0.65, + 3.967, + -0.65, + 1, + 4.178, + -0.65, + 4.389, + -0.39, + 4.6, + -0.39, + 0, + 4.633, + -0.39 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 1.044, + 0, + 1.189, + -1, + 1.333, + -1, + 1, + 1.756, + -1, + 2.178, + -1, + 2.6, + -1, + 1, + 3.267, + -1, + 3.933, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.356, + 0, + 0.711, + 0, + 1.067, + 0, + 1, + 1.3, + 0, + 1.533, + 2, + 1.767, + 2, + 1, + 1.933, + 2, + 2.1, + 0, + 2.267, + 0, + 1, + 2.578, + 0, + 2.889, + 0, + 3.2, + 0, + 1, + 3.667, + 0, + 4.133, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.233, + 0, + 1.467, + 3, + 1.7, + 3, + 1, + 1.867, + 3, + 2.033, + 0, + 2.2, + 0, + 1, + 2.311, + 0, + 2.422, + 0, + 2.533, + 0, + 1, + 2.644, + 0, + 2.756, + 4, + 2.867, + 4, + 1, + 2.944, + 4, + 3.022, + -1, + 3.1, + -1, + 1, + 3.244, + -1, + 3.389, + 0, + 3.533, + 0, + 1, + 3.889, + 0, + 4.244, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + -5, + 0.9, + -5, + 1, + 1.133, + -5, + 1.367, + 0, + 1.6, + 0, + 1, + 2.389, + 0, + 3.178, + 0, + 3.967, + 0, + 1, + 4.178, + 0, + 4.389, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.749, + 0.467, + 0.76, + 1, + 1.778, + 0.856, + 3.089, + 0.89, + 4.4, + 0.89, + 1, + 4.467, + 0.89, + 4.533, + 0.5, + 4.6, + 0.5, + 0, + 4.633, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.743, + 0.467, + 0.76, + 1, + 1.778, + 0.9, + 3.089, + 0.95, + 4.4, + 0.95, + 1, + 4.467, + 0.95, + 4.533, + 0.5, + 4.6, + 0.5, + 0, + 4.633, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0.3, + 1, + 0.311, + 0.3, + 0.622, + 0.3, + 0.933, + 0.3, + 1, + 1.178, + 0.3, + 1.422, + 0.5, + 1.667, + 0.5, + 1, + 1.844, + 0.5, + 2.022, + 0.3, + 2.2, + 0.3, + 1, + 3, + 0.3, + 3.8, + 0.3, + 4.6, + 0.3, + 0, + 4.633, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0.3, + 1, + 0.289, + 0.3, + 0.578, + 0.3, + 0.867, + 0.3, + 1, + 1.111, + 0.3, + 1.356, + 0.5, + 1.6, + 0.5, + 1, + 1.778, + 0.5, + 1.956, + 0.3, + 2.133, + 0.3, + 1, + 2.956, + 0.3, + 3.778, + 0.3, + 4.6, + 0.3, + 0, + 4.633, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.66, + 1, + 0.356, + 0.66, + 0.711, + 0.662, + 1.067, + 0.64, + 1, + 1.322, + 0.624, + 1.578, + 0.12, + 1.833, + 0.12, + 1, + 1.978, + 0.12, + 2.122, + 0.66, + 2.267, + 0.66, + 1, + 3.044, + 0.66, + 3.822, + 0.66, + 4.6, + 0.66, + 0, + 4.633, + 0.66 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -1, + 1, + 0.322, + -1, + 0.644, + -1, + 0.967, + -1, + 1, + 1.233, + -1, + 1.5, + -0.68, + 1.767, + -0.68, + 1, + 1.933, + -0.68, + 2.1, + -1, + 2.267, + -1, + 1, + 3.044, + -1, + 3.822, + -1, + 4.6, + -1, + 0, + 4.633, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.533, + 0, + 3.067, + 0, + 4.6, + 0, + 0, + 4.633, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 4.6, + 0, + 0, + 4.63, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 4.6, + 0, + 0, + 4.63, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4.6, + 1, + 0, + 4.63, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4.6, + 0, + 0, + 4.63, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m04.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m04.motion3.json new file mode 100644 index 0000000..b555601 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m04.motion3.json @@ -0,0 +1,2484 @@ +{ + "Version": 3, + "Meta": { + "Duration": 5.3, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 328, + "TotalPointCount": 881, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.76, + 1, + 3.51, + 1, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.611, + 0, + 0.922, + 0, + 1.233, + 0, + 1, + 1.289, + 0, + 1.344, + 0, + 1.4, + 0, + 1, + 1.8, + 0, + 2.2, + 0, + 2.6, + 0, + 1, + 2.711, + 0, + 2.822, + 0, + 2.933, + 0, + 1, + 3.044, + 0, + 3.156, + 0, + 3.267, + 0, + 1, + 3.367, + 0, + 3.467, + 0, + 3.567, + 0, + 1, + 3.633, + 0, + 3.7, + 0, + 3.767, + 0, + 1, + 3.889, + 0, + 4.011, + 0, + 4.133, + 0, + 1, + 4.322, + 0, + 4.511, + 0, + 4.7, + 0, + 1, + 4.889, + 0, + 5.078, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.611, + 0, + 0.922, + 0, + 1.233, + 0, + 1, + 1.289, + 0, + 1.344, + 0, + 1.4, + 0, + 1, + 1.822, + 0, + 2.244, + 0, + 2.667, + 0, + 1, + 2.778, + 0, + 2.889, + 13, + 3, + 13, + 1, + 3.111, + 13, + 3.222, + -9.823, + 3.333, + -9.823, + 1, + 3.411, + -9.823, + 3.489, + 8.938, + 3.567, + 8.938, + 1, + 3.678, + 8.938, + 3.789, + -5.187, + 3.9, + -5.187, + 1, + 4.044, + -5.187, + 4.189, + 3, + 4.333, + 3, + 1, + 4.556, + 3, + 4.778, + 0, + 5, + 0, + 1, + 5.089, + 0, + 5.178, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.956, + 0, + 3.611, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.789, + 0, + 3.278, + 0, + 4.767, + 0, + 1, + 4.933, + 0, + 5.1, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.1, + 1, + 0.2, + 1, + 0.3, + 1, + 1, + 0.367, + 1, + 0.433, + 1, + 0.5, + 1, + 1, + 0.544, + 1, + 0.589, + 0, + 0.633, + 0, + 1, + 0.667, + 0, + 0.7, + 0, + 0.733, + 0, + 1, + 0.789, + 0, + 0.844, + 1.1, + 0.9, + 1.1, + 1, + 0.967, + 1.1, + 1.033, + 1, + 1.1, + 1, + 1, + 1.333, + 1, + 1.567, + 1, + 1.8, + 1, + 1, + 1.878, + 1, + 1.956, + 1.2, + 2.033, + 1.2, + 1, + 2.089, + 1.2, + 2.144, + 0, + 2.2, + 0, + 1, + 2.256, + 0, + 2.311, + 0, + 2.367, + 0, + 1, + 2.456, + 0, + 2.544, + 1, + 2.633, + 1, + 1, + 2.789, + 1, + 2.944, + 1, + 3.1, + 1, + 1, + 3.156, + 1, + 3.211, + 0, + 3.267, + 0, + 1, + 3.589, + 0, + 3.911, + 0, + 4.233, + 0, + 1, + 4.344, + 0, + 4.456, + 1, + 4.567, + 1, + 1, + 4.633, + 1, + 4.7, + 1, + 4.767, + 1, + 1, + 4.933, + 1, + 5.1, + 1, + 5.267, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.789, + 0, + 3.278, + 0, + 4.767, + 0, + 1, + 4.933, + 0, + 5.1, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.1, + 1, + 0.2, + 1, + 0.3, + 1, + 1, + 0.367, + 1, + 0.433, + 1, + 0.5, + 1, + 1, + 0.544, + 1, + 0.589, + 0, + 0.633, + 0, + 1, + 0.667, + 0, + 0.7, + 0, + 0.733, + 0, + 1, + 0.789, + 0, + 0.844, + 1.1, + 0.9, + 1.1, + 1, + 0.967, + 1.1, + 1.033, + 1, + 1.1, + 1, + 1, + 1.333, + 1, + 1.567, + 1, + 1.8, + 1, + 1, + 1.878, + 1, + 1.956, + 1.2, + 2.033, + 1.2, + 1, + 2.089, + 1.2, + 2.144, + 0, + 2.2, + 0, + 1, + 2.256, + 0, + 2.311, + 0, + 2.367, + 0, + 1, + 2.456, + 0, + 2.544, + 1, + 2.633, + 1, + 1, + 2.789, + 1, + 2.944, + 1, + 3.1, + 1, + 1, + 3.156, + 1, + 3.211, + 0, + 3.267, + 0, + 1, + 3.589, + 0, + 3.911, + 0, + 4.233, + 0, + 1, + 4.344, + 0, + 4.456, + 1, + 4.567, + 1, + 1, + 4.633, + 1, + 4.7, + 1, + 4.767, + 1, + 1, + 4.933, + 1, + 5.1, + 1, + 5.267, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.789, + 0, + 3.278, + 0, + 4.767, + 0, + 1, + 4.933, + 0, + 5.1, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.5, + 0, + 0.7, + 0, + 0.9, + 0, + 1, + 1.133, + 0, + 1.367, + 0, + 1.6, + 0, + 1, + 1.744, + 0, + 1.889, + -0.1, + 2.033, + -0.1, + 1, + 2.144, + -0.1, + 2.256, + 0, + 2.367, + 0, + 1, + 2.456, + 0, + 2.544, + 0, + 2.633, + 0, + 1, + 3.344, + 0, + 4.056, + 0, + 4.767, + 0, + 1, + 4.933, + 0, + 5.1, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.5, + 0, + 0.7, + 0, + 0.9, + 0, + 1, + 1.133, + 0, + 1.367, + 0, + 1.6, + 0, + 1, + 1.667, + 0, + 1.733, + -0.085, + 1.8, + -0.2, + 1, + 1.878, + -0.334, + 1.956, + -0.38, + 2.033, + -0.38, + 1, + 2.089, + -0.38, + 2.144, + -0.384, + 2.2, + -0.3, + 1, + 2.256, + -0.216, + 2.311, + 0, + 2.367, + 0, + 1, + 2.456, + 0, + 2.544, + 0, + 2.633, + 0, + 1, + 3.167, + 0, + 3.7, + -0.1, + 4.233, + -0.1, + 1, + 4.344, + -0.1, + 4.456, + 0, + 4.567, + 0, + 1, + 4.633, + 0, + 4.7, + 0, + 4.767, + 0, + 1, + 4.933, + 0, + 5.1, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.367, + 0, + 0.433, + 0, + 0.5, + 0, + 1, + 0.556, + 0, + 0.611, + -0.1, + 0.667, + -0.1, + 1, + 0.689, + -0.1, + 0.711, + -0.1, + 0.733, + -0.1, + 1, + 0.789, + -0.1, + 0.844, + 0.1, + 0.9, + 0.1, + 1, + 0.967, + 0.1, + 1.033, + 0, + 1.1, + 0, + 1, + 1.411, + 0, + 1.722, + 0.5, + 2.033, + 0.5, + 1, + 2.089, + 0.5, + 2.144, + -0.3, + 2.2, + -0.3, + 1, + 2.256, + -0.3, + 2.311, + -0.3, + 2.367, + -0.3, + 1, + 2.456, + -0.3, + 2.544, + -0.215, + 2.633, + -0.2, + 1, + 3.511, + -0.056, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.367, + 0, + 0.433, + 0, + 0.5, + 0, + 1, + 0.556, + 0, + 0.611, + -0.1, + 0.667, + -0.1, + 1, + 0.689, + -0.1, + 0.711, + -0.1, + 0.733, + -0.1, + 1, + 0.789, + -0.1, + 0.844, + 0.1, + 0.9, + 0.1, + 1, + 0.967, + 0.1, + 1.033, + 0, + 1.1, + 0, + 1, + 1.411, + 0, + 1.722, + 0.5, + 2.033, + 0.5, + 1, + 2.089, + 0.5, + 2.144, + -0.3, + 2.2, + -0.3, + 1, + 2.256, + -0.3, + 2.311, + -0.3, + 2.367, + -0.3, + 1, + 2.456, + -0.3, + 2.544, + -0.215, + 2.633, + -0.2, + 1, + 3.511, + -0.056, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + 0, + 1.1, + 0, + 1, + 1.411, + 0, + 1.722, + 0.2, + 2.033, + 0.2, + 1, + 2.233, + 0.2, + 2.433, + -0.3, + 2.633, + -0.3, + 1, + 3.511, + -0.3, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + 0, + 1.1, + 0, + 1, + 1.411, + 0, + 1.722, + 0.2, + 2.033, + 0.2, + 1, + 2.233, + 0.2, + 2.433, + -0.3, + 2.633, + -0.3, + 1, + 3.511, + -0.3, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + -0.4, + 1.1, + -0.4, + 1, + 1.411, + -0.4, + 1.722, + 0.1, + 2.033, + 0.1, + 1, + 2.233, + 0.1, + 2.433, + -0.4, + 2.633, + -0.4, + 1, + 3.511, + -0.4, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + -0.4, + 1.1, + -0.4, + 1, + 1.411, + -0.4, + 1.722, + 0.1, + 2.033, + 0.1, + 1, + 2.233, + 0.1, + 2.433, + -0.4, + 2.633, + -0.4, + 1, + 3.511, + -0.4, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + -0.35, + 1.1, + -0.35, + 1, + 1.411, + -0.35, + 1.722, + 0, + 2.033, + 0, + 1, + 2.233, + 0, + 2.433, + -0.4, + 2.633, + -0.4, + 1, + 3.511, + -0.4, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + -0.35, + 1.1, + -0.35, + 1, + 1.411, + -0.35, + 1.722, + 0, + 2.033, + 0, + 1, + 2.233, + 0, + 2.433, + -0.4, + 2.633, + -0.4, + 1, + 3.511, + -0.4, + 4.389, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + 0, + 0.467, + 0, + 1, + 0.522, + 0, + 0.578, + -1, + 0.633, + -1, + 1, + 0.933, + -1, + 1.233, + -1, + 1.533, + -1, + 1, + 2.422, + -1, + 3.311, + -1, + 4.2, + -1, + 1, + 4.411, + -1, + 4.622, + -1, + 4.833, + -1, + 1, + 4.978, + -1, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + 0, + 0.467, + 0, + 1, + 0.767, + 0, + 1.067, + 0, + 1.367, + 0, + 1, + 1.5, + 0, + 1.633, + 0.6, + 1.767, + 0.6, + 1, + 1.844, + 0.6, + 1.922, + 0.608, + 2, + 0.5, + 1, + 2.067, + 0.408, + 2.133, + 0, + 2.2, + 0, + 1, + 2.344, + 0, + 2.489, + 0, + 2.633, + 0, + 1, + 3.367, + 0, + 4.1, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.622, + 0, + 0.944, + 0, + 1.267, + 0, + 1, + 1.5, + 0, + 1.733, + 2, + 1.967, + 2, + 1, + 2.133, + 2, + 2.3, + 0, + 2.467, + 0, + 1, + 2.778, + 0, + 3.089, + 0, + 3.4, + 0, + 1, + 3.878, + 0, + 4.356, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.6, + 0, + 0.9, + 0, + 1.2, + 0, + 1, + 1.433, + 0, + 1.667, + 3, + 1.9, + 3, + 1, + 2.067, + 3, + 2.233, + 0, + 2.4, + 0, + 1, + 2.511, + 0, + 2.622, + 0, + 2.733, + 0, + 1, + 2.844, + 0, + 2.956, + 4, + 3.067, + 4, + 1, + 3.156, + 4, + 3.244, + -1, + 3.333, + -1, + 1, + 3.422, + -1, + 3.511, + 0.817, + 3.6, + 0.817, + 1, + 3.7, + 0.817, + 3.8, + 0, + 3.9, + 0, + 1, + 4.211, + 0, + 4.522, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.567, + 0, + 0.833, + -5, + 1.1, + -5, + 1, + 1.333, + -5, + 1.567, + 0, + 1.8, + 0, + 1, + 2.011, + 0, + 2.222, + 0, + 2.433, + 0, + 1, + 3.233, + 0, + 4.033, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.956, + 0, + 3.611, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.1, + 0.5, + 0.2, + 0.5, + 0.3, + 0.5, + 1, + 0.422, + 0.5, + 0.544, + 0.752, + 0.667, + 0.76, + 1, + 2.056, + 0.854, + 3.444, + 0.89, + 4.833, + 0.89, + 1, + 4.978, + 0.89, + 5.122, + 0.5, + 5.267, + 0.5, + 0, + 5.3, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.1, + 0.5, + 0.2, + 0.5, + 0.3, + 0.5, + 1, + 0.422, + 0.5, + 0.544, + 0.748, + 0.667, + 0.76, + 1, + 2.056, + 0.897, + 3.444, + 0.95, + 4.833, + 0.95, + 1, + 4.978, + 0.95, + 5.122, + 0.5, + 5.267, + 0.5, + 0, + 5.3, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0.2, + 1, + 0.1, + 0.2, + 0.2, + 0.2, + 0.3, + 0.2, + 1, + 0.578, + 0.2, + 0.856, + 0.21, + 1.133, + 0.3, + 1, + 1.378, + 0.38, + 1.622, + 0.5, + 1.867, + 0.5, + 1, + 2.122, + 0.5, + 2.378, + 0.2, + 2.633, + 0.2, + 1, + 3.511, + 0.2, + 4.389, + 0.2, + 5.267, + 0.2, + 0, + 5.3, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0.2, + 1, + 0.1, + 0.2, + 0.2, + 0.2, + 0.3, + 0.2, + 1, + 0.556, + 0.2, + 0.811, + 0.211, + 1.067, + 0.3, + 1, + 1.311, + 0.386, + 1.556, + 0.5, + 1.8, + 0.5, + 1, + 2.056, + 0.5, + 2.311, + 0.2, + 2.567, + 0.2, + 1, + 3.467, + 0.2, + 4.367, + 0.2, + 5.267, + 0.2, + 0, + 5.3, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.66, + 1, + 0.1, + 0.66, + 0.2, + 0.66, + 0.3, + 0.66, + 1, + 0.622, + 0.66, + 0.944, + 0.663, + 1.267, + 0.64, + 1, + 1.522, + 0.621, + 1.778, + 0.12, + 2.033, + 0.12, + 1, + 2.178, + 0.12, + 2.322, + 0.66, + 2.467, + 0.66, + 1, + 3.256, + 0.66, + 4.044, + 0.66, + 4.833, + 0.66, + 1, + 4.978, + 0.66, + 5.122, + 0.66, + 5.267, + 0.66, + 0, + 5.3, + 0.66 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.611, + 0, + 3.222, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -1, + 1, + 0.1, + -1, + 0.2, + -1, + 0.3, + -1, + 1, + 0.589, + -1, + 0.878, + -1, + 1.167, + -1, + 1, + 1.433, + -1, + 1.7, + -0.68, + 1.967, + -0.68, + 1, + 2.133, + -0.68, + 2.3, + -1, + 2.467, + -1, + 1, + 3.256, + -1, + 4.044, + -1, + 4.833, + -1, + 1, + 4.978, + -1, + 5.122, + -1, + 5.267, + -1, + 0, + 5.3, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 1.811, + 0, + 3.322, + 0, + 4.833, + 0, + 1, + 4.978, + 0, + 5.122, + 0, + 5.267, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 5.27, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 5.27, + 0, + 0, + 5.3, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 5.27, + 1, + 0, + 5.3, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 5.27, + 0, + 0, + 5.3, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m05.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m05.motion3.json new file mode 100644 index 0000000..fffb9fc --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m05.motion3.json @@ -0,0 +1,1441 @@ +{ + "Version": 3, + "Meta": { + "Duration": 2.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 179, + "TotalPointCount": 434, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 0.67, + 1, + 1.33, + 1, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.122, + 0, + 0.244, + 0, + 0.367, + 0, + 1, + 0.489, + 0, + 0.611, + 0, + 0.733, + 0, + 1, + 0.833, + 0, + 0.933, + 0, + 1.033, + 0, + 1, + 1.222, + 0, + 1.411, + 0, + 1.6, + 0, + 1, + 1.733, + 0, + 1.867, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -5.165, + 0.3, + -9, + 1, + 0.333, + -10.278, + 0.367, + -10, + 0.4, + -10, + 1, + 0.489, + -10, + 0.578, + 13, + 0.667, + 13, + 1, + 0.767, + 13, + 0.867, + -9, + 0.967, + -9, + 1, + 1.156, + -9, + 1.344, + 0, + 1.533, + 0, + 1, + 1.689, + 0, + 1.844, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 2, + 1, + 0.233, + 2, + 0.467, + 2, + 0.7, + 2, + 1, + 0.756, + 2, + 0.811, + 0, + 0.867, + 0, + 1, + 0.967, + 0, + 1.067, + 0, + 1.167, + 0, + 1, + 1.244, + 0, + 1.322, + 2, + 1.4, + 2, + 1, + 1.6, + 2, + 1.8, + 2, + 2, + 2, + 0, + 2.033, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 2, + 1, + 0.233, + 2, + 0.467, + 2, + 0.7, + 2, + 1, + 0.756, + 2, + 0.811, + 0, + 0.867, + 0, + 1, + 0.967, + 0, + 1.067, + 0, + 1.167, + 0, + 1, + 1.244, + 0, + 1.322, + 2, + 1.4, + 2, + 1, + 1.6, + 2, + 1.8, + 2, + 2, + 2, + 0, + 2.033, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.422, + 0, + 0.511, + 0, + 0.6, + 0, + 1, + 0.633, + 0, + 0.667, + 0, + 0.7, + 0, + 1, + 1.133, + 0, + 1.567, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0.3, + 1, + 0.111, + 0.3, + 0.222, + 0.3, + 0.333, + 0.3, + 1, + 0.422, + 0.3, + 0.511, + 0.3, + 0.6, + 0.3, + 1, + 0.633, + 0.3, + 0.667, + 0.3, + 0.7, + 0.3, + 1, + 0.756, + 0.3, + 0.811, + -0.2, + 0.867, + -0.2, + 1, + 0.967, + -0.2, + 1.067, + -0.2, + 1.167, + -0.2, + 1, + 1.244, + -0.2, + 1.322, + 0.3, + 1.4, + 0.3, + 1, + 1.6, + 0.3, + 1.8, + 0.3, + 2, + 0.3, + 0, + 2.033, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 1, + 1, + 0.233, + 1, + 0.467, + 1, + 0.7, + 1, + 1, + 0.756, + 1, + 0.811, + 0.7, + 0.867, + 0.7, + 1, + 0.967, + 0.7, + 1.067, + 0.7, + 1.167, + 0.7, + 1, + 1.244, + 0.7, + 1.322, + 1, + 1.4, + 1, + 1, + 1.6, + 1, + 1.8, + 1, + 2, + 1, + 0, + 2.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 1, + 1, + 0.233, + 1, + 0.467, + 1, + 0.7, + 1, + 1, + 0.756, + 1, + 0.811, + 0.7, + 0.867, + 0.7, + 1, + 0.967, + 0.7, + 1.067, + 0.7, + 1.167, + 0.7, + 1, + 1.244, + 0.7, + 1.322, + 1, + 1.4, + 1, + 1, + 1.6, + 1, + 1.8, + 1, + 2, + 1, + 0, + 2.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + -0.84, + 1, + 0.667, + -0.84, + 1.333, + -0.84, + 2, + -0.84, + 0, + 2.033, + -0.84 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.133, + 0, + 0.267, + -2, + 0.4, + -2, + 1, + 0.533, + -2, + 0.667, + 2, + 0.8, + 2, + 1, + 0.911, + 2, + 1.022, + 0, + 1.133, + 0, + 1, + 1.422, + 0, + 1.711, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + -0.16, + 1, + 0.189, + -0.16, + 0.378, + -0.16, + 0.567, + -0.16, + 1, + 0.678, + -0.16, + 0.789, + -0.026, + 0.9, + -0.026, + 1, + 1, + -0.026, + 1.1, + -0.182, + 1.2, + -0.182, + 1, + 1.322, + -0.182, + 1.444, + -0.16, + 1.567, + -0.16, + 1, + 1.711, + -0.16, + 1.856, + -0.16, + 2, + -0.16, + 0, + 2.033, + -0.16 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + -0.15, + 1, + 0.189, + -0.15, + 0.378, + -0.15, + 0.567, + -0.15, + 1, + 0.678, + -0.15, + 0.789, + -0.025, + 0.9, + -0.025, + 1, + 1, + -0.025, + 1.1, + -0.181, + 1.2, + -0.181, + 1, + 1.322, + -0.181, + 1.444, + -0.15, + 1.567, + -0.15, + 1, + 1.711, + -0.15, + 1.856, + -0.15, + 2, + -0.15, + 0, + 2.033, + -0.15 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 0.644, + 0, + 0.722, + 0.614, + 0.8, + 0.614, + 1, + 0.889, + 0.614, + 0.978, + -0.1, + 1.067, + -0.1, + 1, + 1.178, + -0.1, + 1.289, + 0, + 1.4, + 0, + 1, + 1.6, + 0, + 1.8, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 0.644, + 0, + 0.722, + -0.6, + 0.8, + -0.6, + 1, + 0.889, + -0.6, + 0.978, + 0.1, + 1.067, + 0.1, + 1, + 1.178, + 0.1, + 1.289, + 0, + 1.4, + 0, + 1, + 1.6, + 0, + 1.8, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.667, + 0, + 1.333, + 0, + 2, + 0, + 0, + 2.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 2, + 0, + 0, + 2.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 2, + 0, + 0, + 2.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2, + 1, + 0, + 2.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2, + 0, + 0, + 2.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m06.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m06.motion3.json new file mode 100644 index 0000000..b03be90 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m06.motion3.json @@ -0,0 +1,1539 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.53, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 193, + "TotalPointCount": 476, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.5, + 1, + 3, + 1, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.467, + 0, + 0.933, + -14, + 1.4, + -14, + 1, + 1.567, + -14, + 1.733, + -14, + 1.9, + -14, + 1, + 2.367, + -14, + 2.833, + 0, + 3.3, + 0, + 1, + 3.7, + 0, + 4.1, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.9, + 0, + 1.067, + -13, + 1.233, + -13, + 1, + 1.422, + -13, + 1.611, + 5, + 1.8, + 5, + 1, + 2.267, + 5, + 2.733, + 0, + 3.2, + 0, + 1, + 3.633, + 0, + 4.067, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + -18, + 1.1, + -18, + 1, + 1.4, + -18, + 1.7, + -18, + 2, + -18, + 1, + 2.3, + -18, + 2.6, + 18, + 2.9, + 18, + 1, + 3.133, + 18, + 3.367, + -30, + 3.6, + -30, + 1, + 3.9, + -30, + 4.2, + -21, + 4.5, + -21, + 0, + 4.533, + -21 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.311, + 0, + 2.622, + 0, + 3.933, + 0, + 1, + 4.122, + 0, + 4.311, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.344, + 1, + 0.689, + 1, + 1.033, + 1, + 1, + 1.078, + 1, + 1.122, + 0, + 1.167, + 0, + 1, + 1.222, + 0, + 1.278, + 0, + 1.333, + 0, + 1, + 1.411, + 0, + 1.489, + 1, + 1.567, + 1, + 1, + 2.544, + 1, + 3.522, + 1, + 4.5, + 1, + 0, + 4.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.344, + 1, + 0.689, + 1, + 1.033, + 1, + 1, + 1.078, + 1, + 1.122, + 0, + 1.167, + 0, + 1, + 1.222, + 0, + 1.278, + 0, + 1.333, + 0, + 1, + 1.411, + 0, + 1.489, + 1, + 1.567, + 1, + 1, + 2.544, + 1, + 3.522, + 1, + 4.5, + 1, + 0, + 4.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0.29, + 0.9, + 0.29, + 1, + 0.989, + 0.29, + 1.078, + 0.29, + 1.167, + 0.29, + 1, + 1.2, + 0.29, + 1.233, + -0.39, + 1.267, + -0.39, + 1, + 1.378, + -0.39, + 1.489, + -0.39, + 1.6, + -0.39, + 1, + 2, + -0.39, + 2.4, + 0, + 2.8, + 0, + 1, + 3.367, + 0, + 3.933, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0.5, + 0.9, + 0.5, + 1, + 0.989, + 0.5, + 1.078, + 0.5, + 1.167, + 0.5, + 1, + 1.2, + 0.5, + 1.233, + 0.33, + 1.267, + 0.33, + 1, + 1.378, + 0.33, + 1.489, + 0.33, + 1.6, + 0.33, + 1, + 2, + 0.33, + 2.4, + 0, + 2.8, + 0, + 1, + 3.367, + 0, + 3.933, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 1.5, + 1, + 3, + 1, + 4.5, + 1, + 0, + 4.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.533, + 0, + 1.067, + 7, + 1.6, + 7, + 1, + 2.056, + 7, + 2.511, + -7, + 2.967, + -7, + 1, + 3.478, + -7, + 3.989, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.578, + 0, + 1.156, + -7, + 1.733, + -7, + 1, + 2.1, + -7, + 2.467, + 7, + 2.833, + 7, + 1, + 3.389, + 7, + 3.944, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.746, + 0.467, + 0.76, + 1, + 1.556, + 0.858, + 2.644, + 0.89, + 3.733, + 0.89, + 1, + 3.8, + 0.89, + 3.867, + 0.637, + 3.933, + 0.5, + 1, + 4.122, + 0.111, + 4.311, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.74, + 0.467, + 0.76, + 1, + 1.556, + 0.903, + 2.644, + 0.95, + 3.733, + 0.95, + 1, + 3.8, + 0.95, + 3.867, + 0.64, + 3.933, + 0.5, + 1, + 4.122, + 0.104, + 4.311, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 3.5, + 1, + 0.133, + 3.5, + 0.267, + 3.2, + 0.4, + 3.2, + 1, + 0.733, + 3.2, + 1.067, + 4.098, + 1.4, + 4.8, + 1, + 1.522, + 5.057, + 1.644, + 5, + 1.767, + 5, + 1, + 2.278, + 5, + 2.789, + 4.1, + 3.3, + 4.1, + 1, + 3.433, + 4.1, + 3.567, + 4.3, + 3.7, + 4.3, + 1, + 3.967, + 4.3, + 4.233, + 4.3, + 4.5, + 4.3, + 0, + 4.533, + 4.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 2.5, + 1, + 0.133, + 2.5, + 0.267, + 2.3, + 0.4, + 2.3, + 1, + 0.567, + 2.3, + 0.733, + 2.48, + 0.9, + 2.9, + 1, + 1.156, + 3.545, + 1.411, + 3.9, + 1.667, + 3.9, + 1, + 1.933, + 3.9, + 2.2, + 3.807, + 2.467, + 3.5, + 1, + 2.767, + 3.154, + 3.067, + 2.9, + 3.367, + 2.9, + 1, + 3.489, + 2.9, + 3.611, + 3, + 3.733, + 3, + 1, + 3.989, + 3, + 4.244, + 3, + 4.5, + 3, + 0, + 4.533, + 3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 0.978, + 0, + 1.056, + 0.5, + 1.133, + 0.5, + 1, + 2.256, + 0.5, + 3.378, + 0.5, + 4.5, + 0.5, + 0, + 4.533, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0.8, + 0.5, + 0.8, + 1, + 0.956, + 0.8, + 1.411, + -1, + 1.867, + -1, + 1, + 2.111, + -1, + 2.356, + -1, + 2.6, + -1, + 1, + 2.8, + -1, + 3, + -0.52, + 3.2, + -0.52, + 1, + 3.411, + -0.52, + 3.622, + -1, + 3.833, + -1, + 1, + 4.056, + -1, + 4.278, + -1, + 4.5, + -1, + 0, + 4.533, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0.5, + 1, + 1.5, + 0.5, + 3, + 0.5, + 4.5, + 0.5, + 0, + 4.533, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + 0.41, + 0.267, + 0.41, + 1, + 0.344, + 0.41, + 0.422, + -0.174, + 0.5, + -0.33, + 1, + 0.656, + -0.643, + 0.811, + -0.68, + 0.967, + -0.68, + 1, + 1.222, + -0.68, + 1.478, + 0.36, + 1.733, + 0.36, + 1, + 1.933, + 0.36, + 2.133, + 0.36, + 2.333, + 0.36, + 1, + 2.422, + 0.36, + 2.511, + -0.26, + 2.6, + -0.26, + 1, + 2.767, + -0.26, + 2.933, + -0.26, + 3.1, + -0.26, + 1, + 3.233, + -0.26, + 3.367, + -0.46, + 3.5, + -0.46, + 1, + 3.633, + -0.46, + 3.767, + -0.31, + 3.9, + -0.31, + 1, + 4.1, + -0.31, + 4.3, + -0.31, + 4.5, + -0.31, + 0, + 4.533, + -0.31 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.5, + 0, + 3, + 0, + 4.5, + 0, + 0, + 4.533, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 4.5, + 0, + 0, + 4.53, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 4.5, + 0, + 0, + 4.53, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4.5, + 1, + 0, + 4.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4.5, + 0, + 0, + 4.53, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m07.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m07.motion3.json new file mode 100644 index 0000000..a7d6d86 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m07.motion3.json @@ -0,0 +1,1497 @@ +{ + "Version": 3, + "Meta": { + "Duration": 3.93, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 187, + "TotalPointCount": 458, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.3, + 1, + 2.6, + 1, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.467, + 0, + 0.933, + 9.534, + 1.4, + 14, + 1, + 1.567, + 15.595, + 1.733, + 15, + 1.9, + 15, + 1, + 2.289, + 15, + 2.678, + 0, + 3.067, + 0, + 1, + 3.344, + 0, + 3.622, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0.061, + 0.733, + -1, + 1, + 0.9, + -1.723, + 1.067, + -13, + 1.233, + -13, + 1, + 1.422, + -13, + 1.611, + 5, + 1.8, + 5, + 1, + 2.189, + 5, + 2.578, + 0, + 2.967, + 0, + 1, + 3.278, + 0, + 3.589, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + -18, + 1.1, + -18, + 1, + 1.4, + -18, + 1.7, + -18, + 2, + -18, + 1, + 2.3, + -18, + 2.6, + 18, + 2.9, + 18, + 1, + 3.233, + 18, + 3.567, + 18, + 3.9, + 18, + 0, + 3.933, + 18 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.344, + 1, + 0.689, + 1, + 1.033, + 1, + 1, + 1.078, + 1, + 1.122, + 0, + 1.167, + 0, + 1, + 1.222, + 0, + 1.278, + 0, + 1.333, + 0, + 1, + 1.411, + 0, + 1.489, + 1, + 1.567, + 1, + 1, + 2.344, + 1, + 3.122, + 1, + 3.9, + 1, + 0, + 3.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.344, + 1, + 0.689, + 1, + 1.033, + 1, + 1, + 1.078, + 1, + 1.122, + 0, + 1.167, + 0, + 1, + 1.222, + 0, + 1.278, + 0, + 1.333, + 0, + 1, + 1.411, + 0, + 1.489, + 1, + 1.567, + 1, + 1, + 2.344, + 1, + 3.122, + 1, + 3.9, + 1, + 0, + 3.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + -0.27, + 0.9, + -0.27, + 1, + 0.989, + -0.27, + 1.078, + -0.27, + 1.167, + -0.27, + 1, + 1.2, + -0.27, + 1.233, + 0.37, + 1.267, + 0.37, + 1, + 1.378, + 0.37, + 1.489, + 0.37, + 1.6, + 0.37, + 1, + 1.944, + 0.37, + 2.289, + 0, + 2.633, + 0, + 1, + 3.056, + 0, + 3.478, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0.58, + 0.9, + 0.58, + 1, + 0.989, + 0.58, + 1.078, + 0.58, + 1.167, + 0.58, + 1, + 1.2, + 0.58, + 1.233, + 0.29, + 1.267, + 0.29, + 1, + 1.378, + 0.29, + 1.489, + 0.29, + 1.6, + 0.29, + 1, + 1.944, + 0.29, + 2.289, + 0, + 2.633, + 0, + 1, + 3.056, + 0, + 3.478, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 1.3, + 1, + 2.6, + 1, + 3.9, + 1, + 0, + 3.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.533, + 0, + 1.067, + -7, + 1.6, + -7, + 1, + 2.056, + -7, + 2.511, + 4, + 2.967, + 4, + 1, + 3.278, + 4, + 3.589, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.578, + 0, + 1.156, + -10, + 1.733, + -10, + 1, + 2.1, + -10, + 2.467, + -7.702, + 2.833, + -4, + 1, + 3.122, + -1.083, + 3.411, + 0, + 3.7, + 0, + 1, + 3.767, + 0, + 3.833, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.734, + 0.467, + 0.76, + 1, + 1.533, + 0.94, + 2.6, + 1, + 3.667, + 1, + 1, + 3.744, + 1, + 3.822, + 0.5, + 3.9, + 0.5, + 0, + 3.933, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.734, + 0.467, + 0.76, + 1, + 1.533, + 0.94, + 2.6, + 1, + 3.667, + 1, + 1, + 3.744, + 1, + 3.822, + 0.5, + 3.9, + 0.5, + 0, + 3.933, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 2.5, + 1, + 0.133, + 2.5, + 0.267, + 2.3, + 0.4, + 2.3, + 1, + 0.567, + 2.3, + 0.733, + 2.42, + 0.9, + 2.9, + 1, + 1.067, + 3.38, + 1.233, + 3.8, + 1.4, + 3.8, + 1, + 1.556, + 3.8, + 1.711, + 3.857, + 1.867, + 3.7, + 1, + 2.356, + 3.207, + 2.844, + 2.4, + 3.333, + 2.4, + 1, + 3.522, + 2.4, + 3.711, + 2.5, + 3.9, + 2.5, + 0, + 3.933, + 2.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 3.5, + 1, + 0.133, + 3.5, + 0.267, + 3.1, + 0.4, + 3.1, + 1, + 0.733, + 3.1, + 1.067, + 5, + 1.4, + 5, + 1, + 1.522, + 5, + 1.644, + 5, + 1.767, + 5, + 1, + 2, + 5, + 2.233, + 4.5, + 2.467, + 4.5, + 1, + 2.944, + 4.5, + 3.422, + 4.5, + 3.9, + 4.5, + 0, + 3.933, + 4.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + -0.42, + 0.267, + -0.42, + 1, + 0.344, + -0.42, + 0.422, + 0.35, + 0.5, + 0.35, + 1, + 0.833, + 0.35, + 1.167, + 0, + 1.5, + 0, + 1, + 1.622, + 0, + 1.744, + 0.36, + 1.867, + 0.36, + 1, + 2.111, + 0.36, + 2.356, + -1, + 2.6, + -1, + 1, + 2.867, + -1, + 3.133, + -0.92, + 3.4, + -0.92, + 1, + 3.567, + -0.92, + 3.733, + -0.92, + 3.9, + -0.92, + 0, + 3.933, + -0.92 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0.5, + 1, + 0.278, + 0.5, + 0.556, + 0.5, + 0.833, + 0.5, + 1, + 0.9, + 0.5, + 0.967, + 0, + 1.033, + 0, + 1, + 1.989, + 0, + 2.944, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + -0.39, + 0.267, + -0.39, + 1, + 0.344, + -0.39, + 0.422, + -0.33, + 0.5, + -0.33, + 1, + 0.656, + -0.33, + 0.811, + -0.68, + 0.967, + -0.68, + 1, + 1.222, + -0.68, + 1.478, + 0.36, + 1.733, + 0.36, + 1, + 1.933, + 0.36, + 2.133, + 0.36, + 2.333, + 0.36, + 1, + 2.422, + 0.36, + 2.511, + -0.26, + 2.6, + -0.26, + 1, + 2.767, + -0.26, + 2.933, + -0.26, + 3.1, + -0.26, + 1, + 3.367, + -0.26, + 3.633, + -0.26, + 3.9, + -0.26, + 0, + 3.933, + -0.26 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.3, + 0, + 2.6, + 0, + 3.9, + 0, + 0, + 3.933, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 3.9, + 0, + 0, + 3.93, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 3.9, + 0, + 0, + 3.93, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.9, + 1, + 0, + 3.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.9, + 0, + 0, + 3.93, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m08.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m08.motion3.json new file mode 100644 index 0000000..d24f5ee --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m08.motion3.json @@ -0,0 +1,1581 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.6, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 199, + "TotalPointCount": 494, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.52, + 1, + 3.04, + 1, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.556, + 0, + 0.611, + 0, + 0.667, + 0, + 1, + 0.756, + 0, + 0.844, + 0, + 0.933, + 0, + 1, + 1.022, + 0, + 1.111, + 0, + 1.2, + 0, + 1, + 1.322, + 0, + 1.444, + 0, + 1.567, + 0, + 1, + 1.733, + 0, + 1.9, + 0, + 2.067, + 0, + 1, + 2.156, + 0, + 2.244, + 0, + 2.333, + 0, + 1, + 2.7, + 0, + 3.067, + 3, + 3.433, + 3, + 1, + 3.589, + 3, + 3.744, + 0, + 3.9, + 0, + 1, + 4.122, + 0, + 4.344, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.556, + 0, + 0.611, + 10, + 0.667, + 10, + 1, + 0.756, + 10, + 0.844, + -19.633, + 0.933, + -25, + 1, + 1.022, + -30.367, + 1.111, + -30, + 1.2, + -30, + 1, + 1.322, + -30, + 1.444, + -30, + 1.567, + -30, + 1, + 1.733, + -30, + 1.9, + 5, + 2.067, + 5, + 1, + 2.156, + 5, + 2.244, + 0.198, + 2.333, + 0, + 1, + 2.7, + -0.815, + 3.067, + -1, + 3.433, + -1, + 1, + 3.589, + -1, + 3.744, + 0, + 3.9, + 0, + 1, + 4.122, + 0, + 4.344, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.933, + 0, + 1.867, + 0, + 2.8, + 0, + 1, + 2.978, + 0, + 3.156, + 30, + 3.333, + 30, + 1, + 3.5, + 30, + 3.667, + -1, + 3.833, + -1, + 1, + 3.922, + -1, + 4.011, + 0, + 4.1, + 0, + 1, + 4.256, + 0, + 4.411, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.756, + 1, + 0.844, + 1, + 0.933, + 1, + 1, + 0.978, + 1, + 1.022, + 0, + 1.067, + 0, + 1, + 1.233, + 0, + 1.4, + 0, + 1.567, + 0, + 1, + 1.744, + 0, + 1.922, + 1, + 2.1, + 1, + 1, + 2.333, + 1, + 2.567, + 1, + 2.8, + 1, + 1, + 2.978, + 1, + 3.156, + 0.87, + 3.333, + 0.87, + 1, + 3.456, + 0.87, + 3.578, + 1, + 3.7, + 1, + 1, + 3.989, + 1, + 4.278, + 1, + 4.567, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.756, + 1, + 0.844, + 1, + 0.933, + 1, + 1, + 0.978, + 1, + 1.022, + 0, + 1.067, + 0, + 1, + 1.233, + 0, + 1.4, + 0, + 1.567, + 0, + 1, + 1.744, + 0, + 1.922, + 1, + 2.1, + 1, + 1, + 2.333, + 1, + 2.567, + 1, + 2.8, + 1, + 1, + 2.978, + 1, + 3.156, + 0.87, + 3.333, + 0.87, + 1, + 3.456, + 0.87, + 3.578, + 1, + 3.7, + 1, + 1, + 3.989, + 1, + 4.278, + 1, + 4.567, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.311, + 0, + 0.622, + 0, + 0.933, + 0, + 1, + 0.978, + 0, + 1.022, + -1, + 1.067, + -1, + 1, + 1.233, + -1, + 1.4, + -1, + 1.567, + -1, + 1, + 1.744, + -1, + 1.922, + 0, + 2.1, + 0, + 1, + 2.333, + 0, + 2.567, + 0, + 2.8, + 0, + 1, + 2.978, + 0, + 3.156, + -0.35, + 3.333, + -0.35, + 1, + 3.5, + -0.35, + 3.667, + 0, + 3.833, + 0, + 1, + 4.078, + 0, + 4.322, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.311, + 0, + 0.622, + 0, + 0.933, + 0, + 1, + 0.978, + 0, + 1.022, + -1, + 1.067, + -1, + 1, + 1.233, + -1, + 1.4, + -1, + 1.567, + -1, + 1, + 1.744, + -1, + 1.922, + 0, + 2.1, + 0, + 1, + 2.333, + 0, + 2.567, + 0, + 2.8, + 0, + 1, + 2.978, + 0, + 3.156, + -0.35, + 3.333, + -0.35, + 1, + 3.5, + -0.35, + 3.667, + 0, + 3.833, + 0, + 1, + 4.078, + 0, + 4.322, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 1.522, + 1, + 3.044, + 1, + 4.567, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + 0, + 0.533, + 0, + 1, + 0.689, + 0, + 0.844, + -10, + 1, + -10, + 1, + 1.189, + -10, + 1.378, + -10, + 1.567, + -10, + 1, + 1.7, + -10, + 1.833, + 0, + 1.967, + 0, + 1, + 2.133, + 0, + 2.3, + 0, + 2.467, + 0, + 1, + 3.167, + 0, + 3.867, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + 0, + 0.533, + 0, + 1, + 0.689, + 0, + 0.844, + 8.088, + 1, + 9, + 1, + 1.189, + 10.108, + 1.378, + 10, + 1.567, + 10, + 1, + 1.7, + 10, + 1.833, + 0, + 1.967, + 0, + 1, + 2.133, + 0, + 2.3, + 2, + 2.467, + 2, + 1, + 2.611, + 2, + 2.756, + 0, + 2.9, + 0, + 1, + 3.456, + 0, + 4.011, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0.91, + 1, + 0.678, + 0.91, + 1.356, + 0, + 2.033, + 0, + 1, + 2.422, + 0, + 2.811, + 1, + 3.2, + 1, + 1, + 3.656, + 1, + 4.111, + 1, + 4.567, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.178, + 0.5, + 0.356, + 0.5, + 0.533, + 0.5, + 1, + 0.733, + 0.5, + 0.933, + 1, + 1.133, + 1, + 1, + 2.278, + 1, + 3.422, + 1, + 4.567, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.178, + 0.5, + 0.356, + 0.5, + 0.533, + 0.5, + 1, + 0.733, + 0.5, + 0.933, + 1, + 1.133, + 1, + 1, + 2.278, + 1, + 3.422, + 1, + 4.567, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.078, + 0, + 1.156, + 0.19, + 1.233, + 0.19, + 1, + 2.344, + 0.19, + 3.456, + 0.19, + 4.567, + 0.19, + 0, + 4.6, + 0.19 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.078, + 0, + 1.156, + -0.17, + 1.233, + -0.17, + 1, + 2.344, + -0.17, + 3.456, + -0.17, + 4.567, + -0.17, + 0, + 4.6, + -0.17 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.522, + 0, + 3.044, + 0, + 4.567, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 4.57, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 4.57, + 0, + 0, + 4.6, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4.57, + 1, + 0, + 4.6, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4.57, + 0, + 0, + 4.6, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m09.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m09.motion3.json new file mode 100644 index 0000000..55583e3 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m09.motion3.json @@ -0,0 +1,2691 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 369, + "TotalPointCount": 964, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 0.96, + 1, + 1.91, + 1, + 2.87, + 1, + 1, + 3.24, + 1, + 3.62, + 1, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 1, + 1.133, + 1, + 1, + 1.311, + 1, + 1.489, + -0.44, + 1.667, + -0.984, + 1, + 1.833, + -1.291, + 2, + -1.455, + 2.167, + -1.455, + 1, + 2.344, + -1.455, + 2.522, + 0.37, + 2.7, + 0.37, + 1, + 2.944, + 0.37, + 3.189, + 0, + 3.433, + 0, + 1, + 3.622, + 0, + 3.811, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.267, + 0, + 0.533, + 0, + 0.8, + 0, + 1, + 0.956, + 0, + 1.111, + 17, + 1.267, + 17, + 1, + 1.444, + 17, + 1.622, + -16, + 1.8, + -16, + 1, + 1.978, + -16, + 2.156, + -16, + 2.333, + -16, + 1, + 2.411, + -16, + 2.489, + -16.369, + 2.567, + -15.184, + 1, + 2.7, + -13.151, + 2.833, + 1, + 2.967, + 1, + 1, + 3.233, + 1, + 3.5, + 0, + 3.767, + 0, + 1, + 3.844, + 0, + 3.922, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 3, + 1.133, + 3, + 1, + 1.311, + 3, + 1.489, + 0.06, + 1.667, + -1, + 1, + 1.844, + -2.06, + 2.022, + -2, + 2.2, + -2, + 1, + 2.378, + -2, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.822, + 1, + 0.978, + 1.1, + 1.133, + 1.1, + 1, + 1.311, + 1.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.3, + 0, + 2.4, + -0.009, + 2.5, + 0.2, + 1, + 2.578, + 0.362, + 2.656, + 1.1, + 2.733, + 1.1, + 1, + 2.933, + 1.1, + 3.133, + 1, + 3.333, + 1, + 1, + 3.556, + 1, + 3.778, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.822, + 1, + 0.978, + 1.1, + 1.133, + 1.1, + 1, + 1.311, + 1.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.3, + 0, + 2.4, + -0.009, + 2.5, + 0.2, + 1, + 2.578, + 0.362, + 2.656, + 1.1, + 2.733, + 1.1, + 1, + 2.933, + 1.1, + 3.133, + 1, + 3.333, + 1, + 1, + 3.556, + 1, + 3.778, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + -0.3, + 1.667, + -0.3, + 1, + 1.844, + -0.3, + 2.022, + -0.3, + 2.2, + -0.3, + 1, + 2.378, + -0.3, + 2.556, + 0.1, + 2.733, + 0.1, + 1, + 2.933, + 0.1, + 3.133, + 0, + 3.333, + 0, + 1, + 3.556, + 0, + 3.778, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + -0.3, + 1.667, + -0.3, + 1, + 1.844, + -0.3, + 2.022, + -0.3, + 2.2, + -0.3, + 1, + 2.378, + -0.3, + 2.556, + 0.1, + 2.733, + 0.1, + 1, + 2.933, + 0.1, + 3.133, + 0, + 3.333, + 0, + 1, + 3.556, + 0, + 3.778, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.822, + 1, + 0.978, + 1, + 1.133, + 1, + 1, + 1.311, + 1, + 1.489, + 1, + 1.667, + 1, + 1, + 1.844, + 1, + 2.022, + 1, + 2.2, + 1, + 1, + 2.378, + 1, + 2.556, + 1, + 2.733, + 1, + 1, + 3.156, + 1, + 3.578, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + -1, + 1.133, + -1, + 1, + 1.311, + -1, + 1.489, + -0.667, + 1.667, + 0, + 1, + 1.844, + 0.667, + 2.022, + 1, + 2.2, + 1, + 1, + 2.378, + 1, + 2.556, + -1, + 2.733, + -1, + 1, + 2.978, + -1, + 3.222, + 0, + 3.467, + 0, + 1, + 3.644, + 0, + 3.822, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 2, + 1.133, + 2, + 1, + 1.311, + 2, + 1.489, + -2.258, + 1.667, + -2.668, + 1, + 1.844, + -3.079, + 2.022, + -3, + 2.2, + -3, + 1, + 2.378, + -3, + 2.556, + 1, + 2.733, + 1, + 1, + 2.978, + 1, + 3.222, + 0, + 3.467, + 0, + 1, + 3.644, + 0, + 3.822, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 1, + 1.133, + 1, + 1, + 1.311, + 1, + 1.489, + -0.112, + 1.667, + -1, + 1, + 1.844, + -1.888, + 2.022, + -2, + 2.2, + -2, + 1, + 2.378, + -2, + 2.556, + 1, + 2.733, + 1, + 1, + 2.978, + 1, + 3.222, + 0, + 3.467, + 0, + 1, + 3.644, + 0, + 3.822, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + -1, + 1.133, + -1, + 1, + 1.311, + -1, + 1.489, + 1.94, + 1.667, + 3, + 1, + 1.844, + 4.06, + 2.022, + 4, + 2.2, + 4, + 1, + 2.378, + 4, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.822, + 1, + 0.978, + 1, + 1.133, + 1, + 1, + 1.311, + 1, + 1.489, + 1, + 1.667, + 1, + 1, + 1.844, + 1, + 2.022, + 1, + 2.2, + 1, + 1, + 2.378, + 1, + 2.556, + 1, + 2.733, + 1, + 1, + 3.156, + 1, + 3.578, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.222, + 1, + 0.444, + 1, + 0.667, + 1, + 1, + 0.822, + 1, + 0.978, + 1, + 1.133, + 1, + 1, + 1.311, + 1, + 1.489, + 1, + 1.667, + 1, + 1, + 1.844, + 1, + 2.022, + 1, + 2.2, + 1, + 1, + 2.378, + 1, + 2.556, + 1, + 2.733, + 1, + 1, + 3.156, + 1, + 3.578, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.222, + 5, + 0.444, + 5, + 0.667, + 5, + 1, + 0.822, + 5, + 0.978, + 5, + 1.133, + 5, + 1, + 1.311, + 5, + 1.489, + 5, + 1.667, + 5, + 1, + 1.844, + 5, + 2.022, + 5, + 2.2, + 5, + 1, + 2.378, + 5, + 2.556, + 5, + 2.733, + 5, + 1, + 3.156, + 5, + 3.578, + 5, + 4, + 5, + 0, + 4.033, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + -0.1, + 1, + 0.222, + -0.1, + 0.444, + -0.1, + 0.667, + -0.1, + 1, + 0.822, + -0.1, + 0.978, + -0.1, + 1.133, + -0.1, + 1, + 1.311, + -0.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + -0.1, + 2.733, + -0.1, + 1, + 3.156, + -0.1, + 3.578, + -0.1, + 4, + -0.1, + 0, + 4.033, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0.1, + 1, + 0.222, + 0.1, + 0.444, + 0.1, + 0.667, + 0.1, + 1, + 0.822, + 0.1, + 0.978, + 0.1, + 1.133, + 0.1, + 1, + 1.311, + 0.1, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0.1, + 2.733, + 0.1, + 1, + 3.156, + 0.1, + 3.578, + 0.1, + 4, + 0.1, + 0, + 4.033, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + 0, + 0.667, + 0, + 1, + 0.822, + 0, + 0.978, + 0, + 1.133, + 0, + 1, + 1.311, + 0, + 1.489, + 0, + 1.667, + 0, + 1, + 1.844, + 0, + 2.022, + 0, + 2.2, + 0, + 1, + 2.378, + 0, + 2.556, + 0, + 2.733, + 0, + 1, + 3.156, + 0, + 3.578, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 2.87, + 0, + 2, + 4, + 0, + 0, + 4.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 2.87, + 0, + 2, + 4, + 0, + 0, + 4.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2.87, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2.87, + 0, + 2, + 4, + 0, + 0, + 4.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m10.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m10.motion3.json new file mode 100644 index 0000000..e8d4acf --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m10.motion3.json @@ -0,0 +1,3706 @@ +{ + "Version": 3, + "Meta": { + "Duration": 5.53, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 514, + "TotalPointCount": 1399, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.13, + 1, + 2.27, + 1, + 3.4, + 1, + 1, + 4.1, + 1, + 4.8, + 1, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0.15, + 0.7, + 2, + 1, + 0.844, + 4.186, + 0.989, + 7, + 1.133, + 7, + 1, + 1.211, + 7, + 1.289, + 7.283, + 1.367, + 6.75, + 1, + 1.622, + 4.997, + 1.878, + -2, + 2.133, + -2, + 1, + 2.611, + -2, + 3.089, + -2, + 3.567, + -2, + 1, + 3.667, + -2, + 3.767, + 2, + 3.867, + 2, + 1, + 4.178, + 2, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.133, + 0, + 0.267, + 0, + 0.4, + 0, + 1, + 0.467, + 0, + 0.533, + 27, + 0.6, + 27, + 1, + 0.656, + 27, + 0.711, + -11.41, + 0.767, + -15, + 1, + 0.911, + -24.333, + 1.056, + -26, + 1.2, + -26, + 1, + 1.344, + -26, + 1.489, + -25.361, + 1.633, + -25.361, + 1, + 1.756, + -25.361, + 1.878, + -30, + 2, + -30, + 1, + 2.111, + -30, + 2.222, + -3, + 2.333, + -3, + 1, + 2.744, + -3, + 3.156, + -3, + 3.567, + -3, + 1, + 3.689, + -3, + 3.811, + -22, + 3.933, + -22, + 1, + 4.089, + -22, + 4.244, + 12, + 4.4, + 12, + 1, + 4.556, + 12, + 4.711, + 0, + 4.867, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 1, + 0.7, + 1, + 1, + 0.844, + 1, + 0.989, + -5, + 1.133, + -5, + 1, + 1.211, + -5, + 1.289, + -5.066, + 1.367, + -4.944, + 1, + 1.622, + -4.546, + 1.878, + -3, + 2.133, + -3, + 1, + 2.611, + -3, + 3.089, + -3, + 3.567, + -3, + 1, + 3.667, + -3, + 3.767, + -9, + 3.867, + -9, + 1, + 4.022, + -9, + 4.178, + 7, + 4.333, + 7, + 1, + 4.489, + 7, + 4.644, + -2, + 4.8, + -2, + 1, + 4.989, + -2, + 5.178, + 0, + 5.367, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0.5, + 0.7, + 0.5, + 1, + 0.844, + 0.5, + 0.989, + 0.5, + 1.133, + 0.5, + 1, + 1.211, + 0.5, + 1.289, + 0.5, + 1.367, + 0.5, + 1, + 1.622, + 0.5, + 1.878, + 0.5, + 2.133, + 0.5, + 1, + 2.611, + 0.5, + 3.089, + 0.5, + 3.567, + 0.5, + 1, + 3.978, + 0.5, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.4, + 1, + 0.467, + 2, + 0.533, + 2, + 1, + 0.589, + 2, + 0.644, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.3, + 0, + 1.467, + 0, + 1.633, + 0, + 1, + 1.756, + 0, + 1.878, + 0, + 2, + 0, + 1, + 2.044, + 0, + 2.089, + 1.5, + 2.133, + 1.5, + 1, + 2.2, + 1.5, + 2.267, + 1.5, + 2.333, + 1.5, + 1, + 2.389, + 1.5, + 2.444, + 0, + 2.5, + 0, + 1, + 2.533, + 0, + 2.567, + 0, + 2.6, + 0, + 1, + 2.644, + 0, + 2.689, + 0.788, + 2.733, + 1.4, + 1, + 2.744, + 1.553, + 2.756, + 1.5, + 2.767, + 1.5, + 1, + 2.822, + 1.5, + 2.878, + 0, + 2.933, + 0, + 1, + 2.944, + 0, + 2.956, + 0, + 2.967, + 0, + 1, + 3.011, + 0, + 3.056, + 1.4, + 3.1, + 1.4, + 1, + 3.256, + 1.4, + 3.411, + 1.4, + 3.567, + 1.4, + 1, + 3.667, + 1.4, + 3.767, + 0, + 3.867, + 0, + 1, + 4.022, + 0, + 4.178, + 0, + 4.333, + 0, + 1, + 4.489, + 0, + 4.644, + 1, + 4.8, + 1, + 0, + 5.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 1, + 0.533, + 1, + 1, + 0.589, + 1, + 0.644, + 1, + 0.7, + 1, + 1, + 0.844, + 1, + 0.989, + 1, + 1.133, + 1, + 1, + 1.3, + 1, + 1.467, + 1.009, + 1.633, + 0.913, + 1, + 1.756, + 0.843, + 1.878, + 0, + 2, + 0, + 1, + 2.044, + 0, + 2.089, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.4, + 1, + 0.467, + 2, + 0.533, + 2, + 1, + 0.589, + 2, + 0.644, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.3, + 0, + 1.467, + 0, + 1.633, + 0, + 1, + 1.756, + 0, + 1.878, + 0, + 2, + 0, + 1, + 2.044, + 0, + 2.089, + 1.5, + 2.133, + 1.5, + 1, + 2.2, + 1.5, + 2.267, + 1.5, + 2.333, + 1.5, + 1, + 2.389, + 1.5, + 2.444, + 0, + 2.5, + 0, + 1, + 2.533, + 0, + 2.567, + 0, + 2.6, + 0, + 1, + 2.644, + 0, + 2.689, + 0.788, + 2.733, + 1.4, + 1, + 2.744, + 1.553, + 2.756, + 1.5, + 2.767, + 1.5, + 1, + 2.822, + 1.5, + 2.878, + 0, + 2.933, + 0, + 1, + 2.944, + 0, + 2.956, + 0, + 2.967, + 0, + 1, + 3.011, + 0, + 3.056, + 1.4, + 3.1, + 1.4, + 1, + 3.256, + 1.4, + 3.411, + 1.4, + 3.567, + 1.4, + 1, + 3.667, + 1.4, + 3.767, + 0, + 3.867, + 0, + 1, + 4.022, + 0, + 4.178, + 0, + 4.333, + 0, + 1, + 4.489, + 0, + 4.644, + 1, + 4.8, + 1, + 0, + 5.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 1, + 0.533, + 1, + 1, + 0.589, + 1, + 0.644, + 1, + 0.7, + 1, + 1, + 0.844, + 1, + 0.989, + 1, + 1.133, + 1, + 1, + 1.3, + 1, + 1.467, + 1.009, + 1.633, + 0.913, + 1, + 1.756, + 0.843, + 1.878, + 0, + 2, + 0, + 1, + 2.044, + 0, + 2.089, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + -0.6, + 0.533, + -0.6, + 1, + 0.589, + -0.6, + 0.644, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.1, + 0.533, + 0.1, + 1, + 0.589, + 0.1, + 0.644, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.3, + 0, + 1.467, + 0, + 1.633, + 0, + 1, + 1.756, + 0, + 1.878, + 0, + 2, + 0, + 1, + 2.044, + 0, + 2.089, + 0, + 2.133, + 0, + 1, + 2.2, + 0, + 2.267, + 0, + 2.333, + 0, + 1, + 2.389, + 0, + 2.444, + -0.1, + 2.5, + -0.1, + 1, + 2.533, + -0.1, + 2.567, + -0.1, + 2.6, + -0.1, + 1, + 2.644, + -0.1, + 2.689, + 0, + 2.733, + 0, + 1, + 2.744, + 0, + 2.756, + 0, + 2.767, + 0, + 1, + 2.822, + 0, + 2.878, + -0.1, + 2.933, + -0.1, + 1, + 2.944, + -0.1, + 2.956, + -0.1, + 2.967, + -0.1, + 1, + 3.011, + -0.1, + 3.056, + 0, + 3.1, + 0, + 1, + 3.256, + 0, + 3.411, + 0, + 3.567, + 0, + 1, + 3.667, + 0, + 3.767, + -0.2, + 3.867, + -0.2, + 1, + 4.022, + -0.2, + 4.178, + -0.2, + 4.333, + -0.2, + 1, + 4.489, + -0.2, + 4.644, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.2, + 0.533, + 0.2, + 1, + 0.589, + 0.2, + 0.644, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.3, + 0, + 1.467, + 0, + 1.633, + 0, + 1, + 1.756, + 0, + 1.878, + 0, + 2, + 0, + 1, + 2.044, + 0, + 2.089, + 0, + 2.133, + 0, + 1, + 2.2, + 0, + 2.267, + 0, + 2.333, + 0, + 1, + 2.389, + 0, + 2.444, + -0.1, + 2.5, + -0.1, + 1, + 2.533, + -0.1, + 2.567, + -0.1, + 2.6, + -0.1, + 1, + 2.644, + -0.1, + 2.689, + 0, + 2.733, + 0, + 1, + 2.744, + 0, + 2.756, + 0, + 2.767, + 0, + 1, + 2.822, + 0, + 2.878, + -0.1, + 2.933, + -0.1, + 1, + 2.944, + -0.1, + 2.956, + -0.1, + 2.967, + -0.1, + 1, + 3.011, + -0.1, + 3.056, + 0, + 3.1, + 0, + 1, + 3.256, + 0, + 3.411, + 0, + 3.567, + 0, + 1, + 3.667, + 0, + 3.767, + -0.2, + 3.867, + -0.2, + 1, + 4.022, + -0.2, + 4.178, + -0.2, + 4.333, + -0.2, + 1, + 4.489, + -0.2, + 4.644, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.7, + 0.533, + 0.7, + 1, + 0.589, + 0.7, + 0.644, + -0.6, + 0.7, + -0.6, + 1, + 0.844, + -0.6, + 0.989, + -0.6, + 1.133, + -0.6, + 1, + 1.3, + -0.6, + 1.467, + -0.564, + 1.633, + -0.564, + 1, + 1.756, + -0.564, + 1.878, + -0.7, + 2, + -0.7, + 1, + 2.044, + -0.7, + 2.089, + 0.7, + 2.133, + 0.7, + 1, + 2.2, + 0.7, + 2.267, + 0.7, + 2.333, + 0.7, + 1, + 2.389, + 0.7, + 2.444, + 0.6, + 2.5, + 0.6, + 1, + 2.533, + 0.6, + 2.567, + 0.6, + 2.6, + 0.6, + 1, + 2.644, + 0.6, + 2.689, + 0.7, + 2.733, + 0.7, + 1, + 2.744, + 0.7, + 2.756, + 0.7, + 2.767, + 0.7, + 1, + 2.811, + 0.7, + 2.856, + 0.6, + 2.9, + 0.6, + 1, + 2.922, + 0.6, + 2.944, + 0.6, + 2.967, + 0.6, + 1, + 3.011, + 0.6, + 3.056, + 0.7, + 3.1, + 0.7, + 1, + 3.256, + 0.7, + 3.411, + 0.7, + 3.567, + 0.7, + 1, + 3.667, + 0.7, + 3.767, + -0.5, + 3.867, + -0.5, + 1, + 4.178, + -0.5, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.7, + 0.533, + 0.7, + 1, + 0.589, + 0.7, + 0.644, + -0.6, + 0.7, + -0.6, + 1, + 0.844, + -0.6, + 0.989, + -0.6, + 1.133, + -0.6, + 1, + 1.3, + -0.6, + 1.467, + -0.564, + 1.633, + -0.564, + 1, + 1.756, + -0.564, + 1.878, + -0.7, + 2, + -0.7, + 1, + 2.044, + -0.7, + 2.089, + 0.7, + 2.133, + 0.7, + 1, + 2.2, + 0.7, + 2.267, + 0.7, + 2.333, + 0.7, + 1, + 2.389, + 0.7, + 2.444, + 0.6, + 2.5, + 0.6, + 1, + 2.533, + 0.6, + 2.567, + 0.6, + 2.6, + 0.6, + 1, + 2.644, + 0.6, + 2.689, + 0.7, + 2.733, + 0.7, + 1, + 2.744, + 0.7, + 2.756, + 0.7, + 2.767, + 0.7, + 1, + 2.811, + 0.7, + 2.856, + 0.6, + 2.9, + 0.6, + 1, + 2.922, + 0.6, + 2.944, + 0.6, + 2.967, + 0.6, + 1, + 3.011, + 0.6, + 3.056, + 0.7, + 3.1, + 0.7, + 1, + 3.256, + 0.7, + 3.411, + 0.7, + 3.567, + 0.7, + 1, + 3.667, + 0.7, + 3.767, + -0.5, + 3.867, + -0.5, + 1, + 4.178, + -0.5, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.4, + 0.533, + 0.4, + 1, + 0.589, + 0.4, + 0.644, + -0.4, + 0.7, + -0.4, + 1, + 0.844, + -0.4, + 0.989, + -0.4, + 1.133, + -0.4, + 1, + 1.3, + -0.4, + 1.467, + -0.378, + 1.633, + -0.378, + 1, + 1.756, + -0.378, + 1.878, + -0.378, + 2, + -0.378, + 1, + 2.044, + -0.378, + 2.089, + 0.4, + 2.133, + 0.4, + 1, + 2.611, + 0.4, + 3.089, + 0.4, + 3.567, + 0.4, + 1, + 3.667, + 0.4, + 3.767, + -0.4, + 3.867, + -0.4, + 1, + 4.178, + -0.4, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.4, + 0.533, + 0.4, + 1, + 0.589, + 0.4, + 0.644, + -0.4, + 0.7, + -0.4, + 1, + 0.844, + -0.4, + 0.989, + -0.4, + 1.133, + -0.4, + 1, + 1.3, + -0.4, + 1.467, + -0.378, + 1.633, + -0.378, + 1, + 1.756, + -0.378, + 1.878, + -0.378, + 2, + -0.378, + 1, + 2.044, + -0.378, + 2.089, + 0.4, + 2.133, + 0.4, + 1, + 2.611, + 0.4, + 3.089, + 0.4, + 3.567, + 0.4, + 1, + 3.978, + 0.4, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.5, + 0.533, + 0.5, + 1, + 0.589, + 0.5, + 0.644, + -0.4, + 0.7, + -0.4, + 1, + 0.844, + -0.4, + 0.989, + -0.4, + 1.133, + -0.4, + 1, + 1.3, + -0.4, + 1.467, + -0.378, + 1.633, + -0.378, + 1, + 1.756, + -0.378, + 1.878, + -0.378, + 2, + -0.378, + 1, + 2.044, + -0.378, + 2.089, + 0.4, + 2.133, + 0.4, + 1, + 2.611, + 0.4, + 3.089, + 0.4, + 3.567, + 0.4, + 1, + 3.667, + 0.4, + 3.767, + 0, + 3.867, + 0, + 1, + 4.178, + 0, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.5, + 0.533, + 0.5, + 1, + 0.589, + 0.5, + 0.644, + -0.4, + 0.7, + -0.4, + 1, + 0.844, + -0.4, + 0.989, + -0.4, + 1.133, + -0.4, + 1, + 1.3, + -0.4, + 1.467, + -0.378, + 1.633, + -0.378, + 1, + 1.756, + -0.378, + 1.878, + -0.378, + 2, + -0.378, + 1, + 2.044, + -0.378, + 2.089, + 0.4, + 2.133, + 0.4, + 1, + 2.611, + 0.4, + 3.089, + 0.4, + 3.567, + 0.4, + 1, + 3.667, + 0.4, + 3.767, + 0, + 3.867, + 0, + 1, + 4.178, + 0, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.4, + 0.533, + 0.4, + 1, + 0.589, + 0.4, + 0.644, + -0.8, + 0.7, + -0.8, + 1, + 0.844, + -0.8, + 0.989, + -0.8, + 1.133, + -0.8, + 1, + 1.3, + -0.8, + 1.467, + -0.767, + 1.633, + -0.767, + 1, + 1.756, + -0.767, + 1.878, + -0.767, + 2, + -0.767, + 1, + 2.044, + -0.767, + 2.089, + 0.4, + 2.133, + 0.4, + 1, + 2.611, + 0.4, + 3.089, + 0.4, + 3.567, + 0.4, + 1, + 3.667, + 0.4, + 3.767, + -0.3, + 3.867, + -0.3, + 1, + 4.178, + -0.3, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.4, + 0.533, + 0.4, + 1, + 0.589, + 0.4, + 0.644, + -0.8, + 0.7, + -0.8, + 1, + 0.844, + -0.8, + 0.989, + -0.8, + 1.133, + -0.8, + 1, + 1.3, + -0.8, + 1.467, + -0.767, + 1.633, + -0.767, + 1, + 1.756, + -0.767, + 1.878, + -0.767, + 2, + -0.767, + 1, + 2.044, + -0.767, + 2.089, + 0.4, + 2.133, + 0.4, + 1, + 2.611, + 0.4, + 3.089, + 0.4, + 3.567, + 0.4, + 1, + 3.667, + 0.4, + 3.767, + -0.3, + 3.867, + -0.3, + 1, + 4.178, + -0.3, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.456, + 1, + 0.578, + -0.6, + 0.7, + -0.6, + 1, + 0.844, + -0.6, + 0.989, + -0.6, + 1.133, + -0.6, + 1, + 1.3, + -0.6, + 1.467, + -0.6, + 1.633, + -0.6, + 1, + 1.756, + -0.6, + 1.878, + -0.6, + 2, + -0.6, + 1, + 2.044, + -0.6, + 2.089, + -0.6, + 2.133, + -0.6, + 1, + 2.611, + -0.6, + 3.089, + -0.6, + 3.567, + -0.6, + 1, + 3.667, + -0.6, + 3.767, + -0.005, + 3.867, + 0.2, + 1, + 4.178, + 0.839, + 4.489, + 1, + 4.8, + 1, + 0, + 5.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 0.3, + 0.533, + 0.3, + 1, + 0.589, + 0.3, + 0.644, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.3, + 0, + 1.467, + 0.006, + 1.633, + 0.006, + 1, + 1.756, + 0.006, + 1.878, + 0.006, + 2, + 0.006, + 1, + 2.044, + 0.006, + 2.089, + 0.2, + 2.133, + 0.2, + 1, + 2.611, + 0.2, + 3.089, + 0.2, + 3.567, + 0.2, + 1, + 3.667, + 0.2, + 3.767, + 0, + 3.867, + 0, + 1, + 4.178, + 0, + 4.489, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 7, + 0.7, + 7, + 1, + 0.844, + 7, + 0.989, + 7, + 1.133, + 7, + 1, + 1.211, + 7, + 1.289, + 7.224, + 1.367, + 6.805, + 1, + 1.622, + 5.431, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.4, + 0, + 0.467, + 5, + 0.533, + 5, + 1, + 0.589, + 5, + 0.644, + -6, + 0.7, + -6, + 1, + 0.844, + -6, + 0.989, + -5.999, + 1.133, + -5.953, + 1, + 1.211, + -5.928, + 1.289, + -5.922, + 1.367, + -5.445, + 1, + 1.622, + -3.877, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.667, + 0, + 3.767, + -4, + 3.867, + -4, + 1, + 4.022, + -4, + 4.178, + 4, + 4.333, + 4, + 1, + 4.489, + 4, + 4.644, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + -4, + 0.7, + -4, + 1, + 0.844, + -4, + 0.989, + -4, + 1.133, + -4, + 1, + 1.211, + -4, + 1.289, + -4.13, + 1.367, + -3.889, + 1, + 1.622, + -3.096, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 8.063, + 0.7, + 9, + 1, + 0.844, + 10.107, + 0.989, + 10, + 1.133, + 10, + 1, + 1.367, + 10, + 1.6, + 10.026, + 1.833, + 9.364, + 1, + 1.978, + 8.954, + 2.122, + 0, + 2.267, + 0, + 1, + 2.7, + 0, + 3.133, + 0, + 3.567, + 0, + 1, + 3.667, + 0, + 3.767, + 1.903, + 3.867, + 3, + 1, + 4.022, + 4.706, + 4.178, + 5, + 4.333, + 5, + 1, + 4.489, + 5, + 4.644, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.4, + 1, + 0.467, + 0.281, + 0.533, + 0.2, + 1, + 0.589, + 0.133, + 0.644, + 0.124, + 0.7, + 0.1, + 1, + 0.867, + 0.027, + 1.033, + 0, + 1.2, + 0, + 1, + 1.322, + 0, + 1.444, + -0.006, + 1.567, + 0.008, + 1, + 1.8, + 0.036, + 2.033, + 0.3, + 2.267, + 0.3, + 1, + 2.4, + 0.3, + 2.533, + 0.264, + 2.667, + 0.264, + 1, + 2.967, + 0.264, + 3.267, + 0.27, + 3.567, + 0.3, + 1, + 3.667, + 0.31, + 3.767, + 0.4, + 3.867, + 0.4, + 1, + 4.022, + 0.4, + 4.178, + 0.4, + 4.333, + 0.4, + 1, + 4.489, + 0.4, + 4.644, + 1, + 4.8, + 1, + 0, + 5.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.4, + 1, + 0.467, + 0.281, + 0.533, + 0.2, + 1, + 0.589, + 0.133, + 0.644, + 0.124, + 0.7, + 0.1, + 1, + 0.867, + 0.027, + 1.033, + 0, + 1.2, + 0, + 1, + 1.322, + 0, + 1.444, + -0.006, + 1.567, + 0.008, + 1, + 1.8, + 0.036, + 2.033, + 0.3, + 2.267, + 0.3, + 1, + 2.4, + 0.3, + 2.533, + 0.263, + 2.667, + 0.263, + 1, + 2.967, + 0.263, + 3.267, + 0.268, + 3.567, + 0.3, + 1, + 3.667, + 0.311, + 3.767, + 0.4, + 3.867, + 0.4, + 1, + 4.022, + 0.4, + 4.178, + 0.4, + 4.333, + 0.4, + 1, + 4.489, + 0.4, + 4.644, + 1, + 4.8, + 1, + 0, + 5.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.111, + 5, + 0.222, + 5, + 0.333, + 5, + 1, + 0.456, + 5, + 0.578, + 0, + 0.7, + 0, + 1, + 0.867, + 0, + 1.033, + 0, + 1.2, + 0, + 1, + 1.322, + 0, + 1.444, + 0, + 1.567, + 0, + 1, + 1.8, + 0, + 2.033, + 0, + 2.267, + 0, + 1, + 2.7, + 0, + 3.133, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 5, + 4.8, + 5, + 0, + 5.533, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.867, + 0, + 1.033, + 0, + 1.2, + 0, + 1, + 1.322, + 0, + 1.444, + 0, + 1.567, + 0, + 1, + 1.8, + 0, + 2.033, + 0, + 2.267, + 0, + 1, + 2.7, + 0, + 3.133, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.889, + 0, + 1.078, + 0, + 1.267, + 0, + 1, + 1.4, + 0, + 1.533, + 0, + 1.667, + 0, + 1, + 1.9, + 0, + 2.133, + 0, + 2.367, + 0, + 1, + 2.767, + 0, + 3.167, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + -0.1, + 1, + 0.111, + -0.1, + 0.222, + -0.1, + 0.333, + -0.1, + 1, + 0.456, + -0.1, + 0.578, + 0, + 0.7, + 0, + 1, + 0.889, + 0, + 1.078, + 0, + 1.267, + 0, + 1, + 1.4, + 0, + 1.533, + 0, + 1.667, + 0, + 1, + 1.9, + 0, + 2.133, + 0.4, + 2.367, + 0.4, + 1, + 2.767, + 0.4, + 3.167, + 0.4, + 3.567, + 0.4, + 1, + 3.667, + 0.4, + 3.767, + -0.8, + 3.867, + -0.8, + 1, + 4.022, + -0.8, + 4.178, + -0.629, + 4.333, + -0.4, + 1, + 4.489, + -0.171, + 4.644, + -0.1, + 4.8, + -0.1, + 0, + 5.533, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.889, + 0, + 1.078, + 0, + 1.267, + 0, + 1, + 1.4, + 0, + 1.533, + 0, + 1.667, + 0, + 1, + 1.9, + 0, + 2.133, + 0, + 2.367, + 0, + 1, + 2.767, + 0, + 3.167, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0.1, + 1, + 0.111, + 0.1, + 0.222, + 0.1, + 0.333, + 0.1, + 1, + 0.456, + 0.1, + 0.578, + 0, + 0.7, + 0, + 1, + 0.889, + 0, + 1.078, + 0, + 1.267, + 0, + 1, + 1.4, + 0, + 1.533, + 0, + 1.667, + 0, + 1, + 1.9, + 0, + 2.133, + -0.4, + 2.367, + -0.4, + 1, + 2.767, + -0.4, + 3.167, + -0.4, + 3.567, + -0.4, + 1, + 3.667, + -0.4, + 3.767, + 1, + 3.867, + 1, + 1, + 4.022, + 1, + 4.178, + 0.967, + 4.333, + 0.7, + 1, + 4.489, + 0.433, + 4.644, + 0.1, + 4.8, + 0.1, + 0, + 5.533, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 0, + 0.7, + 0, + 1, + 0.844, + 0, + 0.989, + 0, + 1.133, + 0, + 1, + 1.211, + 0, + 1.289, + 0, + 1.367, + 0, + 1, + 1.622, + 0, + 1.878, + 0, + 2.133, + 0, + 1, + 2.611, + 0, + 3.089, + 0, + 3.567, + 0, + 1, + 3.978, + 0, + 4.389, + 0, + 4.8, + 0, + 0, + 5.533, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 3.4, + 0, + 2, + 5.5, + 0, + 0, + 5.53, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 3.4, + 0, + 2, + 5.5, + 0, + 0, + 5.53, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 2, + 5.5, + 1, + 0, + 5.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.4, + 0, + 2, + 5.5, + 0, + 0, + 5.53, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m11.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m11.motion3.json new file mode 100644 index 0000000..e18f08a --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m11.motion3.json @@ -0,0 +1,1455 @@ +{ + "Version": 3, + "Meta": { + "Duration": 3.43, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 181, + "TotalPointCount": 440, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.13, + 1, + 2.27, + 1, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.344, + 0, + 0.689, + 0, + 1.033, + 0, + 1, + 1.089, + 0, + 1.144, + 0, + 1.2, + 0, + 1, + 1.333, + 0, + 1.467, + 2, + 1.6, + 2, + 1, + 1.744, + 2, + 1.889, + -8, + 2.033, + -8, + 1, + 2.156, + -8, + 2.278, + 8, + 2.4, + 8, + 1, + 2.533, + 8, + 2.667, + 0, + 2.8, + 0, + 1, + 2.911, + 0, + 3.022, + 0, + 3.133, + 0, + 1, + 3.222, + 0, + 3.311, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.344, + 0, + 0.689, + 0, + 1.033, + 0, + 1, + 1.089, + 0, + 1.144, + 0, + 1.2, + 0, + 1, + 1.333, + 0, + 1.467, + 16, + 1.6, + 16, + 1, + 1.722, + 16, + 1.844, + -21, + 1.967, + -21, + 1, + 2.111, + -21, + 2.256, + -19.167, + 2.4, + -18, + 1, + 2.522, + -17.012, + 2.644, + -17.151, + 2.767, + -16, + 1, + 2.878, + -14.954, + 2.989, + 0, + 3.1, + 0, + 1, + 3.2, + 0, + 3.3, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 2, + 1, + 0.533, + 2, + 1.067, + 2, + 1.6, + 2, + 1, + 1.656, + 2, + 1.711, + 0, + 1.767, + 0, + 1, + 2.067, + 0, + 2.367, + 0, + 2.667, + 0, + 1, + 2.756, + 0, + 2.844, + 2, + 2.933, + 2, + 1, + 3.089, + 2, + 3.244, + 2, + 3.4, + 2, + 0, + 3.433, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 2, + 1, + 0.533, + 2, + 1.067, + 2, + 1.6, + 2, + 1, + 1.656, + 2, + 1.711, + 0, + 1.767, + 0, + 1, + 2.067, + 0, + 2.367, + 0, + 2.667, + 0, + 1, + 2.756, + 0, + 2.844, + 2, + 2.933, + 2, + 1, + 3.089, + 2, + 3.244, + 2, + 3.4, + 2, + 0, + 3.433, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.389, + 0, + 0.778, + 0, + 1.167, + 0, + 1, + 1.289, + 0, + 1.411, + -0.1, + 1.533, + -0.1, + 1, + 1.9, + -0.1, + 2.267, + 0, + 2.633, + 0, + 1, + 2.889, + 0, + 3.144, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.389, + 0, + 0.778, + 0, + 1.167, + 0, + 1, + 1.289, + 0, + 1.411, + -0.38, + 1.533, + -0.38, + 1, + 1.9, + -0.38, + 2.267, + 0, + 2.633, + 0, + 1, + 2.889, + 0, + 3.144, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0.61, + 1, + 1.133, + 0.61, + 2.267, + 0.61, + 3.4, + 0.61, + 0, + 3.433, + 0.61 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0.61, + 1, + 1.133, + 0.61, + 2.267, + 0.61, + 3.4, + 0.61, + 0, + 3.433, + 0.61 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + -0.64, + 1, + 1.133, + -0.64, + 2.267, + -0.64, + 3.4, + -0.64, + 0, + 3.433, + -0.64 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.344, + 0, + 0.689, + 0, + 1.033, + 0, + 1, + 1.244, + 0, + 1.456, + 2, + 1.667, + 2, + 1, + 1.822, + 2, + 1.978, + -3, + 2.133, + -3, + 1, + 2.256, + -3, + 2.378, + 2, + 2.5, + 2, + 1, + 2.622, + 2, + 2.744, + -2, + 2.867, + -2, + 1, + 2.978, + -2, + 3.089, + 0, + 3.2, + 0, + 1, + 3.267, + 0, + 3.333, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.211, + 0, + 1.422, + 3, + 1.633, + 3, + 1, + 1.778, + 3, + 1.922, + 0, + 2.067, + 0, + 1, + 2.511, + 0, + 2.956, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + -5, + 0.9, + -5, + 1, + 1.167, + -5, + 1.433, + 0, + 1.7, + 0, + 1, + 2.267, + 0, + 2.833, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.743, + 0.467, + 0.76, + 1, + 1.378, + 0.86, + 2.289, + 0.89, + 3.2, + 0.89, + 1, + 3.267, + 0.89, + 3.333, + 0.5, + 3.4, + 0.5, + 0, + 3.433, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.735, + 0.467, + 0.76, + 1, + 1.378, + 0.905, + 2.289, + 0.95, + 3.2, + 0.95, + 1, + 3.267, + 0.95, + 3.333, + 0.5, + 3.4, + 0.5, + 0, + 3.433, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0.3, + 1, + 0.311, + 0.3, + 0.622, + 0.3, + 0.933, + 0.3, + 1, + 1.156, + 0.3, + 1.378, + 0.5, + 1.6, + 0.5, + 1, + 1.756, + 0.5, + 1.911, + 0.3, + 2.067, + 0.3, + 1, + 2.511, + 0.3, + 2.956, + 0.3, + 3.4, + 0.3, + 0, + 3.433, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0.3, + 1, + 0.289, + 0.3, + 0.578, + 0.3, + 0.867, + 0.3, + 1, + 1.089, + 0.3, + 1.311, + 0.5, + 1.533, + 0.5, + 1, + 1.689, + 0.5, + 1.844, + 0.3, + 2, + 0.3, + 1, + 2.467, + 0.3, + 2.933, + 0.3, + 3.4, + 0.3, + 0, + 3.433, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.66, + 1, + 0.344, + 0.66, + 0.689, + 0.662, + 1.033, + 0.64, + 1, + 1.267, + 0.625, + 1.5, + 0.12, + 1.733, + 0.12, + 1, + 1.867, + 0.12, + 2, + 0.66, + 2.133, + 0.66, + 1, + 2.556, + 0.66, + 2.978, + 0.66, + 3.4, + 0.66, + 0, + 3.433, + 0.66 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -1, + 1, + 0.322, + -1, + 0.644, + -1, + 0.967, + -1, + 1, + 1.2, + -1, + 1.433, + -0.68, + 1.667, + -0.68, + 1, + 1.822, + -0.68, + 1.978, + -1, + 2.133, + -1, + 1, + 2.556, + -1, + 2.978, + -1, + 3.4, + -1, + 0, + 3.433, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.133, + 0, + 2.267, + 0, + 3.4, + 0, + 0, + 3.433, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 3.4, + 0, + 0, + 3.43, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 3.4, + 0, + 0, + 3.43, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.4, + 1, + 0, + 3.43, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.4, + 0, + 0, + 3.43, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m12.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m12.motion3.json new file mode 100644 index 0000000..7df2740 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m12.motion3.json @@ -0,0 +1,2352 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.93, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 328, + "TotalPointCount": 815, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.63, + 1, + 3.27, + 1, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + -18, + 0.633, + -18, + 1, + 0.744, + -18, + 0.856, + 19, + 0.967, + 19, + 1, + 1.078, + 19, + 1.189, + -11, + 1.3, + -11, + 1, + 1.411, + -11, + 1.522, + 5, + 1.633, + 5, + 1, + 1.722, + 5, + 1.811, + 0, + 1.9, + 0, + 1, + 2.089, + 0, + 2.278, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.567, + 0, + 2.667, + 4, + 2.767, + 4, + 1, + 2.9, + 4, + 3.033, + -13, + 3.167, + -13, + 1, + 3.422, + -13, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + -11, + 1, + 0.1, + -11, + 0.2, + -11, + 0.3, + -11, + 1, + 0.411, + -11, + 0.522, + -11, + 0.633, + -11, + 1, + 1.244, + -11, + 1.856, + -11, + 2.467, + -11, + 1, + 2.956, + -11, + 3.444, + -6.965, + 3.933, + -2, + 1, + 4.122, + -0.082, + 4.311, + 0, + 4.5, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 2, + 1, + 0.1, + 2, + 0.2, + 2, + 0.3, + 2, + 1, + 0.411, + 2, + 0.522, + 1, + 0.633, + 1, + 1, + 1.233, + 1, + 1.833, + 1, + 2.433, + 1, + 1, + 2.678, + 1, + 2.922, + 0, + 3.167, + 0, + 1, + 3.422, + 0, + 3.678, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 2, + 1, + 0.1, + 2, + 0.2, + 2, + 0.3, + 2, + 1, + 0.411, + 2, + 0.522, + 1, + 0.633, + 1, + 1, + 1.244, + 1, + 1.856, + 1, + 2.467, + 1, + 1, + 2.7, + 1, + 2.933, + 0, + 3.167, + 0, + 1, + 3.422, + 0, + 3.678, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0.6, + 0.633, + 0.6, + 1, + 0.744, + 0.6, + 0.856, + -0.5, + 0.967, + -0.5, + 1, + 1.078, + -0.5, + 1.189, + 0.3, + 1.3, + 0.3, + 1, + 1.411, + 0.3, + 1.522, + -0.2, + 1.633, + -0.2, + 1, + 1.722, + -0.2, + 1.811, + 0.1, + 1.9, + 0.1, + 1, + 2.089, + 0.1, + 2.278, + 0.1, + 2.467, + 0.1, + 1, + 2.956, + 0.1, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0.293, + 0.633, + 0.4, + 1, + 0.744, + 0.507, + 0.856, + 0.5, + 0.967, + 0.5, + 1, + 1.078, + 0.5, + 1.189, + 0.5, + 1.3, + 0.5, + 1, + 1.411, + 0.5, + 1.522, + 0.473, + 1.633, + 0.4, + 1, + 1.722, + 0.341, + 1.811, + 0.3, + 1.9, + 0.3, + 1, + 2.089, + 0.3, + 2.278, + 0.3, + 2.467, + 0.3, + 1, + 2.956, + 0.3, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0.9, + 1, + 0.1, + 0.9, + 0.2, + 0.9, + 0.3, + 0.9, + 1, + 0.411, + 0.9, + 0.522, + -0.3, + 0.633, + -0.3, + 1, + 1.244, + -0.3, + 1.856, + -0.3, + 2.467, + -0.3, + 1, + 2.7, + -0.3, + 2.933, + 0.3, + 3.167, + 0.3, + 1, + 3.422, + 0.3, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0.9, + 1, + 0.1, + 0.9, + 0.2, + 0.9, + 0.3, + 0.9, + 1, + 0.411, + 0.9, + 0.522, + -0.3, + 0.633, + -0.3, + 1, + 1.244, + -0.3, + 1.856, + -0.3, + 2.467, + -0.3, + 1, + 2.7, + -0.3, + 2.933, + 0.3, + 3.167, + 0.3, + 1, + 3.422, + 0.3, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0.8, + 1, + 0.1, + 0.8, + 0.2, + 0.8, + 0.3, + 0.8, + 1, + 0.411, + 0.8, + 0.522, + -0.3, + 0.633, + -0.3, + 1, + 1.244, + -0.3, + 1.856, + -0.3, + 2.467, + -0.3, + 1, + 2.7, + -0.3, + 2.933, + 0.3, + 3.167, + 0.3, + 1, + 3.422, + 0.3, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0.8, + 1, + 0.1, + 0.8, + 0.2, + 0.8, + 0.3, + 0.8, + 1, + 0.411, + 0.8, + 0.522, + -0.3, + 0.633, + -0.3, + 1, + 1.244, + -0.3, + 1.856, + -0.3, + 2.467, + -0.3, + 1, + 2.7, + -0.3, + 2.933, + 0.3, + 3.167, + 0.3, + 1, + 3.422, + 0.3, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0.7, + 1, + 0.1, + 0.7, + 0.2, + 0.7, + 0.3, + 0.7, + 1, + 0.411, + 0.7, + 0.522, + 0.4, + 0.633, + 0.4, + 1, + 1.244, + 0.4, + 1.856, + 0.4, + 2.467, + 0.4, + 1, + 2.956, + 0.4, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0.7, + 1, + 0.1, + 0.7, + 0.2, + 0.7, + 0.3, + 0.7, + 1, + 0.411, + 0.7, + 0.522, + 0.4, + 0.633, + 0.4, + 1, + 1.244, + 0.4, + 1.856, + 0.4, + 2.467, + 0.4, + 1, + 2.956, + 0.4, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0.6, + 1, + 0.1, + 0.6, + 0.2, + 0.6, + 0.3, + 0.6, + 1, + 0.411, + 0.6, + 0.522, + -0.5, + 0.633, + -0.5, + 1, + 1.244, + -0.5, + 1.856, + -0.5, + 2.467, + -0.5, + 1, + 2.7, + -0.5, + 2.933, + 0.2, + 3.167, + 0.2, + 1, + 3.422, + 0.2, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0.6, + 1, + 0.1, + 0.6, + 0.2, + 0.6, + 0.3, + 0.6, + 1, + 0.411, + 0.6, + 0.522, + -0.5, + 0.633, + -0.5, + 1, + 1.244, + -0.5, + 1.856, + -0.5, + 2.467, + -0.5, + 1, + 2.7, + -0.5, + 2.933, + 0.2, + 3.167, + 0.2, + 1, + 3.422, + 0.2, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + -0.5, + 1, + 0.1, + -0.5, + 0.2, + -0.5, + 0.3, + -0.5, + 1, + 0.411, + -0.5, + 0.522, + -0.6, + 0.633, + -0.6, + 1, + 1.244, + -0.6, + 1.856, + -0.6, + 2.467, + -0.6, + 1, + 2.7, + -0.6, + 2.933, + 1, + 3.167, + 1, + 1, + 3.422, + 1, + 3.678, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0.5, + 0.633, + 0.5, + 1, + 1.244, + 0.5, + 1.856, + 0.5, + 2.467, + 0.5, + 1, + 2.7, + 0.5, + 2.933, + 0, + 3.167, + 0, + 1, + 3.422, + 0, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + -1, + 1, + 0.1, + -1, + 0.2, + -1, + 0.3, + -1, + 1, + 0.411, + -1, + 0.522, + -1, + 0.633, + -1, + 1, + 1.244, + -1, + 1.856, + -1, + 2.467, + -1, + 1, + 2.956, + -1, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 5, + 1, + 0.1, + 5, + 0.2, + 5.234, + 0.3, + 3.279, + 1, + 0.411, + 1.107, + 0.522, + -10, + 0.633, + -10, + 1, + 1.244, + -10, + 1.856, + -10, + 2.467, + -10, + 1, + 2.7, + -10, + 2.933, + 8, + 3.167, + 8, + 1, + 3.422, + 8, + 3.678, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 3, + 1, + 0.1, + 3, + 0.2, + 3, + 0.3, + 3, + 1, + 0.411, + 3, + 0.522, + 3, + 0.633, + 3, + 1, + 1.244, + 3, + 1.856, + 3, + 2.467, + 3, + 1, + 2.956, + 3, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + -7, + 1, + 0.1, + -7, + 0.2, + -7.215, + 0.3, + -5.509, + 1, + 0.411, + -3.613, + 0.522, + 6, + 0.633, + 6, + 1, + 1.244, + 6, + 1.856, + 6, + 2.467, + 6, + 1, + 2.956, + 6, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.7, + 1, + 0.1, + 0.7, + 0.2, + 1, + 0.3, + 1, + 1, + 0.411, + 1, + 0.522, + 1, + 0.633, + 1, + 1, + 1.244, + 1, + 1.856, + 0, + 2.467, + 0, + 1, + 2.611, + 0, + 2.756, + 0.331, + 2.9, + 0.5, + 1, + 3.244, + 0.902, + 3.589, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.7, + 1, + 0.1, + 0.7, + 0.2, + 1, + 0.3, + 1, + 1, + 0.411, + 1, + 0.522, + 1, + 0.633, + 1, + 1, + 1.244, + 1, + 1.856, + 0, + 2.467, + 0, + 1, + 2.611, + 0, + 2.756, + 0.331, + 2.9, + 0.5, + 1, + 3.244, + 0.902, + 3.589, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 4.7, + 1, + 0.1, + 4.7, + 0.2, + 4.7, + 0.3, + 4.7, + 1, + 0.411, + 4.7, + 0.522, + 4.7, + 0.633, + 4.7, + 1, + 0.767, + 4.7, + 0.9, + 4.2, + 1.033, + 4.2, + 1, + 1.178, + 4.2, + 1.322, + 4.656, + 1.467, + 4.656, + 1, + 1.611, + 4.656, + 1.756, + 4.555, + 1.9, + 4.555, + 1, + 2.089, + 4.555, + 2.278, + 4.55, + 2.467, + 4.6, + 1, + 2.611, + 4.638, + 2.756, + 5, + 2.9, + 5, + 1, + 3.244, + 5, + 3.589, + 5, + 3.933, + 5, + 0, + 4.933, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 4.7, + 1, + 0.1, + 4.7, + 0.2, + 4.7, + 0.3, + 4.7, + 1, + 0.411, + 4.7, + 0.522, + 4.7, + 0.633, + 4.7, + 1, + 0.767, + 4.7, + 0.9, + 4.2, + 1.033, + 4.2, + 1, + 1.178, + 4.2, + 1.322, + 4.65, + 1.467, + 4.65, + 1, + 1.611, + 4.65, + 1.756, + 4.529, + 1.9, + 4.529, + 1, + 2.089, + 4.529, + 2.278, + 4.525, + 2.467, + 4.6, + 1, + 2.611, + 4.658, + 2.756, + 5, + 2.9, + 5, + 1, + 3.244, + 5, + 3.589, + 5, + 3.933, + 5, + 0, + 4.933, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 1, + 1, + 0.1, + 1, + 0.2, + 1, + 0.3, + 1, + 1, + 0.411, + 1, + 0.522, + 1, + 0.633, + 1, + 1, + 1.244, + 1, + 1.856, + 1, + 2.467, + 1, + 1, + 2.956, + 1, + 3.444, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.1, + 1, + 0.1, + 0.1, + 0.2, + 0.1, + 0.3, + 0.1, + 1, + 0.411, + 0.1, + 0.522, + -0.9, + 0.633, + -0.9, + 1, + 0.844, + -0.9, + 1.056, + 0.2, + 1.267, + 0.2, + 1, + 1.422, + 0.2, + 1.578, + -0.6, + 1.733, + -0.6, + 1, + 1.978, + -0.6, + 2.222, + -0.6, + 2.467, + -0.6, + 1, + 2.956, + -0.6, + 3.444, + -0.1, + 3.933, + -0.1, + 0, + 4.933, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 1, + 1, + 0.1, + 1, + 0.2, + 1, + 0.3, + 1, + 1, + 0.411, + 1, + 0.522, + 1, + 0.633, + 1, + 1, + 1.244, + 1, + 1.856, + 1, + 2.467, + 1, + 1, + 2.956, + 1, + 3.444, + 1, + 3.933, + 1, + 0, + 4.933, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.1, + 1, + 0.1, + -0.1, + 0.2, + -0.1, + 0.3, + -0.1, + 1, + 0.411, + -0.1, + 0.522, + 1, + 0.633, + 1, + 1, + 0.844, + 1, + 1.056, + -0.2, + 1.267, + -0.2, + 1, + 1.422, + -0.2, + 1.578, + 0.6, + 1.733, + 0.6, + 1, + 1.978, + 0.6, + 2.222, + 0.6, + 2.467, + 0.6, + 1, + 2.956, + 0.6, + 3.444, + 0.1, + 3.933, + 0.1, + 0, + 4.933, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.411, + 0, + 0.522, + 0, + 0.633, + 0, + 1, + 1.244, + 0, + 1.856, + 0, + 2.467, + 0, + 1, + 2.956, + 0, + 3.444, + 0, + 3.933, + 0, + 0, + 4.933, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 1, + 2.72, + 1, + 2.81, + 0, + 2.9, + 0, + 2, + 4.9, + 0, + 0, + 4.93, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 1, + 0.88, + 1, + 1.76, + 1, + 2.63, + 1, + 1, + 2.72, + 1, + 2.81, + 0, + 2.9, + 0, + 2, + 4.9, + 0, + 0, + 4.93, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 1, + 0.88, + 0, + 1.76, + 0, + 2.63, + 0, + 1, + 2.72, + 0, + 2.81, + 1, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 1, + 0.88, + 0, + 1.76, + 0, + 2.63, + 0, + 1, + 2.72, + 0, + 2.81, + 1, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2.63, + 1, + 2, + 2.9, + 1, + 2, + 4.9, + 1, + 0, + 4.93, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2.63, + 0, + 2, + 2.9, + 0, + 2, + 4.9, + 0, + 0, + 4.93, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m13.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m13.motion3.json new file mode 100644 index 0000000..045dfe2 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m13.motion3.json @@ -0,0 +1,1133 @@ +{ + "Version": 3, + "Meta": { + "Duration": 2.53, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 135, + "TotalPointCount": 302, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 0.83, + 1, + 1.67, + 1, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + 0, + 0.467, + 0, + 1, + 0.533, + 0, + 0.6, + 0, + 0.667, + 0, + 1, + 0.878, + 0, + 1.089, + 0, + 1.3, + 0, + 1, + 1.378, + 0, + 1.456, + 0, + 1.533, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + 0, + 0.467, + 0, + 1, + 0.5, + 0, + 0.533, + -1, + 0.567, + -1, + 1, + 0.689, + -1, + 0.811, + 11, + 0.933, + 11, + 1, + 1.056, + 11, + 1.178, + -11, + 1.3, + -11, + 1, + 1.378, + -11, + 1.456, + 1, + 1.533, + 1, + 1, + 1.656, + 1, + 1.778, + 0, + 1.9, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 0.678, + 0, + 0.789, + -6, + 0.9, + -6, + 1, + 1.011, + -6, + 1.122, + 19, + 1.233, + 19, + 1, + 1.4, + 19, + 1.567, + 17, + 1.733, + 17, + 0, + 2.533, + 17 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 2, + 1, + 0.544, + 2, + 1.089, + 2, + 1.633, + 2, + 1, + 1.667, + 2, + 1.7, + 0, + 1.733, + 0, + 1, + 1.756, + 0, + 1.778, + 0, + 1.8, + 0, + 1, + 1.822, + 0, + 1.844, + 2, + 1.867, + 2, + 1, + 1.9, + 2, + 1.933, + 0, + 1.967, + 0, + 1, + 2.011, + 0, + 2.056, + 0, + 2.1, + 0, + 1, + 2.144, + 0, + 2.189, + 2, + 2.233, + 2, + 0, + 2.533, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 2, + 1, + 0.544, + 2, + 1.089, + 2, + 1.633, + 2, + 1, + 1.667, + 2, + 1.7, + 0, + 1.733, + 0, + 1, + 1.756, + 0, + 1.778, + 0, + 1.8, + 0, + 1, + 1.822, + 0, + 1.844, + 2, + 1.867, + 2, + 1, + 1.9, + 2, + 1.933, + 0, + 1.967, + 0, + 1, + 2.011, + 0, + 2.056, + 0, + 2.1, + 0, + 1, + 2.144, + 0, + 2.189, + 2, + 2.233, + 2, + 0, + 2.533, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.411, + 0, + 0.822, + 0.1, + 1.233, + 0.1, + 0, + 2.533, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.411, + 0, + 0.822, + 0.4, + 1.233, + 0.4, + 0, + 2.533, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 1, + 0, + 2.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 1, + 0, + 2.533, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + -0.84, + 0, + 2.533, + -0.84 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 0.678, + 0, + 0.789, + 5, + 0.9, + 5, + 1, + 1.011, + 5, + 1.122, + 0, + 1.233, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 0.678, + 0, + 0.789, + -1, + 0.9, + -1, + 1, + 1.011, + -1, + 1.122, + 6, + 1.233, + 6, + 0, + 2.533, + 6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 0.678, + 0, + 0.789, + -2, + 0.9, + -2, + 1, + 1.011, + -2, + 1.122, + 9, + 1.233, + 9, + 0, + 2.533, + 9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + -0.16, + 1, + 0.211, + -0.16, + 0.422, + -0.16, + 0.633, + -0.16, + 1, + 0.789, + -0.16, + 0.944, + 0, + 1.1, + 0, + 1, + 1.189, + 0, + 1.278, + -0.16, + 1.367, + -0.16, + 0, + 2.533, + -0.16 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + -0.15, + 1, + 0.211, + -0.15, + 0.422, + -0.15, + 0.633, + -0.15, + 1, + 0.789, + -0.15, + 0.944, + 0, + 1.1, + 0, + 1, + 1.189, + 0, + 1.278, + -0.15, + 1.367, + -0.15, + 0, + 2.533, + -0.15 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.267, + 0, + 0.533, + 0, + 0.8, + 0, + 1, + 0.911, + 0, + 1.022, + -0.53, + 1.133, + -0.53, + 1, + 1.233, + -0.53, + 1.333, + 0, + 1.433, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.267, + 0, + 0.533, + 0, + 0.8, + 0, + 1, + 0.911, + 0, + 1.022, + 0.54, + 1.133, + 0.54, + 1, + 1.233, + 0.54, + 1.333, + 0, + 1.433, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 2.533, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 2.5, + 0, + 0, + 2.53, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 2.5, + 0, + 0, + 2.53, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2.5, + 1, + 0, + 2.53, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2.5, + 0, + 0, + 2.53, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m14.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m14.motion3.json new file mode 100644 index 0000000..a0c55c0 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m14.motion3.json @@ -0,0 +1,2176 @@ +{ + "Version": 3, + "Meta": { + "Duration": 3.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 284, + "TotalPointCount": 749, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + 1, + 0.767, + 1, + 1, + 0.889, + 1, + 1.011, + 1.06, + 1.133, + 0.632, + 1, + 1.256, + 0.204, + 1.378, + -2, + 1.5, + -2, + 1, + 2, + -2, + 2.5, + -2, + 3, + -2, + 0, + 3.033, + -2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.122, + 0, + 0.244, + 0, + 0.367, + 0, + 1, + 0.433, + 0, + 0.5, + -1, + 0.567, + -1, + 1, + 0.689, + -1, + 0.811, + 16, + 0.933, + 16, + 1, + 1.067, + 16, + 1.2, + 16.106, + 1.333, + 13.915, + 1, + 1.444, + 12.09, + 1.556, + -1, + 1.667, + -1, + 1, + 2.111, + -1, + 2.556, + -1, + 3, + -1, + 0, + 3.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.211, + 0, + 0.422, + 0, + 0.633, + 0, + 1, + 0.767, + 0, + 0.9, + -9, + 1.033, + -9, + 1, + 1.1, + -9, + 1.167, + -9.696, + 1.233, + -5.567, + 1, + 1.356, + 2.004, + 1.478, + 15.49, + 1.6, + 19, + 1, + 1.778, + 19.291, + 1.956, + 18, + 2.133, + 18, + 1, + 2.422, + 18, + 2.711, + 18, + 3, + 18, + 0, + 3.033, + 18 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.167, + 1, + 0.333, + 1, + 0.5, + 1, + 1, + 0.589, + 1, + 0.678, + 0, + 0.767, + 0, + 1, + 0.8, + 0, + 0.833, + 0, + 0.867, + 0, + 1, + 0.956, + 0, + 1.044, + 1.332, + 1.133, + 1.616, + 1, + 1.256, + 2.007, + 1.378, + 2, + 1.5, + 2, + 1, + 1.667, + 2, + 1.833, + 2, + 2, + 2, + 1, + 2.044, + 2, + 2.089, + 0, + 2.133, + 0, + 1, + 2.167, + 0, + 2.2, + 0, + 2.233, + 0, + 1, + 2.311, + 0, + 2.389, + 2, + 2.467, + 2, + 1, + 2.644, + 2, + 2.822, + 2, + 3, + 2, + 0, + 3.033, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.167, + 1, + 0.333, + 1, + 0.5, + 1, + 1, + 0.589, + 1, + 0.678, + 0, + 0.767, + 0, + 1, + 0.8, + 0, + 0.833, + 0, + 0.867, + 0, + 1, + 0.956, + 0, + 1.044, + 1.332, + 1.133, + 1.616, + 1, + 1.256, + 2.007, + 1.378, + 2, + 1.5, + 2, + 1, + 1.667, + 2, + 1.833, + 2, + 2, + 2, + 1, + 2.044, + 2, + 2.089, + 0, + 2.133, + 0, + 1, + 2.167, + 0, + 2.2, + 0, + 2.233, + 0, + 1, + 2.311, + 0, + 2.389, + 2, + 2.467, + 2, + 1, + 2.644, + 2, + 2.822, + 2, + 3, + 2, + 0, + 3.033, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0.3, + 1.5, + 0.3, + 1, + 2, + 0.3, + 2.5, + 0.3, + 3, + 0.3, + 0, + 3.033, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.039, + 1.133, + 0.123, + 1, + 1.256, + 0.172, + 1.378, + 0.2, + 1.5, + 0.2, + 1, + 1.667, + 0.2, + 1.833, + 0.2, + 2, + 0.2, + 1, + 2.044, + 0.2, + 2.089, + -0.2, + 2.133, + -0.2, + 1, + 2.167, + -0.2, + 2.2, + -0.2, + 2.233, + -0.2, + 1, + 2.311, + -0.2, + 2.389, + 0.2, + 2.467, + 0.2, + 1, + 2.644, + 0.2, + 2.822, + 0.2, + 3, + 0.2, + 0, + 3.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + -0.1, + 0.767, + -0.1, + 1, + 0.8, + -0.1, + 0.833, + -0.1, + 0.867, + -0.1, + 1, + 0.956, + -0.1, + 1.044, + 0.291, + 1.133, + 0.493, + 1, + 1.256, + 0.77, + 1.378, + 0.8, + 1.5, + 0.8, + 1, + 2, + 0.8, + 2.5, + 0.8, + 3, + 0.8, + 0, + 3.033, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + -0.1, + 0.767, + -0.1, + 1, + 0.8, + -0.1, + 0.833, + -0.1, + 0.867, + -0.1, + 1, + 0.956, + -0.1, + 1.044, + 0.291, + 1.133, + 0.493, + 1, + 1.256, + 0.77, + 1.378, + 0.8, + 1.5, + 0.8, + 1, + 2, + 0.8, + 2.5, + 0.8, + 3, + 0.8, + 0, + 3.033, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.039, + 1.133, + 0.123, + 1, + 1.256, + 0.172, + 1.378, + 0.2, + 1.5, + 0.2, + 1, + 2, + 0.2, + 2.5, + 0.2, + 3, + 0.2, + 0, + 3.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.039, + 1.133, + 0.123, + 1, + 1.256, + 0.172, + 1.378, + 0.2, + 1.5, + 0.2, + 1, + 2, + 0.2, + 2.5, + 0.2, + 3, + 0.2, + 0, + 3.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.039, + 1.133, + 0.123, + 1, + 1.256, + 0.172, + 1.378, + 0.2, + 1.5, + 0.2, + 1, + 2, + 0.2, + 2.5, + 0.2, + 3, + 0.2, + 0, + 3.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.039, + 1.133, + 0.123, + 1, + 1.256, + 0.172, + 1.378, + 0.2, + 1.5, + 0.2, + 1, + 2, + 0.2, + 2.5, + 0.2, + 3, + 0.2, + 0, + 3.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.078, + 1.133, + 0.246, + 1, + 1.256, + 0.344, + 1.378, + 0.4, + 1.5, + 0.4, + 1, + 2, + 0.4, + 2.5, + 0.4, + 3, + 0.4, + 0, + 3.033, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0.078, + 1.133, + 0.246, + 1, + 1.256, + 0.344, + 1.378, + 0.4, + 1.5, + 0.4, + 1, + 2, + 0.4, + 2.5, + 0.4, + 3, + 0.4, + 0, + 3.033, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.167, + 1, + 0.333, + 1, + 0.5, + 1, + 1, + 0.589, + 1, + 0.678, + -0.5, + 0.767, + -0.5, + 1, + 0.889, + -0.5, + 1.011, + -0.232, + 1.133, + -0.232, + 1, + 1.256, + -0.232, + 1.378, + -1, + 1.5, + -1, + 1, + 2, + -1, + 2.5, + -1, + 3, + -1, + 0, + 3.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + 3, + 0.767, + 3, + 1, + 0.889, + 3, + 1.011, + 1.294, + 1.133, + -0.616, + 1, + 1.256, + -2.526, + 1.378, + -3, + 1.5, + -3, + 1, + 2, + -3, + 2.5, + -3, + 3, + -3, + 0, + 3.033, + -3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 7, + 1.133, + 7, + 1, + 1.256, + 7, + 1.378, + -9, + 1.5, + -9, + 1, + 2, + -9, + 2.5, + -9, + 3, + -9, + 0, + 3.033, + -9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + -4.509, + 0.767, + -4.728, + 1, + 0.889, + -5.029, + 1.011, + -5, + 1.133, + -5, + 1, + 1.256, + -5, + 1.378, + 7, + 1.5, + 7, + 1, + 2, + 7, + 2.5, + 7, + 3, + 7, + 0, + 3.033, + 7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + -1.507, + 0.767, + -1.507, + 1, + 0.889, + -1.507, + 1.011, + -1.675, + 1.133, + -0.529, + 1, + 1.256, + 0.618, + 1.378, + 10, + 1.5, + 10, + 1, + 2, + 10, + 2.5, + 10, + 3, + 10, + 0, + 3.033, + 10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.167, + 1, + 0.333, + 1, + 0.5, + 1, + 1, + 0.711, + 1, + 0.922, + 0.3, + 1.133, + 0.3, + 1, + 1.256, + 0.3, + 1.378, + 0.327, + 1.5, + 0.4, + 1, + 1.6, + 0.459, + 1.7, + 0.5, + 1.8, + 0.5, + 1, + 2.2, + 0.5, + 2.6, + 0.5, + 3, + 0.5, + 0, + 3.033, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.167, + 1, + 0.333, + 1, + 0.5, + 1, + 1, + 0.711, + 1, + 0.922, + 0.3, + 1.133, + 0.3, + 1, + 1.256, + 0.3, + 1.378, + 0.327, + 1.5, + 0.4, + 1, + 1.6, + 0.459, + 1.7, + 0.5, + 1.8, + 0.5, + 1, + 2.2, + 0.5, + 2.6, + 0.5, + 3, + 0.5, + 0, + 3.033, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.744, + 0, + 0.989, + 0, + 1.233, + 0, + 1, + 1.467, + 0, + 1.7, + 0, + 1.933, + 0, + 1, + 2.289, + 0, + 2.644, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + 0.9, + 0.767, + 0.9, + 1, + 0.922, + 0.9, + 1.078, + 0.681, + 1.233, + 0, + 1, + 1.344, + -0.486, + 1.456, + -0.9, + 1.567, + -0.9, + 1, + 1.689, + -0.9, + 1.811, + -0.6, + 1.933, + -0.6, + 1, + 2.289, + -0.6, + 2.644, + -0.6, + 3, + -0.6, + 0, + 3.033, + -0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.744, + 0, + 0.989, + 0, + 1.233, + 0, + 1, + 1.467, + 0, + 1.7, + 0, + 1.933, + 0, + 1, + 2.289, + 0, + 2.644, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.589, + 0, + 0.678, + -0.9, + 0.767, + -0.9, + 1, + 0.922, + -0.9, + 1.078, + -0.681, + 1.233, + 0, + 1, + 1.344, + 0.486, + 1.456, + 0.9, + 1.567, + 0.9, + 1, + 1.689, + 0.9, + 1.811, + 0.6, + 1.933, + 0.6, + 1, + 2.289, + 0.6, + 2.644, + 0.6, + 3, + 0.6, + 0, + 3.033, + 0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.167, + 0, + 0.333, + 0, + 0.5, + 0, + 1, + 0.711, + 0, + 0.922, + 0, + 1.133, + 0, + 1, + 1.256, + 0, + 1.378, + 0, + 1.5, + 0, + 1, + 2, + 0, + 2.5, + 0, + 3, + 0, + 0, + 3.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 3, + 0, + 0, + 3.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 3, + 0, + 0, + 3.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3, + 1, + 0, + 3.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3, + 0, + 0, + 3.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m15.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m15.motion3.json new file mode 100644 index 0000000..c774ddf --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m15.motion3.json @@ -0,0 +1,1357 @@ +{ + "Version": 3, + "Meta": { + "Duration": 5.33, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 167, + "TotalPointCount": 398, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.77, + 1, + 3.53, + 1, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + -3, + 0.6, + -3, + 1, + 1.333, + -3, + 2.067, + -3, + 2.8, + -3, + 1, + 3.056, + -3, + 3.311, + 1, + 3.567, + 1, + 1, + 3.833, + 1, + 4.1, + 0, + 4.367, + 0, + 1, + 4.678, + 0, + 4.989, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + -10, + 0.6, + -10, + 1, + 1.333, + -10, + 2.067, + -10, + 2.8, + -10, + 1, + 3.056, + -10, + 3.311, + 11, + 3.567, + 11, + 1, + 3.833, + 11, + 4.1, + 0, + 4.367, + 0, + 1, + 4.678, + 0, + 4.989, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.211, + 0, + 0.422, + -30, + 0.633, + -30, + 1, + 0.689, + -30, + 0.744, + -30, + 0.8, + -30, + 1, + 1.1, + -30, + 1.4, + 30, + 1.7, + 30, + 1, + 1.744, + 30, + 1.789, + 30, + 1.833, + 30, + 1, + 2.167, + 30, + 2.5, + -30, + 2.833, + -30, + 1, + 2.878, + -30, + 2.922, + -30, + 2.967, + -30, + 1, + 3.222, + -30, + 3.478, + 0, + 3.733, + 0, + 1, + 4.256, + 0, + 4.778, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 1.767, + 1, + 3.533, + 1, + 5.3, + 1, + 0, + 5.333, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 1.767, + 1, + 3.533, + 1, + 5.3, + 1, + 0, + 5.333, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + 0.03, + 0.6, + 0.03, + 1, + 0.989, + 0.03, + 1.378, + 0.03, + 1.767, + 0.03, + 1, + 2.144, + 0.03, + 2.522, + 0.03, + 2.9, + 0.03, + 1, + 3.1, + 0.03, + 3.3, + -0.1, + 3.5, + -0.1, + 1, + 3.767, + -0.1, + 4.033, + 0, + 4.3, + 0, + 1, + 4.633, + 0, + 4.967, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + 0.67, + 0.6, + 0.67, + 1, + 0.989, + 0.67, + 1.378, + 0.67, + 1.767, + 0.67, + 1, + 2.144, + 0.67, + 2.522, + 0.67, + 2.9, + 0.67, + 1, + 3.1, + 0.67, + 3.3, + -0.21, + 3.5, + -0.21, + 1, + 3.767, + -0.21, + 4.033, + 0, + 4.3, + 0, + 1, + 4.633, + 0, + 4.967, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 1.767, + 1, + 3.533, + 1, + 5.3, + 1, + 0, + 5.333, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.322, + 0, + 0.644, + 6, + 0.967, + 6, + 1, + 1.322, + 6, + 1.678, + -2, + 2.033, + -2, + 1, + 2.344, + -2, + 2.656, + 0, + 2.967, + 0, + 1, + 3.178, + 0, + 3.389, + -3, + 3.6, + -3, + 1, + 3.833, + -3, + 4.067, + 0, + 4.3, + 0, + 1, + 4.633, + 0, + 4.967, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.967, + 0, + 1.933, + 0, + 2.9, + 0, + 1, + 3.111, + 0, + 3.322, + 2, + 3.533, + 2, + 1, + 3.767, + 2, + 4, + 0, + 4.233, + 0, + 1, + 4.589, + 0, + 4.944, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.75, + 0.467, + 0.76, + 1, + 1.978, + 0.855, + 3.489, + 0.89, + 5, + 0.89, + 1, + 5.1, + 0.89, + 5.2, + 0.5, + 5.3, + 0.5, + 0, + 5.333, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.156, + 0.5, + 0.311, + 0.746, + 0.467, + 0.76, + 1, + 1.978, + 0.899, + 3.489, + 0.95, + 5, + 0.95, + 1, + 5.1, + 0.95, + 5.2, + 0.5, + 5.3, + 0.5, + 0, + 5.333, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.24, + 1, + 0.356, + 0.24, + 0.711, + 0, + 1.067, + 0, + 1, + 1.389, + 0, + 1.711, + 0.24, + 2.033, + 0.24, + 1, + 3.122, + 0.24, + 4.211, + 0.24, + 5.3, + 0.24, + 0, + 5.333, + 0.24 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.24, + 1, + 0.356, + -0.24, + 0.711, + 0, + 1.067, + 0, + 1, + 1.389, + 0, + 1.711, + -0.24, + 2.033, + -0.24, + 1, + 3.122, + -0.24, + 4.211, + -0.24, + 5.3, + -0.24, + 0, + 5.333, + -0.24 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.767, + 0, + 3.533, + 0, + 5.3, + 0, + 0, + 5.333, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 5.3, + 0, + 0, + 5.33, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 5.3, + 0, + 0, + 5.33, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 5.3, + 1, + 0, + 5.33, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 5.3, + 0, + 0, + 5.33, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m16.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m16.motion3.json new file mode 100644 index 0000000..aa0e834 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m16.motion3.json @@ -0,0 +1,1917 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 247, + "TotalPointCount": 638, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.32, + 1, + 2.64, + 1, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 2, + 1, + 0.333, + 2, + 0.667, + 2, + 1, + 2, + 1, + 1.133, + 2, + 1.267, + 2, + 1.4, + 2, + 1, + 1.511, + 2, + 1.622, + 2.132, + 1.733, + 1.634, + 1, + 1.878, + 0.986, + 2.022, + -4, + 2.167, + -4, + 1, + 2.367, + -4, + 2.567, + 0, + 2.767, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 3, + 1, + 0.267, + 3, + 0.533, + 3, + 0.8, + 3, + 1, + 0.878, + 3, + 0.956, + -4, + 1.033, + -4, + 1, + 1.189, + -4, + 1.344, + 2.269, + 1.5, + 11, + 1, + 1.611, + 17.237, + 1.722, + 19, + 1.833, + 19, + 1, + 1.978, + 19, + 2.122, + -28, + 2.267, + -28, + 1, + 2.467, + -28, + 2.667, + -23, + 2.867, + -23, + 0, + 4, + -23 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + -7, + 1, + 0.4, + -7, + 0.8, + -7, + 1.2, + -7, + 1, + 1.333, + -7, + 1.467, + 19, + 1.6, + 19, + 1, + 1.711, + 19, + 1.822, + 19.636, + 1.933, + 16.192, + 1, + 2.078, + 11.714, + 2.222, + -27, + 2.367, + -27, + 1, + 2.567, + -27, + 2.767, + -23, + 2.967, + -23, + 0, + 4, + -23 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.5, + 1.4, + 0.5, + 1, + 1.511, + 0.5, + 1.622, + 0.5, + 1.733, + 0.5, + 1, + 1.878, + 0.5, + 2.022, + 0.5, + 2.167, + 0.5, + 0, + 4, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.133, + 1, + 1.267, + 1.6, + 1.4, + 1.6, + 1, + 1.511, + 1.6, + 1.622, + 1.502, + 1.733, + 1.502, + 1, + 1.767, + 1.502, + 1.8, + 1.8, + 1.833, + 1.8, + 1, + 1.944, + 1.8, + 2.056, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0, + 1.4, + 0, + 1, + 1.511, + 0, + 1.622, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.133, + 1, + 1.267, + 1.6, + 1.4, + 1.6, + 1, + 1.511, + 1.6, + 1.622, + 1.502, + 1.733, + 1.502, + 1, + 1.767, + 1.502, + 1.8, + 1.8, + 1.833, + 1.8, + 1, + 1.944, + 1.8, + 2.056, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0, + 1.4, + 0, + 1, + 1.511, + 0, + 1.622, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0.015, + 1.733, + 0.186, + 1, + 1.878, + 0.286, + 2.022, + 0.6, + 2.167, + 0.6, + 0, + 4, + 0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0, + 1.4, + 0, + 1, + 1.511, + 0, + 1.622, + -0.023, + 1.733, + 0.061, + 1, + 1.878, + 0.171, + 2.022, + 1, + 2.167, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0, + 1.4, + 0, + 1, + 1.511, + 0, + 1.622, + 0.031, + 1.733, + 0.031, + 1, + 1.878, + 0.031, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + -0.2, + 1.4, + -0.2, + 1, + 1.511, + -0.2, + 1.622, + -0.157, + 1.733, + -0.157, + 1, + 1.878, + -0.157, + 2.022, + -0.4, + 2.167, + -0.4, + 0, + 4, + -0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.7, + 1.4, + 0.7, + 1, + 1.511, + 0.7, + 1.622, + 0.735, + 1.733, + 0.608, + 1, + 1.878, + 0.444, + 2.022, + -0.8, + 2.167, + -0.8, + 0, + 4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.7, + 1.4, + 0.7, + 1, + 1.511, + 0.7, + 1.622, + 0.735, + 1.733, + 0.608, + 1, + 1.878, + 0.444, + 2.022, + -0.8, + 2.167, + -0.8, + 0, + 4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.1, + 1.4, + 0.1, + 1, + 1.511, + 0.1, + 1.622, + 0.112, + 1.733, + 0.069, + 1, + 1.878, + 0.015, + 2.022, + -0.4, + 2.167, + -0.4, + 0, + 4, + -0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.1, + 1.4, + 0.1, + 1, + 1.511, + 0.1, + 1.622, + 0.112, + 1.733, + 0.069, + 1, + 1.878, + 0.015, + 2.022, + -0.4, + 2.167, + -0.4, + 0, + 4, + -0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.7, + 1.4, + 0.7, + 1, + 1.511, + 0.7, + 1.622, + 0.4, + 1.733, + 0.4, + 1, + 1.878, + 0.4, + 2.022, + 0.8, + 2.167, + 0.8, + 0, + 4, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.7, + 1.4, + 0.7, + 1, + 1.511, + 0.7, + 1.622, + 0.4, + 1.733, + 0.4, + 1, + 1.878, + 0.4, + 2.022, + 0.8, + 2.167, + 0.8, + 0, + 4, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + -0.451, + 1.4, + -0.7, + 1, + 1.511, + -0.908, + 1.622, + -0.9, + 1.733, + -0.9, + 1, + 1.878, + -0.9, + 2.022, + -0.8, + 2.167, + -0.8, + 0, + 4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + -0.451, + 1.4, + -0.7, + 1, + 1.511, + -0.908, + 1.622, + -0.9, + 1.733, + -0.9, + 1, + 1.878, + -0.9, + 2.022, + -0.8, + 2.167, + -0.8, + 0, + 4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.133, + 1, + 1.267, + -0.37, + 1.4, + -0.4, + 1, + 1.511, + -0.425, + 1.622, + -0.417, + 1.733, + -0.435, + 1, + 1.878, + -0.459, + 2.022, + -0.5, + 2.167, + -0.5, + 0, + 4, + -0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 0.4, + 1.4, + 0.4, + 1, + 1.511, + 0.4, + 1.622, + 0.409, + 1.733, + 0.376, + 1, + 1.878, + 0.332, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.322, + 0, + 0.644, + 0, + 0.967, + 0, + 1, + 1.1, + 0, + 1.233, + 5, + 1.367, + 5, + 1, + 1.478, + 5, + 1.589, + 5.238, + 1.7, + 4.267, + 1, + 1.844, + 3.005, + 1.989, + -7, + 2.133, + -7, + 1, + 2.333, + -7, + 2.533, + -6, + 2.733, + -6, + 0, + 4, + -6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + 3, + 1.4, + 3, + 1, + 1.511, + 3, + 1.622, + 3.254, + 1.733, + 2.206, + 1, + 1.878, + 0.845, + 2.022, + -10, + 2.167, + -10, + 1, + 2.367, + -10, + 2.567, + -9, + 2.767, + -9, + 0, + 4, + -9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.389, + 0, + 0.778, + 0, + 1.167, + 0, + 1, + 1.3, + 0, + 1.433, + 2, + 1.567, + 2, + 1, + 1.678, + 2, + 1.789, + 2.188, + 1.9, + 1.451, + 1, + 2.044, + 0.491, + 2.189, + -7, + 2.333, + -7, + 1, + 2.533, + -7, + 2.733, + -6, + 2.933, + -6, + 0, + 4, + -6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.133, + 0, + 1.267, + -3, + 1.4, + -3, + 1, + 1.511, + -3, + 1.622, + -3.069, + 1.733, + -2.817, + 1, + 1.878, + -2.489, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.244, + 1, + 1.489, + 1, + 1.733, + 1, + 1, + 1.878, + 1, + 2.022, + 1, + 2.167, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.244, + 1, + 1.489, + 1, + 1.733, + 1, + 1, + 1.878, + 1, + 2.022, + 1, + 2.167, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 2.7, + 1, + 0.333, + 2.7, + 0.667, + 2.7, + 1, + 2.7, + 1, + 1.133, + 2.7, + 1.267, + 4.3, + 1.4, + 4.3, + 1, + 1.511, + 4.3, + 1.622, + 4.356, + 1.733, + 4.19, + 1, + 1.922, + 3.907, + 2.111, + 2.5, + 2.3, + 2.5, + 0, + 4, + 2.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 2.7, + 1, + 0.333, + 2.7, + 0.667, + 2.7, + 1, + 2.7, + 1, + 1.133, + 2.7, + 1.267, + 4.3, + 1.4, + 4.3, + 1, + 1.511, + 4.3, + 1.622, + 4.356, + 1.733, + 4.19, + 1, + 1.922, + 3.907, + 2.111, + 2.5, + 2.3, + 2.5, + 0, + 4, + 2.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0.5, + 1, + 0.333, + 0.5, + 0.667, + 0.5, + 1, + 0.5, + 1, + 1.311, + 0.5, + 1.622, + 0.5, + 1.933, + 0.5, + 1, + 2.178, + 0.5, + 2.422, + 0.5, + 2.667, + 0.5, + 0, + 4, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.3, + 1, + 0.333, + 0.3, + 0.667, + 0.3, + 1, + 0.3, + 1, + 1.078, + 0.3, + 1.156, + 1, + 1.233, + 1, + 1, + 1.356, + 1, + 1.478, + 0.4, + 1.6, + 0.4, + 1, + 1.711, + 0.4, + 1.822, + 0.387, + 1.933, + 0.327, + 1, + 2.178, + 0.255, + 2.422, + 0.2, + 2.667, + 0.2, + 0, + 4, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.311, + 0, + 1.622, + 0, + 1.933, + 0, + 1, + 2.178, + 0, + 2.422, + 0, + 2.667, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.17, + 1, + 0.333, + -0.17, + 0.667, + -0.17, + 1, + -0.17, + 1, + 1.078, + -0.17, + 1.156, + -1, + 1.233, + -1, + 1, + 1.356, + -1, + 1.478, + -0.4, + 1.6, + -0.4, + 1, + 1.711, + -0.4, + 1.822, + -0.379, + 1.933, + -0.333, + 1, + 2.178, + -0.262, + 2.422, + -0.2, + 2.667, + -0.2, + 0, + 4, + -0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.244, + 0, + 1.489, + 0, + 1.733, + 0, + 1, + 1.878, + 0, + 2.022, + 0, + 2.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 3.97, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 3.97, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.97, + 0, + 0, + 4, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m17.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m17.motion3.json new file mode 100644 index 0000000..3057b7a --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m17.motion3.json @@ -0,0 +1,1637 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.5, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 207, + "TotalPointCount": 518, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.49, + 1, + 2.98, + 1, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.4, + 0, + 1.7, + -5, + 2, + -5, + 1, + 2.244, + -5, + 2.489, + 17, + 2.733, + 17, + 1, + 3.311, + 17, + 3.889, + 17, + 4.467, + 17, + 0, + 4.5, + 17 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.4, + 0, + 1.7, + 6.189, + 2, + 8, + 1, + 2.211, + 9.275, + 2.422, + 9, + 2.633, + 9, + 1, + 2.9, + 9, + 3.167, + -8, + 3.433, + -8, + 1, + 3.778, + -8, + 4.122, + -8, + 4.467, + -8, + 0, + 4.5, + -8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.922, + 0, + 2.744, + -10, + 3.567, + -10, + 1, + 3.867, + -10, + 4.167, + -10, + 4.467, + -10, + 0, + 4.5, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0.5, + 1, + 0.744, + 0.5, + 1.489, + 0.5, + 2.233, + 0.5, + 1, + 2.389, + 0.5, + 2.544, + 1, + 2.7, + 1, + 1, + 3.289, + 1, + 3.878, + 1, + 4.467, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 0.91, + 1, + 0.367, + 0.91, + 0.733, + 0.91, + 1.1, + 0.91, + 1, + 1.689, + 0.91, + 2.278, + 0.91, + 2.867, + 0.91, + 1, + 2.922, + 0.91, + 2.978, + 0, + 3.033, + 0, + 1, + 3.1, + 0, + 3.167, + 0, + 3.233, + 0, + 1, + 3.311, + 0, + 3.389, + 0.91, + 3.467, + 0.91, + 1, + 3.8, + 0.91, + 4.133, + 0.91, + 4.467, + 0.91, + 0, + 4.5, + 0.91 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 0.9, + 1, + 0.367, + 0.9, + 0.733, + 0.9, + 1.1, + 0.9, + 1, + 1.689, + 0.9, + 2.278, + 0.9, + 2.867, + 0.9, + 1, + 2.922, + 0.9, + 2.978, + 0, + 3.033, + 0, + 1, + 3.1, + 0, + 3.167, + 0, + 3.233, + 0, + 1, + 3.311, + 0, + 3.389, + 0.9, + 3.467, + 0.9, + 1, + 3.8, + 0.9, + 4.133, + 0.9, + 4.467, + 0.9, + 0, + 4.5, + 0.9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.378, + 0, + 1.656, + 0.06, + 1.933, + 0.06, + 1, + 2.411, + 0.06, + 2.889, + -0.58, + 3.367, + -0.58, + 1, + 3.733, + -0.58, + 4.1, + -0.58, + 4.467, + -0.58, + 0, + 4.5, + -0.58 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.378, + 0, + 1.656, + -0.08, + 1.933, + -0.08, + 1, + 2.411, + -0.08, + 2.889, + 0.83, + 3.367, + 0.83, + 1, + 3.733, + 0.83, + 4.1, + 0.83, + 4.467, + 0.83, + 0, + 4.5, + 0.83 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + -0.37, + 1, + 0.7, + -0.37, + 1.4, + -0.37, + 2.1, + -0.37, + 1, + 2.267, + -0.37, + 2.433, + -0.37, + 2.6, + -0.37, + 1, + 3.222, + -0.37, + 3.844, + -0.37, + 4.467, + -0.37, + 0, + 4.5, + -0.37 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + -0.37, + 1, + 0.7, + -0.37, + 1.4, + -0.37, + 2.1, + -0.37, + 1, + 2.267, + -0.37, + 2.433, + -0.37, + 2.6, + -0.37, + 1, + 3.222, + -0.37, + 3.844, + -0.37, + 4.467, + -0.37, + 0, + 4.5, + -0.37 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.7, + 0, + 1.4, + 0, + 2.1, + 0, + 1, + 2.267, + 0, + 2.433, + 0, + 2.6, + 0, + 1, + 3.222, + 0, + 3.844, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.7, + 0, + 1.4, + 0, + 2.1, + 0, + 1, + 2.267, + 0, + 2.433, + 0, + 2.6, + 0, + 1, + 3.222, + 0, + 3.844, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0.18, + 1, + 0.7, + 0.18, + 1.4, + 0.18, + 2.1, + 0.18, + 1, + 2.267, + 0.18, + 2.433, + 0.18, + 2.6, + 0.18, + 1, + 3.222, + 0.18, + 3.844, + 0.18, + 4.467, + 0.18, + 0, + 4.5, + 0.18 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0.28, + 1, + 0.7, + 0.28, + 1.4, + 0.28, + 2.1, + 0.28, + 1, + 2.267, + 0.28, + 2.433, + 0.28, + 2.6, + 0.28, + 1, + 3.222, + 0.28, + 3.844, + 0.28, + 4.467, + 0.28, + 0, + 4.5, + 0.28 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.7, + 0, + 1.4, + 0, + 2.1, + 0, + 1, + 2.267, + 0, + 2.433, + -0.64, + 2.6, + -0.64, + 1, + 3.222, + -0.64, + 3.844, + -0.64, + 4.467, + -0.64, + 0, + 4.5, + -0.64 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.7, + 0, + 1.4, + 0, + 2.1, + 0, + 1, + 2.267, + 0, + 2.433, + -0.51, + 2.6, + -0.51, + 1, + 3.222, + -0.51, + 3.844, + -0.51, + 4.467, + -0.51, + 0, + 4.5, + -0.51 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.367, + 1, + 0.733, + 1, + 1.1, + 1, + 1, + 2.222, + 1, + 3.344, + 1, + 4.467, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.278, + 0, + 1.456, + -6, + 1.633, + -6, + 1, + 2.2, + -6, + 2.767, + 10, + 3.333, + 10, + 1, + 3.711, + 10, + 4.089, + 10, + 4.467, + 10, + 0, + 4.5, + 10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.311, + 0, + 1.522, + 3, + 1.733, + 3, + 1, + 2.211, + 3, + 2.689, + -10, + 3.167, + -10, + 1, + 3.6, + -10, + 4.033, + -10, + 4.467, + -10, + 0, + 4.5, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.356, + 0, + 1.611, + -1.366, + 1.867, + -2, + 1, + 2.233, + -2.91, + 2.6, + -3, + 2.967, + -3, + 1, + 3.467, + -3, + 3.967, + -3, + 4.467, + -3, + 0, + 4.5, + -3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.389, + 0, + 1.678, + -4, + 1.967, + -4, + 1, + 2.244, + -4, + 2.522, + 7, + 2.8, + 7, + 1, + 3.356, + 7, + 3.911, + 7, + 4.467, + 7, + 0, + 4.5, + 7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + -1, + 1, + 0.367, + -1, + 0.733, + -1, + 1.1, + -1, + 1, + 1.411, + -1, + 1.722, + -0.9, + 2.033, + -0.9, + 1, + 2.522, + -0.9, + 3.011, + -1, + 3.5, + -1, + 1, + 3.822, + -1, + 4.144, + -1, + 4.467, + -1, + 0, + 4.5, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + -1, + 1, + 0.367, + -1, + 0.733, + -1, + 1.1, + -1, + 1, + 1.411, + -1, + 1.722, + -0.91, + 2.033, + -0.91, + 1, + 2.522, + -0.91, + 3.011, + -1, + 3.5, + -1, + 1, + 3.822, + -1, + 4.144, + -1, + 4.467, + -1, + 0, + 4.5, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 2.222, + 0, + 3.344, + 0, + 4.467, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 4.47, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 4.47, + 0, + 0, + 4.5, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4.47, + 1, + 0, + 4.5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4.47, + 0, + 0, + 4.5, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m18.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m18.motion3.json new file mode 100644 index 0000000..192a3a1 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m18.motion3.json @@ -0,0 +1,1343 @@ +{ + "Version": 3, + "Meta": { + "Duration": 3.2, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 165, + "TotalPointCount": 392, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.06, + 1, + 2.11, + 1, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + -30, + 0.567, + -30, + 1, + 0.733, + -30, + 0.9, + -30.83, + 1.067, + -25, + 1, + 1.267, + -18.004, + 1.467, + 30, + 1.667, + 30, + 1, + 1.944, + 30, + 2.222, + 0, + 2.5, + 0, + 1, + 2.722, + 0, + 2.944, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 1, + 1, + 1.056, + 1, + 2.111, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 0, + 1, + 0.4, + 0, + 0.8, + 0, + 1.2, + 0, + 1, + 1.333, + 0, + 1.467, + 1.17, + 1.6, + 1.17, + 1, + 1.711, + 1.17, + 1.822, + 1, + 1.933, + 1, + 1, + 2.122, + 1, + 2.311, + 1, + 2.5, + 1, + 1, + 2.722, + 1, + 2.944, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 1, + 1, + 1.056, + 1, + 2.111, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 0, + 1, + 0.4, + 0, + 0.8, + 0, + 1.2, + 0, + 1, + 1.333, + 0, + 1.467, + 1.17, + 1.6, + 1.17, + 1, + 1.711, + 1.17, + 1.822, + 1, + 1.933, + 1, + 1, + 2.122, + 1, + 2.311, + 1, + 2.5, + 1, + 1, + 2.722, + 1, + 2.944, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 1, + 1, + 1.056, + 1, + 2.111, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + -1, + 1, + 0.311, + -1, + 0.622, + -1, + 0.933, + -1, + 1, + 1.022, + -1, + 1.111, + -1, + 1.2, + -1, + 1, + 1.333, + -1, + 1.467, + 0.21, + 1.6, + 0.21, + 1, + 2.122, + 0.21, + 2.644, + 0.21, + 3.167, + 0.21, + 0, + 3.2, + 0.21 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + -1, + 1, + 0.311, + -1, + 0.622, + -1, + 0.933, + -1, + 1, + 1.022, + -1, + 1.111, + -1, + 1.2, + -1, + 1, + 1.333, + -1, + 1.467, + 0.2, + 1.6, + 0.2, + 1, + 2.122, + 0.2, + 2.644, + 0.2, + 3.167, + 0.2, + 0, + 3.2, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0.61, + 1, + 0.311, + 0.61, + 0.622, + 0.61, + 0.933, + 0.61, + 1, + 1.156, + 0.61, + 1.378, + 0.39, + 1.6, + 0.39, + 1, + 2.122, + 0.39, + 2.644, + 0.39, + 3.167, + 0.39, + 0, + 3.2, + 0.39 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0.61, + 1, + 0.311, + 0.61, + 0.622, + 0.61, + 0.933, + 0.61, + 1, + 1.156, + 0.61, + 1.378, + 0.39, + 1.6, + 0.39, + 1, + 2.122, + 0.39, + 2.644, + 0.39, + 3.167, + 0.39, + 0, + 3.2, + 0.39 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + -1, + 1, + 0.311, + -1, + 0.622, + -1, + 0.933, + -1, + 1, + 1.156, + -1, + 1.378, + 0, + 1.6, + 0, + 1, + 2.122, + 0, + 2.644, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + -1, + 1, + 0.311, + -1, + 0.622, + -1, + 0.933, + -1, + 1, + 1.156, + -1, + 1.378, + 0, + 1.6, + 0, + 1, + 2.122, + 0, + 2.644, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 1.056, + 1, + 2.111, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + -3.302, + 0.567, + -3.302, + 1, + 0.789, + -3.302, + 1.011, + -2.342, + 1.233, + -1, + 1, + 1.367, + -0.195, + 1.5, + 0, + 1.633, + 0, + 1, + 1.922, + 0, + 2.211, + 0, + 2.5, + 0, + 1, + 2.722, + 0, + 2.944, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + -4.918, + 0.567, + -4.918, + 1, + 0.789, + -4.918, + 1.011, + -4.041, + 1.233, + -2, + 1, + 1.367, + -0.776, + 1.5, + 0, + 1.633, + 0, + 1, + 1.922, + 0, + 2.211, + 0, + 2.5, + 0, + 1, + 2.722, + 0, + 2.944, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.489, + 0, + 0.978, + 1, + 1.467, + 1, + 1, + 2.033, + 1, + 2.6, + 0.006, + 3.167, + 0.006, + 0, + 3.2, + 0.006 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + -1, + 1, + 0.267, + -1, + 0.533, + -1, + 0.8, + -1, + 1, + 1.067, + -1, + 1.333, + 1, + 1.6, + 1, + 1, + 1.9, + 1, + 2.2, + 1, + 2.5, + 1, + 1, + 2.722, + 1, + 2.944, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + -1, + 1, + 0.267, + -1, + 0.533, + -1, + 0.8, + -1, + 1, + 1.067, + -1, + 1.333, + 1, + 1.6, + 1, + 1, + 1.9, + 1, + 2.2, + 1, + 2.5, + 1, + 1, + 2.722, + 1, + 2.944, + 1, + 3.167, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 3.17, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 3.17, + 0, + 0, + 3.2, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.17, + 1, + 0, + 3.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.17, + 0, + 0, + 3.2, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m19.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m19.motion3.json new file mode 100644 index 0000000..674bc3f --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m19.motion3.json @@ -0,0 +1,1105 @@ +{ + "Version": 3, + "Meta": { + "Duration": 8, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 131, + "TotalPointCount": 290, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 2.66, + 1, + 5.31, + 1, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + -8, + 1, + 2.656, + -8, + 5.311, + -8, + 7.967, + -8, + 0, + 8, + -8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + -30, + 1, + 2.656, + -30, + 5.311, + -30, + 7.967, + -30, + 0, + 8, + -30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + -30, + 1, + 2.656, + -30, + 5.311, + -30, + 7.967, + -30, + 0, + 8, + -30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 1, + 1, + 2.656, + 1, + 5.311, + 1, + 7.967, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + -1, + 1, + 2.656, + -1, + 5.311, + -1, + 7.967, + -1, + 0, + 8, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0.11, + 1, + 2.656, + 0.11, + 5.311, + 0.11, + 7.967, + 0.11, + 0, + 8, + 0.11 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0.46, + 1, + 2.656, + 0.46, + 5.311, + 0.46, + 7.967, + 0.46, + 0, + 8, + 0.46 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + -1, + 1, + 2.656, + -1, + 5.311, + -1, + 7.967, + -1, + 0, + 8, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + -1, + 1, + 2.656, + -1, + 5.311, + -1, + 7.967, + -1, + 0, + 8, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + -0.69, + 1, + 2.656, + -0.69, + 5.311, + -0.69, + 7.967, + -0.69, + 0, + 8, + -0.69 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + -0.67, + 1, + 2.656, + -0.67, + 5.311, + -0.67, + 7.967, + -0.67, + 0, + 8, + -0.67 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 2.656, + 1, + 5.311, + 1, + 7.967, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + -4.909, + 1, + 0.211, + -4.909, + 0.422, + -5.158, + 0.633, + -4.278, + 1, + 0.922, + -3.075, + 1.211, + 5.81, + 1.5, + 5.81, + 1, + 1.844, + 5.81, + 2.189, + -4.909, + 2.533, + -4.909, + 1, + 2.811, + -4.909, + 3.089, + 2.657, + 3.367, + 2.657, + 1, + 3.644, + 2.657, + 3.922, + -4.278, + 4.2, + -4.278, + 1, + 4.433, + -4.278, + 4.667, + 3.918, + 4.9, + 3.918, + 1, + 5.2, + 3.918, + 5.5, + -3.017, + 5.8, + -3.017, + 1, + 6.178, + -3.017, + 6.556, + 3.288, + 6.933, + 3.288, + 1, + 7.278, + 3.288, + 7.622, + -4.909, + 7.967, + -4.909, + 0, + 8, + -4.909 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + -10, + 1, + 2.656, + -10, + 5.311, + -10, + 7.967, + -10, + 0, + 8, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + -2, + 1, + 2.656, + -2, + 5.311, + -2, + 7.967, + -2, + 0, + 8, + -2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 10, + 1, + 2.656, + 10, + 5.311, + 10, + 7.967, + 10, + 0, + 8, + 10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.656, + 0, + 1.311, + 1, + 1.967, + 1, + 1, + 2.633, + 1, + 3.3, + 0, + 3.967, + 0, + 1, + 4.656, + 0, + 5.344, + 1, + 6.033, + 1, + 1, + 6.678, + 1, + 7.322, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 2.656, + 1, + 5.311, + 1, + 7.967, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 2.656, + 1, + 5.311, + 1, + 7.967, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 2.656, + 0, + 5.311, + 0, + 7.967, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 7.97, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 7.97, + 0, + 0, + 8, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 7.97, + 1, + 0, + 8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 7.97, + 0, + 0, + 8, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m20.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m20.motion3.json new file mode 100644 index 0000000..6820adc --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m20.motion3.json @@ -0,0 +1,2477 @@ +{ + "Version": 3, + "Meta": { + "Duration": 6.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 327, + "TotalPointCount": 878, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 2, + 1, + 4, + 1, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.733, + 0, + 1.133, + -21, + 1.533, + -21, + 1, + 1.611, + -21, + 1.689, + -21, + 1.767, + -21, + 1, + 1.944, + -21, + 2.122, + -20.074, + 2.3, + -17.479, + 1, + 2.5, + -12.897, + 2.7, + 19, + 2.9, + 19, + 1, + 3.078, + 19, + 3.256, + 19, + 3.433, + 19, + 1, + 3.689, + 19, + 3.944, + 19, + 4.2, + 19, + 1, + 4.8, + 19, + 5.4, + 19, + 6, + 19, + 0, + 6.033, + 19 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.544, + 0, + 0.756, + -13, + 0.967, + -13, + 1, + 1.122, + -13, + 1.278, + 7.633, + 1.433, + 8.986, + 1, + 1.578, + 10.242, + 1.722, + 9.689, + 1.867, + 11, + 1, + 2.044, + 12.613, + 2.222, + 28, + 2.4, + 28, + 1, + 2.6, + 28, + 2.8, + -9.978, + 3, + -11.975, + 1, + 3.144, + -13.418, + 3.289, + -13, + 3.433, + -13, + 1, + 3.689, + -13, + 3.944, + -13, + 4.2, + -13, + 1, + 4.311, + -13, + 4.422, + -6, + 4.533, + -6, + 1, + 4.644, + -6, + 4.756, + -13, + 4.867, + -13, + 1, + 5.244, + -13, + 5.622, + -13, + 6, + -13, + 0, + 6.033, + -13 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + -6, + 1, + 0.111, + -6, + 0.222, + -6, + 0.333, + -6, + 1, + 0.811, + -6, + 1.289, + -17, + 1.767, + -17, + 1, + 1.844, + -17, + 1.922, + -16.739, + 2, + -16, + 1, + 2.3, + -7.838, + 2.6, + 30, + 2.9, + 30, + 1, + 3.078, + 30, + 3.256, + 30, + 3.433, + 30, + 1, + 3.722, + 30, + 4.011, + 30, + 4.3, + 30, + 1, + 4.411, + 30, + 4.522, + 20, + 4.633, + 20, + 1, + 4.744, + 20, + 4.856, + 30, + 4.967, + 30, + 1, + 5.311, + 30, + 5.656, + 30, + 6, + 30, + 0, + 6.033, + 30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.767, + 0, + 1.2, + 0, + 1.633, + 0, + 1, + 1.767, + 0, + 1.9, + 0, + 2.033, + 0, + 1, + 3.356, + 0, + 4.678, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 2.222, + 0, + 4.111, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.467, + 1, + 0.6, + 1, + 0.733, + 1, + 1, + 0.789, + 1, + 0.844, + 0, + 0.9, + 0, + 1, + 0.967, + 0, + 1.033, + 1, + 1.1, + 1, + 1, + 1.278, + 1, + 1.456, + 1, + 1.633, + 1, + 1, + 1.767, + 1, + 1.9, + 1, + 2.033, + 1, + 1, + 2.1, + 1, + 2.167, + 0, + 2.233, + 0, + 1, + 2.267, + 0, + 2.3, + 0, + 2.333, + 0, + 1, + 2.411, + 0, + 2.489, + 0.9, + 2.567, + 0.9, + 1, + 2.678, + 0.9, + 2.789, + 0.8, + 2.9, + 0.8, + 1, + 3.244, + 0.8, + 3.589, + 0.8, + 3.933, + 0.8, + 1, + 3.978, + 0.8, + 4.022, + 0, + 4.067, + 0, + 1, + 4.178, + 0, + 4.289, + 0, + 4.4, + 0, + 1, + 4.478, + 0, + 4.556, + 0.8, + 4.633, + 0.8, + 1, + 5.089, + 0.8, + 5.544, + 0.8, + 6, + 0.8, + 0, + 6.033, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.767, + 0, + 1.2, + 0, + 1.633, + 0, + 1, + 1.767, + 0, + 1.9, + 0, + 2.033, + 0, + 1, + 3.356, + 0, + 4.678, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.111, + 1, + 0.222, + 1, + 0.333, + 1, + 1, + 0.467, + 1, + 0.6, + 1, + 0.733, + 1, + 1, + 0.789, + 1, + 0.844, + 0, + 0.9, + 0, + 1, + 0.967, + 0, + 1.033, + 1, + 1.1, + 1, + 1, + 1.278, + 1, + 1.456, + 1, + 1.633, + 1, + 1, + 1.767, + 1, + 1.9, + 1, + 2.033, + 1, + 1, + 2.1, + 1, + 2.167, + 0, + 2.233, + 0, + 1, + 2.267, + 0, + 2.3, + 0, + 2.333, + 0, + 1, + 2.411, + 0, + 2.489, + 0.9, + 2.567, + 0.9, + 1, + 2.678, + 0.9, + 2.789, + 0.8, + 2.9, + 0.8, + 1, + 3.244, + 0.8, + 3.589, + 0.8, + 3.933, + 0.8, + 1, + 3.978, + 0.8, + 4.022, + 0, + 4.067, + 0, + 1, + 4.178, + 0, + 4.289, + 0, + 4.4, + 0, + 1, + 4.478, + 0, + 4.556, + 0.8, + 4.633, + 0.8, + 1, + 5.089, + 0.8, + 5.544, + 0.8, + 6, + 0.8, + 0, + 6.033, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.767, + 0, + 1.2, + 0, + 1.633, + 0, + 1, + 1.767, + 0, + 1.9, + 0, + 2.033, + 0, + 1, + 3.356, + 0, + 4.678, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.767, + 0, + 1.2, + 0, + 1.633, + 0, + 1, + 1.767, + 0, + 1.9, + 0, + 2.033, + 0, + 1, + 3.356, + 0, + 4.678, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.767, + 0, + 1.2, + 0, + 1.633, + 0, + 1, + 1.767, + 0, + 1.9, + 0, + 2.033, + 0, + 1, + 3.356, + 0, + 4.678, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.467, + 0, + 0.6, + 0, + 0.733, + 0, + 1, + 0.856, + 0, + 0.978, + -0.82, + 1.1, + -0.82, + 1, + 1.411, + -0.82, + 1.722, + -0.82, + 2.033, + -0.82, + 1, + 2.667, + -0.82, + 3.3, + -0.82, + 3.933, + -0.82, + 1, + 4.167, + -0.82, + 4.4, + 1, + 4.633, + 1, + 1, + 5.089, + 1, + 5.544, + 1, + 6, + 1, + 0, + 6.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.467, + 0, + 0.6, + 0, + 0.733, + 0, + 1, + 0.789, + 0, + 0.844, + -0.4, + 0.9, + -0.4, + 1, + 0.967, + -0.4, + 1.033, + 0.33, + 1.1, + 0.33, + 1, + 1.411, + 0.33, + 1.722, + 0.33, + 2.033, + 0.33, + 1, + 2.211, + 0.33, + 2.389, + -0.6, + 2.567, + -0.6, + 1, + 3.022, + -0.6, + 3.478, + 0.33, + 3.933, + 0.33, + 1, + 3.978, + 0.33, + 4.022, + -0.5, + 4.067, + -0.5, + 1, + 4.178, + -0.5, + 4.289, + -0.5, + 4.4, + -0.5, + 1, + 4.478, + -0.5, + 4.556, + -1, + 4.633, + -1, + 1, + 5.089, + -1, + 5.544, + -1, + 6, + -1, + 0, + 6.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + -0.73, + 4.2, + -0.73, + 1, + 4.8, + -0.73, + 5.4, + -0.73, + 6, + -0.73, + 0, + 6.033, + -0.73 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + -0.73, + 4.2, + -0.73, + 1, + 4.8, + -0.73, + 5.4, + -0.73, + 6, + -0.73, + 0, + 6.033, + -0.73 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + -0.4, + 4.2, + -0.4, + 1, + 4.8, + -0.4, + 5.4, + -0.4, + 6, + -0.4, + 0, + 6.033, + -0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + -0.34, + 4.2, + -0.34, + 1, + 4.8, + -0.34, + 5.4, + -0.34, + 6, + -0.34, + 0, + 6.033, + -0.34 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + 0.47, + 4.2, + 0.47, + 1, + 4.8, + 0.47, + 5.4, + 0.47, + 6, + 0.47, + 0, + 6.033, + 0.47 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + 0.46, + 4.2, + 0.46, + 1, + 4.8, + 0.46, + 5.4, + 0.46, + 6, + 0.46, + 0, + 6.033, + 0.46 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + -1, + 2.567, + -1, + 1, + 3.111, + -1, + 3.656, + -1, + 4.2, + -1, + 1, + 4.8, + -1, + 5.4, + -1, + 6, + -1, + 0, + 6.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + -1, + 2.567, + -1, + 1, + 3.111, + -1, + 3.656, + -1, + 4.2, + -1, + 1, + 4.8, + -1, + 5.4, + -1, + 6, + -1, + 0, + 6.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.9, + 0, + 1.467, + 0, + 2.033, + 0, + 1, + 2.211, + 0, + 2.389, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + -1, + 4.2, + -1, + 1, + 4.8, + -1, + 5.4, + -1, + 6, + -1, + 0, + 6.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.767, + 0, + 1.2, + 0, + 1.633, + 0, + 1, + 3.089, + 0, + 4.544, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 2.222, + 0, + 4.111, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + 1, + 0.7, + 1, + 1, + 1.056, + 1, + 1.411, + -10, + 1.767, + -10, + 1, + 1.911, + -10, + 2.056, + -10.237, + 2.2, + -9, + 1, + 2.389, + -7.382, + 2.578, + 6.715, + 2.767, + 6.783, + 1, + 3.011, + 6.871, + 3.256, + 6.898, + 3.5, + 6.933, + 1, + 3.711, + 6.963, + 3.922, + 6.965, + 4.133, + 7, + 1, + 4.256, + 7.02, + 4.378, + 10, + 4.5, + 10, + 1, + 4.622, + 10, + 4.744, + 7, + 4.867, + 7, + 1, + 5.244, + 7, + 5.622, + 7, + 6, + 7, + 0, + 6.033, + 7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + -1, + 0.7, + -1, + 1, + 1.056, + -1, + 1.411, + -0.804, + 1.767, + 0, + 1, + 1.911, + 0.327, + 2.056, + 1, + 2.2, + 1, + 1, + 2.389, + 1, + 2.578, + -2.307, + 2.767, + -2.494, + 1, + 3.011, + -2.735, + 3.256, + -2.828, + 3.5, + -2.918, + 1, + 3.711, + -2.996, + 3.922, + -3, + 4.133, + -3, + 1, + 4.256, + -3, + 4.378, + -2, + 4.5, + -2, + 1, + 4.622, + -2, + 4.744, + -3, + 4.867, + -3, + 1, + 5.244, + -3, + 5.622, + -3, + 6, + -3, + 0, + 6.033, + -3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.456, + 0, + 0.578, + -1, + 0.7, + -1, + 1, + 1.056, + -1, + 1.411, + 5, + 1.767, + 5, + 1, + 1.911, + 5, + 2.056, + 0, + 2.2, + 0, + 1, + 2.389, + 0, + 2.578, + 3.604, + 2.767, + 3.716, + 1, + 3.011, + 3.86, + 3.256, + 3.923, + 3.5, + 3.965, + 1, + 3.711, + 4.002, + 3.922, + 4, + 4.133, + 4, + 1, + 4.256, + 4, + 4.378, + 3, + 4.5, + 3, + 1, + 4.622, + 3, + 4.744, + 4, + 4.867, + 4, + 1, + 5.244, + 4, + 5.622, + 4, + 6, + 4, + 0, + 6.033, + 4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.811, + 0, + 1.289, + 0, + 1.767, + 0, + 1, + 1.911, + 0, + 2.056, + -1, + 2.2, + -1, + 1, + 2.389, + -1, + 2.578, + 0, + 2.767, + 0, + 1, + 3.222, + 0, + 3.678, + 0, + 4.133, + 0, + 1, + 4.256, + 0, + 4.378, + -1, + 4.5, + -1, + 1, + 4.622, + -1, + 4.744, + 0, + 4.867, + 0, + 1, + 5.244, + 0, + 5.622, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.678, + 0, + 1.022, + 0, + 1.367, + 0, + 1, + 1.5, + 0, + 1.633, + 0, + 1.767, + 0, + 1, + 3.178, + 0, + 4.589, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.678, + 0, + 1.022, + 0, + 1.367, + 0, + 1, + 1.5, + 0, + 1.633, + 0, + 1.767, + 0, + 1, + 3.178, + 0, + 4.589, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.111, + 0.5, + 0.222, + 0.5, + 0.333, + 0.5, + 1, + 0.678, + 0.5, + 1.022, + 0.5, + 1.367, + 0.5, + 1, + 1.5, + 0.5, + 1.633, + 0.5, + 1.767, + 0.5, + 1, + 3.178, + 0.5, + 4.589, + 0.5, + 6, + 0.5, + 0, + 6.033, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.111, + 0.5, + 0.222, + 0.5, + 0.333, + 0.5, + 1, + 0.678, + 0.5, + 1.022, + 0.5, + 1.367, + 0.5, + 1, + 1.5, + 0.5, + 1.633, + 0.5, + 1.767, + 0.5, + 1, + 3.178, + 0.5, + 4.589, + 0.5, + 6, + 0.5, + 0, + 6.033, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + -0.2, + 1, + 0.111, + -0.2, + 0.222, + -0.2, + 0.333, + -0.2, + 1, + 0.489, + -0.2, + 0.644, + -0.2, + 0.8, + -0.2, + 1, + 0.989, + -0.2, + 1.178, + -1, + 1.367, + -1, + 1, + 1.5, + -1, + 1.633, + -1, + 1.767, + -1, + 1, + 3.178, + -1, + 4.589, + -1, + 6, + -1, + 0, + 6.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0.3, + 1, + 0.111, + 0.3, + 0.222, + 0.3, + 0.333, + 0.3, + 1, + 0.489, + 0.3, + 0.644, + 0.336, + 0.8, + 0.41, + 1, + 0.978, + 0.57, + 1.156, + 1.867, + 1.333, + 2.688, + 1, + 1.478, + 3.355, + 1.622, + 3.8, + 1.767, + 3.8, + 1, + 2.1, + 3.8, + 2.433, + 3.11, + 2.767, + 2.9, + 1, + 3.111, + 2.683, + 3.456, + 2.7, + 3.8, + 2.7, + 1, + 3.933, + 2.7, + 4.067, + 3.2, + 4.2, + 3.2, + 1, + 4.5, + 3.2, + 4.8, + 2.7, + 5.1, + 2.7, + 1, + 5.4, + 2.7, + 5.7, + 2.7, + 6, + 2.7, + 0, + 6.033, + 2.7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 2.378, + 0, + 4.189, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 2.378, + 0, + 4.189, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + 0, + 0.567, + 0, + 1, + 2.378, + 0, + 4.189, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.3, + 1, + 0.189, + -0.3, + 0.378, + -0.3, + 0.567, + -0.3, + 1, + 0.756, + -0.3, + 0.944, + -0.621, + 1.133, + -0.621, + 1, + 1.289, + -0.621, + 1.444, + -0.632, + 1.6, + -0.573, + 1, + 1.767, + -0.509, + 1.933, + -0.064, + 2.1, + 0.312, + 1, + 2.233, + 0.613, + 2.367, + 1, + 2.5, + 1, + 1, + 2.722, + 1, + 2.944, + -0.55, + 3.167, + -0.55, + 1, + 3.456, + -0.55, + 3.744, + -0.55, + 4.033, + -0.55, + 1, + 4.156, + -0.55, + 4.278, + 0.35, + 4.4, + 0.35, + 1, + 4.711, + 0.35, + 5.022, + -0.55, + 5.333, + -0.55, + 1, + 5.556, + -0.55, + 5.778, + -0.55, + 6, + -0.55, + 0, + 6.033, + -0.55 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.678, + 0, + 1.022, + 0, + 1.367, + 0, + 1, + 1.5, + 0, + 1.633, + 0, + 1.767, + 0, + 1, + 3.178, + 0, + 4.589, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 2.222, + 0, + 4.111, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.678, + 0, + 1.022, + 0, + 1.367, + 0, + 1, + 1.5, + 0, + 1.633, + 0, + 1.767, + 0, + 1, + 3.178, + 0, + 4.589, + 0, + 6, + 0, + 0, + 6.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 0, + 2, + 6, + 0, + 0, + 6.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 0, + 2, + 6, + 0, + 0, + 6.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 6, + 1, + 0, + 6.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 6, + 0, + 0, + 6.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m21.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m21.motion3.json new file mode 100644 index 0000000..3d43542 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m21.motion3.json @@ -0,0 +1,2568 @@ +{ + "Version": 3, + "Meta": { + "Duration": 5, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 352, + "TotalPointCount": 911, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 0.89, + 1, + 1.78, + 1, + 2.67, + 1, + 1, + 3.43, + 1, + 4.2, + 1, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.378, + 0, + 0.589, + 0, + 0.8, + 0, + 1, + 1, + 0, + 1.2, + 0, + 1.4, + 0, + 1, + 1.6, + 0, + 1.8, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + 2, + 3.033, + 2, + 1, + 3.344, + 2, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.033, + 0, + 0.067, + 0, + 0.1, + 0, + 1, + 0.156, + 0, + 0.211, + 6, + 0.267, + 6, + 1, + 0.344, + 6, + 0.422, + -11.207, + 0.5, + -11.207, + 1, + 0.6, + -11.207, + 0.7, + 0, + 0.8, + 0, + 1, + 0.967, + 0, + 1.133, + -16.67, + 1.3, + -16.67, + 1, + 1.356, + -16.67, + 1.411, + -16.299, + 1.467, + -8.31, + 1, + 1.578, + 7.668, + 1.689, + 22.901, + 1.8, + 22.901, + 1, + 1.9, + 22.901, + 2, + -0.099, + 2.1, + -0.099, + 1, + 2.3, + -0.099, + 2.5, + 0, + 2.7, + 0, + 1, + 2.833, + 0, + 2.967, + -22, + 3.1, + -22, + 1, + 3.256, + -22, + 3.411, + 12, + 3.567, + 12, + 1, + 3.722, + 12, + 3.878, + -5, + 4.033, + -5, + 1, + 4.222, + -5, + 4.411, + 0, + 4.6, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + 0, + 0.533, + 0, + 1, + 0.622, + 0, + 0.711, + 30, + 0.8, + 30, + 1, + 1, + 30, + 1.2, + -30, + 1.4, + -30, + 1, + 1.6, + -30, + 1.8, + 30, + 2, + 30, + 1, + 2.167, + 30, + 2.333, + 30.456, + 2.5, + 27, + 1, + 2.678, + 23.313, + 2.856, + -9, + 3.033, + -9, + 1, + 3.189, + -9, + 3.344, + 7, + 3.5, + 7, + 1, + 3.656, + 7, + 3.811, + -2, + 3.967, + -2, + 1, + 4.156, + -2, + 4.344, + 0, + 4.533, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.378, + 0, + 0.589, + 0.5, + 0.8, + 0.5, + 1, + 1.2, + 0.5, + 1.6, + 0.5, + 2, + 0.5, + 1, + 2.189, + 0.5, + 2.378, + 0.5, + 2.567, + 0.5, + 1, + 3.033, + 0.5, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.056, + 1, + 0.111, + 1, + 0.167, + 1, + 1, + 0.289, + 1, + 0.411, + 0, + 0.533, + 0, + 1, + 0.622, + 0, + 0.711, + 0, + 0.8, + 0, + 1, + 1, + 0, + 1.2, + 0, + 1.4, + 0, + 1, + 1.522, + 0, + 1.644, + 1, + 1.767, + 1, + 1, + 2.033, + 1, + 2.3, + 1, + 2.567, + 1, + 1, + 2.722, + 1, + 2.878, + 0, + 3.033, + 0, + 1, + 3.189, + 0, + 3.344, + 0, + 3.5, + 0, + 1, + 3.656, + 0, + 3.811, + 1, + 3.967, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + 0, + 0.533, + 0, + 1, + 0.622, + 0, + 0.711, + 1, + 0.8, + 1, + 1, + 1, + 1, + 1.2, + 1, + 1.4, + 1, + 1, + 1.522, + 1, + 1.644, + 0, + 1.767, + 0, + 1, + 2.033, + 0, + 2.3, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.056, + 1, + 0.111, + 1, + 0.167, + 1, + 1, + 0.289, + 1, + 0.411, + 0, + 0.533, + 0, + 1, + 0.622, + 0, + 0.711, + 0, + 0.8, + 0, + 1, + 1, + 0, + 1.2, + 0, + 1.4, + 0, + 1, + 1.522, + 0, + 1.644, + 1, + 1.767, + 1, + 1, + 2.033, + 1, + 2.3, + 1, + 2.567, + 1, + 1, + 2.722, + 1, + 2.878, + 0, + 3.033, + 0, + 1, + 3.189, + 0, + 3.344, + 0, + 3.5, + 0, + 1, + 3.656, + 0, + 3.811, + 1, + 3.967, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + 0, + 0.533, + 0, + 1, + 0.622, + 0, + 0.711, + 1, + 0.8, + 1, + 1, + 1, + 1, + 1.2, + 1, + 1.4, + 1, + 1, + 1.522, + 1, + 1.644, + 0, + 1.767, + 0, + 1, + 2.033, + 0, + 2.3, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + -0.5, + 3.033, + -0.5, + 1, + 3.344, + -0.5, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + -0.5, + 3.033, + -0.5, + 1, + 3.344, + -0.5, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + -0.4, + 3.033, + -0.4, + 1, + 3.344, + -0.4, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + 0, + 3.033, + 0, + 1, + 3.344, + 0, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + 0, + 3.033, + 0, + 1, + 3.344, + 0, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + -0.3, + 3.033, + -0.3, + 1, + 3.344, + -0.3, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + -0.3, + 3.033, + -0.3, + 1, + 3.344, + -0.3, + 3.656, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.056, + 1, + 0.111, + 1, + 0.167, + 1, + 1, + 0.778, + 1, + 1.389, + 1, + 2, + 1, + 1, + 2.189, + 1, + 2.378, + 1, + 2.567, + 1, + 1, + 3.033, + 1, + 3.5, + 1, + 3.967, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.856, + 0, + 1.711, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.578, + 0, + 0.989, + 0, + 1.4, + 0, + 1, + 1.633, + 0, + 1.867, + -2.877, + 2.1, + -6, + 1, + 2.289, + -8.528, + 2.478, + -9, + 2.667, + -9, + 1, + 3.1, + -9, + 3.533, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + -10, + 0.533, + -10, + 1, + 0.622, + -10, + 0.711, + 10, + 0.8, + 10, + 1, + 0.9, + 10, + 1, + -10, + 1.1, + -10, + 1, + 1.2, + -10, + 1.3, + 10, + 1.4, + 10, + 1, + 1.6, + 10, + 1.8, + -7, + 2, + -7, + 1, + 2.189, + -7, + 2.378, + -7, + 2.567, + -7, + 1, + 2.722, + -7, + 2.878, + -6.928, + 3.033, + -4, + 1, + 3.189, + -1.072, + 3.344, + 5, + 3.5, + 5, + 1, + 3.656, + 5, + 3.811, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + 0, + 0.533, + 0, + 1, + 0.622, + 0, + 0.711, + 10, + 0.8, + 10, + 1, + 1, + 10, + 1.2, + -10, + 1.4, + -10, + 1, + 1.567, + -10, + 1.733, + 6, + 1.9, + 6, + 1, + 2.089, + 6, + 2.278, + 6, + 2.467, + 6, + 1, + 2.656, + 6, + 2.844, + 9, + 3.033, + 9, + 1, + 3.189, + 9, + 3.344, + -6, + 3.5, + -6, + 1, + 3.656, + -6, + 3.811, + 1, + 3.967, + 1, + 1, + 4.144, + 1, + 4.322, + 0, + 4.5, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.722, + 0, + 2.878, + 4, + 3.033, + 4, + 1, + 3.189, + 4, + 3.344, + -1, + 3.5, + -1, + 1, + 3.656, + -1, + 3.811, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.856, + 0, + 1.711, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 0.5, + 1, + 0.056, + 0.5, + 0.111, + 0.5, + 0.167, + 0.5, + 1, + 0.289, + 0.5, + 0.411, + 0.6, + 0.533, + 0.6, + 1, + 0.622, + 0.6, + 0.711, + 0, + 0.8, + 0, + 1, + 0.9, + 0, + 1, + 0.57, + 1.1, + 0.57, + 1, + 1.2, + 0.57, + 1.3, + 0, + 1.4, + 0, + 1, + 1.6, + 0, + 1.8, + 0.5, + 2, + 0.5, + 1, + 2.189, + 0.5, + 2.378, + 0.5, + 2.567, + 0.5, + 1, + 2.722, + 0.5, + 2.878, + 0.489, + 3.033, + 0.4, + 1, + 3.189, + 0.311, + 3.344, + 0.2, + 3.5, + 0.2, + 1, + 3.656, + 0.2, + 3.811, + 1, + 3.967, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 0.5, + 1, + 0.056, + 0.5, + 0.111, + 0.5, + 0.167, + 0.5, + 1, + 0.289, + 0.5, + 0.411, + 0.6, + 0.533, + 0.6, + 1, + 0.622, + 0.6, + 0.711, + 0, + 0.8, + 0, + 1, + 0.9, + 0, + 1, + 0.56, + 1.1, + 0.56, + 1, + 1.2, + 0.56, + 1.3, + 0, + 1.4, + 0, + 1, + 1.6, + 0, + 1.8, + 0.5, + 2, + 0.5, + 1, + 2.189, + 0.5, + 2.378, + 0.5, + 2.567, + 0.5, + 1, + 2.722, + 0.5, + 2.878, + 0.489, + 3.033, + 0.4, + 1, + 3.189, + 0.311, + 3.344, + 0.2, + 3.5, + 0.2, + 1, + 3.656, + 0.2, + 3.811, + 1, + 3.967, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 5, + 3.967, + 5, + 0, + 5, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.378, + 0, + 0.589, + 0, + 0.8, + 0, + 1, + 1.389, + 0, + 1.978, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + 0, + 4.2, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + 0.887, + 0.533, + 0.963, + 1, + 0.622, + 1.018, + 0.711, + 1, + 0.8, + 1, + 1, + 0.844, + 1, + 0.889, + -0.593, + 0.933, + -0.684, + 1, + 0.967, + -0.752, + 1, + -0.73, + 1.033, + -0.73, + 1, + 1.111, + -0.73, + 1.189, + 0.874, + 1.267, + 0.969, + 1, + 1.311, + 1.023, + 1.356, + 1, + 1.4, + 1, + 1, + 1.511, + 1, + 1.622, + -0.566, + 1.733, + -0.566, + 1, + 1.822, + -0.566, + 1.911, + -0.1, + 2, + -0.1, + 1, + 2.189, + -0.1, + 2.378, + -0.1, + 2.567, + -0.1, + 1, + 2.722, + -0.1, + 2.878, + -0.8, + 3.033, + -0.8, + 1, + 3.189, + -0.8, + 3.344, + -0.4, + 3.5, + -0.4, + 1, + 3.578, + -0.4, + 3.656, + -1, + 3.733, + -1, + 1, + 3.889, + -1, + 4.044, + -0.1, + 4.2, + -0.1, + 0, + 5, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.378, + 0, + 0.589, + 0, + 0.8, + 0, + 1, + 1.389, + 0, + 1.978, + 0, + 2.567, + 0, + 1, + 3.111, + 0, + 3.656, + 0, + 4.2, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.289, + 0, + 0.411, + -1, + 0.533, + -1, + 1, + 0.622, + -1, + 0.711, + -0.592, + 0.8, + 0, + 1, + 0.844, + 0.296, + 0.889, + 0.664, + 0.933, + 0.725, + 1, + 0.978, + 0.786, + 1.022, + 0.778, + 1.067, + 0.778, + 1, + 1.133, + 0.778, + 1.2, + -0.873, + 1.267, + -0.962, + 1, + 1.311, + -1.022, + 1.356, + -1, + 1.4, + -1, + 1, + 1.5, + -1, + 1.6, + 0.665, + 1.7, + 0.665, + 1, + 1.8, + 0.665, + 1.9, + 0.1, + 2, + 0.1, + 1, + 2.189, + 0.1, + 2.378, + 0.1, + 2.567, + 0.1, + 1, + 2.722, + 0.1, + 2.878, + 1, + 3.033, + 1, + 1, + 3.189, + 1, + 3.344, + 0.7, + 3.5, + 0.7, + 1, + 3.578, + 0.7, + 3.656, + 1, + 3.733, + 1, + 1, + 3.889, + 1, + 4.044, + 0.1, + 4.2, + 0.1, + 0, + 5, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.778, + 0, + 1.389, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 3.033, + 0, + 3.5, + 0, + 3.967, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 2.67, + 0, + 2, + 4.97, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 2.67, + 0, + 2, + 4.97, + 0, + 0, + 5, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 2.67, + 1, + 2, + 4.97, + 1, + 0, + 5, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 2.67, + 0, + 2, + 4.97, + 0, + 0, + 5, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m22.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m22.motion3.json new file mode 100644 index 0000000..196ad33 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m22.motion3.json @@ -0,0 +1,2964 @@ +{ + "Version": 3, + "Meta": { + "Duration": 5.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 408, + "TotalPointCount": 1081, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.41, + 1, + 2.82, + 1, + 4.23, + 1, + 1, + 4.49, + 1, + 4.74, + 1, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + -2, + 1.367, + -2, + 1, + 1.433, + -2, + 1.5, + -2.016, + 1.567, + -1.097, + 1, + 1.644, + -0.026, + 1.722, + 2, + 1.8, + 2, + 1, + 2.033, + 2, + 2.267, + 0, + 2.5, + 0, + 1, + 2.667, + 0, + 2.833, + 0, + 3, + 0, + 1, + 3.211, + 0, + 3.422, + -17, + 3.633, + -17, + 1, + 3.833, + -17, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.278, + 0, + 0.556, + 0, + 0.833, + 0, + 1, + 0.878, + 0, + 0.922, + -2, + 0.967, + -2, + 1, + 1.044, + -2, + 1.122, + 12, + 1.2, + 12, + 1, + 1.267, + 12, + 1.333, + 12.003, + 1.4, + 5.456, + 1, + 1.478, + -2.182, + 1.556, + -17, + 1.633, + -17, + 1, + 1.922, + -17, + 2.211, + -15, + 2.5, + -15, + 1, + 2.689, + -15, + 2.878, + -15, + 3.067, + -15, + 1, + 3.278, + -15, + 3.489, + -8.561, + 3.7, + 5, + 1, + 3.8, + 11.424, + 3.9, + 15, + 4, + 15, + 1, + 4.122, + 15, + 4.244, + 0, + 4.367, + 0, + 1, + 4.578, + 0, + 4.789, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.222, + 0, + 1.344, + -17, + 1.467, + -17, + 1, + 1.533, + -17, + 1.6, + -16.684, + 1.667, + -8.077, + 1, + 1.744, + 1.963, + 1.822, + 18, + 1.9, + 18, + 1, + 2.1, + 18, + 2.3, + 15, + 2.5, + 15, + 1, + 2.722, + 15, + 2.944, + 15, + 3.167, + 15, + 1, + 3.378, + 15, + 3.589, + -21, + 3.8, + -21, + 1, + 4.122, + -21, + 4.444, + 0, + 4.767, + 0, + 1, + 4.844, + 0, + 4.922, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0.5, + 1.8, + 0.5, + 1, + 2.2, + 0.5, + 2.6, + 0.5, + 3, + 0.5, + 1, + 3.411, + 0.5, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.122, + 1, + 1.244, + 1.9, + 1.367, + 1.9, + 1, + 1.433, + 1.9, + 1.5, + 1.913, + 1.567, + 1.471, + 1, + 1.644, + 0.956, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.067, + 0, + 3.133, + 0, + 3.2, + 0, + 1, + 3.267, + 0, + 3.333, + -0.041, + 3.4, + 0.2, + 1, + 3.478, + 0.481, + 3.556, + 1.6, + 3.633, + 1.6, + 1, + 3.833, + 1.6, + 4.033, + 1, + 4.233, + 1, + 1, + 4.489, + 1, + 4.744, + 1, + 5, + 1, + 0, + 5.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.213, + 1.567, + 0.684, + 1, + 1.644, + 0.877, + 1.722, + 1, + 1.8, + 1, + 1, + 2.2, + 1, + 2.6, + 1, + 3, + 1, + 1, + 3.067, + 1, + 3.133, + 1, + 3.2, + 1, + 1, + 3.267, + 1, + 3.333, + 0, + 3.4, + 0, + 1, + 3.478, + 0, + 3.556, + 0, + 3.633, + 0, + 1, + 3.833, + 0, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.122, + 1, + 1.244, + 1.9, + 1.367, + 1.9, + 1, + 1.433, + 1.9, + 1.5, + 1.913, + 1.567, + 1.471, + 1, + 1.644, + 0.956, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.067, + 0, + 3.133, + 0, + 3.2, + 0, + 1, + 3.267, + 0, + 3.333, + -0.041, + 3.4, + 0.2, + 1, + 3.478, + 0.481, + 3.556, + 1.6, + 3.633, + 1.6, + 1, + 3.833, + 1.6, + 4.033, + 1, + 4.233, + 1, + 1, + 4.489, + 1, + 4.744, + 1, + 5, + 1, + 0, + 5.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.213, + 1.567, + 0.684, + 1, + 1.644, + 0.877, + 1.722, + 1, + 1.8, + 1, + 1, + 2.2, + 1, + 2.6, + 1, + 3, + 1, + 1, + 3.067, + 1, + 3.133, + 1, + 3.2, + 1, + 1, + 3.267, + 1, + 3.333, + 0, + 3.4, + 0, + 1, + 3.478, + 0, + 3.556, + 0, + 3.633, + 0, + 1, + 3.833, + 0, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.106, + 1.567, + 0.342, + 1, + 1.644, + 0.439, + 1.722, + 0.5, + 1.8, + 0.5, + 1, + 2.2, + 0.5, + 2.6, + 0.5, + 3, + 0.5, + 1, + 3.411, + 0.5, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + 0.3, + 1.367, + 0.3, + 1, + 1.433, + 0.3, + 1.5, + 0.302, + 1.567, + 0.232, + 1, + 1.644, + 0.151, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.067, + 0, + 3.133, + -0.2, + 3.2, + -0.2, + 1, + 3.344, + -0.2, + 3.489, + 0.5, + 3.633, + 0.5, + 1, + 3.833, + 0.5, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + 0.062, + 1.367, + 0.2, + 1, + 1.433, + 0.275, + 1.5, + 0.32, + 1.567, + 0.439, + 1, + 1.644, + 0.578, + 1.722, + 0.8, + 1.8, + 0.8, + 1, + 2.2, + 0.8, + 2.6, + 0.8, + 3, + 0.8, + 1, + 3.067, + 0.8, + 3.133, + -0.6, + 3.2, + -0.6, + 1, + 3.344, + -0.6, + 3.489, + 0, + 3.633, + 0, + 1, + 3.833, + 0, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.205, + 1.567, + 0.205, + 1, + 1.644, + 0.205, + 1.722, + -0.2, + 1.8, + -0.2, + 1, + 2.2, + -0.2, + 2.6, + -0.2, + 3, + -0.2, + 1, + 3.411, + -0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.205, + 1.567, + 0.205, + 1, + 1.644, + 0.205, + 1.722, + -0.2, + 1.8, + -0.2, + 1, + 2.2, + -0.2, + 2.6, + -0.2, + 3, + -0.2, + 1, + 3.411, + -0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.043, + 1.567, + 0.137, + 1, + 1.644, + 0.175, + 1.722, + 0.2, + 1.8, + 0.2, + 1, + 2.2, + 0.2, + 2.6, + 0.2, + 3, + 0.2, + 1, + 3.411, + 0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.043, + 1.567, + 0.137, + 1, + 1.644, + 0.175, + 1.722, + 0.2, + 1.8, + 0.2, + 1, + 2.2, + 0.2, + 2.6, + 0.2, + 3, + 0.2, + 1, + 3.411, + 0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.043, + 1.567, + 0.137, + 1, + 1.644, + 0.175, + 1.722, + 0.2, + 1.8, + 0.2, + 1, + 2.2, + 0.2, + 2.6, + 0.2, + 3, + 0.2, + 1, + 3.411, + 0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.043, + 1.567, + 0.137, + 1, + 1.644, + 0.175, + 1.722, + 0.2, + 1.8, + 0.2, + 1, + 2.2, + 0.2, + 2.6, + 0.2, + 3, + 0.2, + 1, + 3.411, + 0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.043, + 1.567, + 0.137, + 1, + 1.644, + 0.175, + 1.722, + 0.2, + 1.8, + 0.2, + 1, + 2.2, + 0.2, + 2.6, + 0.2, + 3, + 0.2, + 1, + 3.411, + 0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0.043, + 1.567, + 0.137, + 1, + 1.644, + 0.175, + 1.722, + 0.2, + 1.8, + 0.2, + 1, + 2.2, + 0.2, + 2.6, + 0.2, + 3, + 0.2, + 1, + 3.411, + 0.2, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.189, + 1, + 1.378, + 1, + 1.567, + 1, + 1, + 1.644, + 1, + 1.722, + 1, + 1.8, + 1, + 1, + 2.2, + 1, + 2.6, + 1, + 3, + 1, + 1, + 3.411, + 1, + 3.822, + 1, + 4.233, + 1, + 1, + 4.489, + 1, + 4.744, + 1, + 5, + 1, + 0, + 5.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + 4, + 1.367, + 4, + 1, + 1.433, + 4, + 1.5, + 4.01, + 1.567, + 2.646, + 1, + 1.644, + 1.055, + 1.722, + -2, + 1.8, + -2, + 1, + 2.033, + -2, + 2.267, + -1, + 2.5, + -1, + 1, + 2.667, + -1, + 2.833, + -1, + 3, + -1, + 1, + 3.211, + -1, + 3.422, + -7, + 3.633, + -7, + 1, + 3.833, + -7, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + 10, + 1.367, + 10, + 1, + 1.433, + 10, + 1.5, + 9.987, + 1.567, + 7.518, + 1, + 1.644, + 4.637, + 1.722, + -1, + 1.8, + -1, + 1, + 2.033, + -1, + 2.267, + 0, + 2.5, + 0, + 1, + 2.667, + 0, + 2.833, + 0, + 3, + 0, + 1, + 3.211, + 0, + 3.422, + 8, + 3.633, + 8, + 1, + 3.833, + 8, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + -8, + 1.367, + -8, + 1, + 1.433, + -8, + 1.5, + -8, + 1.567, + -6.195, + 1, + 1.644, + -4.088, + 1.722, + 0, + 1.8, + 0, + 1, + 2.033, + 0, + 2.267, + -1, + 2.5, + -1, + 1, + 2.667, + -1, + 2.833, + -1, + 3, + -1, + 1, + 3.211, + -1, + 3.422, + -5, + 3.633, + -5, + 1, + 3.833, + -5, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.122, + 0, + 1.244, + -5, + 1.367, + -5, + 1, + 1.433, + -5, + 1.5, + -4.991, + 1.567, + -2.743, + 1, + 1.644, + -0.121, + 1.722, + 5, + 1.8, + 5, + 1, + 2.033, + 5, + 2.267, + 4, + 2.5, + 4, + 1, + 2.667, + 4, + 2.833, + 4, + 3, + 4, + 1, + 3.211, + 4, + 3.422, + -5, + 3.633, + -5, + 1, + 3.833, + -5, + 4.033, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.122, + 1, + 1.244, + 0.725, + 1.367, + 0.3, + 1, + 1.433, + 0.068, + 1.5, + -0.024, + 1.567, + -0.297, + 1, + 1.644, + -0.616, + 1.722, + -1, + 1.8, + -1, + 1, + 2.033, + -1, + 2.267, + -0.9, + 2.5, + -0.9, + 1, + 2.667, + -0.9, + 2.833, + -0.9, + 3, + -0.9, + 1, + 3.211, + -0.9, + 3.422, + -0.173, + 3.633, + 0.4, + 1, + 3.833, + 0.943, + 4.033, + 1, + 4.233, + 1, + 1, + 4.489, + 1, + 4.744, + 1, + 5, + 1, + 0, + 5.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.122, + 1, + 1.244, + 0.725, + 1.367, + 0.3, + 1, + 1.433, + 0.068, + 1.5, + -0.024, + 1.567, + -0.297, + 1, + 1.644, + -0.616, + 1.722, + -1, + 1.8, + -1, + 1, + 2.033, + -1, + 2.267, + -0.9, + 2.5, + -0.9, + 1, + 2.667, + -0.9, + 2.833, + -0.9, + 3, + -0.9, + 1, + 3.211, + -0.9, + 3.422, + -0.173, + 3.633, + 0.4, + 1, + 3.833, + 0.943, + 4.033, + 1, + 4.233, + 1, + 1, + 4.489, + 1, + 4.744, + 1, + 5, + 1, + 0, + 5.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.333, + 5, + 0.667, + 5, + 1, + 5, + 1, + 1.189, + 5, + 1.378, + 5, + 1.567, + 5, + 1, + 1.644, + 5, + 1.722, + 5, + 1.8, + 5, + 1, + 2.2, + 5, + 2.6, + 5, + 3, + 5, + 1, + 3.411, + 5, + 3.822, + 5, + 4.233, + 5, + 1, + 4.489, + 5, + 4.744, + 5, + 5, + 5, + 0, + 5.033, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + -0.1, + 1, + 0.333, + -0.1, + 0.667, + -0.1, + 1, + -0.1, + 1, + 1.122, + -0.1, + 1.244, + -0.7, + 1.367, + -0.7, + 1, + 1.433, + -0.7, + 1.5, + -0.705, + 1.567, + -0.542, + 1, + 1.644, + -0.352, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + -0.1, + 4.233, + -0.1, + 1, + 4.489, + -0.1, + 4.744, + -0.1, + 5, + -0.1, + 0, + 5.033, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0.1, + 1, + 0.333, + 0.1, + 0.667, + 0.1, + 1, + 0.1, + 1, + 1.122, + 0.1, + 1.244, + 0.7, + 1.367, + 0.7, + 1, + 1.433, + 0.7, + 1.5, + 0.705, + 1.567, + 0.542, + 1, + 1.644, + 0.352, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0.1, + 4.233, + 0.1, + 1, + 4.489, + 0.1, + 4.744, + 0.1, + 5, + 0.1, + 0, + 5.033, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.189, + 0, + 1.378, + 0, + 1.567, + 0, + 1, + 1.644, + 0, + 1.722, + 0, + 1.8, + 0, + 1, + 2.2, + 0, + 2.6, + 0, + 3, + 0, + 1, + 3.411, + 0, + 3.822, + 0, + 4.233, + 0, + 1, + 4.489, + 0, + 4.744, + 0, + 5, + 0, + 0, + 5.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 4.23, + 0, + 2, + 5, + 0, + 0, + 5.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 4.23, + 0, + 2, + 5, + 0, + 0, + 5.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4.23, + 1, + 2, + 5, + 1, + 0, + 5.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4.23, + 0, + 2, + 5, + 0, + 0, + 5.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m23.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m23.motion3.json new file mode 100644 index 0000000..a2e5001 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m23.motion3.json @@ -0,0 +1,1721 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 219, + "TotalPointCount": 554, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.32, + 1, + 2.64, + 1, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 9, + 1, + 0.333, + 9, + 0.667, + 9, + 1, + 9, + 1, + 1.156, + 9, + 1.311, + -3, + 1.467, + -3, + 1, + 1.722, + -3, + 1.978, + -2.724, + 2.233, + -2, + 1, + 2.444, + -1.402, + 2.656, + -1, + 2.867, + -1, + 0, + 4, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + -6, + 1, + 0.289, + -6, + 0.578, + -6, + 0.867, + -6, + 1, + 0.944, + -6, + 1.022, + -8, + 1.1, + -8, + 1, + 1.256, + -8, + 1.411, + -1.51, + 1.567, + 5, + 1, + 1.656, + 8.72, + 1.744, + 9, + 1.833, + 9, + 1, + 2, + 9, + 2.167, + -7, + 2.333, + -7, + 1, + 2.544, + -7, + 2.756, + -6, + 2.967, + -6, + 0, + 4, + -6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + -16, + 1, + 0.333, + -16, + 0.667, + -16, + 1, + -16, + 1, + 1.156, + -16, + 1.311, + -26, + 1.467, + -26, + 1, + 1.722, + -26, + 1.978, + 27, + 2.233, + 27, + 1, + 2.444, + 27, + 2.656, + 24, + 2.867, + 24, + 0, + 4, + 24 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.156, + 1, + 1.311, + 1.898, + 1.467, + 1.898, + 1, + 1.667, + 1.898, + 1.867, + 1, + 2.067, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.156, + 1, + 1.311, + 1.898, + 1.467, + 1.898, + 1, + 1.667, + 1.898, + 1.867, + 1, + 2.067, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0.1, + 2.067, + 0.1, + 0, + 4, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + -0.3, + 1, + 0.333, + -0.3, + 0.667, + -0.3, + 1, + -0.3, + 1, + 1.156, + -0.3, + 1.311, + 0.2, + 1.467, + 0.2, + 1, + 1.667, + 0.2, + 1.867, + 0.1, + 2.067, + 0.1, + 0, + 4, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0.5, + 1, + 0.333, + 0.5, + 0.667, + 0.5, + 1, + 0.5, + 1, + 1.156, + 0.5, + 1.311, + 0.2, + 1.467, + 0.2, + 1, + 1.667, + 0.2, + 1.867, + 0.3, + 2.067, + 0.3, + 0, + 4, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.399, + 1.467, + 0.399, + 1, + 1.667, + 0.399, + 1.867, + 0.2, + 2.067, + 0.2, + 0, + 4, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.399, + 1.467, + 0.399, + 1, + 1.667, + 0.399, + 1.867, + 0.2, + 2.067, + 0.2, + 0, + 4, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.699, + 1.467, + 0.699, + 1, + 1.667, + 0.699, + 1.867, + 0.5, + 2.067, + 0.5, + 0, + 4, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.699, + 1.467, + 0.699, + 1, + 1.667, + 0.699, + 1.867, + 0.5, + 2.067, + 0.5, + 0, + 4, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.698, + 1.467, + 0.698, + 1, + 1.667, + 0.698, + 1.867, + 0.4, + 2.067, + 0.4, + 0, + 4, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.698, + 1.467, + 0.698, + 1, + 1.667, + 0.698, + 1.867, + 0.4, + 2.067, + 0.4, + 0, + 4, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.599, + 1.467, + 0.599, + 1, + 1.667, + 0.599, + 1.867, + 0.4, + 2.067, + 0.4, + 0, + 4, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.599, + 1.467, + 0.599, + 1, + 1.667, + 0.599, + 1.867, + 0.4, + 2.067, + 0.4, + 0, + 4, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.156, + 1, + 1.311, + 0.603, + 1.467, + 0.603, + 1, + 1.667, + 0.603, + 1.867, + 1, + 2.067, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0.1, + 1.467, + 0.1, + 1, + 1.667, + 0.1, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 9, + 1, + 0.333, + 9, + 0.667, + 9, + 1, + 9, + 1, + 1.156, + 9, + 1.311, + 7.216, + 1.467, + 2.03, + 1, + 1.667, + -4.639, + 1.867, + -9, + 2.067, + -9, + 0, + 4, + -9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.344, + 0, + 0.689, + 0, + 1.033, + 0, + 1, + 1.189, + 0, + 1.344, + 6, + 1.5, + 6, + 1, + 1.7, + 6, + 1.9, + -1, + 2.1, + -1, + 1, + 2.456, + -1, + 2.811, + 0, + 3.167, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.289, + 0, + 0.578, + 0, + 0.867, + 0, + 1, + 1.022, + 0, + 1.178, + -4.928, + 1.333, + -4.928, + 1, + 1.533, + -4.928, + 1.733, + 5, + 1.933, + 5, + 1, + 2.289, + 5, + 2.644, + 4, + 3, + 4, + 0, + 4, + 4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.256, + 0, + 1.411, + -3.95, + 1.567, + -3.95, + 1, + 1.767, + -3.95, + 1.967, + 3, + 2.167, + 3, + 1, + 2.522, + 3, + 2.878, + 2, + 3.233, + 2, + 0, + 4, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.156, + 1, + 1.311, + 0.5, + 1.467, + 0.5, + 1, + 1.667, + 0.5, + 1.867, + 1, + 2.067, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.156, + 1, + 1.311, + 0.5, + 1.467, + 0.5, + 1, + 1.667, + 0.5, + 1.867, + 1, + 2.067, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.333, + 5, + 0.667, + 5, + 1, + 5, + 1, + 1.156, + 5, + 1.311, + 5, + 1.467, + 5, + 1, + 1.667, + 5, + 1.867, + 5, + 2.067, + 5, + 0, + 4, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 5, + 1, + 0.333, + 5, + 0.667, + 5, + 1, + 5, + 1, + 1.156, + 5, + 1.311, + 5, + 1.467, + 5, + 1, + 1.667, + 5, + 1.867, + 5, + 2.067, + 5, + 0, + 4, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + -0.2, + 1, + 0.333, + -0.2, + 0.667, + -0.2, + 1, + -0.2, + 1, + 1.078, + -0.2, + 1.156, + 0.7, + 1.233, + 0.7, + 1, + 1.311, + 0.7, + 1.389, + 0.508, + 1.467, + 0.069, + 1, + 1.578, + -0.557, + 1.689, + -0.9, + 1.8, + -0.9, + 1, + 1.889, + -0.9, + 1.978, + -0.1, + 2.067, + -0.1, + 0, + 4, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + 0.3, + 1, + 0.333, + 0.3, + 0.667, + 0.3, + 1, + 0.3, + 1, + 1.078, + 0.3, + 1.156, + -1, + 1.233, + -1, + 1, + 1.311, + -1, + 1.389, + -0.785, + 1.467, + -0.239, + 1, + 1.578, + 0.542, + 1.689, + 1, + 1.8, + 1, + 1, + 1.889, + 1, + 1.978, + 0.1, + 2.067, + 0.1, + 0, + 4, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.156, + 0, + 1.311, + 0, + 1.467, + 0, + 1, + 1.667, + 0, + 1.867, + 0, + 2.067, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 3.97, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 3.97, + 0, + 0, + 4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.97, + 1, + 0, + 4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.97, + 0, + 0, + 4, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m24.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m24.motion3.json new file mode 100644 index 0000000..0be005d --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m24.motion3.json @@ -0,0 +1,1854 @@ +{ + "Version": 3, + "Meta": { + "Duration": 3.4, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 238, + "TotalPointCount": 611, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.12, + 1, + 2.24, + 1, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 3, + 1.3, + 3, + 1, + 1.422, + 3, + 1.544, + 3.072, + 1.667, + 1.363, + 1, + 1.756, + 0.121, + 1.844, + -30, + 1.933, + -30, + 1, + 2.078, + -30, + 2.222, + -28, + 2.367, + -28, + 0, + 3.4, + -28 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.311, + 0, + 0.622, + 0, + 0.933, + 0, + 1, + 0.978, + 0, + 1.022, + -1, + 1.067, + -1, + 1, + 1.178, + -1, + 1.289, + 23, + 1.4, + 23, + 1, + 1.522, + 23, + 1.644, + 23.023, + 1.767, + 19.188, + 1, + 1.856, + 16.4, + 1.944, + -30, + 2.033, + -30, + 1, + 2.178, + -30, + 2.322, + -28, + 2.467, + -28, + 0, + 3.4, + -28 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + -1.536, + 1.667, + -7.828, + 1, + 1.756, + -10.345, + 1.844, + -17, + 1.933, + -17, + 1, + 2.078, + -17, + 2.222, + -16, + 2.367, + -16, + 0, + 3.4, + -16 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0.051, + 1.667, + 0.255, + 1, + 1.756, + 0.337, + 1.844, + 0.5, + 1.933, + 0.5, + 0, + 3.4, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 1.9, + 1.3, + 1.9, + 1, + 1.422, + 1.9, + 1.544, + 1.908, + 1.667, + 1.828, + 1, + 1.756, + 1.77, + 1.844, + 0.8, + 1.933, + 0.8, + 0, + 3.4, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 1.9, + 1.3, + 1.9, + 1, + 1.422, + 1.9, + 1.544, + 1.908, + 1.667, + 1.828, + 1, + 1.756, + 1.77, + 1.844, + 0.8, + 1.933, + 0.8, + 0, + 3.4, + 0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -0.1, + 1.3, + -0.1, + 1, + 1.422, + -0.1, + 1.544, + -0.051, + 1.667, + -0.051, + 1, + 1.756, + -0.051, + 1.844, + -1, + 1.933, + -1, + 0, + 3.4, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.422, + 0, + 1.544, + 0.009, + 1.667, + 0.074, + 1, + 1.756, + 0.121, + 1.844, + 0.2, + 1.933, + 0.2, + 0, + 3.4, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.422, + 0.3, + 1.544, + 0.308, + 1.667, + 0.228, + 1, + 1.756, + 0.17, + 1.844, + -0.7, + 1.933, + -0.7, + 0, + 3.4, + -0.7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.422, + 0.3, + 1.544, + 0.308, + 1.667, + 0.228, + 1, + 1.756, + 0.17, + 1.844, + -0.7, + 1.933, + -0.7, + 0, + 3.4, + -0.7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.422, + 0.3, + 1.544, + 0.309, + 1.667, + 0.21, + 1, + 1.756, + 0.138, + 1.844, + -0.8, + 1.933, + -0.8, + 0, + 3.4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.422, + 0.3, + 1.544, + 0.309, + 1.667, + 0.21, + 1, + 1.756, + 0.138, + 1.844, + -0.8, + 1.933, + -0.8, + 0, + 3.4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.422, + 0.3, + 1.544, + 0.309, + 1.667, + 0.2, + 1, + 1.756, + 0.121, + 1.844, + -0.8, + 1.933, + -0.8, + 0, + 3.4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.422, + 0.3, + 1.544, + 0.309, + 1.667, + 0.2, + 1, + 1.756, + 0.121, + 1.844, + -0.8, + 1.933, + -0.8, + 0, + 3.4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.2, + 1.3, + 0.2, + 1, + 1.422, + 0.2, + 1.544, + 0.14, + 1.667, + -0.2, + 1, + 1.756, + -0.448, + 1.844, + -0.8, + 1.933, + -0.8, + 0, + 3.4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.2, + 1.3, + 0.2, + 1, + 1.422, + 0.2, + 1.544, + 0.14, + 1.667, + -0.2, + 1, + 1.756, + -0.448, + 1.844, + -0.8, + 1.933, + -0.8, + 0, + 3.4, + -0.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 0.268, + 1.3, + 0.1, + 1, + 1.422, + -0.105, + 1.544, + -0.093, + 1.667, + -0.288, + 1, + 1.756, + -0.43, + 1.844, + -1, + 1.933, + -1, + 0, + 3.4, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.1, + 1.3, + 0.1, + 1, + 1.422, + 0.1, + 1.544, + 0.101, + 1.667, + 0.092, + 1, + 1.756, + 0.085, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + 0, + 0.9, + 0, + 1, + 1, + 0, + 1.1, + 6, + 1.2, + 6, + 1, + 1.322, + 6, + 1.444, + 6.063, + 1.567, + 5.062, + 1, + 1.656, + 4.334, + 1.744, + -9, + 1.833, + -9, + 1, + 1.978, + -9, + 2.122, + -8, + 2.267, + -8, + 0, + 3.4, + -8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 6, + 1.3, + 6, + 1, + 1.422, + 6, + 1.544, + 6.057, + 1.667, + 5.249, + 1, + 1.756, + 4.662, + 1.844, + -6, + 1.933, + -6, + 1, + 2.078, + -6, + 2.222, + -5, + 2.367, + -5, + 0, + 3.4, + -5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.2, + 0, + 1.3, + 6, + 1.4, + 6, + 1, + 1.522, + 6, + 1.644, + 6.052, + 1.767, + 5.374, + 1, + 1.856, + 4.882, + 1.944, + -4, + 2.033, + -4, + 1, + 2.178, + -4, + 2.322, + -3, + 2.467, + -3, + 0, + 3.4, + -3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + -0.511, + 1.667, + -2.763, + 1, + 1.756, + -3.664, + 1.844, + -6, + 1.933, + -6, + 1, + 2.078, + -6, + 2.222, + -5, + 2.367, + -5, + 0, + 3.4, + -5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 0.472, + 1.3, + 0.3, + 1, + 1.422, + 0.089, + 1.544, + 0.096, + 1.667, + -0.117, + 1, + 1.756, + -0.272, + 1.844, + -1, + 1.933, + -1, + 1, + 2.078, + -1, + 2.222, + -0.9, + 2.367, + -0.9, + 0, + 3.4, + -0.9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 0.472, + 1.3, + 0.3, + 1, + 1.422, + 0.089, + 1.544, + 0.096, + 1.667, + -0.117, + 1, + 1.756, + -0.272, + 1.844, + -1, + 1.933, + -1, + 1, + 2.078, + -1, + 2.222, + -0.9, + 2.367, + -0.9, + 0, + 3.4, + -0.9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.333, + 5, + 0.667, + 5, + 1, + 5, + 1, + 1.222, + 5, + 1.444, + 5, + 1.667, + 5, + 1, + 1.756, + 5, + 1.844, + 5, + 1.933, + 5, + 0, + 3.4, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.19, + 1, + 0.333, + 0.19, + 0.667, + 0.19, + 1, + 0.19, + 1, + 1.222, + 0.19, + 1.444, + 0.183, + 1.667, + 0.149, + 1, + 1.756, + 0.135, + 1.844, + 0.1, + 1.933, + 0.1, + 0, + 3.4, + 0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.17, + 1, + 0.333, + -0.17, + 0.667, + -0.17, + 1, + -0.17, + 1, + 1.222, + -0.17, + 1.444, + -0.123, + 1.667, + 0.092, + 1, + 1.756, + 0.179, + 1.844, + 0.4, + 1.933, + 0.4, + 0, + 3.4, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.222, + 0, + 1.444, + 0, + 1.667, + 0, + 1, + 1.756, + 0, + 1.844, + 0, + 1.933, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 3.37, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 3.37, + 0, + 0, + 3.4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 3.37, + 1, + 0, + 3.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 3.37, + 0, + 0, + 3.4, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m25.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m25.motion3.json new file mode 100644 index 0000000..5745701 --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m25.motion3.json @@ -0,0 +1,1805 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.03, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 231, + "TotalPointCount": 590, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.33, + 1, + 2.67, + 1, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -1, + 0.7, + -1, + 1, + 0.789, + -1, + 0.878, + 7, + 0.967, + 7, + 1, + 1.2, + 7, + 1.433, + 7, + 1.667, + 7, + 1, + 1.767, + 7, + 1.867, + -4, + 1.967, + -4, + 1, + 2.111, + -4, + 2.256, + 2, + 2.4, + 2, + 1, + 2.622, + 2, + 2.844, + 0, + 3.067, + 0, + 1, + 3.378, + 0, + 3.689, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + -21, + 1, + 0.122, + -21, + 0.244, + -21, + 0.367, + -21, + 1, + 0.567, + -21, + 0.767, + -12.835, + 0.967, + 0, + 1, + 1.2, + 14.974, + 1.433, + 21, + 1.667, + 21, + 1, + 2, + 21, + 2.333, + 0, + 2.667, + 0, + 1, + 3.111, + 0, + 3.556, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.233, + 1, + 0.467, + 1, + 0.7, + 1, + 1, + 0.744, + 1, + 0.789, + 0, + 0.833, + 0, + 1, + 0.878, + 0, + 0.922, + 2, + 0.967, + 2, + 1, + 0.989, + 2, + 1.011, + 1.9, + 1.033, + 1.9, + 1, + 1.267, + 1.9, + 1.5, + 1.9, + 1.733, + 1.9, + 1, + 1.789, + 1.9, + 1.844, + 0, + 1.9, + 0, + 1, + 1.978, + 0, + 2.056, + 0, + 2.133, + 0, + 1, + 2.2, + 0, + 2.267, + 1.1, + 2.333, + 1.1, + 1, + 2.356, + 1.1, + 2.378, + 1, + 2.4, + 1, + 1, + 2.933, + 1, + 3.467, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.233, + 1, + 0.467, + 1, + 0.7, + 1, + 1, + 0.744, + 1, + 0.789, + 0, + 0.833, + 0, + 1, + 0.878, + 0, + 0.922, + 2, + 0.967, + 2, + 1, + 0.989, + 2, + 1.011, + 1.9, + 1.033, + 1.9, + 1, + 1.267, + 1.9, + 1.5, + 1.9, + 1.733, + 1.9, + 1, + 1.789, + 1.9, + 1.844, + 0, + 1.9, + 0, + 1, + 1.978, + 0, + 2.056, + 0, + 2.133, + 0, + 1, + 2.2, + 0, + 2.267, + 1.1, + 2.333, + 1.1, + 1, + 2.356, + 1.1, + 2.378, + 1, + 2.4, + 1, + 1, + 2.933, + 1, + 3.467, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + 0, + 0.7, + 0, + 1, + 0.789, + 0, + 0.878, + -0.49, + 0.967, + -0.49, + 1, + 1.6, + -0.49, + 2.233, + -0.49, + 2.867, + -0.49, + 1, + 3.244, + -0.49, + 3.622, + -0.49, + 4, + -0.49, + 0, + 4.033, + -0.49 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + 0, + 0.7, + 0, + 1, + 0.811, + 0, + 0.922, + 0, + 1.033, + 0, + 1, + 1.267, + 0, + 1.5, + 0, + 1.733, + 0, + 1, + 1.956, + 0, + 2.178, + 0, + 2.4, + 0, + 1, + 2.933, + 0, + 3.467, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + 0, + 0.7, + 0, + 1, + 0.744, + 0, + 0.789, + -0.1, + 0.833, + -0.1, + 1, + 0.878, + -0.1, + 0.922, + 0.1, + 0.967, + 0.1, + 1, + 0.989, + 0.1, + 1.011, + 0, + 1.033, + 0, + 1, + 1.267, + 0, + 1.5, + 0, + 1.733, + 0, + 1, + 1.789, + 0, + 1.844, + -0.1, + 1.9, + -0.1, + 1, + 1.978, + -0.1, + 2.056, + -0.1, + 2.133, + -0.1, + 1, + 2.2, + -0.1, + 2.267, + 0.1, + 2.333, + 0.1, + 1, + 2.356, + 0.1, + 2.378, + 0, + 2.4, + 0, + 1, + 2.933, + 0, + 3.467, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.767, + 0, + 0.8, + -0.2, + 0.833, + -0.2, + 1, + 0.878, + -0.2, + 0.922, + 0.555, + 0.967, + 0.56, + 1, + 1.222, + 0.591, + 1.478, + 0.6, + 1.733, + 0.6, + 1, + 1.789, + 0.6, + 1.844, + -0.1, + 1.9, + -0.1, + 1, + 1.978, + -0.1, + 2.056, + -0.1, + 2.133, + -0.1, + 1, + 2.222, + -0.1, + 2.311, + 0.3, + 2.4, + 0.3, + 1, + 2.933, + 0.3, + 3.467, + 0.3, + 4, + 0.3, + 0, + 4.033, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.767, + 0, + 0.8, + -0.2, + 0.833, + -0.2, + 1, + 0.878, + -0.2, + 0.922, + 0.61, + 0.967, + 0.61, + 1, + 1.222, + 0.61, + 1.478, + 0.608, + 1.733, + 0.6, + 1, + 1.789, + 0.598, + 1.844, + -0.1, + 1.9, + -0.1, + 1, + 1.978, + -0.1, + 2.056, + -0.1, + 2.133, + -0.1, + 1, + 2.222, + -0.1, + 2.311, + 0.3, + 2.4, + 0.3, + 1, + 2.933, + 0.3, + 3.467, + 0.3, + 4, + 0.3, + 0, + 4.033, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.811, + 0, + 0.889, + 0.3, + 0.967, + 0.3, + 1, + 1.222, + 0.3, + 1.478, + 0.3, + 1.733, + 0.3, + 1, + 1.956, + 0.3, + 2.178, + 0.2, + 2.4, + 0.2, + 1, + 2.933, + 0.2, + 3.467, + 0.2, + 4, + 0.2, + 0, + 4.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.811, + 0, + 0.889, + 0.3, + 0.967, + 0.3, + 1, + 1.222, + 0.3, + 1.478, + 0.3, + 1.733, + 0.3, + 1, + 1.956, + 0.3, + 2.178, + 0.2, + 2.4, + 0.2, + 1, + 2.933, + 0.2, + 3.467, + 0.2, + 4, + 0.2, + 0, + 4.033, + 0.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.811, + 0, + 0.889, + 0.4, + 0.967, + 0.4, + 1, + 1.222, + 0.4, + 1.478, + 0.4, + 1.733, + 0.4, + 1, + 1.956, + 0.4, + 2.178, + 0.5, + 2.4, + 0.5, + 1, + 2.933, + 0.5, + 3.467, + 0.5, + 4, + 0.5, + 0, + 4.033, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.811, + 0, + 0.889, + 0.4, + 0.967, + 0.4, + 1, + 1.222, + 0.4, + 1.478, + 0.4, + 1.733, + 0.4, + 1, + 1.956, + 0.4, + 2.178, + 0.5, + 2.4, + 0.5, + 1, + 2.933, + 0.5, + 3.467, + 0.5, + 4, + 0.5, + 0, + 4.033, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.811, + 0, + 0.889, + 0.4, + 0.967, + 0.4, + 1, + 1.222, + 0.4, + 1.478, + 0.4, + 1.733, + 0.4, + 1, + 1.956, + 0.4, + 2.178, + 0.3, + 2.4, + 0.3, + 1, + 2.933, + 0.3, + 3.467, + 0.3, + 4, + 0.3, + 0, + 4.033, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 0.811, + 0, + 0.889, + 0.4, + 0.967, + 0.4, + 1, + 1.222, + 0.4, + 1.478, + 0.4, + 1.733, + 0.4, + 1, + 1.956, + 0.4, + 2.178, + 0.3, + 2.4, + 0.3, + 1, + 2.933, + 0.3, + 3.467, + 0.3, + 4, + 0.3, + 0, + 4.033, + 0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.244, + 1, + 0.489, + 1, + 0.733, + 1, + 1, + 0.811, + 1, + 0.889, + -1, + 0.967, + -1, + 1, + 1.222, + -1, + 1.478, + -1, + 1.733, + -1, + 1, + 1.833, + -1, + 1.933, + -0.594, + 2.033, + 0, + 1, + 2.156, + 0.726, + 2.278, + 1, + 2.4, + 1, + 1, + 2.933, + 1, + 3.467, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.311, + 0, + 0.622, + 0, + 0.933, + 0, + 1, + 1.222, + 0, + 1.511, + -6, + 1.8, + -6, + 1, + 2.122, + -6, + 2.444, + 0, + 2.767, + 0, + 1, + 3.178, + 0, + 3.589, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -1, + 0.7, + -1, + 1, + 0.789, + -1, + 0.878, + 1, + 0.967, + 1, + 1, + 1.056, + 1, + 1.144, + 0, + 1.233, + 0, + 1, + 2.156, + 0, + 3.078, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.322, + 0, + 0.644, + 0, + 0.967, + 0, + 1, + 1.244, + 0, + 1.522, + 4, + 1.8, + 4, + 1, + 2.167, + 4, + 2.533, + 0, + 2.9, + 0, + 1, + 3.267, + 0, + 3.633, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 6, + 1, + 1.189, + 6, + 2.378, + 6, + 3.567, + 6, + 1, + 3.711, + 6, + 3.856, + 6, + 4, + 6, + 0, + 4.033, + 6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + -1, + 1, + 0.344, + -1, + 0.689, + -1, + 1.033, + -1, + 1, + 1.189, + -1, + 1.344, + -0.9, + 1.5, + -0.9, + 1, + 1.6, + -0.9, + 1.7, + -1, + 1.8, + -1, + 1, + 2.389, + -1, + 2.978, + -1, + 3.567, + -1, + 1, + 3.711, + -1, + 3.856, + -1, + 4, + -1, + 0, + 4.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + -1, + 1, + 0.344, + -1, + 0.689, + -1, + 1.033, + -1, + 1, + 1.189, + -1, + 1.344, + -0.9, + 1.5, + -0.9, + 1, + 1.6, + -0.9, + 1.7, + -1, + 1.8, + -1, + 1, + 2.389, + -1, + 2.978, + -1, + 3.567, + -1, + 1, + 3.711, + -1, + 3.856, + -1, + 4, + -1, + 0, + 4.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 1, + 1, + 1.333, + 1, + 2.667, + 1, + 4, + 1, + 0, + 4.033, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -1, + 1, + 1.333, + -1, + 2.667, + -1, + 4, + -1, + 0, + 4.033, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 1.333, + 0, + 2.667, + 0, + 4, + 0, + 0, + 4.033, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 4, + 0, + 0, + 4.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 4, + 0, + 0, + 4.03, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4, + 1, + 0, + 4.03, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4, + 0, + 0, + 4.03, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m26.motion3.json b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m26.motion3.json new file mode 100644 index 0000000..0b1b05d --- /dev/null +++ b/app/src/main/assets/live2d_model/Haru_pro_jp/motion/haru_g_m26.motion3.json @@ -0,0 +1,2470 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.97, + "Fps": 30.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 63, + "TotalSegmentCount": 326, + "TotalPointCount": 875, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Model", + "Id": "Opacity", + "Segments": [ + 0, + 1, + 1, + 1.64, + 1, + 3.29, + 1, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -5, + 1.3, + -5, + 1, + 1.489, + -5, + 1.678, + -4, + 1.867, + -4, + 1, + 2.244, + -4, + 2.622, + -4, + 3, + -4, + 1, + 3.144, + -4, + 3.289, + 2, + 3.433, + 2, + 1, + 3.744, + 2, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.367, + 0, + 0.733, + 0, + 1.1, + 0, + 1, + 1.144, + 0, + 1.189, + -13, + 1.233, + -13, + 1, + 1.289, + -13, + 1.344, + 11, + 1.4, + 11, + 1, + 1.589, + 11, + 1.778, + 6, + 1.967, + 6, + 1, + 2.333, + 6, + 2.7, + 6, + 3.067, + 6, + 1, + 3.211, + 6, + 3.356, + -22, + 3.5, + -22, + 1, + 3.656, + -22, + 3.811, + 12, + 3.967, + 12, + 1, + 4.122, + 12, + 4.278, + 0, + 4.433, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -8, + 1.3, + -8, + 1, + 1.489, + -8, + 1.678, + -6, + 1.867, + -6, + 1, + 2.244, + -6, + 2.622, + -6, + 3, + -6, + 1, + 3.144, + -6, + 3.289, + -9, + 3.433, + -9, + 1, + 3.589, + -9, + 3.744, + 7, + 3.9, + 7, + 1, + 4.056, + 7, + 4.211, + -2, + 4.367, + -2, + 1, + 4.556, + -2, + 4.744, + 0, + 4.933, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTere", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.5, + 1.3, + 0.5, + 1, + 1.867, + 0.5, + 2.433, + 0.5, + 3, + 0.5, + 1, + 3.456, + 0.5, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceForm", + "Segments": [ + 0, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.044, + 1, + 1.089, + 0, + 1.133, + 0, + 1, + 1.189, + 0, + 1.244, + 1.7, + 1.3, + 1.7, + 1, + 1.522, + 1.7, + 1.744, + 1.7, + 1.967, + 1.7, + 1, + 2, + 1.7, + 2.033, + 0, + 2.067, + 0, + 1, + 2.078, + 0, + 2.089, + 0, + 2.1, + 0, + 1, + 2.133, + 0, + 2.167, + 1.7, + 2.2, + 1.7, + 1, + 2.211, + 1.7, + 2.222, + 1.7, + 2.233, + 1.7, + 1, + 2.267, + 1.7, + 2.3, + 0, + 2.333, + 0, + 1, + 2.344, + 0, + 2.356, + 0, + 2.367, + 0, + 1, + 2.433, + 0, + 2.5, + 1.7, + 2.567, + 1.7, + 1, + 2.711, + 1.7, + 2.856, + 1.7, + 3, + 1.7, + 1, + 3.144, + 1.7, + 3.289, + 0, + 3.433, + 0, + 1, + 3.589, + 0, + 3.744, + 0, + 3.9, + 0, + 1, + 4.056, + 0, + 4.211, + 1, + 4.367, + 1, + 0, + 4.967, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.044, + 1, + 1.089, + 0, + 1.133, + 0, + 1, + 1.189, + 0, + 1.244, + 1.7, + 1.3, + 1.7, + 1, + 1.522, + 1.7, + 1.744, + 1.7, + 1.967, + 1.7, + 1, + 2, + 1.7, + 2.033, + 0, + 2.067, + 0, + 1, + 2.078, + 0, + 2.089, + 0, + 2.1, + 0, + 1, + 2.133, + 0, + 2.167, + 1.7, + 2.2, + 1.7, + 1, + 2.211, + 1.7, + 2.222, + 1.7, + 2.233, + 1.7, + 1, + 2.267, + 1.7, + 2.3, + 0, + 2.333, + 0, + 1, + 2.344, + 0, + 2.356, + 0, + 2.367, + 0, + 1, + 2.433, + 0, + 2.5, + 1.7, + 2.567, + 1.7, + 1, + 2.711, + 1.7, + 2.856, + 1.7, + 3, + 1.7, + 1, + 3.144, + 1.7, + 3.289, + 0, + 3.433, + 0, + 1, + 3.589, + 0, + 3.744, + 0, + 3.9, + 0, + 1, + 4.056, + 0, + 4.211, + 1, + 4.367, + 1, + 0, + 4.967, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -0.6, + 1.3, + -0.6, + 1, + 1.867, + -0.6, + 2.433, + -0.6, + 3, + -0.6, + 1, + 3.456, + -0.6, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamTear", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.2, + 1.3, + 0.2, + 1, + 1.522, + 0.2, + 1.744, + 0.2, + 1.967, + 0.2, + 1, + 2, + 0.2, + 2.033, + 0.2, + 2.067, + 0.2, + 1, + 2.078, + 0.2, + 2.089, + 0.2, + 2.1, + 0.2, + 1, + 2.133, + 0.2, + 2.167, + 0.2, + 2.2, + 0.2, + 1, + 2.211, + 0.2, + 2.222, + 0.2, + 2.233, + 0.2, + 1, + 2.267, + 0.2, + 2.3, + 0.2, + 2.333, + 0.2, + 1, + 2.344, + 0.2, + 2.356, + 0.2, + 2.367, + 0.2, + 1, + 2.433, + 0.2, + 2.5, + 0.2, + 2.567, + 0.2, + 1, + 2.711, + 0.2, + 2.856, + 0.2, + 3, + 0.2, + 1, + 3.456, + 0.2, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.1, + 1.3, + 0.1, + 1, + 1.522, + 0.1, + 1.744, + 0.1, + 1.967, + 0.1, + 1, + 2, + 0.1, + 2.033, + -0.2, + 2.067, + -0.2, + 1, + 2.078, + -0.2, + 2.089, + -0.2, + 2.1, + -0.2, + 1, + 2.133, + -0.2, + 2.167, + 0.1, + 2.2, + 0.1, + 1, + 2.211, + 0.1, + 2.222, + 0.1, + 2.233, + 0.1, + 1, + 2.267, + 0.1, + 2.3, + -0.2, + 2.333, + -0.2, + 1, + 2.344, + -0.2, + 2.356, + -0.2, + 2.367, + -0.2, + 1, + 2.433, + -0.2, + 2.5, + 0.1, + 2.567, + 0.1, + 1, + 2.711, + 0.1, + 2.856, + 0.1, + 3, + 0.1, + 1, + 3.456, + 0.1, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.8, + 1.3, + 0.8, + 1, + 1.867, + 0.8, + 2.433, + 0.8, + 3, + 0.8, + 1, + 3.144, + 0.8, + 3.289, + -0.5, + 3.433, + -0.5, + 1, + 3.744, + -0.5, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.8, + 1.3, + 0.8, + 1, + 1.867, + 0.8, + 2.433, + 0.8, + 3, + 0.8, + 1, + 3.144, + 0.8, + 3.289, + -0.5, + 3.433, + -0.5, + 1, + 3.744, + -0.5, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.5, + 1.3, + 0.5, + 1, + 1.867, + 0.5, + 2.433, + 0.5, + 3, + 0.5, + 1, + 3.144, + 0.5, + 3.289, + -0.4, + 3.433, + -0.4, + 1, + 3.744, + -0.4, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.5, + 1.3, + 0.5, + 1, + 1.867, + 0.5, + 2.433, + 0.5, + 3, + 0.5, + 1, + 3.456, + 0.5, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.4, + 1.3, + 0.4, + 1, + 1.867, + 0.4, + 2.433, + 0.4, + 3, + 0.4, + 1, + 3.144, + 0.4, + 3.289, + 0, + 3.433, + 0, + 1, + 3.744, + 0, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0.4, + 1.3, + 0.4, + 1, + 1.867, + 0.4, + 2.433, + 0.4, + 3, + 0.4, + 1, + 3.144, + 0.4, + 3.289, + 0, + 3.433, + 0, + 1, + 3.744, + 0, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -0.6, + 1.3, + -0.6, + 1, + 1.867, + -0.6, + 2.433, + -0.6, + 3, + -0.6, + 1, + 3.144, + -0.6, + 3.289, + -0.412, + 3.433, + -0.3, + 1, + 3.744, + -0.059, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -0.6, + 1.3, + -0.6, + 1, + 1.867, + -0.6, + 2.433, + -0.6, + 3, + -0.6, + 1, + 3.144, + -0.6, + 3.289, + -0.412, + 3.433, + -0.3, + 1, + 3.744, + -0.059, + 4.056, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthForm", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + -0.6, + 1.3, + -0.6, + 1, + 1.867, + -0.6, + 2.433, + -0.6, + 3, + -0.6, + 1, + 3.456, + -0.6, + 3.911, + 1, + 4.367, + 1, + 0, + 4.967, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthOpenY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamScarf", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -3, + 1.3, + -3, + 1, + 1.489, + -3, + 1.678, + -2, + 1.867, + -2, + 1, + 2.244, + -2, + 2.622, + -2, + 3, + -2, + 1, + 3.456, + -2, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.044, + 0, + 1.089, + -2, + 1.133, + -2, + 1, + 1.189, + -2, + 1.244, + 5, + 1.3, + 5, + 1, + 1.489, + 5, + 1.678, + 4, + 1.867, + 4, + 1, + 2.244, + 4, + 2.622, + 4, + 3, + 4, + 1, + 3.144, + 4, + 3.289, + -7, + 3.433, + -7, + 1, + 3.589, + -7, + 3.744, + 9, + 3.9, + 9, + 1, + 4.056, + 9, + 4.211, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -3, + 1.3, + -3, + 1, + 1.489, + -3, + 1.678, + -2, + 1.867, + -2, + 1, + 2.244, + -2, + 2.622, + -2, + 3, + -2, + 1, + 3.456, + -2, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyUpper", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + -7, + 1.3, + -7, + 1, + 1.489, + -7, + 1.678, + -6, + 1.867, + -6, + 1, + 2.244, + -6, + 2.622, + -6, + 3, + -6, + 1, + 3.144, + -6, + 3.289, + 1.057, + 3.433, + 3, + 1, + 3.589, + 5.092, + 3.744, + 5, + 3.9, + 5, + 1, + 4.056, + 5, + 4.211, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBustY", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.489, + 0.3, + 1.678, + 0.4, + 1.867, + 0.4, + 1, + 2.244, + 0.4, + 2.622, + 0.4, + 3, + 0.4, + 1, + 3.144, + 0.4, + 3.289, + 0.4, + 3.433, + 0.4, + 1, + 3.589, + 0.4, + 3.744, + 0.4, + 3.9, + 0.4, + 1, + 4.056, + 0.4, + 4.211, + 1, + 4.367, + 1, + 0, + 4.967, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA", + "Segments": [ + 0, + 1, + 1, + 0.333, + 1, + 0.667, + 1, + 1, + 1, + 1, + 1.1, + 1, + 1.2, + 0.3, + 1.3, + 0.3, + 1, + 1.489, + 0.3, + 1.678, + 0.4, + 1.867, + 0.4, + 1, + 2.244, + 0.4, + 2.622, + 0.4, + 3, + 0.4, + 1, + 3.144, + 0.4, + 3.289, + 0.4, + 3.433, + 0.4, + 1, + 3.589, + 0.4, + 3.744, + 0.4, + 3.9, + 0.4, + 1, + 4.056, + 0.4, + 4.211, + 1, + 4.367, + 1, + 0, + 4.967, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB", + "Segments": [ + 0, + 5, + 1, + 0.333, + 5, + 0.667, + 5, + 1, + 5, + 1, + 1.1, + 5, + 1.2, + 5, + 1.3, + 5, + 1, + 1.867, + 5, + 2.433, + 5, + 3, + 5, + 1, + 3.456, + 5, + 3.911, + 5, + 4.367, + 5, + 0, + 4.967, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandChangeR", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleR", + "Segments": [ + 0, + 0.19, + 1, + 0.333, + 0.19, + 0.667, + 0.19, + 1, + 0.19, + 1, + 1.044, + 0.19, + 1.089, + 1, + 1.133, + 1, + 1, + 1.189, + 1, + 1.244, + 0.19, + 1.3, + 0.19, + 1, + 1.489, + 0.19, + 1.678, + 0.4, + 1.867, + 0.4, + 1, + 2.244, + 0.4, + 2.622, + 0.4, + 3, + 0.4, + 1, + 3.144, + 0.4, + 3.289, + -0.8, + 3.433, + -0.8, + 1, + 3.589, + -0.8, + 3.744, + -0.718, + 3.9, + -0.4, + 1, + 4.056, + -0.082, + 4.211, + 0.19, + 4.367, + 0.19, + 0, + 4.967, + 0.19 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandDhangeL", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandAngleL", + "Segments": [ + 0, + -0.17, + 1, + 0.333, + -0.17, + 0.667, + -0.17, + 1, + -0.17, + 1, + 1.044, + -0.17, + 1.089, + -0.6, + 1.133, + -0.6, + 1, + 1.189, + -0.6, + 1.244, + -0.17, + 1.3, + -0.17, + 1, + 1.489, + -0.17, + 1.678, + -0.5, + 1.867, + -0.5, + 1, + 2.244, + -0.5, + 2.622, + -0.5, + 3, + -0.5, + 1, + 3.144, + -0.5, + 3.289, + 1, + 3.433, + 1, + 1, + 3.589, + 1, + 3.744, + 0.997, + 3.9, + 0.7, + 1, + 4.056, + 0.403, + 4.211, + -0.17, + 4.367, + -0.17, + 0, + 4.967, + -0.17 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSide", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 1, + 0.333, + 0, + 0.667, + 0, + 1, + 0, + 1, + 1.1, + 0, + 1.2, + 0, + 1.3, + 0, + 1, + 1.867, + 0, + 2.433, + 0, + 3, + 0, + 1, + 3.456, + 0, + 3.911, + 0, + 4.367, + 0, + 0, + 4.967, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Core", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Hoho001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Brow001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Tear", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01EyeBall001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Eye001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Nose001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Mouth001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Face001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Ear001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Neck001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairFront001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairSide001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01HairBack001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRB001", + "Segments": [ + 0, + 0, + 2, + 4.93, + 0, + 0, + 4.97, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLB001", + "Segments": [ + 0, + 0, + 2, + 4.93, + 0, + 0, + 4.97, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmRA001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01ArmLA001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Body001", + "Segments": [ + 0, + 1, + 2, + 4.93, + 1, + 0, + 4.97, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "Part01Sketch", + "Segments": [ + 0, + 0, + 2, + 4.93, + 0, + 0, + 4.97, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_01.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_01.exp3.json new file mode 100644 index 0000000..bad34d9 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_01.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_02.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_02.exp3.json new file mode 100644 index 0000000..137d0be --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_02.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 0, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 0, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_03.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_03.exp3.json new file mode 100644 index 0000000..032bdb1 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_03.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 0, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 0, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_04.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_04.exp3.json new file mode 100644 index 0000000..6d23927 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_04.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 1.2, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 1.2, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_05.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_05.exp3.json new file mode 100644 index 0000000..1d44e13 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_05.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_06.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_06.exp3.json new file mode 100644 index 0000000..551a0ae --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_06.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_07.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_07.exp3.json new file mode 100644 index 0000000..cff53e1 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_07.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 1.2, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 1.2, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 0, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_08.exp3.json b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_08.exp3.json new file mode 100644 index 0000000..38d376d --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/expressions/exp_08.exp3.json @@ -0,0 +1,147 @@ +{ + "Type": "Live2D Expression", + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Parameters": [ + { + "Id": "ParamCheek", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLOpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeLSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeLForm", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeROpen", + "Value": 1, + "Blend": "Multiply" + }, + { + "Id": "ParamEyeRSmile", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeRForm", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeBallForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamEyeEffect", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRY", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRX", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRAngle", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowLForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamBrowRForm", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamA", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamI", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamU", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamE", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamO", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthUp", + "Value": -1, + "Blend": "Add" + }, + { + "Id": "ParamMouthDown", + "Value": 0, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngry", + "Value": 1, + "Blend": "Add" + }, + { + "Id": "ParamMouthAngryLine", + "Value": 1, + "Blend": "Add" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.4096/texture_00.png b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.4096/texture_00.png new file mode 100644 index 0000000..b8501e8 Binary files /dev/null and b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.4096/texture_00.png differ diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.cdi3.json b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.cdi3.json new file mode 100644 index 0000000..e5a44c0 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.cdi3.json @@ -0,0 +1,886 @@ +{ + "Version": 3, + "Parameters": [ + { + "Id": "ParamAngleX", + "GroupId": "ParamGroupFace", + "Name": "角度X" + }, + { + "Id": "ParamAngleY", + "GroupId": "ParamGroupFace", + "Name": "角度Y" + }, + { + "Id": "ParamAngleZ", + "GroupId": "ParamGroupFace", + "Name": "角度Z" + }, + { + "Id": "ParamCheek", + "GroupId": "ParamGroupFace", + "Name": "脸颊红晕" + }, + { + "Id": "ParamFaceInkOn", + "GroupId": "ParamGroupFace", + "Name": "脸墨水 显示" + }, + { + "Id": "ParamEyeLOpen", + "GroupId": "ParamGroupEyes", + "Name": "左眼开闭" + }, + { + "Id": "ParamEyeLSmile", + "GroupId": "ParamGroupEyes", + "Name": "左眼微笑" + }, + { + "Id": "ParamEyeLForm", + "GroupId": "ParamGroupEyes", + "Name": "左眼变形" + }, + { + "Id": "ParamEyeROpen", + "GroupId": "ParamGroupEyes", + "Name": "右眼开闭" + }, + { + "Id": "ParamEyeRSmile", + "GroupId": "ParamGroupEyes", + "Name": "右眼微笑" + }, + { + "Id": "ParamEyeRForm", + "GroupId": "ParamGroupEyes", + "Name": "右眼变形" + }, + { + "Id": "ParamEyeBallX", + "GroupId": "ParamGroupEyeballs", + "Name": "眼珠X" + }, + { + "Id": "ParamEyeBallY", + "GroupId": "ParamGroupEyeballs", + "Name": "眼珠Y" + }, + { + "Id": "ParamEyeBallForm", + "GroupId": "ParamGroupEyeballs", + "Name": "眼珠收缩" + }, + { + "Id": "ParamEyeEffect", + "GroupId": "ParamGroupEyeballs", + "Name": "眼睛 特效" + }, + { + "Id": "ParamBrowLY", + "GroupId": "ParamGroupBrows", + "Name": "左眉上下" + }, + { + "Id": "ParamBrowRY", + "GroupId": "ParamGroupBrows", + "Name": "右眉上下" + }, + { + "Id": "ParamBrowLX", + "GroupId": "ParamGroupBrows", + "Name": "左眉左右" + }, + { + "Id": "ParamBrowRX", + "GroupId": "ParamGroupBrows", + "Name": "右眉左右" + }, + { + "Id": "ParamBrowLAngle", + "GroupId": "ParamGroupBrows", + "Name": "左眉角度" + }, + { + "Id": "ParamBrowRAngle", + "GroupId": "ParamGroupBrows", + "Name": "右眉角度" + }, + { + "Id": "ParamBrowLForm", + "GroupId": "ParamGroupBrows", + "Name": "左眉变形" + }, + { + "Id": "ParamBrowRForm", + "GroupId": "ParamGroupBrows", + "Name": "右眉变形" + }, + { + "Id": "ParamA", + "GroupId": "ParamGroupMouth", + "Name": "A" + }, + { + "Id": "ParamI", + "GroupId": "ParamGroupMouth", + "Name": "I" + }, + { + "Id": "ParamU", + "GroupId": "ParamGroupMouth", + "Name": "U" + }, + { + "Id": "ParamE", + "GroupId": "ParamGroupMouth", + "Name": "E" + }, + { + "Id": "ParamO", + "GroupId": "ParamGroupMouth", + "Name": "O" + }, + { + "Id": "ParamMouthUp", + "GroupId": "ParamGroupMouth", + "Name": "嘴角上扬" + }, + { + "Id": "ParamMouthDown", + "GroupId": "ParamGroupMouth", + "Name": "嘴角下垂" + }, + { + "Id": "ParamMouthAngry", + "GroupId": "ParamGroupMouth", + "Name": "嘟嘴" + }, + { + "Id": "ParamMouthAngryLine", + "GroupId": "ParamGroupMouth", + "Name": "嘟嘴 描线" + }, + { + "Id": "ParamBodyAngleX", + "GroupId": "ParamGroupBody", + "Name": "身体的旋转X" + }, + { + "Id": "ParamBodyAngleY", + "GroupId": "ParamGroupBody", + "Name": "身体的旋转Y" + }, + { + "Id": "ParamBodyAngleZ", + "GroupId": "ParamGroupBody", + "Name": "身体的旋转Z" + }, + { + "Id": "ParamBreath", + "GroupId": "ParamGroupBody", + "Name": "呼吸" + }, + { + "Id": "ParamLeftShoulderUp", + "GroupId": "ParamGroupBody", + "Name": "左肩的上下" + }, + { + "Id": "ParamRightShoulderUp", + "GroupId": "ParamGroupBody", + "Name": "右肩的上下" + }, + { + "Id": "ParamArmLA01", + "GroupId": "ParamGroupArmLA", + "Name": "左手臂A 肩的旋转" + }, + { + "Id": "ParamArmLA02", + "GroupId": "ParamGroupArmLA", + "Name": "左手臂A 手肘的旋转" + }, + { + "Id": "ParamArmLA03", + "GroupId": "ParamGroupArmLA", + "Name": "左手臂A 手腕的旋转" + }, + { + "Id": "ParamHandLA", + "GroupId": "ParamGroupArmLA", + "Name": "左手A" + }, + { + "Id": "ParamArmRA01", + "GroupId": "ParamGroupArmRA", + "Name": "右手臂A 肩的旋转" + }, + { + "Id": "ParamArmRA02", + "GroupId": "ParamGroupArmRA", + "Name": "右手臂A 手肘的旋转" + }, + { + "Id": "ParamArmRA03", + "GroupId": "ParamGroupArmRA", + "Name": "右手臂A 手腕的旋转" + }, + { + "Id": "ParamWandRotate", + "GroupId": "ParamGroupArmRA", + "Name": "手杖旋转" + }, + { + "Id": "ParamHandRA", + "GroupId": "ParamGroupArmRA", + "Name": "右手A" + }, + { + "Id": "ParamInkDrop", + "GroupId": "ParamGroupArmRA", + "Name": "墨滴" + }, + { + "Id": "ParamInkDropRotate", + "GroupId": "ParamGroupArmRA", + "Name": "墨滴 旋转" + }, + { + "Id": "ParamInkDropOn", + "GroupId": "ParamGroupArmRA", + "Name": "墨滴 显示" + }, + { + "Id": "ParamArmLB01", + "GroupId": "ParamGroupArmLB", + "Name": "左手臂B 肩的旋转" + }, + { + "Id": "ParamArmLB02", + "GroupId": "ParamGroupArmLB", + "Name": "左手臂B 手肘的旋转" + }, + { + "Id": "ParamArmLB03", + "GroupId": "ParamGroupArmLB", + "Name": "左手臂B 手腕的旋转" + }, + { + "Id": "ParamHandLB", + "GroupId": "ParamGroupArmLB", + "Name": "左手B" + }, + { + "Id": "ParamHatForm", + "GroupId": "ParamGroupArmLB", + "Name": "帽子的变形" + }, + { + "Id": "ParamArmRB01", + "GroupId": "ParamGroupArmRB", + "Name": "右手臂B 肩的旋转" + }, + { + "Id": "ParamArmRB02", + "GroupId": "ParamGroupArmRB", + "Name": "右手臂B 手肘的旋转" + }, + { + "Id": "ParamArmRB02Y", + "GroupId": "ParamGroupArmRB", + "Name": "右手臂B 臂的Y" + }, + { + "Id": "ParamArmRB03", + "GroupId": "ParamGroupArmRB", + "Name": "右手臂B 手腕的旋转" + }, + { + "Id": "ParamHandRB", + "GroupId": "ParamGroupArmRB", + "Name": "右手B" + }, + { + "Id": "ParamAllX", + "GroupId": "ParamGroupOverall", + "Name": "整体的移动X" + }, + { + "Id": "ParamAllY", + "GroupId": "ParamGroupOverall", + "Name": "整体的移动Y" + }, + { + "Id": "ParamAllRotate", + "GroupId": "ParamGroupOverall", + "Name": "整体的旋转" + }, + { + "Id": "ParamHairFront", + "GroupId": "ParamGroupSway", + "Name": "头发摇动 前" + }, + { + "Id": "ParamHairSideL", + "GroupId": "ParamGroupSway", + "Name": "头发摇动 左侧" + }, + { + "Id": "ParamHairSideR", + "GroupId": "ParamGroupSway", + "Name": "头发摇动 右侧" + }, + { + "Id": "ParamHairBack", + "GroupId": "ParamGroupSway", + "Name": "头发摇动 后" + }, + { + "Id": "ParamHairBackR", + "GroupId": "ParamGroupSway", + "Name": "头发摇动 右后" + }, + { + "Id": "ParamHairBackL", + "GroupId": "ParamGroupSway", + "Name": "头发摇动 左后" + }, + { + "Id": "ParamoHairMesh", + "GroupId": "ParamGroupSway", + "Name": "挑染的摇动" + }, + { + "Id": "ParamHairFrontFuwa", + "GroupId": "ParamGroupSway", + "Name": "前发 蓬松" + }, + { + "Id": "ParamHairSideFuwa", + "GroupId": "ParamGroupSway", + "Name": "侧发 蓬松" + }, + { + "Id": "ParamHairBackFuwa", + "GroupId": "ParamGroupSway", + "Name": "后发 蓬松" + }, + { + "Id": "ParamWing", + "GroupId": "ParamGroupSway", + "Name": "羽毛的摇动" + }, + { + "Id": "ParamRibbon", + "GroupId": "ParamGroupSway", + "Name": "帽子蝴蝶结的摇动" + }, + { + "Id": "ParamHatBrim", + "GroupId": "ParamGroupSway", + "Name": "帽檐的摇动" + }, + { + "Id": "ParamHatTop", + "GroupId": "ParamGroupSway", + "Name": "帽盖的摇动" + }, + { + "Id": "ParamAccessory1", + "GroupId": "ParamGroupSway", + "Name": "颈饰的摇动1" + }, + { + "Id": "ParamAccessory2", + "GroupId": "ParamGroupSway", + "Name": "颈饰的摇动2" + }, + { + "Id": "ParamString", + "GroupId": "ParamGroupSway", + "Name": "帽带的摇动" + }, + { + "Id": "ParamRobeL", + "GroupId": "ParamGroupSway", + "Name": "长袍的摇动 左" + }, + { + "Id": "ParamRobeR", + "GroupId": "ParamGroupSway", + "Name": "长袍的摇动 右" + }, + { + "Id": "ParamRobeFuwa", + "GroupId": "ParamGroupSway", + "Name": "长袍的蓬松" + }, + { + "Id": "ParamHeartMissOn", + "GroupId": "ParamGroupHeart", + "Name": "爱心失败的显示" + }, + { + "Id": "ParamHeartBackMissOn", + "GroupId": "ParamGroupHeart", + "Name": "爱心背侧失败的显示" + }, + { + "Id": "ParamHeartColorRainbow", + "GroupId": "ParamGroupHeart", + "Name": "爱心失败的彩虹" + }, + { + "Id": "ParamHeartHealOn", + "GroupId": "ParamGroupHeart", + "Name": "爱心恢复的显示" + }, + { + "Id": "ParamHeartBackHealOn", + "GroupId": "ParamGroupHeart", + "Name": "爱心背侧恢复的显示" + }, + { + "Id": "ParamHeartColorHeal", + "GroupId": "ParamGroupHeart", + "Name": "爱心恢复 绿色" + }, + { + "Id": "ParamHeartDrow", + "GroupId": "ParamGroupHeart", + "Name": "爱心绘制" + }, + { + "Id": "ParamHeartSize", + "GroupId": "ParamGroupHeart", + "Name": "爱心缩放" + }, + { + "Id": "ParamHeartColorLight", + "GroupId": "ParamGroupHeart", + "Name": "爱心颜色变化" + }, + { + "Id": "ParamWandInkColorRainbow", + "GroupId": "ParamGroupInk", + "Name": "手杖的墨水 彩虹" + }, + { + "Id": "ParamWandInkColorHeal", + "GroupId": "ParamGroupInk", + "Name": "手杖的墨水 绿色" + }, + { + "Id": "ParamWandInk", + "GroupId": "ParamGroupInk", + "Name": "手杖的墨水" + }, + { + "Id": "ParamSmokeOn", + "GroupId": "ParamGroupExplosion", + "Name": "烟雾 显示" + }, + { + "Id": "ParamSmoke", + "GroupId": "ParamGroupExplosion", + "Name": "烟雾" + }, + { + "Id": "ParamExplosionChargeOn", + "GroupId": "ParamGroupExplosion", + "Name": "爆炸光效 聚合光波的显示" + }, + { + "Id": "ParamExplosionLightCharge", + "GroupId": "ParamGroupExplosion", + "Name": "爆炸光效 聚合光波" + }, + { + "Id": "ParamExplosionOn", + "GroupId": "ParamGroupExplosion", + "Name": "爆炸 显示" + }, + { + "Id": "ParamExplosion", + "GroupId": "ParamGroupExplosion", + "Name": "爆炸" + }, + { + "Id": "ParamRabbitElimination", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 消失" + }, + { + "Id": "ParamRabbitAppearance", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 出现" + }, + { + "Id": "ParamRabbitSize", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 缩放" + }, + { + "Id": "ParamRabbitDraworder", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 绘制顺序" + }, + { + "Id": "ParamRabbitEar", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 耳朵" + }, + { + "Id": "ParamRabbitDirection", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 方向" + }, + { + "Id": "ParamRabbitLight", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 颜色变化" + }, + { + "Id": "ParamRabbitLightSize", + "GroupId": "ParamGroupRabbit", + "Name": "兔子 光 缩放" + }, + { + "Id": "ParamRabbitX", + "GroupId": "ParamGroupRabbit", + "Name": "兔子的移动 X" + }, + { + "Id": "ParamRabbitY", + "GroupId": "ParamGroupRabbit", + "Name": "兔子的移动 Y" + }, + { + "Id": "ParamRabbitRotate", + "GroupId": "ParamGroupRabbit", + "Name": "兔子的旋转" + }, + { + "Id": "ParamAuraOn", + "GroupId": "ParamGroupAura", + "Name": "光环 显示" + }, + { + "Id": "ParamAura", + "GroupId": "ParamGroupAura", + "Name": "光环" + }, + { + "Id": "ParamAuraColor1", + "GroupId": "ParamGroupAura", + "Name": "光环 颜色变化1" + }, + { + "Id": "ParamAuraColor2", + "GroupId": "ParamGroupAura", + "Name": "光环 颜色变化2" + }, + { + "Id": "ParamHeartLightOn", + "GroupId": "ParamGroupLight", + "Name": "光效 显示" + }, + { + "Id": "ParamHeartLight", + "GroupId": "ParamGroupLight", + "Name": "光效 星星" + }, + { + "Id": "ParamHeartLightColor", + "GroupId": "ParamGroupLight", + "Name": "光效 颜色变化" + }, + { + "Id": "ParamHealLightOn", + "GroupId": "ParamGroupLight", + "Name": "恢复魔法光效 显示" + }, + { + "Id": "ParamHealLight", + "GroupId": "ParamGroupLight", + "Name": "恢复魔法光效" + }, + { + "Id": "ParamStrengthenLightOn", + "GroupId": "ParamGroupLight", + "Name": "魔法效果 强化 显示" + }, + { + "Id": "ParamStrengthenLight", + "GroupId": "ParamGroupLight", + "Name": "魔法效果 强化 光" + }, + { + "Id": "ParamStrengthenLightMove", + "GroupId": "ParamGroupLight", + "Name": "魔法效果 强化 移动" + }, + { + "Id": "ParamMagicPositionX", + "GroupId": "ParamGroupAllEffects", + "Name": "魔法的位置X" + }, + { + "Id": "ParamMagicPositionY", + "GroupId": "ParamGroupAllEffects", + "Name": "魔法的位置Y" + }, + { + "Id": "ParamAllColor1", + "GroupId": "ParamGroupAllEffects", + "Name": "整体的颜色1" + }, + { + "Id": "ParamAllColor2", + "GroupId": "ParamGroupAllEffects", + "Name": "整体的颜色2" + } + ], + "ParameterGroups": [ + { + "Id": "ParamGroupFace", + "GroupId": "", + "Name": "脸" + }, + { + "Id": "ParamGroupEyes", + "GroupId": "", + "Name": "眼睛" + }, + { + "Id": "ParamGroupEyeballs", + "GroupId": "", + "Name": "眼珠" + }, + { + "Id": "ParamGroupBrows", + "GroupId": "", + "Name": "眉毛" + }, + { + "Id": "ParamGroupMouth", + "GroupId": "", + "Name": "嘴" + }, + { + "Id": "ParamGroupBody", + "GroupId": "", + "Name": "身体" + }, + { + "Id": "ParamGroupArmLA", + "GroupId": "", + "Name": "左手臂A" + }, + { + "Id": "ParamGroupArmRA", + "GroupId": "", + "Name": "右手臂A" + }, + { + "Id": "ParamGroupArmLB", + "GroupId": "", + "Name": "左手臂B" + }, + { + "Id": "ParamGroupArmRB", + "GroupId": "", + "Name": "右手臂B" + }, + { + "Id": "ParamGroupOverall", + "GroupId": "", + "Name": "整体" + }, + { + "Id": "ParamGroupSway", + "GroupId": "", + "Name": "摇动" + }, + { + "Id": "ParamGroupHeart", + "GroupId": "", + "Name": "爱心" + }, + { + "Id": "ParamGroupInk", + "GroupId": "", + "Name": "墨水" + }, + { + "Id": "ParamGroupExplosion", + "GroupId": "", + "Name": "爆炸" + }, + { + "Id": "ParamGroupRabbit", + "GroupId": "", + "Name": "兔子" + }, + { + "Id": "ParamGroupAura", + "GroupId": "", + "Name": "光环" + }, + { + "Id": "ParamGroupLight", + "GroupId": "", + "Name": "光效" + }, + { + "Id": "ParamGroupAllEffects", + "GroupId": "", + "Name": "整体 光效" + } + ], + "Parts": [ + { + "Id": "PartCore", + "Name": "Core" + }, + { + "Id": "Part", + "Name": "兔子" + }, + { + "Id": "Part2", + "Name": "光效" + }, + { + "Id": "PartInk", + "Name": "墨水" + }, + { + "Id": "PartSmoke", + "Name": "烟雾" + }, + { + "Id": "PartExplosionLight", + "Name": "爆炸光效" + }, + { + "Id": "Partaura", + "Name": "光环" + }, + { + "Id": "PartLight", + "Name": "光效" + }, + { + "Id": "PartHeart", + "Name": "爱心" + }, + { + "Id": "PartHat", + "Name": "帽子" + }, + { + "Id": "PartHairSide", + "Name": "侧发" + }, + { + "Id": "PartHairFront", + "Name": "前发" + }, + { + "Id": "PartHairBack", + "Name": "后发" + }, + { + "Id": "PartBrow", + "Name": "眉毛" + }, + { + "Id": "PartEye", + "Name": "眼睛" + }, + { + "Id": "PartCheek", + "Name": "脸颊" + }, + { + "Id": "PartNose", + "Name": "鼻子" + }, + { + "Id": "PartMouth", + "Name": "嘴" + }, + { + "Id": "PartFace", + "Name": "脸" + }, + { + "Id": "PartEar", + "Name": "耳朵" + }, + { + "Id": "PartNeck", + "Name": "脖子" + }, + { + "Id": "PartRobe", + "Name": "长袍" + }, + { + "Id": "PartHoodie", + "Name": "帽衫" + }, + { + "Id": "PartLeg", + "Name": "腿" + }, + { + "Id": "PartArmLA", + "Name": "左手臂A" + }, + { + "Id": "PartArmRA", + "Name": "右手臂A" + }, + { + "Id": "PartArmLB", + "Name": "左手臂B" + }, + { + "Id": "PartArmRB", + "Name": "右手臂B" + }, + { + "Id": "PartSketch", + "Name": "[参考图]" + }, + { + "Id": "PartEyeBall", + "Name": "眼珠" + }, + { + "Id": "PartWandA", + "Name": "手杖A" + }, + { + "Id": "PartWandB", + "Name": "手杖B" + } + ], + "CombinedParameters": [ + [ + "ParamAngleX", + "ParamAngleY" + ], + [ + "ParamAllX", + "ParamAllY" + ], + [ + "ParamMagicPositionX", + "ParamMagicPositionY" + ] + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.moc3 b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.moc3 new file mode 100644 index 0000000..e0236f7 Binary files /dev/null and b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.moc3 differ diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.model3.json b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.model3.json new file mode 100644 index 0000000..1ea28ff --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.model3.json @@ -0,0 +1,100 @@ +{ + "Version": 3, + "FileReferences": { + "Moc": "mao_pro.moc3", + "Textures": [ + "mao_pro.4096/texture_00.png" + ], + "Physics": "mao_pro.physics3.json", + "Pose": "mao_pro.pose3.json", + "DisplayInfo": "mao_pro.cdi3.json", + "Expressions": [ + { + "Name": "exp_01", + "File": "expressions/exp_01.exp3.json" + }, + { + "Name": "exp_02", + "File": "expressions/exp_02.exp3.json" + }, + { + "Name": "exp_03", + "File": "expressions/exp_03.exp3.json" + }, + { + "Name": "exp_04", + "File": "expressions/exp_04.exp3.json" + }, + { + "Name": "exp_05", + "File": "expressions/exp_05.exp3.json" + }, + { + "Name": "exp_06", + "File": "expressions/exp_06.exp3.json" + }, + { + "Name": "exp_07", + "File": "expressions/exp_07.exp3.json" + }, + { + "Name": "exp_08", + "File": "expressions/exp_08.exp3.json" + } + ], + "Motions": { + "Idle": [ + { + "File": "motions/mtn_01.motion3.json" + } + ], + "": [ + { + "File": "motions/mtn_02.motion3.json" + }, + { + "File": "motions/mtn_03.motion3.json" + }, + { + "File": "motions/mtn_04.motion3.json" + }, + { + "File": "motions/special_01.motion3.json" + }, + { + "File": "motions/special_02.motion3.json" + }, + { + "File": "motions/special_03.motion3.json" + } + ] + } + }, + "Groups": [ + { + "Target": "Parameter", + "Name": "EyeBlink", + "Ids": [ + "ParamEyeLOpen", + "ParamEyeROpen" + ] + }, + { + "Target": "Parameter", + "Name": "LipSync", + "Ids": [ + "ParamA" + ] + } + ], + "HitAreas": [ + { + "Id": "HitAreaHead", + "Name": "" + }, + { + "Id": "HitAreaBody", + "Name": "" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.physics3.json b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.physics3.json new file mode 100644 index 0000000..3bcdee9 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.physics3.json @@ -0,0 +1,1361 @@ +{ + "Version": 3, + "Meta": { + "PhysicsSettingCount": 16, + "TotalInputCount": 43, + "TotalOutputCount": 20, + "VertexCount": 33, + "Fps": 30, + "EffectiveForces": { + "Gravity": { + "X": 0, + "Y": -1 + }, + "Wind": { + "X": 0, + "Y": 0 + } + }, + "PhysicsDictionary": [ + { + "Id": "PhysicsSetting1", + "Name": "头发摇动 前" + }, + { + "Id": "PhysicsSetting2", + "Name": "头发摇动 侧" + }, + { + "Id": "PhysicsSetting3", + "Name": "头发摇动 后" + }, + { + "Id": "PhysicsSetting4", + "Name": "头发摇动 后左右" + }, + { + "Id": "PhysicsSetting5", + "Name": "挑染摇动" + }, + { + "Id": "PhysicsSetting6", + "Name": "前发 蓬松" + }, + { + "Id": "PhysicsSetting7", + "Name": "侧发 蓬松" + }, + { + "Id": "PhysicsSetting8", + "Name": "后发 蓬松" + }, + { + "Id": "PhysicsSetting9", + "Name": "帽檐摇动" + }, + { + "Id": "PhysicsSetting10", + "Name": "帽子蝴蝶结摇动" + }, + { + "Id": "PhysicsSetting11", + "Name": "羽毛摇动" + }, + { + "Id": "PhysicsSetting12", + "Name": "帽盖摇动" + }, + { + "Id": "PhysicsSetting13", + "Name": "帽带摇动" + }, + { + "Id": "PhysicsSetting14", + "Name": "颈饰摇动" + }, + { + "Id": "PhysicsSetting15", + "Name": "长袍摇动" + }, + { + "Id": "PhysicsSetting16", + "Name": "长袍摇动Y" + } + ] + }, + "PhysicsSettings": [ + { + "Id": "PhysicsSetting1", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairFront" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 10 + }, + "Mobility": 0.95, + "Delay": 0.8, + "Acceleration": 1.12, + "Radius": 10 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting2", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairSideL" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + }, + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairSideR" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 15 + }, + "Mobility": 0.95, + "Delay": 0.8, + "Acceleration": 1.27, + "Radius": 15 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting3", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairBack" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 15.7 + }, + "Mobility": 0.9, + "Delay": 0.8, + "Acceleration": 1.5, + "Radius": 15.7 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting4", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairBackR" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + }, + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairBackL" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 16 + }, + "Mobility": 0.93, + "Delay": 0.8, + "Acceleration": 1.41, + "Radius": 16 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting5", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleZ" + }, + "Weight": 60, + "Type": "Angle", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 40, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamoHairMesh" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 10 + }, + "Mobility": 0.95, + "Delay": 0.7, + "Acceleration": 1, + "Radius": 10 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting6", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleY" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 11.6 + }, + "Mobility": 0.98, + "Delay": 0.88, + "Acceleration": 0.95, + "Radius": 11.6 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting7", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleY" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairSideFuwa" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 15.7 + }, + "Mobility": 0.98, + "Delay": 0.89, + "Acceleration": 0.75, + "Radius": 15.7 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting8", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleY" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHairBackFuwa" + }, + "VertexIndex": 1, + "Scale": 1.5, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 17.7 + }, + "Mobility": 0.98, + "Delay": 0.8, + "Acceleration": 0.81, + "Radius": 17.7 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting9", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleY" + }, + "Weight": 60, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 40, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHatBrim" + }, + "VertexIndex": 1, + "Scale": 1.5, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 13.9 + }, + "Mobility": 0.92, + "Delay": 0.67, + "Acceleration": 3.02, + "Radius": 13.9 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting10", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleY" + }, + "Weight": 50, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 30, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 20, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamRibbon" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 7.9 + }, + "Mobility": 0.95, + "Delay": 0.9, + "Acceleration": 0.82, + "Radius": 7.9 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting11", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleY" + }, + "Weight": 50, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 30, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 20, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamWing" + }, + "VertexIndex": 1, + "Scale": 0.9, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 10 + }, + "Mobility": 0.95, + "Delay": 0.65, + "Acceleration": 0.85, + "Radius": 10 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting12", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamAngleX" + }, + "Weight": 100, + "Type": "X", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamHatTop" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 61.4 + }, + "Mobility": 0.96, + "Delay": 0.81, + "Acceleration": 1.5, + "Radius": 61.4 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting13", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 100, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamString" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 15 + }, + "Mobility": 0.85, + "Delay": 1.3, + "Acceleration": 0.8, + "Radius": 15 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting14", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 100, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamAccessory1" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + }, + { + "Destination": { + "Target": "Parameter", + "Id": "ParamAccessory2" + }, + "VertexIndex": 2, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 7 + }, + "Mobility": 0.8, + "Delay": 0.6, + "Acceleration": 3, + "Radius": 7 + }, + { + "Position": { + "X": 0, + "Y": 15 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 3, + "Radius": 8 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting15", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleX" + }, + "Weight": 100, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamRobeL" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + }, + { + "Destination": { + "Target": "Parameter", + "Id": "ParamRobeR" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 10 + }, + "Mobility": 0.9, + "Delay": 0.7, + "Acceleration": 1.5, + "Radius": 10 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + }, + { + "Id": "PhysicsSetting16", + "Input": [ + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleY" + }, + "Weight": 100, + "Type": "X", + "Reflect": false + }, + { + "Source": { + "Target": "Parameter", + "Id": "ParamBodyAngleZ" + }, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Output": [ + { + "Destination": { + "Target": "Parameter", + "Id": "ParamRobeFuwa" + }, + "VertexIndex": 1, + "Scale": 1, + "Weight": 100, + "Type": "Angle", + "Reflect": false + } + ], + "Vertices": [ + { + "Position": { + "X": 0, + "Y": 0 + }, + "Mobility": 1, + "Delay": 1, + "Acceleration": 1, + "Radius": 0 + }, + { + "Position": { + "X": 0, + "Y": 10 + }, + "Mobility": 0.9, + "Delay": 0.7, + "Acceleration": 1.5, + "Radius": 10 + } + ], + "Normalization": { + "Position": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + }, + "Angle": { + "Minimum": -10, + "Default": 0, + "Maximum": 10 + } + } + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.pose3.json b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.pose3.json new file mode 100644 index 0000000..76fd2fd --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/mao_pro.pose3.json @@ -0,0 +1,25 @@ +{ + "Type": "Live2D Pose", + "Groups": [ + [ + { + "Id": "PartArmLA", + "Link": [] + }, + { + "Id": "PartArmLB", + "Link": [] + } + ], + [ + { + "Id": "PartArmRA", + "Link": [] + }, + { + "Id": "PartArmRB", + "Link": [] + } + ] + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_01.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_01.motion3.json new file mode 100644 index 0000000..e12a5bb --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_01.motion3.json @@ -0,0 +1,2311 @@ +{ + "Version": 3, + "Meta": { + "Duration": 5.57, + "Fps": 30.0, + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 209, + "TotalPointCount": 535, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + 0, + 0.233, + 0, + 1, + 0.7, + 0, + 1.167, + -2, + 1.633, + -2, + 1, + 2.333, + -2, + 3.033, + 2, + 3.733, + 2, + 1, + 4.222, + 2, + 4.711, + 0, + 5.2, + 0, + 1, + 5.322, + 0, + 5.444, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + 0, + 0.233, + 0, + 1, + 0.7, + 0, + 1.167, + -2.089, + 1.633, + -3, + 1, + 2.144, + -3.997, + 2.656, + -4, + 3.167, + -4, + 1, + 3.722, + -4, + 4.278, + -3.606, + 4.833, + -2, + 1, + 5.078, + -1.293, + 5.322, + -0.109, + 5.567, + -0.007 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 0, + 0.167, + 0, + 1, + 0.611, + 0, + 1.056, + 4, + 1.5, + 4, + 1, + 1.733, + 4, + 1.967, + 4.263, + 2.2, + 3, + 1, + 2.689, + 0.353, + 3.178, + -4, + 3.667, + -4, + 1, + 3.867, + -4, + 4.067, + -3.812, + 4.267, + -3, + 1, + 4.7, + -1.241, + 5.133, + -0.06, + 5.567, + -0.002 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 1, + 1, + 0.344, + 1, + 0.689, + 1, + 1.033, + 1, + 1, + 1.056, + 1, + 1.078, + 0, + 1.1, + 0, + 1, + 1.122, + 0, + 1.144, + 0, + 1.167, + 0, + 1, + 1.2, + 0, + 1.233, + 1, + 1.267, + 1, + 1, + 1.967, + 1, + 2.667, + 1, + 3.367, + 1, + 1, + 3.389, + 1, + 3.411, + 0, + 3.433, + 0, + 1, + 3.456, + 0, + 3.478, + 0, + 3.5, + 0, + 1, + 3.533, + 0, + 3.567, + 1, + 3.6, + 1, + 1, + 4.256, + 1, + 4.911, + 1, + 5.567, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 1, + 1, + 0.344, + 1, + 0.689, + 1, + 1.033, + 1, + 1, + 1.056, + 1, + 1.078, + 0, + 1.1, + 0, + 1, + 1.122, + 0, + 1.144, + 0, + 1.167, + 0, + 1, + 1.2, + 0, + 1.233, + 1, + 1.267, + 1, + 1, + 1.967, + 1, + 2.667, + 1, + 3.367, + 1, + 1, + 3.389, + 1, + 3.411, + 0, + 3.433, + 0, + 1, + 3.456, + 0, + 3.478, + 0, + 3.5, + 0, + 1, + 3.533, + 0, + 3.567, + 1, + 3.6, + 1, + 1, + 4.256, + 1, + 4.911, + 1, + 5.567, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 1, + 0, + 5.567, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.3, + 1.921, + 0.6, + 3, + 0.9, + 3, + 1, + 1.233, + 3, + 1.567, + 2.913, + 1.9, + 1, + 1, + 2.522, + -2.571, + 3.144, + -6, + 3.767, + -6, + 1, + 4.233, + -6, + 4.7, + -4.951, + 5.167, + -2.564, + 1, + 5.3, + -1.882, + 5.433, + -1.062, + 5.567, + -0.213 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.433, + -0.707, + 0.867, + -1, + 1.3, + -1, + 1, + 1.656, + -1, + 2.011, + 0, + 2.367, + 0, + 1, + 2.844, + 0, + 3.322, + -2, + 3.8, + -2, + 1, + 4.244, + -2, + 4.689, + 0.459, + 5.133, + 0.459, + 1, + 5.278, + 0.459, + 5.422, + 0.282, + 5.567, + 0.054 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.378, + 1.356, + 0.756, + 3, + 1.133, + 3, + 1, + 1.444, + 3, + 1.756, + 2.619, + 2.067, + 1, + 1, + 2.5, + -1.255, + 2.933, + -3, + 3.367, + -3, + 1, + 4.022, + -3, + 4.678, + -1.995, + 5.333, + -0.405, + 1, + 5.411, + -0.216, + 5.489, + -0.292, + 5.567, + -0.1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.411, + -1.092, + 0.822, + -2, + 1.233, + -2, + 1, + 1.611, + -2, + 1.989, + 0, + 2.367, + 0, + 1, + 2.711, + 0, + 3.056, + -1, + 3.4, + -1, + 1, + 3.822, + -1, + 4.244, + 1, + 4.667, + 1, + 1, + 4.967, + 1, + 5.267, + 0.838, + 5.567, + 0.086 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.089, + 0.089, + 0.178, + 0.041, + 0.267, + 0.041, + 1, + 0.678, + 0.041, + 1.089, + -1, + 1.5, + -1, + 1, + 1.878, + -1, + 2.256, + 0, + 2.633, + 0, + 1, + 2.978, + 0, + 3.322, + -0.627, + 3.667, + -1, + 1, + 3.889, + -1.241, + 4.111, + -1.215, + 4.333, + -1.215, + 1, + 4.744, + -1.215, + 5.156, + -0.465, + 5.567, + -0.034 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.389, + -1.052, + 0.778, + -2, + 1.167, + -2, + 1, + 1.544, + -2, + 1.922, + 0, + 2.3, + 0, + 1, + 2.644, + 0, + 2.989, + -1, + 3.333, + -1, + 1, + 3.778, + -1, + 4.222, + 1, + 4.667, + 1, + 1, + 4.967, + 1, + 5.267, + 0.853, + 5.567, + 0.088 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.089, + 0.089, + 0.178, + 0.041, + 0.267, + 0.041, + 1, + 0.656, + 0.041, + 1.044, + -1, + 1.433, + -1, + 1, + 1.811, + -1, + 2.189, + 0, + 2.567, + 0, + 1, + 2.911, + 0, + 3.256, + -0.659, + 3.6, + -1, + 1, + 3.844, + -1.242, + 4.089, + -1.215, + 4.333, + -1.215, + 1, + 4.744, + -1.215, + 5.156, + -0.465, + 5.567, + -0.034 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 1.856, + 0, + 3.711, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 1.167, + 0, + 0, + 1.6, + 30, + 0, + 3.767, + 0, + 0, + 4.2, + 30, + 1, + 4.656, + 30, + 5.111, + 1.412, + 5.567, + 0.05 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.389, + 0.246, + 0.778, + 1, + 1.167, + 1, + 1, + 1.211, + 1, + 1.256, + 0.02, + 1.3, + 0, + 1, + 1.422, + -0.054, + 1.544, + -0.094, + 1.667, + -0.12, + 1, + 2.367, + -0.269, + 3.067, + -0.387, + 3.767, + -0.54, + 1, + 3.844, + -0.557, + 3.922, + -0.706, + 4, + -0.706, + 1, + 4.056, + -0.706, + 4.111, + -0.625, + 4.167, + -0.6, + 1, + 4.633, + -0.39, + 5.1, + -0.307, + 5.567, + -0.021 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 1, + 0.4, + 0, + 0.8, + 0, + 1.2, + 0, + 1, + 1.244, + 0, + 1.289, + 1, + 1.333, + 1, + 1, + 1.4, + 1, + 1.467, + 1, + 1.533, + 1, + 1, + 1.556, + 1, + 1.578, + 0, + 1.6, + 0, + 1, + 2.333, + 0, + 3.067, + 0, + 3.8, + 0, + 1, + 3.844, + 0, + 3.889, + 1, + 3.933, + 1, + 1, + 4, + 1, + 4.067, + 1, + 4.133, + 1, + 1, + 4.156, + 1, + 4.178, + 0, + 4.2, + 0, + 1, + 4.656, + 0, + 5.111, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 1, + 0, + 5.567, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "FadeInTime": 1.0, + "FadeOutTime": 1.0, + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 0, + 5.567, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLA", + "Segments": [ + 0, + 1, + 0, + 5.57, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 1, + 0, + 5.57, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 0, + 0, + 5.57, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 0, + 0, + 5.57, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_02.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_02.motion3.json new file mode 100644 index 0000000..d5c1522 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_02.motion3.json @@ -0,0 +1,2293 @@ +{ + "Version": 3, + "Meta": { + "Duration": 3.47, + "Fps": 30.0, + "FadeInTime": 0.5, + "FadeOutTime": 1.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 249, + "TotalPointCount": 617, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 7, + 0.333, + 7, + 1, + 0.433, + 7, + 0.533, + -17, + 0.633, + -17, + 1, + 0.744, + -17, + 0.856, + -15, + 0.967, + -15, + 1, + 1.089, + -15, + 1.211, + -15, + 1.333, + -15, + 1, + 1.4, + -15, + 1.467, + -19, + 1.533, + -19, + 1, + 1.6, + -19, + 1.667, + -8.5, + 1.733, + 0, + 1, + 1.767, + 4.25, + 1.8, + 4, + 1.833, + 4, + 1, + 1.9, + 4, + 1.967, + -8, + 2.033, + -8, + 1, + 2.144, + -8, + 2.256, + 4, + 2.367, + 4, + 1, + 2.4, + 4, + 2.433, + -8, + 2.467, + -8, + 1, + 2.611, + -8, + 2.756, + 0, + 2.9, + 0, + 1, + 3.089, + 0, + 3.278, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + 0, + 0.267, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.133, + 1, + 0.267, + 1, + 0.4, + 1, + 1, + 0.444, + 1, + 0.489, + 0, + 0.533, + 0, + 1, + 0.567, + 0, + 0.6, + 0, + 0.633, + 0, + 1, + 0.689, + 0, + 0.744, + 1, + 0.8, + 1, + 1, + 0.944, + 1, + 1.089, + 1, + 1.233, + 1, + 1, + 1.311, + 1, + 1.389, + 0, + 1.467, + 0, + 1, + 1.856, + 0, + 2.244, + 0, + 2.633, + 0, + 1, + 2.689, + 0, + 2.744, + 1, + 2.8, + 1, + 0, + 3.467, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.133, + 1, + 0.267, + 1, + 0.4, + 1, + 1, + 0.444, + 1, + 0.489, + 0, + 0.533, + 0, + 1, + 0.567, + 0, + 0.6, + 0, + 0.633, + 0, + 1, + 0.689, + 0, + 0.744, + 1, + 0.8, + 1, + 1, + 0.944, + 1, + 1.089, + 1, + 1.233, + 1, + 1, + 1.311, + 1, + 1.389, + 0, + 1.467, + 0, + 1, + 1.856, + 0, + 2.244, + 0, + 2.633, + 0, + 1, + 2.689, + 0, + 2.744, + 1, + 2.8, + 1, + 0, + 3.467, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "Segments": [ + 0, + 1, + 0, + 3.467, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 2, + 0.167, + 2, + 1, + 0.278, + 2, + 0.389, + -3, + 0.5, + -3, + 1, + 0.622, + -3, + 0.744, + -1.531, + 0.867, + -1, + 1, + 0.989, + -0.469, + 1.111, + -0.5, + 1.233, + -0.5, + 1, + 1.3, + -0.5, + 1.367, + -4, + 1.433, + -4, + 1, + 1.544, + -4, + 1.656, + 4, + 1.767, + 4, + 1, + 1.833, + 4, + 1.9, + -4, + 1.967, + -4, + 1, + 2.067, + -4, + 2.167, + 4, + 2.267, + 4, + 1, + 2.322, + 4, + 2.378, + -4, + 2.433, + -4, + 1, + 2.533, + -4, + 2.633, + -1.756, + 2.733, + -0.8, + 1, + 2.822, + 0.05, + 2.911, + 0, + 3, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.411, + 0, + 0.489, + -6, + 0.567, + -6, + 1, + 0.856, + -6, + 1.144, + -6, + 1.433, + -6, + 1, + 1.6, + -6, + 1.767, + 0, + 1.933, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.411, + 0, + 0.489, + -6, + 0.567, + -6, + 1, + 0.856, + -6, + 1.144, + -6, + 1.433, + -6, + 1, + 1.6, + -6, + 1.767, + 0, + 1.933, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "Segments": [ + 0, + 0, + 1, + 0.022, + 0, + 0.044, + 0, + 0.067, + 0, + 1, + 0.133, + 0, + 0.2, + 5, + 0.267, + 5, + 1, + 0.344, + 5, + 0.422, + -4, + 0.5, + -4, + 1, + 0.622, + -4, + 0.744, + -2.68, + 0.867, + -2.3, + 1, + 0.978, + -1.955, + 1.089, + -2, + 1.2, + -2, + 1, + 1.278, + -2, + 1.356, + -3, + 1.433, + -3, + 1, + 1.5, + -3, + 1.567, + 4.414, + 1.633, + 9, + 1, + 1.7, + 13.586, + 1.767, + 14, + 1.833, + 14, + 1, + 1.878, + 14, + 1.922, + 9.731, + 1.967, + 7, + 1, + 2.011, + 4.269, + 2.056, + 4, + 2.1, + 4, + 1, + 2.178, + 4, + 2.256, + 14, + 2.333, + 14, + 1, + 2.411, + 14, + 2.489, + 4, + 2.567, + 4, + 1, + 2.667, + 4, + 2.767, + 6.5, + 2.867, + 6.5, + 1, + 3, + 6.5, + 3.133, + 6, + 3.267, + 6, + 0, + 3.467, + 6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.389, + 0, + 0.478, + -3, + 0.567, + -3, + 1, + 0.844, + -3, + 1.122, + -3, + 1.4, + -3, + 1, + 1.478, + -3, + 1.556, + -1.42, + 1.633, + 2, + 1, + 1.722, + 5.908, + 1.811, + 8, + 1.9, + 8, + 1, + 1.933, + 8, + 1.967, + 5.327, + 2, + 4, + 1, + 2.044, + 2.231, + 2.089, + 2, + 2.133, + 2, + 1, + 2.211, + 2, + 2.289, + 8, + 2.367, + 8, + 1, + 2.433, + 8, + 2.5, + 2, + 2.567, + 2, + 0, + 3.467, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.444, + 0, + 0.556, + -8, + 0.667, + -8, + 1, + 0.944, + -8, + 1.222, + -8, + 1.5, + -8, + 1, + 1.544, + -8, + 1.589, + -2.815, + 1.633, + 0, + 1, + 1.733, + 6.334, + 1.833, + 8, + 1.933, + 8, + 1, + 2.011, + 8, + 2.089, + -8, + 2.167, + -8, + 1, + 2.244, + -8, + 2.322, + 8, + 2.4, + 8, + 1, + 2.478, + 8, + 2.556, + -8, + 2.633, + -8, + 1, + 2.7, + -8, + 2.767, + -1.777, + 2.833, + -1, + 1, + 2.922, + 0.035, + 3.011, + 0, + 3.1, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + 0, + 0.433, + 0, + 1, + 0.489, + 0, + 0.544, + -10, + 0.6, + -10, + 0, + 3.467, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "Segments": [ + 0, + 0, + 1, + 0.022, + 0, + 0.044, + 0, + 0.067, + 0, + 1, + 0.133, + 0, + 0.2, + 5, + 0.267, + 5, + 1, + 0.344, + 5, + 0.422, + -4, + 0.5, + -4, + 1, + 0.622, + -4, + 0.744, + -2.68, + 0.867, + -2.3, + 1, + 0.978, + -1.955, + 1.089, + -2, + 1.2, + -2, + 1, + 1.278, + -2, + 1.356, + -3, + 1.433, + -3, + 1, + 1.5, + -3, + 1.567, + 4.414, + 1.633, + 9, + 1, + 1.7, + 13.586, + 1.767, + 14, + 1.833, + 14, + 1, + 1.878, + 14, + 1.922, + 9.731, + 1.967, + 7, + 1, + 2.011, + 4.269, + 2.056, + 4, + 2.1, + 4, + 1, + 2.178, + 4, + 2.256, + 14, + 2.333, + 14, + 1, + 2.411, + 14, + 2.489, + 4, + 2.567, + 4, + 1, + 2.667, + 4, + 2.767, + 6.5, + 2.867, + 6.5, + 1, + 3, + 6.5, + 3.133, + 6, + 3.267, + 6, + 0, + 3.467, + 6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0, + 0.3, + 0, + 1, + 0.389, + 0, + 0.478, + -3, + 0.567, + -3, + 1, + 0.844, + -3, + 1.122, + -3, + 1.4, + -3, + 1, + 1.478, + -3, + 1.556, + -1.42, + 1.633, + 2, + 1, + 1.722, + 5.908, + 1.811, + 8, + 1.9, + 8, + 1, + 1.933, + 8, + 1.967, + 5.327, + 2, + 4, + 1, + 2.044, + 2.231, + 2.089, + 2, + 2.133, + 2, + 1, + 2.211, + 2, + 2.289, + 8, + 2.367, + 8, + 1, + 2.433, + 8, + 2.5, + 2, + 2.567, + 2, + 0, + 3.467, + 2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0, + 1, + 0.444, + 0, + 0.556, + -8, + 0.667, + -8, + 1, + 0.944, + -8, + 1.222, + -8, + 1.5, + -8, + 1, + 1.544, + -8, + 1.589, + -2.815, + 1.633, + 0, + 1, + 1.733, + 6.334, + 1.833, + 8, + 1.933, + 8, + 1, + 2.011, + 8, + 2.089, + -8, + 2.167, + -8, + 1, + 2.244, + -8, + 2.322, + 8, + 2.4, + 8, + 1, + 2.478, + 8, + 2.556, + -8, + 2.633, + -8, + 1, + 2.7, + -8, + 2.767, + -1.777, + 2.833, + -1, + 1, + 2.922, + 0.035, + 3.011, + 0, + 3.1, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + 0, + 0.433, + 0, + 1, + 0.489, + 0, + 0.544, + -10, + 0.6, + -10, + 0, + 3.467, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 1, + 0, + 3.467, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 0, + 3.467, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLA", + "Segments": [ + 0, + 1, + 0, + 3.47, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 1, + 0, + 3.47, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 0, + 0, + 3.47, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 0, + 0, + 3.47, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_03.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_03.motion3.json new file mode 100644 index 0000000..e771f99 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_03.motion3.json @@ -0,0 +1,2163 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.4, + "Fps": 30.0, + "FadeInTime": 0.5, + "FadeOutTime": 1.0, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 231, + "TotalPointCount": 561, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.211, + 0, + 0.422, + 7, + 0.633, + 7, + 1, + 0.878, + 7, + 1.122, + 5.259, + 1.367, + 0, + 1, + 1.544, + -3.825, + 1.722, + -7, + 1.9, + -7, + 1, + 2.233, + -7, + 2.567, + -3.96, + 2.9, + -2, + 1, + 3.222, + -0.105, + 3.544, + 0, + 3.867, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 5, + 0.3, + 5, + 1, + 0.444, + 5, + 0.589, + -2.733, + 0.733, + -6, + 1, + 0.833, + -8.262, + 0.933, + -8, + 1.033, + -8, + 1, + 1.144, + -8, + 1.256, + 3, + 1.367, + 3, + 1, + 1.533, + 3, + 1.7, + -3.876, + 1.867, + -6, + 1, + 2.033, + -8.124, + 2.2, + -8, + 2.367, + -8, + 1, + 2.467, + -8, + 2.567, + -0.595, + 2.667, + 5, + 1, + 2.722, + 8.108, + 2.778, + 8, + 2.833, + 8, + 1, + 2.967, + 8, + 3.1, + -1, + 3.233, + -1, + 1, + 3.3, + -1, + 3.367, + 0, + 3.433, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 15, + 0.733, + 15, + 1, + 0.944, + 15, + 1.156, + 8.954, + 1.367, + 0, + 1, + 1.622, + -10.839, + 1.878, + -15, + 2.133, + -15, + 1, + 2.522, + -15, + 2.911, + 1, + 3.3, + 1, + 1, + 3.467, + 1, + 3.633, + 0, + 3.8, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.1, + 1, + 0.2, + 1, + 0.3, + 1, + 1, + 0.433, + 1, + 0.567, + 0, + 0.7, + 0, + 1, + 1.5, + 0, + 2.3, + 0, + 3.1, + 0, + 1, + 3.178, + 0, + 3.256, + 1, + 3.333, + 1, + 0, + 4.4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.1, + 1, + 0.2, + 1, + 0.3, + 1, + 1, + 0.433, + 1, + 0.567, + 0, + 0.7, + 0, + 1, + 1.5, + 0, + 2.3, + 0, + 3.1, + 0, + 1, + 3.178, + 0, + 3.256, + 1, + 3.333, + 1, + 0, + 4.4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "Segments": [ + 0, + 1, + 0, + 4.4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + 7, + 0.6, + 7, + 1, + 0.711, + 7, + 0.822, + 7, + 0.933, + 7, + 1, + 1.1, + 7, + 1.267, + 4.971, + 1.433, + 0, + 1, + 1.578, + -4.308, + 1.722, + -7, + 1.867, + -7, + 1, + 1.978, + -7, + 2.089, + -7, + 2.2, + -7, + 1, + 2.4, + -7, + 2.6, + 0, + 2.8, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + 3, + 0.233, + 3, + 1, + 0.356, + 3, + 0.478, + 0.167, + 0.6, + -1, + 1, + 0.711, + -2.061, + 0.822, + -2, + 0.933, + -2, + 1, + 1.1, + -2, + 1.267, + 6, + 1.433, + 6, + 1, + 1.578, + 6, + 1.722, + 0.762, + 1.867, + -1, + 1, + 1.967, + -2.22, + 2.067, + -2, + 2.167, + -2, + 1, + 2.3, + -2, + 2.433, + 6, + 2.567, + 6, + 1, + 2.767, + 6, + 2.967, + -2, + 3.167, + -2, + 1, + 3.3, + -2, + 3.433, + -0.973, + 3.567, + -0.4, + 1, + 3.667, + 0.03, + 3.767, + 0, + 3.867, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + 3.902, + 0.7, + 8, + 1, + 0.811, + 9.951, + 0.922, + 10, + 1.033, + 10, + 1, + 1.2, + 10, + 1.367, + 4.87, + 1.533, + 0, + 1, + 1.656, + -3.571, + 1.778, + -6.364, + 1.9, + -8, + 1, + 2.033, + -9.785, + 2.167, + -10, + 2.3, + -10, + 1, + 2.556, + -10, + 2.811, + -2.065, + 3.067, + -1, + 1, + 3.344, + 0.157, + 3.622, + 0, + 3.9, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + 6, + 0.267, + 6, + 1, + 0.444, + 6, + 0.622, + -1.5, + 0.8, + -1.5, + 1, + 0.878, + -1.5, + 0.956, + -1.637, + 1.033, + 0, + 1, + 1.122, + 1.871, + 1.211, + 8, + 1.3, + 8, + 1, + 1.378, + 8, + 1.456, + 8, + 1.533, + 8, + 1, + 1.667, + 8, + 1.8, + -0.32, + 1.933, + -2, + 1, + 2.033, + -3.26, + 2.133, + -3, + 2.233, + -3, + 1, + 2.411, + -3, + 2.589, + 4, + 2.767, + 4, + 1, + 2.956, + 4, + 3.144, + 0, + 3.333, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + 6, + 0.267, + 6, + 1, + 0.444, + 6, + 0.622, + -1.5, + 0.8, + -1.5, + 1, + 0.878, + -1.5, + 0.956, + -1.637, + 1.033, + 0, + 1, + 1.122, + 1.871, + 1.211, + 8, + 1.3, + 8, + 1, + 1.378, + 8, + 1.456, + 8, + 1.533, + 8, + 1, + 1.667, + 8, + 1.8, + -0.32, + 1.933, + -2, + 1, + 2.033, + -3.26, + 2.133, + -3, + 2.233, + -3, + 1, + 2.411, + -3, + 2.589, + 4, + 2.767, + 4, + 1, + 2.956, + 4, + 3.144, + 0, + 3.333, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "Segments": [ + 0, + 0, + 1, + 0.133, + 0, + 0.267, + 13, + 0.4, + 13, + 1, + 0.611, + 13, + 0.822, + 12, + 1.033, + 12, + 1, + 1.111, + 12, + 1.189, + 12, + 1.267, + 12, + 1, + 1.433, + 12, + 1.6, + 10.1, + 1.767, + 8, + 1, + 1.9, + 6.32, + 2.033, + 6, + 2.167, + 6, + 1, + 2.422, + 6, + 2.678, + 11, + 2.933, + 11, + 0, + 4.4, + 11 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "Segments": [ + 0, + 0, + 1, + 0.044, + 0, + 0.089, + 0, + 0.133, + 0, + 1, + 0.278, + 0, + 0.422, + -9.314, + 0.567, + -15, + 1, + 0.689, + -19.812, + 0.811, + -20, + 0.933, + -20, + 1, + 1.233, + -20, + 1.533, + -19, + 1.833, + -19, + 0, + 4.4, + -19 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "Segments": [ + 0, + 0, + 1, + 0.322, + 0, + 0.644, + -18, + 0.967, + -18, + 0, + 4.4, + -18 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "Segments": [ + 0, + 0, + 1, + 0.133, + 0, + 0.267, + 11, + 0.4, + 11, + 1, + 0.611, + 11, + 0.822, + 6, + 1.033, + 6, + 1, + 1.089, + 6, + 1.144, + 6, + 1.2, + 6, + 1, + 1.533, + 6, + 1.867, + 12, + 2.2, + 12, + 1, + 2.444, + 12, + 2.689, + 11, + 2.933, + 11, + 0, + 4.4, + 11 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "Segments": [ + 0, + 0, + 1, + 0.044, + 0, + 0.089, + 0, + 0.133, + 0, + 1, + 0.278, + 0, + 0.422, + -9.314, + 0.567, + -15, + 1, + 0.689, + -19.812, + 0.811, + -20, + 0.933, + -20, + 1, + 1.233, + -20, + 1.533, + -19, + 1.833, + -19, + 0, + 4.4, + -19 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 5, + 0.3, + 5, + 1, + 0.378, + 5, + 0.456, + -7.712, + 0.533, + -11, + 1, + 0.678, + -17.107, + 0.822, + -18, + 0.967, + -18, + 0, + 4.4, + -18 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "Segments": [ + 0, + 0, + 1, + 0.122, + 0, + 0.244, + 0, + 0.367, + 0, + 1, + 0.411, + 0, + 0.456, + 0.439, + 0.5, + 1.8, + 1, + 0.611, + 5.202, + 0.722, + 7.2, + 0.833, + 7.2, + 1, + 1.033, + 7.2, + 1.233, + 7, + 1.433, + 7, + 0, + 4.4, + 7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "Segments": [ + 0, + 0, + 1, + 0.289, + 0, + 0.578, + 1, + 0.867, + 1, + 1, + 1.289, + 1, + 1.711, + -1, + 2.133, + -1, + 1, + 2.444, + -1, + 2.756, + 0, + 3.067, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 1, + 0, + 4.4, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLA", + "Segments": [ + 0, + 1, + 0, + 4.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 1, + 0, + 4.4, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 0, + 0, + 4.4, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_04.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_04.motion3.json new file mode 100644 index 0000000..3240cab --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/mtn_04.motion3.json @@ -0,0 +1,2622 @@ +{ + "Version": 3, + "Meta": { + "Duration": 4.2, + "Fps": 30.0, + "FadeInTime": 0.5, + "FadeOutTime": 0.5, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 296, + "TotalPointCount": 758, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.056, + 0, + 0.111, + 5, + 0.167, + 5, + 1, + 0.222, + 5, + 0.278, + -2, + 0.333, + -2, + 1, + 0.4, + -2, + 0.467, + -0.5, + 0.533, + -0.5, + 1, + 0.578, + -0.5, + 0.622, + -1, + 0.667, + -1, + 1, + 0.833, + -1, + 1, + -1, + 1.167, + -1, + 1, + 1.322, + -1, + 1.478, + -9, + 1.633, + -9, + 1, + 1.778, + -9, + 1.922, + -9, + 2.067, + -9, + 1, + 2.356, + -9, + 2.644, + -4, + 2.933, + -4, + 0, + 4.2, + -4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + -14, + 0.233, + -14, + 1, + 0.333, + -14, + 0.433, + 21.722, + 0.533, + 24, + 1, + 0.633, + 26.278, + 0.733, + 26, + 0.833, + 26, + 1, + 0.956, + 26, + 1.078, + 26.249, + 1.2, + 21, + 1, + 1.367, + 13.842, + 1.533, + -21.382, + 1.7, + -22, + 1, + 1.978, + -23.03, + 2.256, + -23, + 2.533, + -23, + 1, + 2.644, + -23, + 2.756, + -10.413, + 2.867, + -3, + 1, + 2.967, + 3.672, + 3.067, + 4, + 3.167, + 4, + 1, + 3.322, + 4, + 3.478, + -4, + 3.633, + -4, + 1, + 3.744, + -4, + 3.856, + -1, + 3.967, + -1, + 0, + 4.2, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + -3.258, + 0.733, + -5, + 1, + 0.833, + -5.713, + 0.933, + -5.417, + 1.033, + -6, + 1, + 1.133, + -6.583, + 1.233, + -10, + 1.333, + -10, + 1, + 1.467, + -10, + 1.6, + 9.916, + 1.733, + 11, + 1, + 1.878, + 12.175, + 2.022, + 12.099, + 2.167, + 13, + 1, + 2.256, + 13.555, + 2.344, + 15, + 2.433, + 15, + 1, + 2.6, + 15, + 2.767, + 11.667, + 2.933, + 7, + 1, + 3.033, + 4.2, + 3.133, + 3.688, + 3.233, + 0, + 1, + 3.344, + -4.097, + 3.456, + -17, + 3.567, + -17, + 1, + 3.689, + -17, + 3.811, + -13, + 3.933, + -13, + 0, + 4.2, + -13 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.022, + 1, + 0.044, + 1, + 0.067, + 1, + 1, + 0.1, + 1, + 0.133, + 0, + 0.167, + 0, + 1, + 0.222, + 0, + 0.278, + 0, + 0.333, + 0, + 1, + 0.367, + 0, + 0.4, + 1.17, + 0.433, + 1.17, + 1, + 0.633, + 1.17, + 0.833, + 1.17, + 1.033, + 1.17, + 1, + 1.111, + 1.17, + 1.189, + 1.143, + 1.267, + 1, + 1, + 1.289, + 0.959, + 1.311, + 0, + 1.333, + 0, + 1, + 1.356, + 0, + 1.378, + 0, + 1.4, + 0, + 1, + 1.422, + 0, + 1.444, + 0.8, + 1.467, + 0.8, + 1, + 1.733, + 0.8, + 2, + 0.8, + 2.267, + 0.8, + 1, + 2.311, + 0.8, + 2.356, + 0, + 2.4, + 0, + 1, + 2.444, + 0, + 2.489, + 0, + 2.533, + 0, + 1, + 2.611, + 0, + 2.689, + 0.8, + 2.767, + 0.8, + 1, + 2.922, + 0.8, + 3.078, + 0.8, + 3.233, + 0.8, + 1, + 3.267, + 0.8, + 3.3, + 0, + 3.333, + 0, + 1, + 3.389, + 0, + 3.444, + 1, + 3.5, + 1, + 0, + 4.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.022, + 1, + 0.044, + 1, + 0.067, + 1, + 1, + 0.1, + 1, + 0.133, + 0, + 0.167, + 0, + 1, + 0.222, + 0, + 0.278, + 0, + 0.333, + 0, + 1, + 0.367, + 0, + 0.4, + 1.17, + 0.433, + 1.17, + 1, + 0.633, + 1.17, + 0.833, + 1.17, + 1.033, + 1.17, + 1, + 1.111, + 1.17, + 1.189, + 1.143, + 1.267, + 1, + 1, + 1.289, + 0.959, + 1.311, + 0, + 1.333, + 0, + 1, + 1.356, + 0, + 1.378, + 0, + 1.4, + 0, + 1, + 1.422, + 0, + 1.444, + 0.8, + 1.467, + 0.8, + 1, + 1.733, + 0.8, + 2, + 0.8, + 2.267, + 0.8, + 1, + 2.311, + 0.8, + 2.356, + 0, + 2.4, + 0, + 1, + 2.444, + 0, + 2.489, + 0, + 2.533, + 0, + 1, + 2.611, + 0, + 2.689, + 0.8, + 2.767, + 0.8, + 1, + 2.922, + 0.8, + 3.078, + 0.8, + 3.233, + 0.8, + 1, + 3.267, + 0.8, + 3.3, + 0, + 3.333, + 0, + 1, + 3.389, + 0, + 3.444, + 1, + 3.5, + 1, + 0, + 4.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "Segments": [ + 0, + 1, + 0, + 4.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + 3, + 0.6, + 3, + 1, + 0.756, + 3, + 0.911, + 3, + 1.067, + 3, + 1, + 1.2, + 3, + 1.333, + 2, + 1.467, + 2, + 1, + 1.722, + 2, + 1.978, + 2, + 2.233, + 2, + 1, + 2.622, + 2, + 3.011, + -8, + 3.4, + -8, + 0, + 4.2, + -8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.067, + 0, + 0.133, + -6, + 0.2, + -6, + 1, + 0.3, + -6, + 0.4, + 5, + 0.5, + 5, + 1, + 0.567, + 5, + 0.633, + 4.664, + 0.7, + 4.5, + 1, + 0.778, + 4.309, + 0.856, + 4.3, + 0.933, + 4.3, + 1, + 1.022, + 4.3, + 1.111, + 5, + 1.2, + 5, + 1, + 1.367, + 5, + 1.533, + -1.681, + 1.7, + -2, + 1, + 1.867, + -2.319, + 2.033, + -2.23, + 2.2, + -2.5, + 1, + 2.311, + -2.68, + 2.422, + -7, + 2.533, + -7, + 1, + 2.644, + -7, + 2.756, + -1.476, + 2.867, + 0, + 1, + 2.956, + 1.181, + 3.044, + 1, + 3.133, + 1, + 1, + 3.244, + 1, + 3.356, + -2, + 3.467, + -2, + 1, + 3.6, + -2, + 3.733, + 0.089, + 3.867, + 0.6, + 1, + 3.978, + 1.026, + 4.089, + 1.008, + 4.2, + 1.001 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + 2, + 0.233, + 2, + 1, + 0.367, + 2, + 0.5, + -2.243, + 0.633, + -3, + 1, + 0.744, + -3.631, + 0.856, + -3.476, + 0.967, + -4, + 1, + 1.067, + -4.472, + 1.167, + -6, + 1.267, + -6, + 1, + 1.422, + -6, + 1.578, + 0.528, + 1.733, + 2, + 1, + 1.944, + 3.998, + 2.156, + 4, + 2.367, + 4, + 1, + 2.522, + 4, + 2.678, + 0.794, + 2.833, + 0, + 1, + 2.956, + -0.624, + 3.078, + -0.545, + 3.2, + -1, + 1, + 3.289, + -1.331, + 3.378, + -2.623, + 3.467, + -3, + 1, + 3.656, + -3.802, + 3.844, + -4, + 4.033, + -4, + 0, + 4.2, + -4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -10, + 0.3, + -10, + 1, + 0.378, + -10, + 0.456, + 10, + 0.533, + 10, + 1, + 0.744, + 10, + 0.956, + 10, + 1.167, + 10, + 1, + 1.222, + 10, + 1.278, + 9.958, + 1.333, + 7, + 1, + 1.511, + -2.465, + 1.689, + -10, + 1.867, + -10, + 1, + 2.067, + -10, + 2.267, + -10, + 2.467, + -10, + 1, + 2.578, + -10, + 2.689, + 6.333, + 2.8, + 6.333, + 1, + 2.867, + 6.333, + 2.933, + 5.484, + 3, + 2.333, + 1, + 3.122, + -3.443, + 3.244, + -7.333, + 3.367, + -7.333, + 0, + 4.2, + -7.333 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + -1.781, + 0.233, + -1.781, + 1, + 0.3, + -1.781, + 0.367, + 1, + 0.433, + 1, + 1, + 0.578, + 1, + 0.722, + 0, + 0.867, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "Segments": [ + 0, + 0, + 1, + 0.067, + 0, + 0.133, + 1, + 0.2, + 1, + 1, + 0.289, + 1, + 0.378, + -1.648, + 0.467, + -2, + 1, + 0.689, + -2.881, + 0.911, + -3, + 1.133, + -3, + 1, + 1.311, + -3, + 1.489, + -2, + 1.667, + -2, + 1, + 1.867, + -2, + 2.067, + -2, + 2.267, + -2, + 1, + 2.389, + -2, + 2.511, + -3, + 2.633, + -3, + 1, + 2.744, + -3, + 2.856, + -1, + 2.967, + -1, + 1, + 3.167, + -1, + 3.367, + -2.5, + 3.567, + -2.5, + 0, + 4.2, + -2.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 1, + 0.3, + 1, + 1, + 0.389, + 1, + 0.478, + -1, + 0.567, + -1, + 1, + 0.756, + -1, + 0.944, + -1, + 1.133, + -1, + 1, + 1.333, + -1, + 1.533, + 2, + 1.733, + 2, + 1, + 2.111, + 2, + 2.489, + 1.295, + 2.867, + 0.5, + 1, + 2.956, + 0.313, + 3.044, + 0.395, + 3.133, + 0.2, + 1, + 3.267, + -0.092, + 3.4, + -1, + 3.533, + -1, + 0, + 4.2, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "Segments": [ + 0, + 0, + 1, + 0.278, + 0, + 0.556, + -1, + 0.833, + -1, + 1, + 0.978, + -1, + 1.122, + -1, + 1.267, + -1, + 1, + 1.444, + -1, + 1.622, + 0, + 1.8, + 0, + 1, + 2.1, + 0, + 2.4, + 0, + 2.7, + 0, + 1, + 2.933, + 0, + 3.167, + -5, + 3.4, + -5, + 0, + 4.2, + -5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "Segments": [ + 0, + 0, + 1, + 0.433, + 0, + 0.867, + 0, + 1.3, + 0, + 1, + 1.411, + 0, + 1.522, + -10, + 1.633, + -10, + 0, + 4.2, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "Segments": [ + 0, + 0, + 1, + 0.078, + 0, + 0.156, + -5, + 0.233, + -5, + 1, + 0.322, + -5, + 0.411, + 8.336, + 0.5, + 11, + 1, + 0.722, + 17.66, + 0.944, + 19, + 1.167, + 19, + 1, + 1.244, + 19, + 1.322, + 17.013, + 1.4, + 9, + 1, + 1.5, + -1.302, + 1.6, + -26.721, + 1.7, + -28, + 1, + 1.856, + -29.99, + 2.011, + -30, + 2.167, + -30, + 1, + 2.256, + -30, + 2.344, + -30, + 2.433, + -30, + 1, + 2.556, + -30, + 2.678, + -24, + 2.8, + -24, + 1, + 2.856, + -24, + 2.911, + -24, + 2.967, + -24, + 1, + 3.111, + -24, + 3.256, + -30, + 3.4, + -30, + 0, + 4.2, + -30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + -3, + 0.267, + -3, + 1, + 0.356, + -3, + 0.444, + 4.331, + 0.533, + 6, + 1, + 0.756, + 10.172, + 0.978, + 11, + 1.2, + 11, + 1, + 1.278, + 11, + 1.356, + 8.169, + 1.433, + -4, + 1, + 1.522, + -17.907, + 1.611, + -30, + 1.7, + -30, + 1, + 1.944, + -30, + 2.189, + -30, + 2.433, + -30, + 1, + 2.556, + -30, + 2.678, + -19.205, + 2.8, + -16, + 1, + 2.889, + -13.669, + 2.978, + -14, + 3.067, + -14, + 1, + 3.222, + -14, + 3.378, + -24, + 3.533, + -24, + 0, + 4.2, + -24 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + 0.409, + 0.3, + 2, + 1, + 0.378, + 3.238, + 0.456, + 6.701, + 0.533, + 7, + 1, + 0.756, + 7.854, + 0.978, + 8, + 1.2, + 8, + 1, + 1.356, + 8, + 1.511, + -5.41, + 1.667, + -7, + 1, + 1.833, + -8.703, + 2, + -8.925, + 2.167, + -10, + 1, + 2.256, + -10.573, + 2.344, + -11, + 2.433, + -11, + 1, + 2.578, + -11, + 2.722, + 2.063, + 2.867, + 4, + 1, + 2.967, + 5.341, + 3.067, + 4.952, + 3.167, + 6, + 1, + 3.267, + 7.048, + 3.367, + 10, + 3.467, + 10, + 0, + 4.2, + 10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 7, + 0.733, + 7, + 1, + 0.889, + 7, + 1.044, + 7, + 1.2, + 7, + 1, + 1.444, + 7, + 1.689, + -10, + 1.933, + -10, + 1, + 2.1, + -10, + 2.267, + -10, + 2.433, + -10, + 1, + 2.544, + -10, + 2.656, + 10, + 2.767, + 10, + 1, + 2.878, + 10, + 2.989, + 10, + 3.1, + 10, + 1, + 3.222, + 10, + 3.344, + -10, + 3.467, + -10, + 0, + 4.2, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "Segments": [ + 0, + 0, + 1, + 0.4, + 0, + 0.8, + 0, + 1.2, + 0, + 1, + 1.444, + 0, + 1.689, + 18, + 1.933, + 18, + 1, + 2.011, + 18, + 2.089, + 18, + 2.167, + 18, + 1, + 2.256, + 18, + 2.344, + 21, + 2.433, + 21, + 1, + 2.656, + 21, + 2.878, + 0, + 3.1, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + -1, + 0.433, + -1, + 1, + 0.622, + -1, + 0.811, + -1, + 1, + -1, + 1, + 1.122, + -1, + 1.244, + 0, + 1.367, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 1, + 0, + 4.2, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLA", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 1, + 0, + 4.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 1, + 0, + 4.2, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 0, + 0, + 4.2, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_01.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_01.motion3.json new file mode 100644 index 0000000..0a9f7d5 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_01.motion3.json @@ -0,0 +1,3389 @@ +{ + "Version": 3, + "Meta": { + "Duration": 7.8, + "Fps": 30.0, + "FadeInTime": 0.25, + "FadeOutTime": 0.25, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 409, + "TotalPointCount": 1085, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0.3, + 0.333, + -1.7, + 1, + 0.456, + -3.901, + 0.578, + -22.931, + 0.7, + -22.931, + 1, + 0.911, + -22.931, + 1.122, + -21.931, + 1.333, + -21.931, + 1, + 1.533, + -21.931, + 1.733, + -21.958, + 1.933, + -22.931, + 1, + 2.078, + -23.634, + 2.222, + -25.931, + 2.367, + -25.931, + 1, + 2.589, + -25.931, + 2.811, + -22.931, + 3.033, + -22.931, + 1, + 3.156, + -22.931, + 3.278, + -24.931, + 3.4, + -24.931, + 1, + 3.544, + -24.931, + 3.689, + -21.172, + 3.833, + -8, + 1, + 3.9, + -1.92, + 3.967, + 7, + 4.033, + 7, + 1, + 4.133, + 7, + 4.233, + -3, + 4.333, + -3, + 1, + 4.444, + -3, + 4.556, + 0, + 4.667, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -2.583, + 0.3, + -2.583, + 1, + 0.433, + -2.583, + 0.567, + 28, + 0.7, + 28, + 1, + 0.822, + 28, + 0.944, + 25, + 1.067, + 25, + 1, + 1.4, + 25, + 1.733, + 25, + 2.067, + 25, + 1, + 2.167, + 25, + 2.267, + -8, + 2.367, + -8, + 1, + 2.567, + -8, + 2.767, + 29, + 2.967, + 29, + 1, + 3.089, + 29, + 3.211, + 11, + 3.333, + 11, + 1, + 3.478, + 11, + 3.622, + 25, + 3.767, + 25, + 1, + 3.867, + 25, + 3.967, + -12, + 4.067, + -12, + 1, + 4.156, + -12, + 4.244, + -8.815, + 4.333, + -4, + 1, + 4.6, + 10.444, + 4.867, + 17, + 5.133, + 17, + 1, + 5.489, + 17, + 5.844, + 12, + 6.2, + 12, + 0, + 7.8, + 12 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -0.018, + 0.7, + 3, + 1, + 0.9, + 5.587, + 1.1, + 14, + 1.3, + 14, + 1, + 1.478, + 14, + 1.656, + 6.464, + 1.833, + 0, + 1, + 2, + -6.06, + 2.167, + -7, + 2.333, + -7, + 1, + 2.422, + -7, + 2.511, + 6.309, + 2.6, + 7, + 1, + 2.733, + 8.037, + 2.867, + 8, + 3, + 8, + 1, + 3.144, + 8, + 3.289, + -10, + 3.433, + -10, + 1, + 3.533, + -10, + 3.633, + 2, + 3.733, + 2, + 1, + 3.933, + 2, + 4.133, + 0, + 4.333, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.089, + 1, + 0.178, + 1, + 0.267, + 1, + 1, + 0.3, + 1, + 0.333, + 0, + 0.367, + 0, + 1, + 0.389, + 0, + 0.411, + 0, + 0.433, + 0, + 1, + 0.467, + 0, + 0.5, + 1, + 0.533, + 1, + 1, + 1.089, + 1, + 1.644, + 1, + 2.2, + 1, + 1, + 2.244, + 1, + 2.289, + 0, + 2.333, + 0, + 1, + 2.4, + 0, + 2.467, + 0, + 2.533, + 0, + 1, + 2.578, + 0, + 2.622, + 1, + 2.667, + 1, + 1, + 3.044, + 1, + 3.422, + 1, + 3.8, + 1, + 1, + 3.833, + 1, + 3.867, + 0, + 3.9, + 0, + 1, + 3.989, + 0, + 4.078, + 0, + 4.167, + 0, + 1, + 4.2, + 0, + 4.233, + 1.2, + 4.267, + 1.2, + 0, + 7.8, + 1.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.089, + 1, + 0.178, + 1, + 0.267, + 1, + 1, + 0.3, + 1, + 0.333, + 0, + 0.367, + 0, + 1, + 0.389, + 0, + 0.411, + 0, + 0.433, + 0, + 1, + 0.467, + 0, + 0.5, + 1, + 0.533, + 1, + 1, + 1.089, + 1, + 1.644, + 1, + 2.2, + 1, + 1, + 2.244, + 1, + 2.289, + 0, + 2.333, + 0, + 1, + 2.4, + 0, + 2.467, + 0, + 2.533, + 0, + 1, + 2.578, + 0, + 2.622, + 1, + 2.667, + 1, + 1, + 3.044, + 1, + 3.422, + 1, + 3.8, + 1, + 1, + 3.833, + 1, + 3.867, + 0, + 3.9, + 0, + 1, + 3.989, + 0, + 4.078, + 0, + 4.167, + 0, + 1, + 4.2, + 0, + 4.233, + 1.2, + 4.267, + 1.2, + 0, + 7.8, + 1.2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -0.2, + 0.7, + -0.2, + 1, + 1.811, + -0.2, + 2.922, + -0.2, + 4.033, + -0.2, + 1, + 4.078, + -0.2, + 4.122, + 0, + 4.167, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + 0.2, + 0.7, + 0.2, + 1, + 1.811, + 0.2, + 2.922, + 0.2, + 4.033, + 0.2, + 1, + 4.078, + 0.2, + 4.122, + 0, + 4.167, + 0, + 1, + 4.2, + 0, + 4.233, + 0.5, + 4.267, + 0.5, + 0, + 7.8, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "Segments": [ + 0, + 0, + 1, + 1.344, + 0, + 2.689, + 0, + 4.033, + 0, + 1, + 4.111, + 0, + 4.189, + 1, + 4.267, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 1.378, + 0, + 2.756, + 0, + 4.133, + 0, + 1, + 4.211, + 0, + 4.289, + 0.6, + 4.367, + 0.6, + 0, + 7.8, + 0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 1.378, + 0, + 2.756, + 0, + 4.133, + 0, + 1, + 4.211, + 0, + 4.289, + 0.6, + 4.367, + 0.6, + 0, + 7.8, + 0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "Segments": [ + 0, + 0, + 1, + 1.267, + 0, + 2.533, + 0, + 3.8, + 0, + 1, + 3.978, + 0, + 4.156, + 1, + 4.333, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "Segments": [ + 0, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "Segments": [ + 0, + 0, + 1, + 1.233, + 0, + 2.467, + 0, + 3.7, + 0, + 1, + 3.789, + 0, + 3.878, + 0.4, + 3.967, + 0.4, + 1, + 4.089, + 0.4, + 4.211, + 0, + 4.333, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.433, + 0, + 0.867, + -5, + 1.3, + -5, + 1, + 1.633, + -5, + 1.967, + -3, + 2.3, + -3, + 1, + 2.589, + -3, + 2.878, + -3, + 3.167, + -3, + 1, + 3.278, + -3, + 3.389, + -4, + 3.5, + -4, + 1, + 3.722, + -4, + 3.944, + 1, + 4.167, + 1, + 1, + 4.289, + 1, + 4.411, + 0, + 4.533, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -1, + 0.3, + -1, + 1, + 0.4, + -1, + 0.5, + 4.328, + 0.6, + 7, + 1, + 0.678, + 9.079, + 0.756, + 9, + 0.833, + 9, + 1, + 0.978, + 9, + 1.122, + 5, + 1.267, + 5, + 1, + 1.344, + 5, + 1.422, + 6.297, + 1.5, + 7, + 1, + 1.6, + 7.904, + 1.7, + 8, + 1.8, + 8, + 1, + 1.944, + 8, + 2.089, + 3.885, + 2.233, + 0, + 1, + 2.278, + -1.195, + 2.322, + -1, + 2.367, + -1, + 1, + 2.533, + -1, + 2.7, + 6.454, + 2.867, + 9, + 1, + 2.956, + 10, + 3.044, + 10, + 3.133, + 10, + 1, + 3.211, + 10, + 3.289, + 5, + 3.367, + 5, + 1, + 3.467, + 5, + 3.567, + 9, + 3.667, + 9, + 1, + 3.833, + 9, + 4, + -4, + 4.167, + -4, + 1, + 4.311, + -4, + 4.456, + 1.691, + 4.6, + 4, + 1, + 4.778, + 6.842, + 4.956, + 7, + 5.133, + 7, + 1, + 5.456, + 7, + 5.778, + 5, + 6.1, + 5, + 0, + 7.8, + 5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.378, + 0, + 0.756, + 7, + 1.133, + 7, + 1, + 1.5, + 7, + 1.867, + -1, + 2.233, + -1, + 1, + 2.356, + -1, + 2.478, + 4.292, + 2.6, + 4.999, + 1, + 2.778, + 6.026, + 2.956, + 5.999, + 3.133, + 5.999, + 1, + 3.222, + 5.999, + 3.311, + 0, + 3.4, + 0, + 1, + 3.478, + 0, + 3.556, + 0.016, + 3.633, + 1, + 1, + 3.722, + 2.125, + 3.811, + 4, + 3.9, + 4, + 1, + 4.189, + 4, + 4.478, + 0, + 4.767, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + 0, + 0.433, + 0, + 1, + 0.633, + 0, + 0.833, + -1.626, + 1.033, + -1.626, + 1, + 1.311, + -1.626, + 1.589, + -1.626, + 1.867, + -1.626, + 1, + 2.089, + -1.626, + 2.311, + -3, + 2.533, + -3, + 1, + 2.667, + -3, + 2.8, + 0, + 2.933, + 0, + 1, + 3.156, + 0, + 3.378, + -0.149, + 3.6, + -1.626, + 1, + 3.8, + -2.956, + 4, + -5, + 4.2, + -5, + 1, + 4.511, + -5, + 4.822, + 0.891, + 5.133, + 0.891, + 1, + 5.344, + 0.891, + 5.556, + 0, + 5.767, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + -10, + 0.467, + -10, + 1, + 0.667, + -10, + 0.867, + -8.333, + 1.067, + -8.333, + 1, + 1.222, + -8.333, + 1.378, + -8.333, + 1.533, + -8.333, + 1, + 1.7, + -8.333, + 1.867, + -10, + 2.033, + -10, + 1, + 2.278, + -10, + 2.522, + 2, + 2.767, + 2, + 1, + 2.867, + 2, + 2.967, + 2, + 3.067, + 2, + 1, + 3.222, + 2, + 3.378, + 0, + 3.533, + 0, + 1, + 3.6, + 0, + 3.667, + 0, + 3.733, + 0, + 1, + 3.9, + 0, + 4.067, + -5.667, + 4.233, + -5.667, + 1, + 4.533, + -5.667, + 4.833, + 0.677, + 5.133, + 0.677, + 1, + 5.344, + 0.677, + 5.556, + 0, + 5.767, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "Segments": [ + 0, + 0, + 1, + 0.211, + 0, + 0.422, + -1, + 0.633, + -1, + 1, + 0.856, + -1, + 1.078, + 3, + 1.3, + 3, + 1, + 1.633, + 3, + 1.967, + -3, + 2.3, + -3, + 1, + 2.556, + -3, + 2.811, + 8, + 3.067, + 8, + 1, + 3.1, + 8, + 3.133, + 8.298, + 3.167, + 7.32, + 1, + 3.233, + 5.364, + 3.3, + -4, + 3.367, + -4, + 1, + 3.511, + -4, + 3.656, + 0, + 3.8, + 0, + 1, + 3.911, + 0, + 4.022, + -5.91, + 4.133, + -5.91, + 1, + 4.278, + -5.91, + 4.422, + -1.199, + 4.567, + 1, + 1, + 4.7, + 3.03, + 4.833, + 3, + 4.967, + 3, + 1, + 5.222, + 3, + 5.478, + 0.803, + 5.733, + 0.803, + 1, + 5.989, + 0.803, + 6.244, + 1.28, + 6.5, + 1.28, + 0, + 7.8, + 1.28 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "Segments": [ + 0, + 0, + 1, + 0.289, + 0, + 0.578, + -2, + 0.867, + -2, + 1, + 1.089, + -2, + 1.311, + -1, + 1.533, + -1, + 1, + 1.811, + -1, + 2.089, + -5, + 2.367, + -5, + 1, + 2.656, + -5, + 2.944, + -2, + 3.233, + -2, + 1, + 3.333, + -2, + 3.433, + -3, + 3.533, + -3, + 1, + 3.656, + -3, + 3.778, + -2, + 3.9, + -2, + 1, + 4.011, + -2, + 4.122, + -3, + 4.233, + -3, + 1, + 4.5, + -3, + 4.767, + 2, + 5.033, + 2, + 1, + 5.311, + 2, + 5.589, + -0.5, + 5.867, + -0.5, + 1, + 6.1, + -0.5, + 6.333, + 0, + 6.567, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + -1, + 0.9, + -1, + 1, + 1.122, + -1, + 1.344, + 0, + 1.567, + 0, + 1, + 1.844, + 0, + 2.122, + -3, + 2.4, + -3, + 1, + 2.889, + -3, + 3.378, + -2.71, + 3.867, + 0, + 1, + 4.122, + 1.416, + 4.378, + 7, + 4.633, + 7, + 1, + 4.878, + 7, + 5.122, + 5.5, + 5.367, + 5.5, + 1, + 5.733, + 5.5, + 6.1, + 6, + 6.467, + 6, + 0, + 7.8, + 6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + -30, + 0.533, + -30, + 1, + 0.622, + -30, + 0.711, + -13.204, + 0.8, + -3, + 1, + 0.889, + 7.204, + 0.978, + 8, + 1.067, + 8, + 1, + 1.144, + 8, + 1.222, + 3, + 1.3, + 3, + 1, + 1.378, + 3, + 1.456, + 8, + 1.533, + 8, + 1, + 1.656, + 8, + 1.778, + -4.681, + 1.9, + -11, + 1, + 2.056, + -19.043, + 2.211, + -20, + 2.367, + -20, + 1, + 2.478, + -20, + 2.589, + -8.612, + 2.7, + 0, + 1, + 2.822, + 9.474, + 2.944, + 11, + 3.067, + 11, + 1, + 3.156, + 11, + 3.244, + -12, + 3.333, + -12, + 1, + 3.389, + -12, + 3.444, + -10, + 3.5, + -10, + 1, + 3.622, + -10, + 3.744, + -10, + 3.867, + -10, + 1, + 3.989, + -10, + 4.111, + -16, + 4.233, + -16, + 1, + 4.478, + -16, + 4.722, + -10, + 4.967, + -10, + 0, + 7.8, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "Segments": [ + 0, + 0, + 1, + 0.067, + 0, + 0.133, + -0.16, + 0.2, + 1.053, + 1, + 0.289, + 2.669, + 0.378, + 9.24, + 0.467, + 13.846, + 1, + 0.556, + 18.453, + 0.644, + 26.27, + 0.733, + 28.907, + 1, + 0.778, + 30, + 0.822, + 30, + 0.867, + 30, + 1, + 1.011, + 30, + 1.156, + 28.04, + 1.3, + 22.85, + 1, + 1.367, + 20.455, + 1.433, + 18.258, + 1.5, + 13.85, + 1, + 1.622, + 5.77, + 1.744, + -3.15, + 1.867, + -3.15, + 1, + 1.978, + -3.15, + 2.089, + 4.85, + 2.2, + 4.85, + 1, + 2.378, + 4.85, + 2.556, + -16.978, + 2.733, + -20, + 1, + 2.878, + -22.455, + 3.022, + -22, + 3.167, + -22, + 1, + 3.233, + -22, + 3.3, + -2, + 3.367, + -2, + 1, + 3.5, + -2, + 3.633, + -6, + 3.767, + -6, + 1, + 3.9, + -6, + 4.033, + -6, + 4.167, + -6, + 1, + 4.456, + -6, + 4.744, + -2, + 5.033, + -2, + 0, + 7.8, + -2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "Segments": [ + 0, + 0, + 1, + 0.122, + 0, + 0.244, + 9.78, + 0.367, + 23, + 1, + 0.422, + 29.009, + 0.478, + 30, + 0.533, + 30, + 1, + 0.644, + 30, + 0.756, + 0, + 0.867, + 0, + 1, + 1.1, + 0, + 1.333, + 0, + 1.567, + 0, + 1, + 1.756, + 0, + 1.944, + 30, + 2.133, + 30, + 1, + 2.167, + 30, + 2.2, + 30, + 2.233, + 30, + 1, + 2.456, + 30, + 2.678, + 0, + 2.9, + 0, + 1, + 2.944, + 0, + 2.989, + 0, + 3.033, + 0, + 1, + 3.144, + 0, + 3.256, + 14.656, + 3.367, + 14.656, + 1, + 3.467, + 14.656, + 3.567, + 4.615, + 3.667, + 4.615, + 1, + 3.822, + 4.615, + 3.978, + 10.202, + 4.133, + 10.202, + 1, + 4.367, + 10.202, + 4.6, + 0, + 4.833, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + -19.973, + 0.433, + -19.973, + 1, + 0.522, + -19.973, + 0.611, + -18.904, + 0.7, + -8.205, + 1, + 0.767, + -0.181, + 0.833, + 18, + 0.9, + 18, + 1, + 1.033, + 18, + 1.167, + 8.193, + 1.3, + -2.506, + 1, + 1.4, + -10.53, + 1.5, + -11.984, + 1.6, + -11.984, + 1, + 1.756, + -11.984, + 1.911, + -6.611, + 2.067, + -6.611, + 1, + 2.178, + -6.611, + 2.289, + -6.611, + 2.4, + -6.611, + 1, + 2.511, + -6.611, + 2.622, + -3, + 2.733, + -3, + 1, + 2.856, + -3, + 2.978, + -3, + 3.1, + -3, + 1, + 3.189, + -3, + 3.278, + 11, + 3.367, + 11, + 1, + 3.6, + 11, + 3.833, + 11, + 4.067, + 11, + 1, + 4.411, + 11, + 4.756, + 20, + 5.1, + 20, + 1, + 5.567, + 20, + 6.033, + 17.63, + 6.5, + 17.63, + 0, + 7.8, + 17.63 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + -10, + 0.467, + -10, + 1, + 1.078, + -10, + 1.689, + -10, + 2.3, + -10, + 1, + 2.567, + -10, + 2.833, + 10, + 3.1, + 10, + 1, + 3.2, + 10, + 3.3, + -10, + 3.4, + -10, + 1, + 3.6, + -10, + 3.8, + -10, + 4, + -10, + 1, + 4.244, + -10, + 4.489, + 9, + 4.733, + 9, + 1, + 5.222, + 9, + 5.711, + 0, + 6.2, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0.01, + 1, + 0.444, + 0.023, + 0.556, + 1, + 0.667, + 1, + 1, + 1.644, + 1, + 2.622, + 1, + 3.6, + 1, + 1, + 3.767, + 1, + 3.933, + 0, + 4.1, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "Segments": [ + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 3, + 0, + 1, + 3.389, + 0, + 3.778, + 1, + 4.167, + 1, + 1, + 4.178, + 1, + 4.189, + 0, + 4.2, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "Segments": [ + 0, + 0, + 1, + 1.078, + 0, + 2.156, + 0, + 3.233, + 0, + 1, + 3.544, + 0, + 3.856, + 1, + 4.167, + 1, + 1, + 4.178, + 1, + 4.189, + 0, + 4.2, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "Segments": [ + 0, + 0, + 0, + 0.567, + 0, + 1, + 0.8, + 13.228, + 1.033, + 14.173, + 1.267, + 15, + 1, + 1.278, + 15, + 1.289, + 15, + 1.3, + 15, + 1, + 1.6, + 19.829, + 1.9, + 28.166, + 2.2, + 30, + 1, + 2.856, + 30, + 3.511, + 30, + 4.167, + 30, + 1, + 4.178, + 30, + 4.189, + 0, + 4.2, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "Segments": [ + 0, + 0, + 1, + 1.089, + 0, + 2.178, + 0, + 3.267, + 0, + 1, + 3.367, + 0, + 3.467, + 0.166, + 3.567, + 0.3, + 1, + 3.744, + 0.537, + 3.922, + 0.6, + 4.1, + 0.6, + 1, + 4.122, + 0.6, + 4.144, + 0.6, + 4.167, + 0.6, + 1, + 4.178, + 0.6, + 4.189, + 0, + 4.2, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "Segments": [ + 0, + 0, + 1, + 1.078, + 0, + 2.156, + 0, + 3.233, + 0, + 1, + 3.544, + 0, + 3.856, + 1, + 4.167, + 1, + 1, + 4.178, + 1, + 4.189, + 0, + 4.2, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "Segments": [ + 0, + 0, + 1, + 1.044, + 0, + 2.089, + 0, + 3.133, + 0, + 1, + 3.244, + 0, + 3.356, + 1, + 3.467, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "Segments": [ + 0, + 0, + 0, + 0.5, + 0, + 0, + 2, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "Segments": [ + 0, + 0, + 1, + 1.278, + 0, + 2.556, + 0, + 3.833, + 0, + 1, + 4, + 0.957, + 4.167, + 1, + 4.333, + 1, + 1, + 4.833, + 1, + 5.333, + 0.898, + 5.833, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "Segments": [ + 0, + 0, + 1, + 1.211, + 0, + 2.422, + 0, + 3.633, + 0, + 1, + 4.078, + 2.8, + 4.522, + 8.271, + 4.967, + 29.268, + 2, + 5, + 0, + 1, + 5.456, + 14.57, + 5.911, + 29.968, + 6.367, + 29.268, + 0, + 6.4, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "Segments": [ + 0, + 0, + 1, + 1.4, + 0, + 2.8, + 0, + 4.2, + 0, + 1, + 4.656, + 0, + 5.111, + 1, + 5.567, + 1, + 1, + 5.656, + 1, + 5.744, + 1, + 5.833, + 1, + 1, + 5.844, + 1, + 5.856, + 0, + 5.867, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "Segments": [ + 0, + 0, + 1, + 1.089, + 0, + 2.178, + 0, + 3.267, + 0, + 1, + 3.567, + 0.661, + 3.867, + 1, + 4.167, + 1, + 1, + 4.344, + 1, + 4.522, + 0.757, + 4.7, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "Segments": [ + 0, + 0, + 1, + 1.111, + 0, + 2.222, + 0, + 3.333, + 0, + 1, + 3.911, + 17.478, + 4.489, + 30, + 5.067, + 30, + 1, + 5.078, + 30, + 5.089, + 0, + 5.1, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "Segments": [ + 0, + 0, + 1, + 1.078, + 0, + 2.156, + 0, + 3.233, + 0, + 1, + 3.544, + 0, + 3.856, + 1, + 4.167, + 1, + 1, + 4.344, + 1, + 4.522, + 1, + 4.7, + 1, + 1, + 4.711, + 1, + 4.722, + 0, + 4.733, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "Segments": [ + 0, + 0, + 1, + 1.244, + 0, + 2.489, + 0, + 3.733, + 0, + 1, + 3.989, + 0.654, + 4.244, + 1, + 4.5, + 1, + 1, + 4.667, + 1, + 4.833, + 1, + 5, + 1, + 1, + 5.5, + 1, + 6, + 0.928, + 6.5, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "Segments": [ + 0, + 0, + 1, + 1.244, + 0, + 2.489, + 0, + 3.733, + 0, + 1, + 4.489, + 25.63, + 5.244, + 30, + 6, + 30, + 1, + 6.167, + 30, + 6.333, + 30, + 6.5, + 30, + 1, + 6.511, + 30, + 6.522, + 0, + 6.533, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "Segments": [ + 0, + 0, + 1, + 1.456, + 0, + 2.911, + 0, + 4.367, + 0, + 1, + 4.611, + 0, + 4.856, + 0.6, + 5.1, + 0.6, + 1, + 5.244, + 0.6, + 5.389, + 0.4, + 5.533, + 0.4, + 1, + 5.678, + 0.4, + 5.822, + 0.6, + 5.967, + 0.6, + 1, + 6.111, + 0.6, + 6.256, + 0.572, + 6.4, + 0.4, + 1, + 6.567, + 0.201, + 6.733, + 0, + 6.9, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLA", + "Segments": [ + 0, + 1, + 0, + 7.8, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 0, + 0, + 7.8, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 1, + 0, + 7.8, + 1 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_02.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_02.motion3.json new file mode 100644 index 0000000..624695a --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_02.motion3.json @@ -0,0 +1,4206 @@ +{ + "Version": 3, + "Meta": { + "Duration": 9.37, + "Fps": 30.0, + "FadeInTime": 0.25, + "FadeOutTime": 0.25, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 532, + "TotalPointCount": 1432, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.089, + 0, + 0.178, + 0.507, + 0.267, + -1.466, + 1, + 0.411, + -4.672, + 0.556, + -22.794, + 0.7, + -22.794, + 1, + 0.911, + -22.794, + 1.122, + -22.336, + 1.333, + -22.336, + 1, + 1.533, + -22.336, + 1.733, + -22.362, + 1.933, + -22.794, + 1, + 2.067, + -23.081, + 2.2, + -24.238, + 2.333, + -25.081, + 1, + 2.511, + -26.205, + 2.689, + -26.911, + 2.867, + -26.911, + 1, + 3.844, + -26.911, + 4.822, + -26.911, + 5.8, + -26.911, + 1, + 5.833, + -26.911, + 5.867, + -29.911, + 5.9, + -29.911, + 1, + 5.944, + -29.911, + 5.989, + -13, + 6.033, + -13, + 1, + 6.056, + -13, + 6.078, + -15, + 6.1, + -15, + 1, + 6.589, + -15, + 7.078, + -15, + 7.567, + -15, + 0, + 9.367, + -15 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -2.583, + 0.3, + -2.583, + 1, + 0.433, + -2.583, + 0.567, + 28, + 0.7, + 28, + 1, + 0.822, + 28, + 0.944, + 25, + 1.067, + 25, + 1, + 1.4, + 25, + 1.733, + 25, + 2.067, + 25, + 1, + 2.178, + 25, + 2.289, + 9.282, + 2.4, + 6, + 1, + 2.467, + 4.031, + 2.533, + 4.503, + 2.6, + 4.503, + 1, + 2.733, + 4.503, + 2.867, + 30, + 3, + 30, + 1, + 3.922, + 30, + 4.844, + 30, + 5.767, + 30, + 1, + 5.811, + 30, + 5.856, + 4, + 5.9, + 4, + 1, + 5.956, + 4, + 6.011, + 30, + 6.067, + 30, + 1, + 6.578, + 30, + 7.089, + 30, + 7.6, + 30, + 1, + 7.867, + 30, + 8.133, + -17, + 8.4, + -17, + 1, + 8.722, + -17, + 9.044, + -15, + 9.367, + -15 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -0.018, + 0.7, + 3, + 1, + 0.9, + 5.587, + 1.1, + 14, + 1.3, + 14, + 1, + 1.544, + 14, + 1.789, + 6.914, + 2.033, + 0, + 1, + 2.244, + -5.971, + 2.456, + -7, + 2.667, + -7, + 1, + 2.778, + -7, + 2.889, + 5.204, + 3, + 7, + 1, + 3.222, + 10.592, + 3.444, + 11, + 3.667, + 11, + 1, + 4.333, + 11, + 5, + 11, + 5.667, + 11, + 1, + 5.756, + 11, + 5.844, + 5, + 5.933, + 5, + 1, + 6.011, + 5, + 6.089, + 21, + 6.167, + 21, + 1, + 6.622, + 21, + 7.078, + 21, + 7.533, + 21, + 1, + 7.6, + 21, + 7.667, + 23, + 7.733, + 23, + 1, + 7.967, + 23, + 8.2, + -17, + 8.433, + -17, + 1, + 8.611, + -17, + 8.789, + -16, + 8.967, + -16, + 0, + 9.367, + -16 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "Segments": [ + 0, + 0, + 1, + 2.011, + 0, + 4.022, + 0, + 6.033, + 0, + 1, + 6.144, + 0, + 6.256, + 1, + 6.367, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.089, + 1, + 0.178, + 1, + 0.267, + 1, + 1, + 0.3, + 1, + 0.333, + 0, + 0.367, + 0, + 1, + 0.389, + 0, + 0.411, + 0, + 0.433, + 0, + 1, + 0.467, + 0, + 0.5, + 1, + 0.533, + 1, + 1, + 1.078, + 1, + 1.622, + 1, + 2.167, + 1, + 1, + 2.2, + 1, + 2.233, + 0, + 2.267, + 0, + 1, + 2.367, + 0, + 2.467, + 0, + 2.567, + 0, + 1, + 2.6, + 0, + 2.633, + 1, + 2.667, + 1, + 1, + 3.211, + 1, + 3.756, + 1, + 4.3, + 1, + 1, + 4.333, + 1, + 4.367, + 0, + 4.4, + 0, + 1, + 4.422, + 0, + 4.444, + 1, + 4.467, + 1, + 1, + 4.511, + 1, + 4.556, + 1, + 4.6, + 1, + 1, + 4.633, + 1, + 4.667, + 0, + 4.7, + 0, + 1, + 4.722, + 0, + 4.744, + 1, + 4.767, + 1, + 1, + 5.144, + 1, + 5.522, + 1, + 5.9, + 1, + 1, + 5.933, + 1, + 5.967, + 0, + 6, + 0, + 1, + 6.2, + 0, + 6.4, + 0, + 6.6, + 0, + 1, + 6.633, + 0, + 6.667, + 1.2, + 6.7, + 1.2, + 1, + 6.822, + 1.2, + 6.944, + 1.2, + 7.067, + 1.2, + 1, + 7.1, + 1.2, + 7.133, + 0, + 7.167, + 0, + 1, + 7.2, + 0, + 7.233, + 1.2, + 7.267, + 1.2, + 1, + 7.3, + 1.2, + 7.333, + 0, + 7.367, + 0, + 1, + 7.4, + 0, + 7.433, + 1.2, + 7.467, + 1.2, + 1, + 7.656, + 1.2, + 7.844, + 1.149, + 8.033, + 1, + 1, + 8.056, + 0.983, + 8.078, + 0, + 8.1, + 0, + 1, + 8.144, + 0, + 8.189, + 0, + 8.233, + 0, + 1, + 8.256, + 0, + 8.278, + 1, + 8.3, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 1.956, + 0, + 3.911, + 0, + 5.867, + 0, + 1, + 5.878, + 0, + 5.889, + 0.898, + 5.9, + 0.9, + 1, + 6.256, + 0.969, + 6.611, + 1, + 6.967, + 1, + 1, + 6.978, + 1, + 6.989, + 0, + 7, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "Segments": [ + 0, + 0, + 1, + 2.744, + 0, + 5.489, + 0, + 8.233, + 0, + 1, + 8.256, + 0, + 8.278, + 1, + 8.3, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.089, + 1, + 0.178, + 1, + 0.267, + 1, + 1, + 0.3, + 1, + 0.333, + 0, + 0.367, + 0, + 1, + 0.389, + 0, + 0.411, + 0, + 0.433, + 0, + 1, + 0.467, + 0, + 0.5, + 1, + 0.533, + 1, + 1, + 1.078, + 1, + 1.622, + 1, + 2.167, + 1, + 1, + 2.2, + 1, + 2.233, + 0, + 2.267, + 0, + 1, + 2.367, + 0, + 2.467, + 0, + 2.567, + 0, + 1, + 2.6, + 0, + 2.633, + 1, + 2.667, + 1, + 1, + 3.211, + 1, + 3.756, + 1, + 4.3, + 1, + 1, + 4.333, + 1, + 4.367, + 0, + 4.4, + 0, + 1, + 4.422, + 0, + 4.444, + 1, + 4.467, + 1, + 1, + 4.511, + 1, + 4.556, + 1, + 4.6, + 1, + 1, + 4.633, + 1, + 4.667, + 0, + 4.7, + 0, + 1, + 4.722, + 0, + 4.744, + 1, + 4.767, + 1, + 1, + 5.144, + 1, + 5.522, + 1, + 5.9, + 1, + 1, + 5.933, + 1, + 5.967, + 0, + 6, + 0, + 1, + 6.2, + 0, + 6.4, + 0, + 6.6, + 0, + 1, + 6.633, + 0, + 6.667, + 1.2, + 6.7, + 1.2, + 1, + 6.822, + 1.2, + 6.944, + 1.2, + 7.067, + 1.2, + 1, + 7.1, + 1.2, + 7.133, + 0, + 7.167, + 0, + 1, + 7.2, + 0, + 7.233, + 1.2, + 7.267, + 1.2, + 1, + 7.3, + 1.2, + 7.333, + 0, + 7.367, + 0, + 1, + 7.4, + 0, + 7.433, + 1.2, + 7.467, + 1.2, + 1, + 7.656, + 1.2, + 7.844, + 1.149, + 8.033, + 1, + 1, + 8.056, + 0.983, + 8.078, + 0, + 8.1, + 0, + 1, + 8.144, + 0, + 8.189, + 0, + 8.233, + 0, + 1, + 8.256, + 0, + 8.278, + 1, + 8.3, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 1.956, + 0, + 3.911, + 0, + 5.867, + 0, + 1, + 5.878, + 0, + 5.889, + 1, + 5.9, + 1, + 1, + 6.256, + 1, + 6.611, + 1, + 6.967, + 1, + 1, + 6.978, + 1, + 6.989, + 0, + 7, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "Segments": [ + 0, + 0, + 1, + 2.744, + 0, + 5.489, + 0, + 8.233, + 0, + 1, + 8.256, + 0, + 8.278, + 1, + 8.3, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -0.2, + 0.7, + -0.2, + 1, + 2.478, + -0.2, + 4.256, + -0.2, + 6.033, + -0.2, + 1, + 6.256, + -0.2, + 6.478, + -0.4, + 6.7, + -0.4, + 1, + 7.078, + -0.4, + 7.456, + -0.4, + 7.833, + -0.4, + 1, + 7.978, + -0.4, + 8.122, + 0.6, + 8.267, + 0.6, + 0, + 9.367, + 0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + 0.2, + 0.7, + 0.2, + 1, + 2.478, + 0.2, + 4.256, + 0.2, + 6.033, + 0.2, + 1, + 6.256, + 0.2, + 6.478, + 0.7, + 6.7, + 0.7, + 1, + 6.922, + 0.7, + 7.144, + 0.7, + 7.367, + 0.7, + 1, + 7.522, + 0.7, + 7.678, + 0, + 7.833, + 0, + 1, + 7.978, + 0, + 8.122, + 1, + 8.267, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 1, + 2.189, + 0, + 4.378, + 0, + 6.567, + 0, + 1, + 6.611, + 0, + 6.656, + -1, + 6.7, + -1, + 1, + 7.011, + -1, + 7.322, + -0.986, + 7.633, + -0.9, + 1, + 7.789, + -0.857, + 7.944, + -0.707, + 8.1, + -0.6, + 1, + 8.111, + -0.592, + 8.122, + 0, + 8.133, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "Segments": [ + 0, + 0, + 1, + 0.778, + 0, + 1.556, + 0, + 2.333, + 0, + 1, + 2.389, + 0, + 2.444, + 1, + 2.5, + 1, + 1, + 3.667, + 1, + 4.833, + 1, + 6, + 1, + 1, + 6.011, + 1, + 6.022, + 0, + 6.033, + 0, + 1, + 6.256, + 0, + 6.478, + 0, + 6.7, + 0, + 1, + 6.9, + 0, + 7.1, + 0, + 7.3, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 2.644, + 0, + 5.289, + 0, + 7.933, + 0, + 1, + 8.044, + 0, + 8.156, + -0.4, + 8.267, + -0.4, + 0, + 9.367, + -0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 2.644, + 0, + 5.289, + 0, + 7.933, + 0, + 1, + 8.044, + 0, + 8.156, + -0.4, + 8.267, + -0.4, + 0, + 9.367, + -0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 1, + 2.178, + 0, + 4.356, + 0, + 6.533, + 0, + 1, + 6.6, + 0, + 6.667, + -0.4, + 6.733, + -0.4, + 1, + 7.044, + -0.4, + 7.356, + -0.4, + 7.667, + -0.4, + 1, + 7.756, + -0.4, + 7.844, + -0.234, + 7.933, + 0, + 1, + 8.044, + 0.293, + 8.156, + 0.4, + 8.267, + 0.4, + 0, + 9.367, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 1, + 2.178, + 0, + 4.356, + 0, + 6.533, + 0, + 1, + 6.6, + 0, + 6.667, + -0.4, + 6.733, + -0.4, + 1, + 7.044, + -0.4, + 7.356, + -0.4, + 7.667, + -0.4, + 1, + 7.756, + -0.4, + 7.844, + -0.234, + 7.933, + 0, + 1, + 8.044, + 0.293, + 8.156, + 0.4, + 8.267, + 0.4, + 0, + 9.367, + 0.4 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 1, + 2.178, + 0, + 4.356, + 0, + 6.533, + 0, + 1, + 6.6, + 0, + 6.667, + 0.6, + 6.733, + 0.6, + 1, + 7.044, + 0.6, + 7.356, + 0.6, + 7.667, + 0.6, + 1, + 7.756, + 0.6, + 7.844, + 0.351, + 7.933, + 0, + 1, + 8.044, + -0.439, + 8.156, + -0.6, + 8.267, + -0.6, + 0, + 9.367, + -0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 1, + 2.178, + 0, + 4.356, + 0, + 6.533, + 0, + 1, + 6.6, + 0, + 6.667, + 0.6, + 6.733, + 0.6, + 1, + 7.044, + 0.6, + 7.356, + 0.6, + 7.667, + 0.6, + 1, + 7.756, + 0.6, + 7.844, + 0.351, + 7.933, + 0, + 1, + 8.044, + -0.439, + 8.156, + -0.6, + 8.267, + -0.6, + 0, + 9.367, + -0.6 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "Segments": [ + 0, + 0, + 1, + 2.189, + 0, + 4.378, + 0, + 6.567, + 0, + 1, + 6.622, + 0, + 6.678, + 1, + 6.733, + 1, + 1, + 7.056, + 1, + 7.378, + 1, + 7.7, + 1, + 1, + 7.744, + 1, + 7.789, + 0, + 7.833, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "Segments": [ + 0, + 0, + 1, + 0.833, + 0, + 1.667, + 0, + 2.5, + 0, + 1, + 2.611, + 0, + 2.722, + 1, + 2.833, + 1, + 1, + 3.844, + 1, + 4.856, + 1, + 5.867, + 1, + 1, + 5.911, + 1, + 5.956, + 0, + 6, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "Segments": [ + 0, + 1, + 1, + 1.922, + 1, + 3.844, + 1, + 5.767, + 1, + 1, + 5.811, + 1, + 5.856, + 0, + 5.9, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "Segments": [ + 0, + 0, + 1, + 1.956, + 0, + 3.911, + 0, + 5.867, + 0, + 1, + 5.911, + 0, + 5.956, + 1, + 6, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "Segments": [ + 0, + 0, + 1, + 2.633, + 0, + 5.267, + 0, + 7.9, + 0, + 1, + 8.033, + 0, + 8.167, + 1, + 8.3, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "Segments": [ + 0, + 0, + 1, + 2.633, + 0, + 5.267, + 0, + 7.9, + 0, + 1, + 8.033, + 0, + 8.167, + 1, + 8.3, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.433, + 0, + 0.867, + -5, + 1.3, + -5, + 1, + 1.511, + -5, + 1.722, + -3, + 1.933, + -3, + 1, + 2.089, + -3, + 2.244, + -6, + 2.4, + -6, + 1, + 2.667, + -6, + 2.933, + -4.776, + 3.2, + -4, + 1, + 3.511, + -3.095, + 3.822, + -3, + 4.133, + -3, + 1, + 4.867, + -3, + 5.6, + -5, + 6.333, + -5, + 1, + 6.744, + -5, + 7.156, + -5, + 7.567, + -5, + 1, + 7.744, + -5, + 7.922, + -8, + 8.1, + -8, + 0, + 9.367, + -8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -1, + 0.3, + -1, + 1, + 0.4, + -1, + 0.5, + 4.328, + 0.6, + 7, + 1, + 0.678, + 9.079, + 0.756, + 9, + 0.833, + 9, + 1, + 0.978, + 9, + 1.122, + 5, + 1.267, + 5, + 1, + 1.344, + 5, + 1.422, + 6.297, + 1.5, + 7, + 1, + 1.6, + 7.904, + 1.7, + 8, + 1.8, + 8, + 1, + 1.944, + 8, + 2.089, + 3.885, + 2.233, + 0, + 1, + 2.278, + -1.195, + 2.322, + -1, + 2.367, + -1, + 1, + 2.533, + -1, + 2.7, + 7, + 2.867, + 7, + 1, + 3.022, + 7, + 3.178, + 6.6, + 3.333, + 6.6, + 1, + 4.133, + 6.6, + 4.933, + 7, + 5.733, + 7, + 1, + 5.8, + 7, + 5.867, + 3, + 5.933, + 3, + 1, + 5.967, + 3, + 6, + 10, + 6.033, + 10, + 1, + 6.144, + 10, + 6.256, + 6.493, + 6.367, + 6.399, + 1, + 6.767, + 6.062, + 7.167, + 6, + 7.567, + 6, + 1, + 7.644, + 6, + 7.722, + 10, + 7.8, + 10, + 1, + 7.856, + 10, + 7.911, + 9.54, + 7.967, + 6, + 1, + 8.044, + 1.043, + 8.122, + -4, + 8.2, + -4, + 1, + 8.356, + -4, + 8.511, + -2, + 8.667, + -2, + 0, + 9.367, + -2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.378, + 0, + 0.756, + 7, + 1.133, + 7, + 1, + 1.511, + 7, + 1.889, + 5.295, + 2.267, + 1, + 1, + 2.333, + 0.242, + 2.4, + -1, + 2.467, + -1, + 1, + 2.611, + -1, + 2.756, + 5.286, + 2.9, + 6, + 1, + 3.4, + 8.471, + 3.9, + 9, + 4.4, + 9, + 1, + 4.844, + 9, + 5.289, + 8.25, + 5.733, + 6, + 1, + 5.8, + 5.662, + 5.867, + 2, + 5.933, + 2, + 1, + 5.978, + 2, + 6.022, + 10, + 6.067, + 10, + 1, + 6.156, + 10, + 6.244, + 9, + 6.333, + 9, + 1, + 6.822, + 9, + 7.311, + 9, + 7.8, + 9, + 1, + 8.011, + 9, + 8.222, + -3, + 8.433, + -3, + 1, + 8.633, + -3, + 8.833, + -2, + 9.033, + -2, + 0, + 9.367, + -2 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + 0, + 0.433, + 0, + 1, + 0.633, + 0, + 0.833, + -1.599, + 1.033, + -1.599, + 1, + 1.489, + -1.599, + 1.944, + -1.599, + 2.4, + -1.599, + 1, + 2.744, + -1.599, + 3.089, + -0.772, + 3.433, + -0.64, + 1, + 4.189, + -0.349, + 4.944, + -0.229, + 5.7, + 0, + 1, + 5.756, + 0.017, + 5.811, + 8.644, + 5.867, + 8.644, + 1, + 5.978, + 8.644, + 6.089, + -1, + 6.2, + -1, + 1, + 6.267, + -1, + 6.333, + 0, + 6.4, + 0, + 1, + 6.844, + 0, + 7.289, + 0, + 7.733, + 0, + 1, + 7.856, + 0, + 7.978, + 8.298, + 8.1, + 8.298, + 1, + 8.222, + 8.298, + 8.344, + 4.495, + 8.467, + 4.495, + 1, + 8.556, + 4.495, + 8.644, + 6.569, + 8.733, + 6.569, + 0, + 9.367, + 6.569 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + -10, + 0.467, + -10, + 1, + 0.667, + -10, + 0.867, + -10, + 1.067, + -10, + 1, + 1.222, + -10, + 1.378, + -10, + 1.533, + -10, + 1, + 1.822, + -10, + 2.111, + -10, + 2.4, + -10, + 1, + 2.633, + -10, + 2.867, + -10, + 3.1, + -10, + 1, + 3.967, + -10, + 4.833, + -10, + 5.7, + -10, + 1, + 5.756, + -10, + 5.811, + 4, + 5.867, + 4, + 1, + 5.978, + 4, + 6.089, + -2, + 6.2, + -2, + 1, + 6.267, + -2, + 6.333, + 0, + 6.4, + 0, + 1, + 6.844, + 0, + 7.289, + 0, + 7.733, + 0, + 1, + 7.844, + 0, + 7.956, + 8, + 8.067, + 8, + 1, + 8.167, + 8, + 8.267, + -10, + 8.367, + -10, + 0, + 9.367, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "Segments": [ + 0, + 0, + 1, + 0.211, + 0, + 0.422, + -3, + 0.633, + -3, + 1, + 0.9, + -3, + 1.167, + 3, + 1.433, + 3, + 1, + 1.778, + 3, + 2.122, + -6, + 2.467, + -6, + 1, + 2.611, + -6, + 2.756, + 3.403, + 2.9, + 4, + 1, + 3.144, + 5.01, + 3.389, + 5.852, + 3.633, + 6, + 1, + 4.333, + 6.424, + 5.033, + 6.646, + 5.733, + 7, + 1, + 5.778, + 7.022, + 5.822, + 13, + 5.867, + 13, + 1, + 5.944, + 13, + 6.022, + -4.497, + 6.1, + -4.497, + 1, + 6.211, + -4.497, + 6.322, + -3, + 6.433, + -3, + 1, + 6.756, + -3, + 7.078, + -3, + 7.4, + -3, + 1, + 7.511, + -3, + 7.622, + -5, + 7.733, + -5, + 1, + 7.833, + -5, + 7.933, + 24, + 8.033, + 24, + 1, + 8.122, + 24, + 8.211, + 17, + 8.3, + 17, + 1, + 8.4, + 17, + 8.5, + 18, + 8.6, + 18, + 0, + 9.367, + 18 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + -3, + 0.9, + -3, + 1, + 1.178, + -3, + 1.456, + 0, + 1.733, + 0, + 1, + 2.022, + 0, + 2.311, + -5, + 2.6, + -5, + 1, + 2.744, + -5, + 2.889, + -3.126, + 3.033, + -3, + 1, + 3.911, + -2.234, + 4.789, + -2, + 5.667, + -2, + 1, + 5.722, + -2, + 5.778, + -3, + 5.833, + -3, + 1, + 5.878, + -3, + 5.922, + 4, + 5.967, + 4, + 1, + 6.022, + 4, + 6.078, + -4, + 6.133, + -4, + 1, + 6.222, + -4, + 6.311, + -3, + 6.4, + -3, + 1, + 6.8, + -3, + 7.2, + -3, + 7.6, + -3, + 1, + 7.722, + -3, + 7.844, + -6.441, + 7.967, + -13, + 1, + 8.056, + -17.77, + 8.144, + -20, + 8.233, + -20, + 0, + 9.367, + -20 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "Segments": [ + 0, + 0, + 1, + 0.3, + 0, + 0.6, + -1, + 0.9, + -1, + 1, + 1.122, + -1, + 1.344, + 1, + 1.567, + 1, + 1, + 1.844, + 1, + 2.122, + -3, + 2.4, + -3, + 1, + 2.622, + -3, + 2.844, + -1.208, + 3.067, + -1, + 1, + 3.933, + -0.189, + 4.8, + 0, + 5.667, + 0, + 1, + 5.733, + 0, + 5.8, + -7, + 5.867, + -7, + 1, + 5.956, + -7, + 6.044, + 14, + 6.133, + 14, + 1, + 6.222, + 14, + 6.311, + 0, + 6.4, + 0, + 1, + 6.944, + 0, + 7.489, + 0, + 8.033, + 0, + 1, + 8.111, + 0, + 8.189, + 30, + 8.267, + 30, + 0, + 9.367, + 30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "Segments": [ + 0, + 0, + 1, + 0.178, + 0, + 0.356, + -30, + 0.533, + -30, + 1, + 0.622, + -30, + 0.711, + -13.204, + 0.8, + -3, + 1, + 0.889, + 7.204, + 0.978, + 8, + 1.067, + 8, + 1, + 1.144, + 8, + 1.222, + 3, + 1.3, + 3, + 1, + 1.378, + 3, + 1.456, + 8, + 1.533, + 8, + 1, + 1.656, + 8, + 1.778, + -3.927, + 1.9, + -11, + 1, + 2.1, + -22.575, + 2.3, + -25, + 2.5, + -25, + 1, + 2.711, + -25, + 2.922, + -18, + 3.133, + -18, + 1, + 4.033, + -18, + 4.933, + -21, + 5.833, + -21, + 1, + 5.889, + -21, + 5.944, + -19, + 6, + -19, + 1, + 6.067, + -19, + 6.133, + -28, + 6.2, + -28, + 1, + 6.6, + -28, + 7, + -28, + 7.4, + -28, + 1, + 7.511, + -28, + 7.622, + -30, + 7.733, + -30, + 1, + 7.822, + -30, + 7.911, + -11, + 8, + -11, + 1, + 8.122, + -11, + 8.244, + -30, + 8.367, + -30, + 1, + 8.5, + -30, + 8.633, + -28, + 8.767, + -28, + 0, + 9.367, + -28 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "Segments": [ + 0, + 0, + 1, + 0.067, + 0, + 0.133, + -0.16, + 0.2, + 1.053, + 1, + 0.289, + 2.67, + 0.378, + 9.239, + 0.467, + 13.846, + 1, + 0.556, + 18.453, + 0.644, + 26.27, + 0.733, + 28.907, + 1, + 0.778, + 30, + 0.822, + 30, + 0.867, + 30, + 1, + 1.011, + 30, + 1.156, + 28.04, + 1.3, + 22.85, + 1, + 1.367, + 20.455, + 1.433, + 18.257, + 1.5, + 13.85, + 1, + 1.622, + 5.77, + 1.744, + -3.15, + 1.867, + -3.15, + 1, + 2.033, + -3.15, + 2.2, + -2.846, + 2.367, + 0, + 1, + 2.456, + 1.518, + 2.544, + 10, + 2.633, + 10, + 1, + 2.822, + 10, + 3.011, + 1.174, + 3.2, + 0, + 1, + 4.078, + -5.454, + 4.956, + -7, + 5.833, + -7, + 1, + 5.867, + -7, + 5.9, + 30, + 5.933, + 30, + 1, + 6.022, + 30, + 6.111, + -16, + 6.2, + -16, + 1, + 6.289, + -16, + 6.378, + -13, + 6.467, + -13, + 1, + 6.889, + -13, + 7.311, + -13, + 7.733, + -13, + 1, + 7.856, + -13, + 7.978, + -16, + 8.1, + -16, + 1, + 8.211, + -16, + 8.322, + -4, + 8.433, + -4, + 1, + 8.578, + -4, + 8.722, + -5, + 8.867, + -5, + 0, + 9.367, + -5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "Segments": [ + 0, + 0, + 1, + 0.122, + 0, + 0.244, + 9.78, + 0.367, + 23, + 1, + 0.422, + 29.009, + 0.478, + 30, + 0.533, + 30, + 1, + 0.644, + 30, + 0.756, + 0, + 0.867, + 0, + 1, + 1.1, + 0, + 1.333, + 0, + 1.567, + 0, + 1, + 1.756, + 0, + 1.944, + 30, + 2.133, + 30, + 1, + 2.289, + 30, + 2.444, + 30, + 2.6, + 29.514, + 1, + 3.633, + 22.99, + 4.667, + 15.313, + 5.7, + 15.313, + 1, + 5.789, + 15.313, + 5.878, + 22, + 5.967, + 22, + 1, + 6.011, + 22, + 6.056, + 0, + 6.1, + 0, + 1, + 7.189, + 0, + 8.278, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + -19.973, + 0.433, + -19.973, + 1, + 0.522, + -19.973, + 0.611, + -18.904, + 0.7, + -8.205, + 1, + 0.767, + -0.181, + 0.833, + 18, + 0.9, + 18, + 1, + 1.033, + 18, + 1.167, + 8.193, + 1.3, + -2.506, + 1, + 1.4, + -10.53, + 1.5, + -11.984, + 1.6, + -11.984, + 1, + 1.756, + -11.984, + 1.911, + -6.248, + 2.067, + 3, + 1, + 2.178, + 9.606, + 2.289, + 12, + 2.4, + 12, + 1, + 3.544, + 12, + 4.689, + 0, + 5.833, + 0, + 1, + 5.889, + 0, + 5.944, + 18, + 6, + 18, + 1, + 6.078, + 18, + 6.156, + -2, + 6.233, + -2, + 1, + 6.344, + -2, + 6.456, + 0, + 6.567, + 0, + 1, + 6.956, + 0, + 7.344, + 0, + 7.733, + 0, + 1, + 7.856, + 0, + 7.978, + -9, + 8.1, + -9, + 1, + 8.133, + -9, + 8.167, + -3.91, + 8.2, + 0, + 1, + 8.278, + 9.124, + 8.356, + 12, + 8.433, + 12, + 1, + 8.578, + 12, + 8.722, + 8, + 8.867, + 8, + 0, + 9.367, + 8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + -10, + 0.467, + -10, + 1, + 1.167, + -10, + 1.867, + -10, + 2.567, + -10, + 1, + 2.789, + -10, + 3.011, + -4.373, + 3.233, + 0, + 1, + 3.633, + 7.872, + 4.033, + 10, + 4.433, + 10, + 1, + 4.9, + 10, + 5.367, + 10, + 5.833, + 10, + 1, + 5.889, + 10, + 5.944, + -10, + 6, + -10, + 1, + 6.1, + -10, + 6.2, + 0, + 6.3, + 0, + 1, + 6.8, + 0, + 7.3, + 0, + 7.8, + 0, + 1, + 7.878, + 0, + 7.956, + 5, + 8.033, + 5, + 1, + 8.167, + 5, + 8.3, + -10, + 8.433, + -10, + 0, + 9.367, + -10 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "Segments": [ + 0, + 0, + 1, + 1.933, + 0, + 3.867, + 0, + 5.8, + 0, + 1, + 5.844, + 0, + 5.889, + 2, + 5.933, + 2, + 1, + 6.067, + 2, + 6.2, + 0.797, + 6.333, + 0.496, + 1, + 6.544, + 0.02, + 6.756, + 0, + 6.967, + 0, + 1, + 7.4, + 0, + 7.833, + 0, + 8.267, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0, + 0.333, + 0.01, + 1, + 0.444, + 0.023, + 0.556, + 1, + 0.667, + 1, + 1, + 2.2, + 1, + 3.733, + 1, + 5.267, + 1, + 1, + 5.411, + 1, + 5.556, + 0, + 5.7, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "Segments": [ + 0, + 0, + 1, + 0.9, + 0, + 1.8, + 0, + 2.7, + 0, + 1, + 3.156, + 0, + 3.611, + 1, + 4.067, + 1, + 1, + 4.467, + 1, + 4.867, + 1, + 5.267, + 1, + 1, + 5.411, + 1, + 5.556, + 0, + 5.7, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "Segments": [ + 0, + 0, + 1, + 0.756, + 0, + 1.511, + 0, + 2.267, + 0, + 0, + 3.6, + 29.3, + 2, + 3.633, + 0, + 0, + 4.967, + 29.3, + 2, + 5, + 0, + 0, + 6.333, + 29.3, + 0, + 9.367, + 29.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "Segments": [ + 0, + 0, + 0, + 0.567, + 0, + 1, + 0.8, + 13.228, + 1.033, + 14.173, + 1.267, + 15, + 1, + 1.611, + 20.079, + 1.956, + 27.892, + 2.3, + 30, + 0, + 9.367, + 30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "Segments": [ + 0, + 0, + 1, + 1.611, + 0, + 3.222, + 0, + 4.833, + 0, + 1, + 4.944, + 0, + 5.056, + 0.3, + 5.167, + 0.3, + 1, + 5.333, + 0.3, + 5.5, + -0.9, + 5.667, + -0.9, + 0, + 9.367, + -0.9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "Segments": [ + 0, + 0, + 1, + 0.9, + 0, + 1.8, + 0, + 2.7, + 0, + 1, + 3.156, + 0, + 3.611, + 1, + 4.067, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "Segments": [ + 0, + 0, + 1, + 0.656, + 0, + 1.311, + 0, + 1.967, + 0, + 0, + 2.267, + 5, + 0, + 3.6, + 34.3, + 2, + 3.633, + 5, + 0, + 4.967, + 34.3, + 2, + 5, + 5, + 0, + 6.333, + 34.3, + 1, + 6.344, + 34.3, + 6.356, + 5.15, + 6.367, + 5, + 1, + 6.622, + 1.548, + 6.878, + 0, + 7.133, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "Segments": [ + 0, + 0, + 0, + 0.5, + 0, + 1, + 0.744, + 0, + 0.989, + 0.25, + 1.233, + 0.489, + 1, + 1.489, + 0.735, + 1.744, + 1, + 2, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "Segments": [ + 0, + 0, + 1, + 1.833, + 0, + 3.667, + 0, + 5.5, + 0, + 1, + 5.667, + 0, + 5.833, + 1, + 6, + 1, + 1, + 6.511, + 1, + 7.022, + 1, + 7.533, + 1, + 1, + 7.856, + 1, + 8.178, + 0, + 8.5, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "Segments": [ + 0, + 0, + 1, + 1.778, + 0, + 3.556, + 0, + 5.333, + 0, + 1, + 5.833, + 0, + 6.333, + 14.59, + 6.833, + 21.7, + 1, + 7.389, + 29.6, + 7.944, + 30, + 8.5, + 30, + 0, + 9.367, + 30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "Segments": [ + 0, + 0, + 1, + 0.944, + 0, + 1.889, + 0, + 2.833, + 0, + 1, + 3.278, + 0, + 3.722, + 1, + 4.167, + 1, + 1, + 4.444, + 1, + 4.722, + 1, + 5, + 1, + 1, + 5.278, + 1, + 5.556, + 0, + 5.833, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "Segments": [ + 0, + 0, + 1, + 0.767, + 0, + 1.533, + 0, + 2.3, + 0, + 1, + 2.7, + 0, + 3.1, + 14.776, + 3.5, + 28.8, + 2, + 3.533, + 0, + 0, + 4.233, + 28.636, + 2, + 4.267, + 0, + 0, + 4.967, + 28.636, + 2, + 5, + 0, + 1, + 5.367, + 13.273, + 5.733, + 27.986, + 6.1, + 28.8, + 0, + 9.367, + 28.8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 1, + 0.644, + 0, + 1.289, + 0, + 1.933, + 0, + 1, + 1.944, + 0, + 1.956, + 1, + 1.967, + 1, + 1, + 2.678, + 1, + 3.389, + 1, + 4.1, + 1, + 1, + 5.556, + 1, + 7.011, + 1, + 8.467, + 1, + 1, + 8.478, + 1, + 8.489, + 0, + 8.5, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "Segments": [ + 0, + 0, + 1, + 1.833, + 0, + 3.667, + 0, + 5.5, + 0, + 1, + 5.822, + 0, + 6.144, + 30, + 6.467, + 30, + 1, + 6.933, + 30, + 7.4, + 30, + 7.867, + 30, + 0, + 9.367, + 30 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 1, + 0, + 9.367, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 0, + 9.367, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLA", + "Segments": [ + 0, + 1, + 0, + 9.37, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 0, + 0, + 9.37, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 0, + 0, + 9.37, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 1, + 0, + 9.37, + 1 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_03.motion3.json b/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_03.motion3.json new file mode 100644 index 0000000..e128072 --- /dev/null +++ b/app/src/main/assets/live2d_model/mao_pro_zh/motions/special_03.motion3.json @@ -0,0 +1,4855 @@ +{ + "Version": 3, + "Meta": { + "Duration": 9.23, + "Fps": 30.0, + "FadeInTime": 0.25, + "FadeOutTime": 0.25, + "Loop": true, + "AreBeziersRestricted": true, + "CurveCount": 132, + "TotalSegmentCount": 619, + "TotalPointCount": 1713, + "UserDataCount": 0, + "TotalUserDataSize": 0 + }, + "Curves": [ + { + "Target": "Parameter", + "Id": "ParamAngleX", + "Segments": [ + 0, + 0, + 1, + 0.111, + 0, + 0.222, + 0.706, + 0.333, + -1.7, + 1, + 0.544, + -6.272, + 0.756, + -25.931, + 0.967, + -25.931, + 1, + 1.222, + -25.931, + 1.478, + -22.931, + 1.733, + -22.931, + 1, + 1.856, + -22.931, + 1.978, + -24.931, + 2.1, + -24.931, + 1, + 2.411, + -24.931, + 2.722, + -20.287, + 3.033, + -8, + 1, + 3.111, + -4.928, + 3.189, + 2.21, + 3.267, + 7, + 1, + 3.389, + 14.527, + 3.511, + 18, + 3.633, + 18, + 1, + 3.778, + 18, + 3.922, + -11, + 4.067, + -11, + 1, + 4.222, + -11, + 4.378, + 11, + 4.533, + 11, + 1, + 4.767, + 11, + 5, + 0, + 5.233, + 0, + 1, + 6.022, + 0, + 6.811, + 0, + 7.6, + 0, + 1, + 7.733, + 0, + 7.867, + -9.78, + 8, + -9.78, + 0, + 9.233, + -9.78 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -0.929, + 0.3, + -2.583, + 1, + 0.522, + -6.258, + 0.744, + -8, + 0.967, + -8, + 1, + 1.2, + -8, + 1.433, + 29, + 1.667, + 29, + 1, + 1.789, + 29, + 1.911, + 11, + 2.033, + 11, + 1, + 2.344, + 11, + 2.656, + 25, + 2.967, + 25, + 1, + 3.067, + 25, + 3.167, + -12, + 3.267, + -12, + 1, + 3.389, + -12, + 3.511, + -7.897, + 3.633, + -7, + 1, + 3.778, + -5.94, + 3.922, + -6, + 4.067, + -6, + 1, + 4.222, + -6, + 4.378, + -12, + 4.533, + -12, + 1, + 4.733, + -12, + 4.933, + 10.008, + 5.133, + 10.008, + 1, + 5.278, + 10.008, + 5.422, + 0, + 5.567, + 0, + 1, + 5.811, + 0, + 6.056, + 24.18, + 6.3, + 24.18, + 1, + 6.467, + 24.18, + 6.633, + 24.212, + 6.8, + 22.08, + 1, + 6.911, + 20.659, + 7.022, + -8.62, + 7.133, + -8.62, + 1, + 7.278, + -8.62, + 7.422, + 2.9, + 7.567, + 2.9, + 1, + 7.733, + 2.9, + 7.9, + -10.9, + 8.067, + -10.9, + 1, + 8.2, + -10.9, + 8.333, + -0.64, + 8.467, + -0.64, + 1, + 8.722, + -0.64, + 8.978, + -3.7, + 9.233, + -3.7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.256, + 0, + 0.511, + -7, + 0.767, + -7, + 1, + 0.856, + -7, + 0.944, + 6.52, + 1.033, + 7, + 1, + 1.211, + 7.959, + 1.389, + 8, + 1.567, + 8, + 1, + 1.711, + 8, + 1.856, + -10, + 2, + -10, + 1, + 2.311, + -10, + 2.622, + 2, + 2.933, + 2, + 1, + 3.133, + 2, + 3.333, + 0, + 3.533, + 0, + 1, + 4.867, + 0, + 6.2, + 0, + 7.533, + 0, + 1, + 7.678, + 0, + 7.822, + 6, + 7.967, + 6, + 1, + 8.233, + 6, + 8.5, + 4.08, + 8.767, + 4.08, + 0, + 9.233, + 4.08 + ] + }, + { + "Target": "Parameter", + "Id": "ParamCheek", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamFaceInkOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLOpen", + "Segments": [ + 0, + 1, + 1, + 0.267, + 1, + 0.533, + 1, + 0.8, + 1, + 1, + 0.844, + 1, + 0.889, + 0, + 0.933, + 0, + 1, + 1.544, + 0, + 2.156, + 0, + 2.767, + 0, + 1, + 2.8, + 0, + 2.833, + 1, + 2.867, + 1, + 1, + 3.522, + 1, + 4.178, + 1, + 4.833, + 1, + 1, + 4.933, + 1, + 5.033, + 0, + 5.133, + 0, + 1, + 5.744, + 0, + 6.356, + 0, + 6.967, + 0, + 1, + 7.011, + 0, + 7.056, + 1, + 7.1, + 1, + 1, + 7.344, + 1, + 7.589, + 1, + 7.833, + 1, + 1, + 7.889, + 1, + 7.944, + 0, + 8, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLSmile", + "Segments": [ + 0, + 0, + 1, + 2.611, + 0, + 5.222, + 0, + 7.833, + 0, + 1, + 7.889, + 0, + 7.944, + 1, + 8, + 1, + 0, + 9.233, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeLForm", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeROpen", + "Segments": [ + 0, + 1, + 1, + 0.267, + 1, + 0.533, + 1, + 0.8, + 1, + 1, + 0.844, + 1, + 0.889, + 0, + 0.933, + 0, + 1, + 1.178, + 0, + 1.422, + 0, + 1.667, + 0, + 1, + 1.711, + 0, + 1.756, + 1, + 1.8, + 1, + 1, + 2, + 1, + 2.2, + 1, + 2.4, + 1, + 1, + 2.433, + 1, + 2.467, + 0, + 2.5, + 0, + 1, + 2.589, + 0, + 2.678, + 0, + 2.767, + 0, + 1, + 2.8, + 0, + 2.833, + 1, + 2.867, + 1, + 1, + 3.522, + 1, + 4.178, + 1, + 4.833, + 1, + 1, + 4.933, + 1, + 5.033, + 0, + 5.133, + 0, + 1, + 5.744, + 0, + 6.356, + 0, + 6.967, + 0, + 1, + 7.011, + 0, + 7.056, + 1, + 7.1, + 1, + 1, + 7.344, + 1, + 7.589, + 1, + 7.833, + 1, + 1, + 7.889, + 1, + 7.944, + 0, + 8, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRSmile", + "Segments": [ + 0, + 0, + 1, + 2.611, + 0, + 5.222, + 0, + 7.833, + 0, + 1, + 7.889, + 0, + 7.944, + 1, + 8, + 1, + 0, + 9.233, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeRForm", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallX", + "Segments": [ + 0, + 0, + 1, + 0.533, + 0, + 1.067, + 0, + 1.6, + 0, + 1, + 1.622, + 0, + 1.644, + -0.96, + 1.667, + -0.96, + 1, + 1.8, + -0.96, + 1.933, + -0.96, + 2.067, + -0.96, + 1, + 2.222, + -0.96, + 2.378, + -0.2, + 2.533, + -0.2, + 1, + 2.567, + -0.2, + 2.6, + -0.2, + 2.633, + -0.2, + 1, + 2.678, + -0.2, + 2.722, + -0.047, + 2.767, + 0, + 1, + 3.044, + 0.294, + 3.322, + 0.4, + 3.6, + 0.4, + 1, + 3.778, + 0.4, + 3.956, + -0.4, + 4.133, + -0.4, + 1, + 4.3, + -0.4, + 4.467, + 0.5, + 4.633, + 0.5, + 1, + 4.778, + 0.5, + 4.922, + -0.5, + 5.067, + -0.5, + 1, + 5.211, + -0.5, + 5.356, + 0, + 5.5, + 0, + 1, + 6.178, + 0, + 6.856, + 0, + 7.533, + 0, + 1, + 7.644, + 0, + 7.756, + -0.796, + 7.867, + -0.796, + 0, + 9.233, + -0.796 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallY", + "Segments": [ + 0, + 0, + 1, + 0.533, + 0, + 1.067, + 0, + 1.6, + 0, + 1, + 1.622, + 0, + 1.644, + 0.898, + 1.667, + 0.898, + 1, + 1.8, + 0.898, + 1.933, + 0.898, + 2.067, + 0.898, + 1, + 2.222, + 0.898, + 2.378, + 0.2, + 2.533, + 0.2, + 1, + 2.567, + 0.2, + 2.6, + 0.2, + 2.633, + 0.2, + 1, + 2.678, + 0.2, + 2.722, + 0, + 2.767, + 0, + 1, + 2.8, + 0, + 2.833, + 0.5, + 2.867, + 0.5, + 1, + 3.111, + 0.5, + 3.356, + -0.1, + 3.6, + -0.1, + 1, + 3.778, + -0.1, + 3.956, + -0.1, + 4.133, + -0.1, + 1, + 4.3, + -0.1, + 4.467, + -0.8, + 4.633, + -0.8, + 1, + 4.778, + -0.8, + 4.922, + -0.8, + 5.067, + -0.8, + 1, + 5.211, + -0.8, + 5.356, + 0.538, + 5.5, + 0.538, + 1, + 5.911, + 0.538, + 6.322, + 0.5, + 6.733, + 0.5, + 1, + 6.856, + 0.5, + 6.978, + 0.7, + 7.1, + 0.7, + 0, + 9.233, + 0.7 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeBallForm", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamEyeEffect", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLY", + "Segments": [ + 0, + 0, + 1, + 0.911, + 0, + 1.822, + 0, + 2.733, + 0, + 1, + 2.811, + 0, + 2.889, + 0.6, + 2.967, + 0.6, + 1, + 3.589, + 0.6, + 4.211, + 0.6, + 4.833, + 0.6, + 1, + 4.922, + 0.6, + 5.011, + 0, + 5.1, + 0, + 1, + 5.656, + 0, + 6.211, + 0, + 6.767, + 0, + 1, + 6.867, + 0, + 6.967, + -0.3, + 7.067, + -0.3, + 0, + 9.233, + -0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRY", + "Segments": [ + 0, + 0, + 1, + 0.911, + 0, + 1.822, + 0, + 2.733, + 0, + 1, + 2.811, + 0, + 2.889, + 0.6, + 2.967, + 0.6, + 1, + 3.589, + 0.6, + 4.211, + 0.6, + 4.833, + 0.6, + 1, + 4.922, + 0.6, + 5.011, + 0, + 5.1, + 0, + 1, + 5.656, + 0, + 6.211, + 0, + 6.767, + 0, + 1, + 6.867, + 0, + 6.967, + -0.3, + 7.067, + -0.3, + 0, + 9.233, + -0.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLX", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRX", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLAngle", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRAngle", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowLForm", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBrowRForm", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamA", + "Segments": [ + 0, + 0, + 1, + 1.222, + 0, + 2.444, + 0, + 3.667, + 0, + 1, + 3.678, + 0, + 3.689, + 1, + 3.7, + 1, + 1, + 4.778, + 1, + 5.856, + 1, + 6.933, + 1, + 1, + 6.989, + 1, + 7.044, + 0, + 7.1, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamI", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamU", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamE", + "Segments": [ + 0, + 0, + 1, + 1.056, + 0, + 2.111, + 0, + 3.167, + 0, + 1, + 3.267, + 0, + 3.367, + 1, + 3.467, + 1, + 1, + 4.011, + 1, + 4.556, + 1, + 5.1, + 1, + 1, + 5.6, + 1, + 6.1, + 0, + 6.6, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamO", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthUp", + "Segments": [ + 0, + 1, + 0, + 9.233, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthDown", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngry", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMouthAngryLine", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleX", + "Segments": [ + 0, + 0, + 1, + 0.211, + 0, + 0.422, + -3, + 0.633, + -3, + 1, + 0.889, + -3, + 1.144, + -3, + 1.4, + -3, + 1, + 1.589, + -3, + 1.778, + -4, + 1.967, + -4, + 1, + 2.311, + -4, + 2.656, + 1, + 3, + 1, + 1, + 3.122, + 1, + 3.244, + 0, + 3.367, + 0, + 1, + 3.489, + 0, + 3.611, + 0, + 3.733, + 0, + 1, + 3.889, + 0, + 4.044, + -1.992, + 4.2, + -1.992, + 1, + 4.333, + -1.992, + 4.467, + 1, + 4.6, + 1, + 1, + 4.778, + 1, + 4.956, + 0, + 5.133, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleY", + "Segments": [ + 0, + 0, + 1, + 0.1, + 0, + 0.2, + -1, + 0.3, + -1, + 1, + 0.389, + -1, + 0.478, + 0, + 0.567, + 0, + 1, + 0.611, + 0, + 0.656, + -1, + 0.7, + -1, + 1, + 0.778, + -1, + 0.856, + 8.17, + 0.933, + 9, + 1, + 1.033, + 10, + 1.133, + 10, + 1.233, + 10, + 1, + 1.456, + 10, + 1.678, + 5, + 1.9, + 5, + 1, + 2.1, + 5, + 2.3, + 9, + 2.5, + 9, + 1, + 2.667, + 9, + 2.833, + -4, + 3, + -4, + 1, + 3.144, + -4, + 3.289, + 1.691, + 3.433, + 4, + 1, + 3.611, + 6.842, + 3.789, + 7, + 3.967, + 7, + 1, + 4.289, + 7, + 4.611, + 6.848, + 4.933, + 5, + 1, + 5.122, + 3.917, + 5.311, + 0, + 5.5, + 0, + 1, + 5.756, + 0, + 6.011, + 10, + 6.267, + 10, + 1, + 6.422, + 10, + 6.578, + 10, + 6.733, + 9.22, + 1, + 6.833, + 8.7, + 6.933, + -1, + 7.033, + -1, + 1, + 7.167, + -1, + 7.3, + 2, + 7.433, + 2, + 1, + 7.6, + 2, + 7.767, + -1, + 7.933, + -1, + 1, + 8.089, + -1, + 8.244, + 0.56, + 8.4, + 0.56, + 1, + 8.644, + 0.56, + 8.889, + -0.32, + 9.133, + -0.32, + 0, + 9.233, + -0.32 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBodyAngleZ", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + -1, + 0.567, + -1, + 1, + 0.689, + -1, + 0.811, + 4.087, + 0.933, + 4.999, + 1, + 1.078, + 6.077, + 1.222, + 5.999, + 1.367, + 5.999, + 1, + 1.533, + 5.999, + 1.7, + 0, + 1.867, + 0, + 1, + 2.067, + 0, + 2.267, + 0.102, + 2.467, + 1, + 1, + 2.556, + 1.399, + 2.644, + 4, + 2.733, + 4, + 1, + 3.022, + 4, + 3.311, + 0, + 3.6, + 0, + 1, + 4.889, + 0, + 6.178, + 0, + 7.467, + 0, + 1, + 7.667, + 0, + 7.867, + -1.46, + 8.067, + -1.46, + 0, + 9.233, + -1.46 + ] + }, + { + "Target": "Parameter", + "Id": "ParamBreath", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamLeftShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + 0, + 0.433, + 0, + 1, + 0.578, + 0, + 0.722, + -3, + 0.867, + -3, + 1, + 1, + -3, + 1.133, + 0, + 1.267, + 0, + 1, + 1.656, + 0, + 2.044, + -0.146, + 2.433, + -1.626, + 1, + 2.678, + -2.556, + 2.922, + -5, + 3.167, + -5, + 1, + 3.422, + -5, + 3.678, + -0.55, + 3.933, + 0.391, + 1, + 4.211, + 1.414, + 4.489, + 1.31, + 4.767, + 1.31, + 1, + 5.033, + 1.31, + 5.3, + -2.11, + 5.567, + -2.11, + 1, + 5.844, + -2.11, + 6.122, + 4, + 6.4, + 4, + 1, + 6.567, + 4, + 6.733, + 3.965, + 6.9, + 3.44, + 1, + 6.978, + 3.195, + 7.056, + 0, + 7.133, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRightShoulderUp", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + -10, + 0.467, + -10, + 1, + 0.678, + -10, + 0.889, + -4.095, + 1.1, + 0.113, + 1, + 1.222, + 2.549, + 1.344, + 2.402, + 1.467, + 2.402, + 1, + 1.644, + 2.402, + 1.822, + 0, + 2, + 0, + 1, + 2.189, + 0, + 2.378, + 0, + 2.567, + 0, + 1, + 2.778, + 0, + 2.989, + -5.667, + 3.2, + -5.667, + 1, + 3.444, + -5.667, + 3.689, + -0.723, + 3.933, + 0.177, + 1, + 4.211, + 1.199, + 4.489, + 1.098, + 4.767, + 1.098, + 1, + 5.033, + 1.098, + 5.3, + -2.32, + 5.567, + -2.32, + 1, + 5.844, + -2.32, + 6.122, + 4, + 6.4, + 4, + 1, + 6.567, + 4, + 6.733, + 3.959, + 6.9, + 3.38, + 1, + 6.978, + 3.11, + 7.056, + 0, + 7.133, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA01", + "Segments": [ + 0, + 0, + 1, + 0.2, + 0, + 0.4, + -3, + 0.6, + -3, + 1, + 0.844, + -3, + 1.089, + 8, + 1.333, + 8, + 1, + 1.556, + 8, + 1.778, + -4, + 2, + -4, + 1, + 2.2, + -4, + 2.4, + 0, + 2.6, + 0, + 1, + 2.711, + 0, + 2.822, + -5.91, + 2.933, + -5.91, + 1, + 3.078, + -5.91, + 3.222, + -1.199, + 3.367, + 1, + 1, + 3.5, + 3.03, + 3.633, + 3, + 3.767, + 3, + 1, + 4.022, + 3, + 4.278, + 0.803, + 4.533, + 0.803, + 1, + 4.744, + 0.803, + 4.956, + 0.759, + 5.167, + 1.28, + 1, + 5.433, + 1.938, + 5.7, + 3.28, + 5.967, + 3.28, + 1, + 6.222, + 3.28, + 6.478, + 3.247, + 6.733, + 2.8, + 1, + 6.844, + 2.606, + 6.956, + -1, + 7.067, + -1, + 1, + 7.211, + -1, + 7.356, + -0.4, + 7.5, + -0.4, + 1, + 7.678, + -0.4, + 7.856, + -2, + 8.033, + -2, + 1, + 8.233, + -2, + 8.433, + -1, + 8.633, + -1, + 0, + 9.233, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA02", + "Segments": [ + 0, + 0, + 1, + 0.222, + 0, + 0.444, + -5, + 0.667, + -5, + 1, + 0.944, + -5, + 1.222, + -2, + 1.5, + -2, + 1, + 1.722, + -2, + 1.944, + -3, + 2.167, + -3, + 1, + 2.344, + -3, + 2.522, + -2, + 2.7, + -2, + 1, + 2.811, + -2, + 2.922, + -3, + 3.033, + -3, + 1, + 3.3, + -3, + 3.567, + 2, + 3.833, + 2, + 1, + 4.111, + 2, + 4.389, + -0.5, + 4.667, + -0.5, + 1, + 4.856, + -0.5, + 5.044, + -0.337, + 5.233, + 0, + 1, + 5.5, + 0.476, + 5.767, + 0.72, + 6.033, + 0.72, + 1, + 6.278, + 0.72, + 6.522, + 0.654, + 6.767, + 0.18, + 1, + 6.878, + -0.036, + 6.989, + -0.9, + 7.1, + -0.9, + 1, + 7.244, + -0.9, + 7.389, + -0.75, + 7.533, + -0.75, + 1, + 7.711, + -0.75, + 7.889, + -1.62, + 8.067, + -1.62, + 1, + 8.267, + -1.62, + 8.467, + -0.9, + 8.667, + -0.9, + 0, + 9.233, + -0.9 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLA03", + "Segments": [ + 0, + 0, + 1, + 0.233, + 0, + 0.467, + -3, + 0.7, + -3, + 1, + 1.022, + -3, + 1.344, + 5.5, + 1.667, + 5.5, + 1, + 1.833, + 5.5, + 2, + 2.007, + 2.167, + 0.96, + 1, + 2.333, + -0.087, + 2.5, + 0, + 2.667, + 0, + 1, + 2.922, + 0, + 3.178, + 7, + 3.433, + 7, + 1, + 3.678, + 7, + 3.922, + 5.5, + 4.167, + 5.5, + 1, + 4.544, + 5.5, + 4.922, + 5.533, + 5.3, + 6, + 1, + 5.567, + 6.329, + 5.833, + 7.14, + 6.1, + 7.14, + 1, + 6.333, + 7.14, + 6.567, + 7.14, + 6.8, + 7.14, + 1, + 6.911, + 7.14, + 7.022, + 0.96, + 7.133, + 0.96, + 1, + 7.278, + 0.96, + 7.422, + 3.78, + 7.567, + 3.78, + 0, + 9.233, + 3.78 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLA", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA01", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA02", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRA03", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandRotate", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRA", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDrop", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropRotate", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamInkDropOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB01", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB02", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmLB03", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandLB", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatForm", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB01", + "Segments": [ + 0, + 0, + 1, + 0.189, + 0, + 0.378, + -20, + 0.567, + -20, + 1, + 0.711, + -20, + 0.856, + -6.905, + 1, + 0, + 1, + 1.2, + 9.56, + 1.4, + 11, + 1.6, + 11, + 1, + 1.689, + 11, + 1.778, + -12, + 1.867, + -12, + 1, + 1.922, + -12, + 1.978, + -10, + 2.033, + -10, + 1, + 2.244, + -10, + 2.456, + -10, + 2.667, + -10, + 1, + 2.789, + -10, + 2.911, + -16, + 3.033, + -16, + 1, + 3.278, + -16, + 3.522, + -10, + 3.767, + -10, + 1, + 4.233, + -10, + 4.7, + -10, + 5.167, + -10, + 1, + 5.433, + -10, + 5.7, + -6.1, + 5.967, + -6.1, + 1, + 6.222, + -6.1, + 6.478, + -6.228, + 6.733, + -7.48, + 1, + 6.844, + -8.024, + 6.956, + -13.66, + 7.067, + -13.66, + 1, + 7.211, + -13.66, + 7.356, + -12.76, + 7.5, + -12.76, + 1, + 7.678, + -12.76, + 7.856, + -14.44, + 8.033, + -14.44, + 1, + 8.233, + -14.44, + 8.433, + -13.48, + 8.633, + -13.48, + 0, + 9.233, + -13.48 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02", + "Segments": [ + 0, + 0, + 1, + 0.067, + 0, + 0.133, + -0.261, + 0.2, + 1.053, + 1, + 0.289, + 2.805, + 0.378, + 13.846, + 0.467, + 13.846, + 1, + 0.656, + 13.846, + 0.844, + -18.096, + 1.033, + -20, + 1, + 1.256, + -22.24, + 1.478, + -22, + 1.7, + -22, + 1, + 1.767, + -22, + 1.833, + -2, + 1.9, + -2, + 1, + 2.122, + -2, + 2.344, + -6, + 2.567, + -6, + 1, + 2.7, + -6, + 2.833, + -6, + 2.967, + -6, + 1, + 3.256, + -6, + 3.544, + -2, + 3.833, + -2, + 1, + 4.3, + -2, + 4.767, + -2, + 5.233, + -2, + 1, + 5.5, + -2, + 5.767, + -6.74, + 6.033, + -6.74, + 1, + 6.278, + -6.74, + 6.522, + -6.674, + 6.767, + -5.9, + 1, + 6.878, + -5.548, + 6.989, + -2.24, + 7.1, + -2.24, + 1, + 7.244, + -2.24, + 7.389, + -2.96, + 7.533, + -2.96, + 1, + 7.711, + -2.96, + 7.889, + -1.52, + 8.067, + -1.52, + 1, + 8.267, + -1.52, + 8.467, + -2.3, + 8.667, + -2.3, + 0, + 9.233, + -2.3 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB02Y", + "Segments": [ + 0, + 0, + 1, + 0.122, + 0, + 0.244, + 23, + 0.367, + 23, + 1, + 0.644, + 23, + 0.922, + 0, + 1.2, + 0, + 1, + 1.322, + 0, + 1.444, + 0, + 1.567, + 0, + 1, + 1.678, + 0, + 1.789, + 14.656, + 1.9, + 14.656, + 1, + 2, + 14.656, + 2.1, + 4.615, + 2.2, + 4.615, + 1, + 2.444, + 4.615, + 2.689, + 10.202, + 2.933, + 10.202, + 1, + 3.167, + 10.202, + 3.4, + 0, + 3.633, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamArmRB03", + "Segments": [ + 0, + 0, + 1, + 0.144, + 0, + 0.289, + -19.973, + 0.433, + -19.973, + 1, + 0.633, + -19.973, + 0.833, + -3, + 1.033, + -3, + 1, + 1.233, + -3, + 1.433, + -3, + 1.633, + -3, + 1, + 1.722, + -3, + 1.811, + 11, + 1.9, + 11, + 1, + 2.222, + 11, + 2.544, + 11, + 2.867, + 11, + 1, + 3.211, + 11, + 3.556, + 20, + 3.9, + 20, + 1, + 4.367, + 20, + 4.833, + 19.495, + 5.3, + 17.63, + 1, + 5.567, + 16.564, + 5.833, + 14.233, + 6.1, + 12.95, + 1, + 6.333, + 11.828, + 6.567, + 11.55, + 6.8, + 11.55, + 1, + 6.911, + 11.55, + 7.022, + 16.03, + 7.133, + 16.03, + 1, + 7.278, + 16.03, + 7.422, + 8, + 7.567, + 8, + 0, + 9.233, + 8 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHandRB", + "Segments": [ + 0, + 0, + 1, + 0.156, + 0, + 0.311, + -10, + 0.467, + -10, + 1, + 0.667, + -10, + 0.867, + -10, + 1.067, + -10, + 1, + 1.256, + -10, + 1.444, + 10, + 1.633, + 10, + 1, + 1.733, + 10, + 1.833, + -10, + 1.933, + -10, + 1, + 2.222, + -10, + 2.511, + -10, + 2.8, + -10, + 1, + 3.267, + -10, + 3.733, + 0, + 4.2, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllX", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllY", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllRotate", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFront", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideL", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideR", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBack", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackR", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackL", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamoHairMesh", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairFrontFuwa", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairSideFuwa", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHairBackFuwa", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWing", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRibbon", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatBrim", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHatTop", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory1", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAccessory2", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamString", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeL", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeR", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRobeFuwa", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartMissOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackMissOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorRainbow", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartHealOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartBackHealOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorHeal", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartDrow", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartSize", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartColorLight", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorRainbow", + "Segments": [ + 0, + 0, + 1, + 0.544, + 0, + 1.089, + 0, + 1.633, + 0, + 1, + 1.7, + 0, + 1.767, + 9.93, + 1.833, + 9.93, + 1, + 3.622, + 9.93, + 5.411, + 9.93, + 7.2, + 9.93, + 1, + 7.311, + 9.93, + 7.422, + 0, + 7.533, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInkColorHeal", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamWandInk", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmokeOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamSmoke", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionChargeOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionLightCharge", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosionOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamExplosion", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitX", + "Segments": [ + 0, + 0, + 1, + 0.244, + 0, + 0.489, + 0, + 0.733, + 0, + 1, + 1.078, + 0, + 1.422, + 0.179, + 1.767, + 0.179, + 1, + 1.811, + 0.179, + 1.856, + 0.072, + 1.9, + 0.035, + 1, + 1.933, + 0.007, + 1.967, + 0.012, + 2, + 0.012, + 1, + 2.078, + 0.012, + 2.156, + 0.022, + 2.233, + 0.035, + 1, + 2.322, + 0.049, + 2.411, + 0.054, + 2.5, + 0.054, + 1, + 2.578, + 0.054, + 2.656, + 0.053, + 2.733, + 0.046, + 1, + 2.789, + 0.04, + 2.844, + 0.022, + 2.9, + 0.012, + 1, + 2.956, + 0.003, + 3.011, + 0, + 3.067, + 0, + 1, + 3.156, + 0, + 3.244, + 0, + 3.333, + 0.55, + 1, + 3.411, + 1, + 3.489, + 1, + 3.567, + 1, + 1, + 3.656, + 1, + 3.744, + 0.896, + 3.833, + 0.55, + 1, + 3.911, + 0.247, + 3.989, + 0, + 4.067, + 0, + 1, + 4.156, + 0, + 4.244, + 0, + 4.333, + 0.55, + 1, + 4.411, + 1, + 4.489, + 1, + 4.567, + 1, + 1, + 4.656, + 1, + 4.744, + 0.896, + 4.833, + 0.55, + 1, + 4.911, + 0.247, + 4.989, + 0, + 5.067, + 0, + 1, + 5.156, + 0, + 5.244, + 0, + 5.333, + 0.55, + 1, + 5.411, + 1, + 5.489, + 1, + 5.567, + 1, + 1, + 5.656, + 1, + 5.744, + 0.896, + 5.833, + 0.55, + 1, + 5.911, + 0.247, + 5.989, + 0, + 6.067, + 0, + 1, + 6.156, + 0, + 6.244, + 0, + 6.333, + 0.55, + 1, + 6.411, + 1, + 6.489, + 1, + 6.567, + 1, + 1, + 6.656, + 1, + 6.744, + 0.896, + 6.833, + 0.55, + 1, + 6.911, + 0.247, + 6.989, + 0, + 7.067, + 0, + 1, + 7.133, + 0, + 7.2, + 0.013, + 7.267, + 0.032, + 1, + 7.322, + 0.048, + 7.378, + 0.053, + 7.433, + 0.053, + 1, + 7.522, + 0.053, + 7.611, + 0.028, + 7.7, + 0.014, + 1, + 7.789, + 0, + 7.878, + 0, + 7.967, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitY", + "Segments": [ + 0, + 0.94, + 1, + 0.589, + 0.94, + 1.178, + 0.94, + 1.767, + 0.94, + 1, + 1.811, + 0.94, + 1.856, + 0.908, + 1.9, + 0.908, + 1, + 1.933, + 0.908, + 1.967, + 0.914, + 2, + 0.924, + 1, + 2.056, + 0.942, + 2.111, + 0.95, + 2.167, + 0.95, + 1, + 2.3, + 0.95, + 2.433, + 0.95, + 2.567, + 0.944, + 1, + 2.733, + 0.937, + 2.9, + 0.951, + 3.067, + 0.91, + 1, + 3.644, + 0.767, + 4.222, + 0, + 4.8, + 0, + 1, + 5.389, + 0, + 5.978, + 0.94, + 6.567, + 0.94, + 1, + 6.722, + 0.94, + 6.878, + 0.94, + 7.033, + 0.94, + 1, + 7.111, + 0.94, + 7.189, + 0.929, + 7.267, + 0.929, + 1, + 7.356, + 0.929, + 7.444, + 0.943, + 7.533, + 0.943, + 1, + 7.667, + 0.943, + 7.8, + 0.934, + 7.933, + 0.934, + 0, + 9.233, + 0.934 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitRotate", + "Segments": [ + 0, + 0, + 1, + 0.278, + 0, + 0.556, + 0, + 0.833, + 0, + 1, + 1.1, + 0, + 1.367, + -0.002, + 1.633, + -0.037, + 1, + 1.789, + -0.057, + 1.944, + -0.135, + 2.1, + -0.135, + 1, + 2.2, + -0.135, + 2.3, + 0.182, + 2.4, + 0.19, + 1, + 2.589, + 0.205, + 2.778, + 0.202, + 2.967, + 0.22, + 1, + 3.133, + 0.236, + 3.3, + 0.4, + 3.467, + 0.4, + 1, + 3.633, + 0.4, + 3.8, + -0.4, + 3.967, + -0.4, + 1, + 4.133, + -0.4, + 4.3, + 0.4, + 4.467, + 0.4, + 1, + 4.633, + 0.4, + 4.8, + -0.4, + 4.967, + -0.4, + 1, + 5.133, + -0.4, + 5.3, + -0.4, + 5.467, + -0.4, + 1, + 5.633, + -0.4, + 5.8, + 0.4, + 5.967, + 0.4, + 1, + 6.133, + 0.4, + 6.3, + -0.4, + 6.467, + -0.4, + 1, + 6.633, + -0.4, + 6.8, + 0.2, + 6.967, + 0.2, + 1, + 7.067, + 0.2, + 7.167, + 0, + 7.267, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEliminationEffect", + "Segments": [ + 0, + 0, + 1, + 0.322, + 0, + 0.644, + 0, + 0.967, + 0, + 1, + 1.167, + 0, + 1.367, + 30, + 1.567, + 30, + 1, + 3.778, + 30, + 5.989, + 30, + 8.2, + 30, + 1, + 8.4, + 30, + 8.6, + 0, + 8.8, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitAppearance", + "Segments": [ + 0, + 0, + 1, + 0.589, + 0, + 1.178, + 0, + 1.767, + 0, + 1, + 1.922, + 0, + 2.078, + 28.123, + 2.233, + 28.123, + 1, + 2.278, + 28.123, + 2.322, + 27.654, + 2.367, + 27.654, + 1, + 2.411, + 27.654, + 2.456, + 28.949, + 2.5, + 29.309, + 1, + 2.578, + 29.939, + 2.656, + 30, + 2.733, + 30, + 1, + 4.411, + 30, + 6.089, + 30, + 7.767, + 30, + 1, + 7.967, + 30, + 8.167, + 0, + 8.367, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitSize", + "Segments": [ + 0, + 0, + 1, + 0.644, + 0, + 1.289, + 0, + 1.933, + 0, + 1, + 1.978, + 0, + 2.022, + 0.4, + 2.067, + 0.4, + 1, + 2.111, + 0.4, + 2.156, + 0, + 2.2, + 0, + 1, + 2.489, + 0, + 2.778, + 0, + 3.067, + 0, + 1, + 3.156, + 0, + 3.244, + 0.8, + 3.333, + 0.8, + 1, + 3.411, + 0.8, + 3.489, + 0.496, + 3.567, + 0, + 1, + 3.656, + -0.566, + 3.744, + -0.8, + 3.833, + -0.8, + 1, + 3.911, + -0.8, + 3.989, + -0.496, + 4.067, + 0, + 1, + 4.156, + 0.566, + 4.244, + 0.8, + 4.333, + 0.8, + 1, + 4.411, + 0.8, + 4.489, + 0.496, + 4.567, + 0, + 1, + 4.656, + -0.566, + 4.744, + -0.8, + 4.833, + -0.8, + 1, + 4.911, + -0.8, + 4.989, + -0.529, + 5.067, + 0, + 1, + 5.156, + 0.604, + 5.244, + 0.9, + 5.333, + 0.9, + 1, + 5.411, + 0.9, + 5.489, + 0.521, + 5.567, + 0, + 1, + 5.656, + -0.595, + 5.744, + -0.8, + 5.833, + -0.8, + 1, + 5.911, + -0.8, + 5.989, + -0.496, + 6.067, + 0, + 1, + 6.156, + 0.566, + 6.244, + 0.8, + 6.333, + 0.8, + 1, + 6.411, + 0.8, + 6.489, + 0.496, + 6.567, + 0, + 1, + 6.656, + -0.566, + 6.744, + -0.8, + 6.833, + -0.8, + 1, + 6.911, + -0.8, + 6.989, + 0, + 7.067, + 0, + 1, + 7.3, + 0, + 7.533, + 0, + 7.767, + 0, + 1, + 7.811, + 0, + 7.856, + 0.4, + 7.9, + 0.4, + 1, + 7.944, + 0.4, + 7.989, + -1, + 8.033, + -1, + 0, + 9.233, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitDraworder", + "Segments": [ + 0, + 0, + 1, + 1.189, + 0, + 2.378, + 0, + 3.567, + 0, + 1, + 3.578, + 0, + 3.589, + -1, + 3.6, + -1, + 1, + 3.8, + -1, + 4, + -1, + 4.2, + -1, + 1, + 4.211, + -1, + 4.222, + 0, + 4.233, + 0, + 1, + 4.344, + 0, + 4.456, + 0, + 4.567, + 0, + 1, + 4.578, + 0, + 4.589, + -1, + 4.6, + -1, + 1, + 4.756, + -1, + 4.911, + -1, + 5.067, + -1, + 1, + 5.078, + -1, + 5.089, + 0, + 5.1, + 0, + 1, + 5.256, + 0, + 5.411, + 0, + 5.567, + 0, + 1, + 5.578, + 0, + 5.589, + -1, + 5.6, + -1, + 1, + 5.756, + -1, + 5.911, + -1, + 6.067, + -1, + 1, + 6.078, + -1, + 6.089, + 0, + 6.1, + 0, + 1, + 6.256, + 0, + 6.411, + 0, + 6.567, + 0, + 1, + 6.578, + 0, + 6.589, + -1, + 6.6, + -1, + 0, + 9.233, + -1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitEar", + "Segments": [ + 0, + 0, + 1, + 0.322, + 0, + 0.644, + 0, + 0.967, + 0, + 1, + 1.267, + 0, + 1.567, + 0.559, + 1.867, + 0.559, + 1, + 1.978, + 0.559, + 2.089, + -0.597, + 2.2, + -0.597, + 1, + 2.333, + -0.597, + 2.467, + -0.317, + 2.6, + -0.134, + 1, + 2.7, + 0.004, + 2.8, + 0, + 2.9, + 0, + 1, + 3.067, + 0, + 3.233, + -1, + 3.4, + -1, + 1, + 3.567, + -1, + 3.733, + 1, + 3.9, + 1, + 1, + 4.067, + 1, + 4.233, + -1, + 4.4, + -1, + 1, + 4.567, + -1, + 4.733, + 1, + 4.9, + 1, + 1, + 5.067, + 1, + 5.233, + -1, + 5.4, + -1, + 1, + 5.567, + -1, + 5.733, + 1, + 5.9, + 1, + 1, + 6.067, + 1, + 6.233, + -1, + 6.4, + -1, + 1, + 6.567, + -1, + 6.733, + 1, + 6.9, + 1, + 1, + 7.022, + 1, + 7.144, + -0.5, + 7.267, + -0.5, + 1, + 7.344, + -0.5, + 7.422, + 0.559, + 7.5, + 0.559, + 1, + 7.544, + 0.559, + 7.589, + 0.186, + 7.633, + 0.024, + 1, + 7.678, + -0.138, + 7.722, + -0.134, + 7.767, + -0.134, + 1, + 7.822, + -0.134, + 7.878, + 0, + 7.933, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "Param5", + "Segments": [ + 0, + 0, + 1, + 0.589, + 0, + 1.178, + 0, + 1.767, + 0, + 1, + 1.9, + 0, + 2.033, + 0.5, + 2.167, + 0.5, + 1, + 2.344, + 0.5, + 2.522, + 0.5, + 2.7, + 0.5, + 1, + 2.822, + 0.5, + 2.944, + 1, + 3.067, + 1, + 1, + 3.211, + 1, + 3.356, + 1, + 3.5, + 1, + 1, + 3.544, + 1, + 3.589, + 0, + 3.633, + 0, + 1, + 3.756, + 0, + 3.878, + 0, + 4, + 0, + 1, + 4.044, + 0, + 4.089, + 1, + 4.133, + 1, + 1, + 4.256, + 1, + 4.378, + 1, + 4.5, + 1, + 1, + 4.544, + 1, + 4.589, + 0, + 4.633, + 0, + 1, + 4.756, + 0, + 4.878, + 0, + 5, + 0, + 1, + 5.044, + 0, + 5.089, + 1, + 5.133, + 1, + 1, + 5.256, + 1, + 5.378, + 1, + 5.5, + 1, + 1, + 5.544, + 1, + 5.589, + 0, + 5.633, + 0, + 1, + 5.756, + 0, + 5.878, + 0, + 6, + 0, + 1, + 6.044, + 0, + 6.089, + 1, + 6.133, + 1, + 1, + 6.256, + 1, + 6.378, + 1, + 6.5, + 1, + 1, + 6.544, + 1, + 6.589, + 0, + 6.633, + 0, + 1, + 6.756, + 0, + 6.878, + 0, + 7, + 0, + 1, + 7.1, + 0, + 7.2, + 1, + 7.3, + 1, + 0, + 9.233, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLight", + "Segments": [ + 0, + 0, + 1, + 1.022, + 0, + 2.044, + 0, + 3.067, + 0, + 1, + 3.144, + 0, + 3.222, + 1, + 3.3, + 1, + 1, + 4.533, + 1, + 5.767, + 1, + 7, + 1, + 1, + 7.089, + 1, + 7.178, + 0, + 7.267, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamRabbitLightSize", + "Segments": [ + 0, + 0, + 1, + 1.022, + 0, + 2.044, + 0, + 3.067, + 0, + 1, + 3.233, + 0, + 3.4, + 1, + 3.567, + 1, + 1, + 3.733, + 1, + 3.9, + -1, + 4.067, + -1, + 1, + 4.233, + -1, + 4.4, + 1, + 4.567, + 1, + 1, + 4.733, + 1, + 4.9, + -1, + 5.067, + -1, + 1, + 5.233, + -1, + 5.4, + 1, + 5.567, + 1, + 1, + 5.733, + 1, + 5.9, + -1, + 6.067, + -1, + 1, + 6.233, + -1, + 6.4, + 1, + 6.567, + 1, + 1, + 6.733, + 1, + 6.9, + 0, + 7.067, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraOn", + "Segments": [ + 0, + 0, + 1, + 1.233, + 0, + 2.467, + 0, + 3.7, + 0, + 1, + 3.867, + 0.957, + 4.033, + 1, + 4.2, + 1, + 1, + 5, + 1, + 5.8, + 1, + 6.6, + 1, + 1, + 6.956, + 0.996, + 7.311, + 0.638, + 7.667, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAura", + "Segments": [ + 0, + 0, + 1, + 1.167, + 0, + 2.333, + 0, + 3.5, + 0, + 0, + 4.833, + 29.268, + 2, + 4.867, + 0, + 0, + 6.233, + 29.268, + 2, + 6.267, + 0, + 0, + 7.633, + 29.268, + 2, + 7.667, + 0, + 0, + 9.033, + 29.268, + 0, + 9.233, + 29.268 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor1", + "Segments": [ + 0, + 0.5, + 0, + 9.233, + 0.5 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAuraColor2", + "Segments": [ + 0, + 0, + 1, + 0.9, + 0, + 1.8, + 0, + 2.7, + 0, + 1, + 3.6, + 0, + 4.5, + 1, + 5.4, + 1, + 0, + 9.233, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLight", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHeartLightColor", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLightOn", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamHealLight", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightOn", + "Segments": [ + 0, + 0, + 1, + 1.033, + 0, + 2.067, + 0, + 3.1, + 0, + 1, + 3.456, + 0, + 3.811, + 1, + 4.167, + 1, + 1, + 4.778, + 1, + 5.389, + 1, + 6, + 1, + 1, + 6.356, + 1, + 6.711, + 0, + 7.067, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLight", + "Segments": [ + 0, + 0, + 1, + 0.956, + 0, + 1.911, + 0, + 2.867, + 0, + 1, + 2.911, + 0, + 2.956, + 0.8, + 3, + 0.8, + 1, + 3.044, + 0.8, + 3.089, + 0, + 3.133, + 0, + 1, + 3.178, + 0, + 3.222, + 0.8, + 3.267, + 0.8, + 1, + 3.311, + 0.8, + 3.356, + 0, + 3.4, + 0, + 1, + 3.444, + 0, + 3.489, + 0.8, + 3.533, + 0.8, + 1, + 3.578, + 0.8, + 3.622, + 0, + 3.667, + 0, + 1, + 3.711, + 0, + 3.756, + 0.8, + 3.8, + 0.8, + 1, + 3.844, + 0.8, + 3.889, + 0, + 3.933, + 0, + 1, + 3.978, + 0, + 4.022, + 0.8, + 4.067, + 0.8, + 1, + 4.111, + 0.8, + 4.156, + 0, + 4.2, + 0, + 1, + 4.244, + 0, + 4.289, + 0.8, + 4.333, + 0.8, + 1, + 4.378, + 0.8, + 4.422, + 0, + 4.467, + 0, + 1, + 4.511, + 0, + 4.556, + 0.8, + 4.6, + 0.8, + 1, + 4.644, + 0.8, + 4.689, + 0, + 4.733, + 0, + 1, + 4.778, + 0, + 4.822, + 0.8, + 4.867, + 0.8, + 1, + 4.911, + 0.8, + 4.956, + 0, + 5, + 0, + 1, + 5.044, + 0, + 5.089, + 0.8, + 5.133, + 0.8, + 1, + 5.178, + 0.8, + 5.222, + 0, + 5.267, + 0, + 1, + 5.311, + 0, + 5.356, + 0.8, + 5.4, + 0.8, + 1, + 5.444, + 0.8, + 5.489, + 0, + 5.533, + 0, + 1, + 5.578, + 0, + 5.622, + 0.8, + 5.667, + 0.8, + 1, + 5.711, + 0.8, + 5.756, + 0, + 5.8, + 0, + 1, + 5.844, + 0, + 5.889, + 0.8, + 5.933, + 0.8, + 1, + 5.978, + 0.8, + 6.022, + 0, + 6.067, + 0, + 1, + 6.111, + 0, + 6.156, + 0.8, + 6.2, + 0.8, + 1, + 6.244, + 0.8, + 6.289, + 0, + 6.333, + 0, + 1, + 6.378, + 0, + 6.422, + 0.8, + 6.467, + 0.8, + 1, + 6.511, + 0.8, + 6.556, + 0, + 6.6, + 0, + 1, + 6.644, + 0, + 6.689, + 0.8, + 6.733, + 0.8, + 1, + 6.778, + 0.8, + 6.822, + 0, + 6.867, + 0, + 1, + 6.911, + 0, + 6.956, + 0.8, + 7, + 0.8, + 1, + 7.044, + 0.8, + 7.089, + 0, + 7.133, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamStrengthenLightMove", + "Segments": [ + 0, + 0, + 1, + 1.033, + 0, + 2.067, + 0, + 3.1, + 0, + 1, + 4.422, + 0.731, + 5.744, + 1, + 7.067, + 1, + 0, + 9.233, + 1 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionX", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamMagicPositionY", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor1", + "Segments": [ + 0, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "Parameter", + "Id": "ParamAllColor2", + "Segments": [ + 0, + 0, + 1, + 1.022, + 0, + 2.044, + 0, + 3.067, + 0, + 1, + 3.233, + 0, + 3.4, + 0.85, + 3.567, + 0.85, + 1, + 3.733, + 0.85, + 3.9, + 0.7, + 4.067, + 0.7, + 1, + 4.233, + 0.7, + 4.4, + 0.85, + 4.567, + 0.85, + 1, + 4.733, + 0.85, + 4.9, + 0.7, + 5.067, + 0.7, + 1, + 5.233, + 0.7, + 5.4, + 0.85, + 5.567, + 0.85, + 1, + 5.733, + 0.85, + 5.9, + 0.7, + 6.067, + 0.7, + 1, + 6.233, + 0.7, + 6.4, + 0.85, + 6.567, + 0.85, + 1, + 6.733, + 0.85, + 6.9, + 0, + 7.067, + 0, + 0, + 9.233, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRA", + "Segments": [ + 0, + 0, + 0, + 9.23, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmLB", + "Segments": [ + 0, + 0, + 0, + 9.23, + 0 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartArmRB", + "Segments": [ + 0, + 1, + 0, + 9.23, + 1 + ] + }, + { + "Target": "PartOpacity", + "Id": "PartSketch", + "Segments": [ + 0, + 0, + 0, + 9.23, + 0 + ] + } + ] +} \ No newline at end of file diff --git a/app/src/main/java/com/digital_person/MainActivity.kt.bak b/app/src/main/java/com/digital_person/MainActivity.kt.bak deleted file mode 100644 index 0ea208d..0000000 --- a/app/src/main/java/com/digital_person/MainActivity.kt.bak +++ /dev/null @@ -1,957 +0,0 @@ -package com.digitalperson - -import android.Manifest -import android.content.pm.PackageManager -import android.media.AudioAttributes -import android.media.AudioFormat -import android.media.AudioManager -import android.media.AudioRecord -import android.media.AudioTrack -import android.media.MediaRecorder -import android.media.audiofx.AcousticEchoCanceler -import android.media.audiofx.NoiseSuppressor -import android.os.Bundle -import android.os.SystemClock -import android.text.method.ScrollingMovementMethod -import android.util.Log -import android.widget.Button -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.core.app.ActivityCompat -import com.digitalperson.cloud.CloudApiManager -import com.digitalperson.player.VideoPlayerManager -import com.google.android.exoplayer2.ui.PlayerView -import com.digitalperson.engine.SenseVoiceEngineRKNN -import com.digitalperson.metrics.TraceManager -import com.digitalperson.metrics.TraceSession -import com.k2fsa.sherpa.onnx.OfflineTts -import com.k2fsa.sherpa.onnx.SileroVadModelConfig -import com.k2fsa.sherpa.onnx.Vad -import com.k2fsa.sherpa.onnx.VadModelConfig -import com.k2fsa.sherpa.onnx.getOfflineTtsConfig -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.io.File -import java.io.FileOutputStream -import java.util.concurrent.LinkedBlockingQueue -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.math.max - -private const val TAG = "DigitalPerson" -private const val REQUEST_RECORD_AUDIO_PERMISSION = 200 - -class MainActivity : AppCompatActivity() { - - private lateinit var startButton: Button - private lateinit var stopButton: Button - private lateinit var textView: TextView - - private lateinit var vad: Vad - private var senseVoice: SenseVoiceEngineRKNN? = null - private var tts: OfflineTts? = null - private var track: AudioTrack? = null - - private var aec: AcousticEchoCanceler? = null - private var ns: NoiseSuppressor? = null - - private var audioRecord: AudioRecord? = null - private val audioSource = MediaRecorder.AudioSource.MIC - private val sampleRateInHz = 16000 - private val channelConfig = AudioFormat.CHANNEL_IN_MONO - private val audioFormat = AudioFormat.ENCODING_PCM_16BIT - private val permissions: Array = arrayOf(Manifest.permission.RECORD_AUDIO) - - @Volatile - private var isRecording: Boolean = false - - private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) - private var recordingJob: Job? = null - private val nativeLock = Any() - - private lateinit var cloudApiManager: CloudApiManager - private var videoPlayerManager: VideoPlayerManager? = null - private val segmenter = StreamingTextSegmenter( - maxLen = 30, - maxWaitMs = 600 - ) - - private sealed class TtsQueueItem { - data class Segment(val text: String) : TtsQueueItem() - data object End : TtsQueueItem() - } - - private val ttsQueue = LinkedBlockingQueue() - private val ttsStopped = AtomicBoolean(false) - private val ttsWorkerRunning = AtomicBoolean(false) - private val ttsPlaying = AtomicBoolean(false) - @Volatile private var ttsTotalSamplesWritten: Long = 0 - - private var currentTrace: TraceSession? = null - - private var lastUiText: String = "" - @Volatile private var llmInFlight: Boolean = false - private var enableStreaming = true // 默认启用流式输出 - - // ASR 队列和工作器 - private val asrQueue = Channel>() - private val asrWorkerRunning = AtomicBoolean(false) - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - val ok = requestCode == REQUEST_RECORD_AUDIO_PERMISSION && - grantResults.isNotEmpty() && - grantResults[0] == PackageManager.PERMISSION_GRANTED - if (!ok) { - Log.e(TAG, "Audio record is disallowed") - finish() - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - - // 初始化双播放器管理器(silent 与 speaking 两个叠加的 PlayerView) - try { - val silentPv = findViewById(R.id.player_view_silent) - val speakingPv = findViewById(R.id.player_view_speaking) - videoPlayerManager = VideoPlayerManager(this, silentPv, speakingPv) - // 默认 AI 未说话 - videoPlayerManager?.setSpeaking(false) - } catch (e: Exception) { - Log.w(TAG, "PlayerViews not found or init failed: ${e.message}") - } - - ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION) - - startButton = findViewById(R.id.start_button) - stopButton = findViewById(R.id.stop_button) - textView = findViewById(R.id.my_text) - textView.movementMethod = ScrollingMovementMethod() - - startButton.setOnClickListener { onStartClicked() } - stopButton.setOnClickListener { onStopClicked(userInitiated = true) } - - // 初始化流式输出开关 - try { - val streamingSwitch = findViewById(R.id.streaming_switch) - streamingSwitch.isChecked = enableStreaming - streamingSwitch.setOnCheckedChangeListener { _, isChecked -> - enableStreaming = isChecked - cloudApiManager.setEnableStreaming(isChecked) - Toast.makeText(this, "流式输出已${if (isChecked) "启用" else "禁用"}", Toast.LENGTH_SHORT).show() - } - } catch (e: Exception) { - Log.w(TAG, "Streaming switch not found in layout: ${e.message}") - } - - // 避免 UI 线程重初始化导致 ANR:在后台初始化模型与 AudioTrack - startButton.isEnabled = false - stopButton.isEnabled = false - textView.text = "初始化中…" - ioScope.launch { - try { - Log.i(TAG, "Init VAD + SenseVoice(RKNN) + TTS (background)") - synchronized(nativeLock) { - initVadModel() - initSenseVoiceModel() - } - withContext(Dispatchers.Main) { - initTtsAndAudioTrack() - textView.text = getString(R.string.hint) - startButton.isEnabled = true - stopButton.isEnabled = false - } - } catch (t: Throwable) { - Log.e(TAG, "Initialization failed: ${t.message}", t) - withContext(Dispatchers.Main) { - textView.text = "初始化失败:${t.javaClass.simpleName}: ${t.message}" - Toast.makeText( - this@MainActivity, - "初始化失败(请看 Logcat): ${t.javaClass.simpleName}", - Toast.LENGTH_LONG - ).show() - startButton.isEnabled = false - stopButton.isEnabled = false - } - } - } - - cloudApiManager = CloudApiManager(object : CloudApiManager.CloudApiListener { - private var llmFirstChunkMarked = false - - override fun onLLMResponseReceived(response: String) { - currentTrace?.markLlmDone() - llmInFlight = false - - // 根据流式输出模式处理响应 - if (enableStreaming) { - // 启用流式输出时,刷新剩余缓冲区 - for (seg in segmenter.flush()) { - enqueueTtsSegment(seg) - } - // 发送队列结束信号 - ttsQueue.offer(TtsQueueItem.End) - } else { - runOnUiThread { - appendToUi("${response}\n") - } - // 禁用流式输出时,直接使用整段文本进行TTS - enqueueTtsSegment(response) - // 发送队列结束信号 - ttsQueue.offer(TtsQueueItem.End) - } - } - - override fun onLLMStreamingChunkReceived(chunk: String) { - // 启用流式输出时,处理流式chunk - if (enableStreaming) { - if (!llmFirstChunkMarked) { - llmFirstChunkMarked = true - currentTrace?.markLlmFirstChunk() - } - appendToUi(chunk) - - val segments = segmenter.processChunk(chunk) - for (seg in segments) { - enqueueTtsSegment(seg) - } - } - } - - override fun onTTSAudioReceived(audioFilePath: String) { - // unused - } - - override fun onError(errorMessage: String) { - llmInFlight = false - Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_LONG).show() - onStopClicked(userInitiated = false) - } - }, applicationContext) - - // 设置流式输出模式 - cloudApiManager.setEnableStreaming(enableStreaming) - } - - override fun onDestroy() { - super.onDestroy() - onStopClicked(userInitiated = false) - ioScope.cancel() - synchronized(nativeLock) { - try { - vad.release() - } catch (_: Throwable) { - } - try { - senseVoice?.deinitialize() - } catch (_: Throwable) { - } - } - try { - tts?.release() - } catch (_: Throwable) { - } - try { - videoPlayerManager?.release() - } catch (_: Throwable) { - } - } - - private fun onStartClicked() { - if (isRecording) return - - if (!initMicrophone()) { - Toast.makeText(this, "麦克风初始化失败/无权限", Toast.LENGTH_SHORT).show() - return - } - - // Start a new trace turn - currentTrace = TraceManager.getInstance().startNewTurn() - currentTrace?.mark("turn_start") - llmInFlight = false - - lastUiText = "" - textView.text = "" - - ttsStopped.set(false) - ttsPlaying.set(false) - ttsTotalSamplesWritten = 0 - ttsQueue.clear() - segmenter.reset() - - vad.reset() - audioRecord!!.startRecording() - isRecording = true - - startButton.isEnabled = false - stopButton.isEnabled = true - - recordingJob?.cancel() - recordingJob = ioScope.launch { - processSamplesLoop() - } - } - - private fun onStopClicked(userInitiated: Boolean) { - isRecording = false - try { - audioRecord?.stop() - } catch (_: Throwable) { - } - try { - audioRecord?.release() - } catch (_: Throwable) { - } - audioRecord = null - - recordingJob?.cancel() - recordingJob = null - - ttsStopped.set(true) - ttsPlaying.set(false) - ttsTotalSamplesWritten = 0 - ttsQueue.clear() - // wake worker if waiting - ttsQueue.offer(TtsQueueItem.End) - - try { - track?.pause() - track?.flush() - } catch (_: Throwable) { - } - try { aec?.release() } catch (_: Throwable) {} - try { ns?.release() } catch (_: Throwable) {} - aec = null - ns = null - startButton.isEnabled = true - stopButton.isEnabled = false - - if (userInitiated) { - TraceManager.getInstance().endTurn() - currentTrace = null - } - } - - private fun initVadModel() { - // 你的 VAD 模型在 assets/vad_model/ 下 - val config = VadModelConfig( - sileroVadModelConfig = SileroVadModelConfig( - model = "vad_model/silero_vad.onnx", - threshold = 0.5F, - minSilenceDuration = 0.25F, - minSpeechDuration = 0.25F, - windowSize = 512, - ), - sampleRate = sampleRateInHz, - numThreads = 1, - provider = "cpu", - ) - vad = Vad(assetManager = application.assets, config = config) - } - - private fun initSenseVoiceModel() { - Log.i(TAG, "ASR: init SenseVoice RKNN (scheme A)") - // Copy assets/sensevoice_models/* -> filesDir/sensevoice_models/* - val modelDir = copySenseVoiceAssetsToInternal() - val modelPath = File(modelDir, "sense-voice-encoder.rknn").absolutePath - val embeddingPath = File(modelDir, "embedding.npy").absolutePath - val bpePath = File(modelDir, "chn_jpn_yue_eng_ko_spectok.bpe.model").absolutePath - - // Print quick diagnostics for native libs + model files - try { - val libDir = applicationInfo.nativeLibraryDir - Log.i(TAG, "nativeLibraryDir=$libDir") - try { - val names = File(libDir).list()?.joinToString(", ") ?: "(empty)" - Log.i(TAG, "nativeLibraryDir files: $names") - } catch (t: Throwable) { - Log.w(TAG, "Failed to list nativeLibraryDir: ${t.message}") - } - } catch (_: Throwable) { - } - Log.i(TAG, "SenseVoice model paths:") - Log.i(TAG, " model=$modelPath exists=${File(modelPath).exists()} size=${File(modelPath).length()}") - Log.i(TAG, " embedding=$embeddingPath exists=${File(embeddingPath).exists()} size=${File(embeddingPath).length()}") - Log.i(TAG, " bpe=$bpePath exists=${File(bpePath).exists()} size=${File(bpePath).length()}") - - val t0 = SystemClock.elapsedRealtime() - val engine = try { - SenseVoiceEngineRKNN(this) - } catch (e: UnsatisfiedLinkError) { - // Most common: libsensevoiceEngine.so not packaged/built, or dependent libs missing - throw IllegalStateException("Load native libraries failed: ${e.message}", e) - } - - val ok = try { - engine.loadModelDirectly(modelPath, embeddingPath, bpePath) - } catch (t: Throwable) { - throw IllegalStateException("SenseVoice loadModelDirectly crashed: ${t.message}", t) - } - - val dt = SystemClock.elapsedRealtime() - t0 - Log.i(TAG, "SenseVoice loadModelDirectly ok=$ok costMs=$dt") - if (!ok) throw IllegalStateException("SenseVoiceEngineRKNN loadModelDirectly returned false") - - senseVoice = engine - } - - private fun initTtsAndAudioTrack() { - try { - // 你放入的 sherpa-onnx VITS 中文模型目录: - // assets/tts_model/sherpa-onnx-vits-zh-ll/{model.onnx,tokens.txt,lexicon.txt,...} - val modelDir = "tts_model/sherpa-onnx-vits-zh-ll" - val modelName = "model.onnx" - val lexicon = "lexicon.txt" - val dataDir = "" - - val ttsConfig = getOfflineTtsConfig( - modelDir = modelDir, - modelName = modelName, - acousticModelName = "", - vocoder = "", - voices = "", - lexicon = lexicon, - dataDir = dataDir, - dictDir = "", - // 中文规范化规则(目录里已有这些 fst) - ruleFsts = "$modelDir/phone.fst,$modelDir/date.fst,$modelDir/number.fst,$modelDir/new_heteronym.fst", - ruleFars = "", - numThreads = null, - isKitten = false - ) - tts = OfflineTts(assetManager = application.assets, config = ttsConfig) - } catch (t: Throwable) { - Log.e(TAG, "Init TTS failed: ${t.message}", t) - tts = null - runOnUiThread { - Toast.makeText( - this, - "TTS 初始化失败:请确认 assets/tts_model/sherpa-onnx-vits-zh-ll/ 下有 model.onnx、tokens.txt、lexicon.txt 以及 phone/date/number/new_heteronym.fst", - Toast.LENGTH_LONG - ).show() - } - } - - val t = tts ?: return - val sr = t.sampleRate() - val bufLength = AudioTrack.getMinBufferSize( - sr, - AudioFormat.CHANNEL_OUT_MONO, - AudioFormat.ENCODING_PCM_FLOAT - ) - val attr = AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) - .setUsage(AudioAttributes.USAGE_MEDIA) - .build() - val format = AudioFormat.Builder() - .setEncoding(AudioFormat.ENCODING_PCM_FLOAT) - .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) - .setSampleRate(sr) - .build() - track = AudioTrack( - attr, - format, - bufLength, - AudioTrack.MODE_STREAM, - AudioManager.AUDIO_SESSION_ID_GENERATE - ) - track?.play() - } - - private fun assetExists(path: String): Boolean { - return try { - application.assets.open(path).close() - true - } catch (_: Throwable) { - false - } - } - - private fun copySenseVoiceAssetsToInternal(): File { - val outDir = File(filesDir, "sensevoice_models") - if (!outDir.exists()) outDir.mkdirs() - - val files = arrayOf( - "am.mvn", - "chn_jpn_yue_eng_ko_spectok.bpe.model", - "embedding.npy", - "sense-voice-encoder.rknn" - ) - - for (name in files) { - val assetPath = "sensevoice_models/$name" - val outFile = File(outDir, name) - if (outFile.exists() && outFile.length() > 0) continue - application.assets.open(assetPath).use { input -> - FileOutputStream(outFile).use { output -> - input.copyTo(output) - } - } - } - return outDir - } - - private fun initMicrophone(): Boolean { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) - != PackageManager.PERMISSION_GRANTED - ) { - ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION) - return false - } - - val numBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) - audioRecord = AudioRecord( - audioSource, - sampleRateInHz, - channelConfig, - audioFormat, - numBytes * 2 - ) - val sessionId = audioRecord?.audioSessionId ?: 0 - if (sessionId != 0) { - if (android.media.audiofx.AcousticEchoCanceler.isAvailable()) { - aec = android.media.audiofx.AcousticEchoCanceler.create(sessionId)?.apply { - enabled = true - } - Log.i(TAG, "AEC enabled=${aec?.enabled}") - } else { - Log.w(TAG, "AEC not available on this device") - } - - if (android.media.audiofx.NoiseSuppressor.isAvailable()) { - ns = android.media.audiofx.NoiseSuppressor.create(sessionId)?.apply { - enabled = true - } - Log.i(TAG, "NS enabled=${ns?.enabled}") - } else { - Log.w(TAG, "NS not available on this device") - } - } - return true - } - - private suspend fun processSamplesLoop() { - // Avoid calling vad.front()/vad.pop() (native queue APIs) since it crashes on some builds. - // Use vad.compute() and implement a simple VAD segmenter in Kotlin instead. - val windowSize = 512 - val buffer = ShortArray(windowSize) - // 双阈值设置 - val startThreshold = 0.2f // 进入语音的阈值 - val endThreshold = 0.15f // 退出语音的阈值 - val minSilenceSamples = (0.5f * sampleRateInHz).toInt() - val minSpeechSamples = (0.1f * sampleRateInHz).toInt() - val maxSpeechSamples = (5.0f * sampleRateInHz).toInt() - - // VAD 概率数据记录 - val vadProbabilities = mutableListOf() - val vadTimestamps = mutableListOf() - val vadRMSValues = mutableListOf() - val vadSmoothedRMSValues = mutableListOf() - - // 指数平滑相关变量 - var smoothedRms = 0f - val alpha = 0.8f // 平滑系数 - - var inSpeech = false - var silenceSamples = 0 - - var speechBuf = FloatArray(0) - var speechLen = 0 - var processedSpeechBuf = FloatArray(0) - var processedSpeechLen = 0 - - fun appendSpeech(chunk: FloatArray, processedChunk: FloatArray) { - // 保存原始音频 - val needed = speechLen + chunk.size - if (speechBuf.size < needed) { - var newCap = maxOf(needed, maxOf(1024, speechBuf.size * 2)) - if (newCap > maxSpeechSamples) newCap = maxSpeechSamples - val n = FloatArray(newCap) - if (speechLen > 0) System.arraycopy(speechBuf, 0, n, 0, speechLen) - speechBuf = n - } - val copyN = minOf(chunk.size, max(0, maxSpeechSamples - speechLen)) - if (copyN > 0) { - System.arraycopy(chunk, 0, speechBuf, speechLen, copyN) - speechLen += copyN - } - - // 保存增益后的音频 - val processedNeeded = processedSpeechLen + processedChunk.size - if (processedSpeechBuf.size < processedNeeded) { - var newCap = maxOf(processedNeeded, maxOf(1024, processedSpeechBuf.size * 2)) - if (newCap > maxSpeechSamples) newCap = maxSpeechSamples - val n = FloatArray(newCap) - if (processedSpeechLen > 0) System.arraycopy(processedSpeechBuf, 0, n, 0, processedSpeechLen) - processedSpeechBuf = n - } - val processedCopyN = minOf(processedChunk.size, max(0, maxSpeechSamples - processedSpeechLen)) - if (processedCopyN > 0) { - System.arraycopy(processedChunk, 0, processedSpeechBuf, processedSpeechLen, processedCopyN) - processedSpeechLen += processedCopyN - } - } - - suspend fun finalizeSegmentIfAny() { - if (speechLen < minSpeechSamples) { - speechLen = 0 - processedSpeechLen = 0 - inSpeech = false - silenceSamples = 0 - return - } - // ✅ 新增:如果 TTS 正在播放或 LLM 请求中,丢弃此段(避免回声) - if (ttsPlaying.get() || llmInFlight) { - speechLen = 0 - processedSpeechLen = 0 - inSpeech = false - silenceSamples = 0 - return - } - val originalSeg = speechBuf.copyOf(speechLen) - val processedSeg = processedSpeechBuf.copyOf(processedSpeechLen) - speechLen = 0 - processedSpeechLen = 0 - inSpeech = false - silenceSamples = 0 - - // 将语音段加入 ASR 处理队列,异步处理 - asrQueue.send(Pair(originalSeg, processedSeg)) - } - - while (isRecording && ioScope.coroutineContext.isActive) { - val ret = audioRecord?.read(buffer, 0, buffer.size) ?: break - if (ret <= 0) continue - if (ret != windowSize) continue - // 在 processSamplesLoop 方法中 - val chunk = FloatArray(ret) { buffer[it] / 32768.0f } - - // 计算当前音频的RMS值(均方根) - val rms = calculateRMS(chunk) - - // 应用指数平滑 - smoothedRms = if (smoothedRms == 0f) rms else alpha * rms + (1 - alpha) * smoothedRms - - // 动态调整增益因子,目标RMS设为0.1(约-20dB) - val targetRMS = 0.1f - var gainFactor = if (smoothedRms > 0) targetRMS / smoothedRms else 3.0f - - // 设置增益的上下限,避免过度增益导致削波 - gainFactor = gainFactor.coerceIn(0.1f, 10.0f) - - // 应用增益因子 - val processedChunk = FloatArray(chunk.size) { - val value = chunk[it] * gainFactor - // 限制音量范围,避免削波 - if (value > 1.0f) 1.0f else if (value < -1.0f) -1.0f else value - } - - // 使用处理后的音频数据 - val prob = synchronized(nativeLock) { vad.compute(processedChunk) } - - // 记录VAD概率、时间戳、原始RMS值和平滑后的RMS值 - vadProbabilities.add(prob) - vadTimestamps.add(System.currentTimeMillis()) - vadRMSValues.add(rms) - vadSmoothedRMSValues.add(smoothedRms) - - // 双阈值状态机逻辑 - if (!inSpeech && prob >= startThreshold) { - // 进入语音状态 - inSpeech = true - silenceSamples = 0 - appendSpeech(chunk, processedChunk) - } else if (inSpeech && prob <= endThreshold) { - // 开始计数静音样本 - silenceSamples += ret - if (silenceSamples >= minSilenceSamples) { - // 退出语音状态 - finalizeSegmentIfAny() - } else { - // 保留尾音 - appendSpeech(chunk, processedChunk) - } - } else if (inSpeech) { - // 语音过程中,持续添加音频 - appendSpeech(chunk, processedChunk) - silenceSamples = 0 // 重置静音计数 - - if (speechLen >= maxSpeechSamples) { - finalizeSegmentIfAny() - } - } - // 非语音状态且概率低于开始阈值,不做处理 - - // 时间兜底切段(避免长时间无标点导致首包太慢) - val forced = segmenter.maybeForceByTime() - for (seg in forced) enqueueTtsSegment(seg) - } - - // flush last partial segment - finalizeSegmentIfAny() - - // 保存VAD数据到文件 - saveVadData(vadTimestamps, vadProbabilities, vadRMSValues, vadSmoothedRMSValues) - } - - /** - * 保存VAD数据到文件,方便后续分析和绘图 - */ - private fun saveVadData(timestamps: List, probabilities: List, rmsValues: List, smoothedRmsValues: List) { - try { - // 创建保存目录 - val vadDataDir = File(filesDir, "vad_data") - if (!vadDataDir.exists()) { - vadDataDir.mkdirs() - } - - // 生成唯一的文件名 - val timestamp = System.currentTimeMillis() - val fileName = "vad_data_${timestamp}.csv" - val outputFile = File(vadDataDir, fileName) - - // 写入数据 - FileOutputStream(outputFile).use { fos -> - // 写入表头 - fos.write("timestamp,probability,rms,smoothed_rms\n".toByteArray()) - - // 写入数据行 - for (i in timestamps.indices) { - val line = "${timestamps[i]},${probabilities[i]},${rmsValues[i]},${smoothedRmsValues[i]}\n" - fos.write(line.toByteArray()) - } - } - - Log.d(TAG, "Saved VAD data to: ${outputFile.absolutePath}") - } catch (e: Exception) { - Log.e(TAG, "Error saving VAD data: ${e.message}") - } - } - - private fun removeTokens(text: String): String { - // Remove tokens like <|zh|>, <|NEUTRAL|>, <|Speech|>, <|woitn|> and stray '>' chars - var cleaned = text.replace(Regex("<\\|[^>]+\\|>"), "") - cleaned = cleaned.replace(Regex("[>>≥≫]"), "") - cleaned = cleaned.trim().replace(Regex("\\s+"), " ") - return cleaned - } - - private fun enqueueTtsSegment(seg: String) { - // 移除句末的标点符号 - val cleanedSeg = seg.trimEnd('.', '。', '!', '!', '?', '?', ',', ',', ';', ';', ':', ':') - - currentTrace?.markTtsRequestEnqueued() - ttsQueue.offer(TtsQueueItem.Segment(cleanedSeg)) - ensureTtsWorker() - } - - private fun ensureTtsWorker() { - if (!ttsWorkerRunning.compareAndSet(false, true)) return - ioScope.launch { - try { - runTtsWorker() - } finally { - ttsWorkerRunning.set(false) - } - } - } - - private fun ensureAsrWorker() { - if (!asrWorkerRunning.compareAndSet(false, true)) return - ioScope.launch { - try { - runAsrWorker() - } finally { - asrWorkerRunning.set(false) - } - } - } - - private fun runTtsWorker() { - val t = tts ?: return - val audioTrack = track ?: return - - var firstAudioMarked = false - var isFirstSegment = true - while (true) { - val item = ttsQueue.take() - if (ttsStopped.get()) break - - when (item) { - is TtsQueueItem.Segment -> { - ttsPlaying.set(true) - runOnUiThread { videoPlayerManager?.setSpeaking(true) } - val trace = currentTrace - trace?.markTtsSynthesisStart() - Log.d(TAG, "TTS started: processing segment '${item.text}'") - runOnUiThread { - appendToUi("\n[TTS] 开始合成...\n") - } - - val startMs = System.currentTimeMillis() - var firstPcmMarked = false - - if (isFirstSegment) { - try { - audioTrack.pause() - audioTrack.flush() - audioTrack.play() - } catch (_: Throwable) { - } - isFirstSegment = false - } - - t.generateWithCallback( - text = item.text, - sid = 2, // 这里可以修改说话人 - speed = 1.0f - ) { samples -> - if (ttsStopped.get()) return@generateWithCallback 0 - if (!firstPcmMarked && samples.isNotEmpty()) { - firstPcmMarked = true - trace?.markTtsFirstPcmReady() - } - if (!firstAudioMarked && samples.isNotEmpty()) { - firstAudioMarked = true - trace?.markTtsFirstAudioPlay() - } - audioTrack.write(samples, 0, samples.size, AudioTrack.WRITE_BLOCKING) - ttsTotalSamplesWritten += samples.size - 1 - } - - val ttsMs = System.currentTimeMillis() - startMs - trace?.addDuration("tts_segment_ms_total", ttsMs) - } - - TtsQueueItem.End -> { - // 清空 ASR 队列,丢弃所有未处理的段(这些可能是 TTS 播放期间的回声) - while (asrQueue.tryReceive().isSuccess) { } - - waitForPlaybackComplete(audioTrack) - val ttsCompleteTime = System.currentTimeMillis() - - // 在主线程更新UI - runOnUiThread { - appendToUi("\n[LOG] TTS completed at: ${ttsCompleteTime}\n") - } - - ttsPlaying.set(false) - runOnUiThread { videoPlayerManager?.setSpeaking(false) } - ttsTotalSamplesWritten = 0 - isFirstSegment = true - currentTrace?.markTtsDone() - TraceManager.getInstance().endTurn() - currentTrace = null - break - } - } - } - } - - private fun waitForPlaybackComplete(audioTrack: AudioTrack) { - val totalSamples = ttsTotalSamplesWritten - if (totalSamples <= 0) return - - val sampleRate = audioTrack.sampleRate - val timeoutMs = (totalSamples * 1000 / sampleRate) + 2000 - val startTime = System.currentTimeMillis() - - while (true) { - if (ttsStopped.get()) break - - val playbackPos = audioTrack.playbackHeadPosition.toLong() - if (playbackPos >= totalSamples) { - break - } - - if (System.currentTimeMillis() - startTime > timeoutMs) { - Log.w(TAG, "waitForPlaybackComplete timeout, pos=$playbackPos, total=$totalSamples") - break - } - - Thread.sleep(20) - } - // 直接等待 1000ms,确保所有缓冲区清空 - Thread.sleep(1000) - } - - private suspend fun runAsrWorker() { - while (ioScope.coroutineContext.isActive) { - val (seg, trace) = try { - asrQueue.receive() - } catch (_: Throwable) { - break - } - - // 每次只允许一个 LLM 请求在飞,避免堆积导致卡死/竞态 - // TTS 播放期间不做 ASR,避免识别到 TTS 播放的声音 - if (llmInFlight || ttsPlaying.get()) continue - - trace?.markASRStart() - Log.d(TAG, "ASR started: processing audio segment") - withContext(Dispatchers.Main) { - appendToUi("\n[ASR] 开始识别...\n") - } - val raw = synchronized(nativeLock) { - val e = senseVoice - if (e == null || !e.isInitialized) "" else e.transcribeBuffer(seg) - } - val text = removeTokens(raw) - - // 添加过滤逻辑 - if (text.isBlank()) continue - // 过滤英文单字符"i" - if (text.length == 1 && text[0].equals('i', ignoreCase = true)) { - Log.d(TAG, "ASR segment skipped: single 'i'") - continue - } - // 过滤超过50个字符的长文本 - if (text.length > 50) { - Log.d(TAG, "ASR segment skipped: too long (${text.length} chars)") - continue - } - - trace?.markASREnd() - - withContext(Dispatchers.Main) { - appendToUi("\n\n[ASR] ${text}\n") - } - - trace?.markRecordingDone() - trace?.markLlmResponseReceived() - - if (BuildConfig.LLM_API_KEY.isBlank()) { - withContext(Dispatchers.Main) { - Toast.makeText( - this@MainActivity, - "未配置 LLM_API_KEY(在 local.properties 或 gradle.properties 里设置)", - Toast.LENGTH_LONG - ).show() - } - continue - } - - llmInFlight = true - cloudApiManager.callLLM(text) - } - } - - private fun appendToUi(s: String) { - lastUiText += s - textView.text = lastUiText - } -} \ No newline at end of file diff --git a/app/src/main/java/com/digitalperson/EntryActivity.kt b/app/src/main/java/com/digitalperson/EntryActivity.kt new file mode 100644 index 0000000..396b9a9 --- /dev/null +++ b/app/src/main/java/com/digitalperson/EntryActivity.kt @@ -0,0 +1,20 @@ +package com.digitalperson + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.digitalperson.config.AppConfig + +class EntryActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val target = if (AppConfig.Avatar.USE_LIVE2D) { + Live2DChatActivity::class.java + } else { + MainActivity::class.java + } + startActivity(Intent(this, target)) + finish() + } +} diff --git a/app/src/main/java/com/digitalperson/Live2DChatActivity.kt b/app/src/main/java/com/digitalperson/Live2DChatActivity.kt new file mode 100644 index 0000000..bba38ae --- /dev/null +++ b/app/src/main/java/com/digitalperson/Live2DChatActivity.kt @@ -0,0 +1,418 @@ +package com.digitalperson + +import android.Manifest +import android.content.pm.PackageManager +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import com.digitalperson.cloud.CloudApiManager +import com.digitalperson.audio.AudioProcessor +import com.digitalperson.vad.VadManager +import com.digitalperson.asr.AsrManager +import com.digitalperson.tts.TtsManager +import com.digitalperson.ui.Live2DUiManager +import com.digitalperson.config.AppConfig +import com.digitalperson.metrics.TraceManager +import com.digitalperson.metrics.TraceSession +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class Live2DChatActivity : AppCompatActivity() { + + private lateinit var uiManager: Live2DUiManager + private lateinit var vadManager: VadManager + private lateinit var asrManager: AsrManager + private lateinit var ttsManager: TtsManager + private lateinit var audioProcessor: AudioProcessor + + private val permissions: Array = arrayOf(Manifest.permission.RECORD_AUDIO) + + @Volatile + private var isRecording: Boolean = false + + private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + private var recordingJob: Job? = null + private val nativeLock = Any() + + private lateinit var cloudApiManager: CloudApiManager + private val segmenter = StreamingTextSegmenter( + maxLen = AppConfig.Tts.MAX_LEN, + maxWaitMs = AppConfig.Tts.MAX_WAIT_MS + ) + + private var currentTrace: TraceSession? = null + @Volatile private var llmInFlight: Boolean = false + private var enableStreaming = false + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + val ok = requestCode == AppConfig.REQUEST_RECORD_AUDIO_PERMISSION && + grantResults.isNotEmpty() && + grantResults[0] == PackageManager.PERMISSION_GRANTED + if (!ok) { + Log.e(AppConfig.TAG, "Audio record is disallowed") + finish() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_live2d_chat) + + uiManager = Live2DUiManager(this) + uiManager.initViews( + textViewId = R.id.my_text, + scrollViewId = R.id.scroll_view, + startButtonId = R.id.start_button, + stopButtonId = R.id.stop_button, + silentPlayerViewId = 0, + speakingPlayerViewId = 0, + live2dViewId = R.id.live2d_view + ) + + uiManager.setStartButtonListener { onStartClicked() } + uiManager.setStopButtonListener { onStopClicked(userInitiated = true) } + + ActivityCompat.requestPermissions(this, permissions, AppConfig.REQUEST_RECORD_AUDIO_PERMISSION) + + try { + val streamingSwitch = findViewById(R.id.streaming_switch) + streamingSwitch.isChecked = enableStreaming + streamingSwitch.setOnCheckedChangeListener { _, isChecked -> + enableStreaming = isChecked + cloudApiManager.setEnableStreaming(isChecked) + uiManager.showToast("流式输出已${if (isChecked) "启用" else "禁用"}") + } + } catch (e: Exception) { + Log.w(AppConfig.TAG, "Streaming switch not found in layout: ${e.message}") + } + + uiManager.setButtonsEnabled(startEnabled = false, stopEnabled = false) + uiManager.setText("初始化中…") + + audioProcessor = AudioProcessor(this) + + asrManager = AsrManager(this) + asrManager.setAudioProcessor(audioProcessor) + asrManager.setCallback(createAsrCallback()) + + vadManager = VadManager(this) + vadManager.setCallback(createVadCallback()) + + ioScope.launch { + try { + Log.i(AppConfig.TAG, "Init VAD + SenseVoice(RKNN) + TTS (background)") + synchronized(nativeLock) { + vadManager.initVadModel() + asrManager.initSenseVoiceModel() + } + val ttsOk = ttsManager.initTtsAndAudioTrack() + withContext(Dispatchers.Main) { + if (!ttsOk) { + uiManager.showToast( + "TTS 初始化失败:请确认 assets/${AppConfig.Tts.MODEL_DIR}/ 下有 model.onnx、tokens.txt、lexicon.txt 以及 phone/date/number/new_heteronym.fst", + Toast.LENGTH_LONG + ) + } + uiManager.setText(getString(R.string.hint)) + uiManager.setButtonsEnabled(startEnabled = true, stopEnabled = false) + } + } catch (t: Throwable) { + Log.e(AppConfig.TAG, "Initialization failed: ${t.message}", t) + withContext(Dispatchers.Main) { + uiManager.setText("初始化失败:${t.javaClass.simpleName}: ${t.message}") + uiManager.showToast("初始化失败(请看 Logcat): ${t.javaClass.simpleName}", Toast.LENGTH_LONG) + uiManager.setButtonsEnabled(startEnabled = false, stopEnabled = false) + } + } + } + + cloudApiManager = CloudApiManager(createCloudApiListener(), applicationContext) + cloudApiManager.setEnableStreaming(enableStreaming) + + ttsManager = TtsManager(this) + ttsManager.setCallback(createTtsCallback()) + + Log.d(AppConfig.TAG, "Pre-starting ASR worker") + ioScope.launch { + asrManager.runAsrWorker() + } + } + + private fun createAsrCallback() = object : AsrManager.AsrCallback { + override fun onAsrStarted() { + currentTrace?.markASRStart() + runOnUiThread { + uiManager.appendToUi("\n[ASR] 开始识别...\n") + } + } + + override fun onAsrResult(text: String) { + currentTrace?.markASREnd() + runOnUiThread { + uiManager.appendToUi("\n\n[ASR] ${text}\n") + } + currentTrace?.markRecordingDone() + currentTrace?.markLlmResponseReceived() + } + + override fun onAsrSkipped(reason: String) { + Log.d(AppConfig.TAG, "ASR segment skipped: $reason") + } + + override fun shouldSkipAsr(): Boolean = ttsManager.isPlaying() + + override fun isLlmInFlight(): Boolean = llmInFlight + + override fun onLlmCalled(text: String) { + llmInFlight = true + Log.d(AppConfig.TAG, "Calling LLM with text: $text") + cloudApiManager.callLLM(text) + } + } + + private fun createVadCallback() = object : VadManager.VadCallback { + override fun onSpeechSegmentReady(originalAudio: FloatArray, processedAudio: FloatArray) { + Log.d(AppConfig.TAG, "Sending audio segment to ASR queue, size: ${processedAudio.size}") + asrManager.enqueueAudioSegment(originalAudio, processedAudio) + } + + override fun shouldSkipProcessing(): Boolean = ttsManager.isPlaying() || llmInFlight + } + + private fun createCloudApiListener() = object : CloudApiManager.CloudApiListener { + private var llmFirstChunkMarked = false + + override fun onLLMResponseReceived(response: String) { + currentTrace?.markLlmDone() + llmInFlight = false + + if (enableStreaming) { + for (seg in segmenter.flush()) { + ttsManager.enqueueSegment(seg) + } + ttsManager.enqueueEnd() + } else { + runOnUiThread { + uiManager.appendToUi("${response}\n") + } + ttsManager.enqueueSegment(response) + ttsManager.enqueueEnd() + } + } + + override fun onLLMStreamingChunkReceived(chunk: String) { + if (enableStreaming) { + if (!llmFirstChunkMarked) { + llmFirstChunkMarked = true + currentTrace?.markLlmFirstChunk() + } + uiManager.appendToUi(chunk) + + val segments = segmenter.processChunk(chunk) + for (seg in segments) { + ttsManager.enqueueSegment(seg) + } + } + } + + override fun onTTSAudioReceived(audioFilePath: String) {} + + override fun onError(errorMessage: String) { + llmInFlight = false + uiManager.showToast(errorMessage, Toast.LENGTH_LONG) + onStopClicked(userInitiated = false) + } + } + + private fun createTtsCallback() = object : TtsManager.TtsCallback { + override fun onTtsStarted(text: String) { + runOnUiThread { + uiManager.appendToUi("\n[TTS] 开始合成...\n") + } + } + + override fun onTtsCompleted() { + runOnUiThread { + uiManager.appendToUi("\n[LOG] TTS completed at: ${System.currentTimeMillis()}\n") + } + } + + override fun onTtsSegmentCompleted(durationMs: Long) {} + + override fun isTtsStopped(): Boolean = !isRecording + + override fun onClearAsrQueue() { + asrManager.clearQueue() + } + + override fun onSetSpeaking(speaking: Boolean) { + uiManager.setSpeaking(speaking) + } + + override fun getCurrentTrace(): TraceSession? = currentTrace + + override fun onTraceMarkTtsRequestEnqueued() { + currentTrace?.markTtsRequestEnqueued() + } + + override fun onTraceMarkTtsSynthesisStart() { + currentTrace?.markTtsSynthesisStart() + } + + override fun onTraceMarkTtsFirstPcmReady() { + currentTrace?.markTtsFirstPcmReady() + } + + override fun onTraceMarkTtsFirstAudioPlay() { + currentTrace?.markTtsFirstAudioPlay() + } + + override fun onTraceMarkTtsDone() { + currentTrace?.markTtsDone() + } + + override fun onTraceAddDuration(name: String, value: Long) { + currentTrace?.addDuration(name, value) + } + + override fun onEndTurn() { + TraceManager.getInstance().endTurn() + currentTrace = null + } + } + + override fun onDestroy() { + super.onDestroy() + onStopClicked(userInitiated = false) + ioScope.cancel() + synchronized(nativeLock) { + try { vadManager.release() } catch (_: Throwable) {} + try { asrManager.release() } catch (_: Throwable) {} + } + try { ttsManager.release() } catch (_: Throwable) {} + try { uiManager.release() } catch (_: Throwable) {} + try { audioProcessor.release() } catch (_: Throwable) {} + } + + override fun onResume() { + super.onResume() + uiManager.onResume() + } + + override fun onPause() { + uiManager.onPause() + super.onPause() + } + + private fun onStartClicked() { + Log.d(AppConfig.TAG, "onStartClicked called") + if (isRecording) { + Log.d(AppConfig.TAG, "Already recording, returning") + return + } + + if (!audioProcessor.initMicrophone(permissions, AppConfig.REQUEST_RECORD_AUDIO_PERMISSION)) { + uiManager.showToast("麦克风初始化失败/无权限") + return + } + + currentTrace = TraceManager.getInstance().startNewTurn() + currentTrace?.mark("turn_start") + llmInFlight = false + + uiManager.clearText() + + ttsManager.reset() + ttsManager.setCurrentTrace(currentTrace) + segmenter.reset() + + vadManager.reset() + audioProcessor.startRecording() + isRecording = true + + uiManager.setButtonsEnabled(startEnabled = false, stopEnabled = true) + + Log.d(AppConfig.TAG, "Starting processSamplesLoop coroutine") + recordingJob?.cancel() + recordingJob = ioScope.launch { + processSamplesLoop() + } + Log.d(AppConfig.TAG, "onStartClicked completed") + } + + private fun onStopClicked(userInitiated: Boolean) { + isRecording = false + audioProcessor.stopRecording() + + recordingJob?.cancel() + recordingJob = null + + ttsManager.stop() + + uiManager.setButtonsEnabled(startEnabled = true, stopEnabled = false) + + if (userInitiated) { + TraceManager.getInstance().endTurn() + currentTrace = null + } + } + + private suspend fun processSamplesLoop() { + Log.d(AppConfig.TAG, "processSamplesLoop started") + val windowSize = AppConfig.WINDOW_SIZE + val buffer = ShortArray(windowSize) + var loopCount = 0 + + while (isRecording && ioScope.coroutineContext.isActive) { + loopCount++ + if (loopCount % 100 == 0) { + Log.d(AppConfig.TAG, "processSamplesLoop running, loopCount=$loopCount, ttsPlaying=${ttsManager.isPlaying()}") + } + + if (ttsManager.isPlaying()) { + if (vadManager.isInSpeech()) { + Log.d(AppConfig.TAG, "TTS playing, resetting VAD state") + vadManager.clearState() + } + val ret = audioProcessor.readAudio(buffer) + if (ret <= 0) continue + continue + } + + val ret = audioProcessor.readAudio(buffer) + if (ret <= 0) continue + if (ret != windowSize) continue + + val chunk = audioProcessor.convertShortToFloat(buffer) + val processedChunk = audioProcessor.applyGain(chunk) + + val result = vadManager.processAudioChunk(chunk, processedChunk) + + if (vadManager.vadComputeCount % 100 == 0) { + Log.d(AppConfig.TAG, "VAD result: $result, inSpeech=${vadManager.isInSpeech()}") + } + + if (loopCount % 1000 == 0) { + Log.d(AppConfig.TAG, "VAD status: inSpeech=${vadManager.isInSpeech()}, speechLen=${vadManager.getSpeechLength()}") + } + + val forced = segmenter.maybeForceByTime() + for (seg in forced) ttsManager.enqueueSegment(seg) + } + + vadManager.forceFinalize() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/digitalperson/MainActivity.kt b/app/src/main/java/com/digitalperson/MainActivity.kt index c20afa2..de0bcc0 100644 --- a/app/src/main/java/com/digitalperson/MainActivity.kt +++ b/app/src/main/java/com/digitalperson/MainActivity.kt @@ -2,75 +2,39 @@ package com.digitalperson import android.Manifest import android.content.pm.PackageManager -import android.media.AudioAttributes -import android.media.AudioFormat -import android.media.AudioManager -import android.media.AudioRecord -import android.media.AudioTrack -import android.media.MediaRecorder -import android.media.audiofx.AcousticEchoCanceler -import android.media.audiofx.NoiseSuppressor import android.os.Bundle -import android.os.SystemClock -import android.text.method.ScrollingMovementMethod import android.util.Log -import android.widget.Button -import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import com.digitalperson.cloud.CloudApiManager -import com.digitalperson.player.VideoPlayerManager -import com.google.android.exoplayer2.ui.PlayerView -import com.digitalperson.engine.SenseVoiceEngineRKNN +import com.digitalperson.audio.AudioProcessor +import com.digitalperson.vad.VadManager +import com.digitalperson.asr.AsrManager +import com.digitalperson.tts.TtsManager +import com.digitalperson.ui.UiManager +import com.digitalperson.config.AppConfig import com.digitalperson.metrics.TraceManager import com.digitalperson.metrics.TraceSession -import com.k2fsa.sherpa.onnx.OfflineTts -import com.k2fsa.sherpa.onnx.SileroVadModelConfig -import com.k2fsa.sherpa.onnx.Vad -import com.k2fsa.sherpa.onnx.VadModelConfig -import com.k2fsa.sherpa.onnx.getOfflineTtsConfig import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.io.File -import java.io.FileOutputStream -import java.util.concurrent.LinkedBlockingQueue -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.math.max - -private const val TAG = "DigitalPerson" -private const val REQUEST_RECORD_AUDIO_PERMISSION = 200 class MainActivity : AppCompatActivity() { - private lateinit var startButton: Button - private lateinit var stopButton: Button - private lateinit var textView: TextView + private lateinit var uiManager: UiManager + private lateinit var vadManager: VadManager + private lateinit var asrManager: AsrManager + private lateinit var ttsManager: TtsManager + private lateinit var audioProcessor: AudioProcessor - private lateinit var vad: Vad - private var senseVoice: SenseVoiceEngineRKNN? = null - private var tts: OfflineTts? = null - private var track: AudioTrack? = null - - private var aec: AcousticEchoCanceler? = null - private var ns: NoiseSuppressor? = null - - private var audioRecord: AudioRecord? = null - private val audioSource = MediaRecorder.AudioSource.MIC - private val sampleRateInHz = 16000 - private val channelConfig = AudioFormat.CHANNEL_IN_MONO - private val audioFormat = AudioFormat.ENCODING_PCM_16BIT private val permissions: Array = arrayOf(Manifest.permission.RECORD_AUDIO) - - @Volatile private var isRecording: Boolean = false @@ -79,32 +43,14 @@ class MainActivity : AppCompatActivity() { private val nativeLock = Any() private lateinit var cloudApiManager: CloudApiManager - private var videoPlayerManager: VideoPlayerManager? = null private val segmenter = StreamingTextSegmenter( - maxLen = 30, - maxWaitMs = 600 + maxLen = AppConfig.Tts.MAX_LEN, + maxWaitMs = AppConfig.Tts.MAX_WAIT_MS ) - private sealed class TtsQueueItem { - data class Segment(val text: String) : TtsQueueItem() - data object End : TtsQueueItem() - } - - private val ttsQueue = LinkedBlockingQueue() - private val ttsStopped = AtomicBoolean(false) - private val ttsWorkerRunning = AtomicBoolean(false) - private val ttsPlaying = AtomicBoolean(false) - @Volatile private var ttsTotalSamplesWritten: Long = 0 - private var currentTrace: TraceSession? = null - - private var lastUiText: String = "" @Volatile private var llmInFlight: Boolean = false - private var enableStreaming = false // 默认禁用流式输出 - - // ASR 队列和工作器 - private val asrQueue = Channel>(capacity = Channel.UNLIMITED) - private val asrWorkerRunning = AtomicBoolean(false) + private var enableStreaming = false override fun onRequestPermissionsResult( requestCode: Int, @@ -112,11 +58,11 @@ class MainActivity : AppCompatActivity() { grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) - val ok = requestCode == REQUEST_RECORD_AUDIO_PERMISSION && + val ok = requestCode == AppConfig.REQUEST_RECORD_AUDIO_PERMISSION && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED if (!ok) { - Log.e(TAG, "Audio record is disallowed") + Log.e(AppConfig.TAG, "Audio record is disallowed") finish() } } @@ -125,131 +71,226 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - // 初始化双播放器管理器(silent 与 speaking 两个叠加的 PlayerView) - try { - val silentPv = findViewById(R.id.player_view_silent) - val speakingPv = findViewById(R.id.player_view_speaking) - videoPlayerManager = VideoPlayerManager(this, silentPv, speakingPv) - // 默认 AI 未说话 - videoPlayerManager?.setSpeaking(false) - } catch (e: Exception) { - Log.w(TAG, "PlayerViews not found or init failed: ${e.message}") - } + uiManager = UiManager(this) + uiManager.initViews( + textViewId = R.id.my_text, + scrollViewId = R.id.scroll_view, + startButtonId = R.id.start_button, + stopButtonId = R.id.stop_button, + silentPlayerViewId = R.id.player_view_silent, + speakingPlayerViewId = R.id.player_view_speaking + ) + + uiManager.setStartButtonListener { onStartClicked() } + uiManager.setStopButtonListener { onStopClicked(userInitiated = true) } - ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION) + ActivityCompat.requestPermissions(this, permissions, AppConfig.REQUEST_RECORD_AUDIO_PERMISSION) - startButton = findViewById(R.id.start_button) - stopButton = findViewById(R.id.stop_button) - textView = findViewById(R.id.my_text) - textView.movementMethod = ScrollingMovementMethod() - - startButton.setOnClickListener { onStartClicked() } - stopButton.setOnClickListener { onStopClicked(userInitiated = true) } - - // 初始化流式输出开关 try { val streamingSwitch = findViewById(R.id.streaming_switch) streamingSwitch.isChecked = enableStreaming streamingSwitch.setOnCheckedChangeListener { _, isChecked -> enableStreaming = isChecked cloudApiManager.setEnableStreaming(isChecked) - Toast.makeText(this, "流式输出已${if (isChecked) "启用" else "禁用"}", Toast.LENGTH_SHORT).show() + uiManager.showToast("流式输出已${if (isChecked) "启用" else "禁用"}") } } catch (e: Exception) { - Log.w(TAG, "Streaming switch not found in layout: ${e.message}") + Log.w(AppConfig.TAG, "Streaming switch not found in layout: ${e.message}") } - // 避免 UI 线程重初始化导致 ANR:在后台初始化模型与 AudioTrack - startButton.isEnabled = false - stopButton.isEnabled = false - textView.text = "初始化中…" + uiManager.setButtonsEnabled(startEnabled = false, stopEnabled = false) + uiManager.setText("初始化中…") + + audioProcessor = AudioProcessor(this) + + asrManager = AsrManager(this) + asrManager.setAudioProcessor(audioProcessor) + asrManager.setCallback(createAsrCallback()) + + vadManager = VadManager(this) + vadManager.setCallback(createVadCallback()) + ioScope.launch { try { - Log.i(TAG, "Init VAD + SenseVoice(RKNN) + TTS (background)") + Log.i(AppConfig.TAG, "Init VAD + SenseVoice(RKNN) + TTS (background)") synchronized(nativeLock) { - initVadModel() - initSenseVoiceModel() + vadManager.initVadModel() + asrManager.initSenseVoiceModel() } + val ttsOk = ttsManager.initTtsAndAudioTrack() withContext(Dispatchers.Main) { - initTtsAndAudioTrack() - textView.text = getString(R.string.hint) - startButton.isEnabled = true - stopButton.isEnabled = false + if (!ttsOk) { + uiManager.showToast( + "TTS 初始化失败:请确认 assets/${AppConfig.Tts.MODEL_DIR}/ 下有 model.onnx、tokens.txt、lexicon.txt 以及 phone/date/number/new_heteronym.fst", + Toast.LENGTH_LONG + ) + } + uiManager.setText(getString(R.string.hint)) + uiManager.setButtonsEnabled(startEnabled = true, stopEnabled = false) } } catch (t: Throwable) { - Log.e(TAG, "Initialization failed: ${t.message}", t) + Log.e(AppConfig.TAG, "Initialization failed: ${t.message}", t) withContext(Dispatchers.Main) { - textView.text = "初始化失败:${t.javaClass.simpleName}: ${t.message}" - Toast.makeText( - this@MainActivity, - "初始化失败(请看 Logcat): ${t.javaClass.simpleName}", - Toast.LENGTH_LONG - ).show() - startButton.isEnabled = false - stopButton.isEnabled = false + uiManager.setText("初始化失败:${t.javaClass.simpleName}: ${t.message}") + uiManager.showToast("初始化失败(请看 Logcat): ${t.javaClass.simpleName}", Toast.LENGTH_LONG) + uiManager.setButtonsEnabled(startEnabled = false, stopEnabled = false) } } } - cloudApiManager = CloudApiManager(object : CloudApiManager.CloudApiListener { - private var llmFirstChunkMarked = false - - override fun onLLMResponseReceived(response: String) { - currentTrace?.markLlmDone() - llmInFlight = false - - // 根据流式输出模式处理响应 - if (enableStreaming) { - // 启用流式输出时,刷新剩余缓冲区 - for (seg in segmenter.flush()) { - enqueueTtsSegment(seg) - } - // 发送队列结束信号 - ttsQueue.offer(TtsQueueItem.End) - } else { - runOnUiThread { - appendToUi("${response}\n") - } - // 禁用流式输出时,直接使用整段文本进行TTS - enqueueTtsSegment(response) - // 发送队列结束信号 - ttsQueue.offer(TtsQueueItem.End) - } - } - - override fun onLLMStreamingChunkReceived(chunk: String) { - // 启用流式输出时,处理流式chunk - if (enableStreaming) { - if (!llmFirstChunkMarked) { - llmFirstChunkMarked = true - currentTrace?.markLlmFirstChunk() - } - appendToUi(chunk) - - val segments = segmenter.processChunk(chunk) - for (seg in segments) { - enqueueTtsSegment(seg) - } - } - } - - override fun onTTSAudioReceived(audioFilePath: String) { - // unused - } - - override fun onError(errorMessage: String) { - llmInFlight = false - Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_LONG).show() - onStopClicked(userInitiated = false) - } - }, applicationContext) - - // 设置流式输出模式 + cloudApiManager = CloudApiManager(createCloudApiListener(), applicationContext) cloudApiManager.setEnableStreaming(enableStreaming) + + ttsManager = TtsManager(this) + ttsManager.setCallback(createTtsCallback()) - // 预先启动ASR worker - Log.d(TAG, "Pre-starting ASR worker") - ensureAsrWorker() + Log.d(AppConfig.TAG, "Pre-starting ASR worker") + ioScope.launch { + asrManager.runAsrWorker() + } + } + + private fun createAsrCallback() = object : AsrManager.AsrCallback { + override fun onAsrStarted() { + currentTrace?.markASRStart() + runOnUiThread { + uiManager.appendToUi("\n[ASR] 开始识别...\n") + } + } + + override fun onAsrResult(text: String) { + currentTrace?.markASREnd() + runOnUiThread { + uiManager.appendToUi("\n\n[ASR] ${text}\n") + } + currentTrace?.markRecordingDone() + currentTrace?.markLlmResponseReceived() + } + + override fun onAsrSkipped(reason: String) { + Log.d(AppConfig.TAG, "ASR segment skipped: $reason") + } + + override fun shouldSkipAsr(): Boolean = ttsManager.isPlaying() + + override fun isLlmInFlight(): Boolean = llmInFlight + + override fun onLlmCalled(text: String) { + llmInFlight = true + Log.d(AppConfig.TAG, "Calling LLM with text: $text") + cloudApiManager.callLLM(text) + } + } + + private fun createVadCallback() = object : VadManager.VadCallback { + override fun onSpeechSegmentReady(originalAudio: FloatArray, processedAudio: FloatArray) { + Log.d(AppConfig.TAG, "Sending audio segment to ASR queue, size: ${processedAudio.size}") + asrManager.enqueueAudioSegment(originalAudio, processedAudio) + } + + override fun shouldSkipProcessing(): Boolean = ttsManager.isPlaying() || llmInFlight + } + + private fun createCloudApiListener() = object : CloudApiManager.CloudApiListener { + private var llmFirstChunkMarked = false + + override fun onLLMResponseReceived(response: String) { + currentTrace?.markLlmDone() + llmInFlight = false + + if (enableStreaming) { + for (seg in segmenter.flush()) { + ttsManager.enqueueSegment(seg) + } + ttsManager.enqueueEnd() + } else { + runOnUiThread { + uiManager.appendToUi("${response}\n") + } + ttsManager.enqueueSegment(response) + ttsManager.enqueueEnd() + } + } + + override fun onLLMStreamingChunkReceived(chunk: String) { + if (enableStreaming) { + if (!llmFirstChunkMarked) { + llmFirstChunkMarked = true + currentTrace?.markLlmFirstChunk() + } + uiManager.appendToUi(chunk) + + val segments = segmenter.processChunk(chunk) + for (seg in segments) { + ttsManager.enqueueSegment(seg) + } + } + } + + override fun onTTSAudioReceived(audioFilePath: String) {} + + override fun onError(errorMessage: String) { + llmInFlight = false + uiManager.showToast(errorMessage, Toast.LENGTH_LONG) + onStopClicked(userInitiated = false) + } + } + + private fun createTtsCallback() = object : TtsManager.TtsCallback { + override fun onTtsStarted(text: String) { + runOnUiThread { + uiManager.appendToUi("\n[TTS] 开始合成...\n") + } + } + + override fun onTtsCompleted() { + runOnUiThread { + uiManager.appendToUi("\n[LOG] TTS completed at: ${System.currentTimeMillis()}\n") + } + } + + override fun onTtsSegmentCompleted(durationMs: Long) {} + + override fun isTtsStopped(): Boolean = !isRecording + + override fun onClearAsrQueue() { + asrManager.clearQueue() + } + + override fun onSetSpeaking(speaking: Boolean) { + uiManager.setSpeaking(speaking) + } + + override fun getCurrentTrace(): TraceSession? = currentTrace + + override fun onTraceMarkTtsRequestEnqueued() { + currentTrace?.markTtsRequestEnqueued() + } + + override fun onTraceMarkTtsSynthesisStart() { + currentTrace?.markTtsSynthesisStart() + } + + override fun onTraceMarkTtsFirstPcmReady() { + currentTrace?.markTtsFirstPcmReady() + } + + override fun onTraceMarkTtsFirstAudioPlay() { + currentTrace?.markTtsFirstAudioPlay() + } + + override fun onTraceMarkTtsDone() { + currentTrace?.markTtsDone() + } + + override fun onTraceAddDuration(name: String, value: Long) { + currentTrace?.addDuration(name, value) + } + + override fun onEndTurn() { + TraceManager.getInstance().endTurn() + currentTrace = null + } } override fun onDestroy() { @@ -257,99 +298,60 @@ class MainActivity : AppCompatActivity() { onStopClicked(userInitiated = false) ioScope.cancel() synchronized(nativeLock) { - try { - vad.release() - } catch (_: Throwable) { - } - try { - senseVoice?.deinitialize() - } catch (_: Throwable) { - } - } - try { - tts?.release() - } catch (_: Throwable) { - } - try { - videoPlayerManager?.release() - } catch (_: Throwable) { + try { vadManager.release() } catch (_: Throwable) {} + try { asrManager.release() } catch (_: Throwable) {} } + try { ttsManager.release() } catch (_: Throwable) {} + try { uiManager.release() } catch (_: Throwable) {} + try { audioProcessor.release() } catch (_: Throwable) {} } private fun onStartClicked() { - Log.d(TAG, "onStartClicked called") + Log.d(AppConfig.TAG, "onStartClicked called") if (isRecording) { - Log.d(TAG, "Already recording, returning") + Log.d(AppConfig.TAG, "Already recording, returning") return } - if (!initMicrophone()) { - Toast.makeText(this, "麦克风初始化失败/无权限", Toast.LENGTH_SHORT).show() + if (!audioProcessor.initMicrophone(permissions, AppConfig.REQUEST_RECORD_AUDIO_PERMISSION)) { + uiManager.showToast("麦克风初始化失败/无权限") return } - // Start a new trace turn currentTrace = TraceManager.getInstance().startNewTurn() currentTrace?.mark("turn_start") llmInFlight = false - lastUiText = "" - textView.text = "" + uiManager.clearText() - ttsStopped.set(false) - ttsPlaying.set(false) - ttsTotalSamplesWritten = 0 - ttsQueue.clear() + ttsManager.reset() + ttsManager.setCurrentTrace(currentTrace) segmenter.reset() - vad.reset() - audioRecord!!.startRecording() + vadManager.reset() + audioProcessor.startRecording() isRecording = true - startButton.isEnabled = false - stopButton.isEnabled = true + uiManager.setButtonsEnabled(startEnabled = false, stopEnabled = true) - Log.d(TAG, "Starting processSamplesLoop coroutine") + Log.d(AppConfig.TAG, "Starting processSamplesLoop coroutine") recordingJob?.cancel() recordingJob = ioScope.launch { processSamplesLoop() } - Log.d(TAG, "onStartClicked completed") + Log.d(AppConfig.TAG, "onStartClicked completed") } private fun onStopClicked(userInitiated: Boolean) { isRecording = false - try { - audioRecord?.stop() - } catch (_: Throwable) { - } - try { - audioRecord?.release() - } catch (_: Throwable) { - } - audioRecord = null + audioProcessor.stopRecording() recordingJob?.cancel() recordingJob = null - ttsStopped.set(true) - ttsPlaying.set(false) - ttsTotalSamplesWritten = 0 - ttsQueue.clear() - // wake worker if waiting - ttsQueue.offer(TtsQueueItem.End) + ttsManager.stop() - try { - track?.pause() - track?.flush() - } catch (_: Throwable) { - } - try { aec?.release() } catch (_: Throwable) {} - try { ns?.release() } catch (_: Throwable) {} - aec = null - ns = null - startButton.isEnabled = true - stopButton.isEnabled = false + uiManager.setButtonsEnabled(startEnabled = true, stopEnabled = false) if (userInitiated) { TraceManager.getInstance().endTurn() @@ -357,842 +359,49 @@ class MainActivity : AppCompatActivity() { } } - private fun initVadModel() { - // 你的 VAD 模型在 assets/vad_model/ 下 - val config = VadModelConfig( - sileroVadModelConfig = SileroVadModelConfig( - model = "vad_model/silero_vad.onnx", - threshold = 0.5F, - minSilenceDuration = 0.25F, - minSpeechDuration = 0.25F, - windowSize = 512, - ), - sampleRate = sampleRateInHz, - numThreads = 1, - provider = "cpu", - ) - vad = Vad(assetManager = application.assets, config = config) - } - - private fun initSenseVoiceModel() { - Log.i(TAG, "ASR: init SenseVoice RKNN (scheme A)") - // Copy assets/sensevoice_models/* -> filesDir/sensevoice_models/* - val modelDir = copySenseVoiceAssetsToInternal() - val modelPath = File(modelDir, "sense-voice-encoder.rknn").absolutePath - val embeddingPath = File(modelDir, "embedding.npy").absolutePath - val bpePath = File(modelDir, "chn_jpn_yue_eng_ko_spectok.bpe.model").absolutePath - - // Print quick diagnostics for native libs + model files - try { - val libDir = applicationInfo.nativeLibraryDir - Log.i(TAG, "nativeLibraryDir=$libDir") - try { - val names = File(libDir).list()?.joinToString(", ") ?: "(empty)" - Log.i(TAG, "nativeLibraryDir files: $names") - } catch (t: Throwable) { - Log.w(TAG, "Failed to list nativeLibraryDir: ${t.message}") - } - } catch (_: Throwable) { - } - Log.i(TAG, "SenseVoice model paths:") - Log.i(TAG, " model=$modelPath exists=${File(modelPath).exists()} size=${File(modelPath).length()}") - Log.i(TAG, " embedding=$embeddingPath exists=${File(embeddingPath).exists()} size=${File(embeddingPath).length()}") - Log.i(TAG, " bpe=$bpePath exists=${File(bpePath).exists()} size=${File(bpePath).length()}") - - val t0 = SystemClock.elapsedRealtime() - val engine = try { - SenseVoiceEngineRKNN(this) - } catch (e: UnsatisfiedLinkError) { - // Most common: libsensevoiceEngine.so not packaged/built, or dependent libs missing - throw IllegalStateException("Load native libraries failed: ${e.message}", e) - } - - val ok = try { - engine.loadModelDirectly(modelPath, embeddingPath, bpePath) - } catch (t: Throwable) { - throw IllegalStateException("SenseVoice loadModelDirectly crashed: ${t.message}", t) - } - - val dt = SystemClock.elapsedRealtime() - t0 - Log.i(TAG, "SenseVoice loadModelDirectly ok=$ok costMs=$dt") - if (!ok) throw IllegalStateException("SenseVoiceEngineRKNN loadModelDirectly returned false") - - senseVoice = engine - } - - private fun initTtsAndAudioTrack() { - try { - // 你放入的 sherpa-onnx VITS 中文模型目录: - // assets/tts_model/sherpa-onnx-vits-zh-ll/{model.onnx,tokens.txt,lexicon.txt,...} - val modelDir = "tts_model/sherpa-onnx-vits-zh-ll" - val modelName = "model.onnx" - val lexicon = "lexicon.txt" - val dataDir = "" - - val ttsConfig = getOfflineTtsConfig( - modelDir = modelDir, - modelName = modelName, - acousticModelName = "", - vocoder = "", - voices = "", - lexicon = lexicon, - dataDir = dataDir, - dictDir = "", - // 中文规范化规则(目录里已有这些 fst) - ruleFsts = "$modelDir/phone.fst,$modelDir/date.fst,$modelDir/number.fst,$modelDir/new_heteronym.fst", - ruleFars = "", - numThreads = null, - isKitten = false - ) - tts = OfflineTts(assetManager = application.assets, config = ttsConfig) - } catch (t: Throwable) { - Log.e(TAG, "Init TTS failed: ${t.message}", t) - tts = null - runOnUiThread { - Toast.makeText( - this, - "TTS 初始化失败:请确认 assets/tts_model/sherpa-onnx-vits-zh-ll/ 下有 model.onnx、tokens.txt、lexicon.txt 以及 phone/date/number/new_heteronym.fst", - Toast.LENGTH_LONG - ).show() - } - } - - val t = tts ?: return - val sr = t.sampleRate() - val bufLength = AudioTrack.getMinBufferSize( - sr, - AudioFormat.CHANNEL_OUT_MONO, - AudioFormat.ENCODING_PCM_FLOAT - ) - val attr = AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) - .setUsage(AudioAttributes.USAGE_MEDIA) - .build() - val format = AudioFormat.Builder() - .setEncoding(AudioFormat.ENCODING_PCM_FLOAT) - .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) - .setSampleRate(sr) - .build() - track = AudioTrack( - attr, - format, - bufLength, - AudioTrack.MODE_STREAM, - AudioManager.AUDIO_SESSION_ID_GENERATE - ) - track?.play() - } - - private fun assetExists(path: String): Boolean { - return try { - application.assets.open(path).close() - true - } catch (_: Throwable) { - false - } - } - - private fun copySenseVoiceAssetsToInternal(): File { - val outDir = File(filesDir, "sensevoice_models") - if (!outDir.exists()) outDir.mkdirs() - - val files = arrayOf( - "am.mvn", - "chn_jpn_yue_eng_ko_spectok.bpe.model", - "embedding.npy", - "sense-voice-encoder.rknn" - ) - - for (name in files) { - val assetPath = "sensevoice_models/$name" - val outFile = File(outDir, name) - if (outFile.exists() && outFile.length() > 0) continue - application.assets.open(assetPath).use { input -> - FileOutputStream(outFile).use { output -> - input.copyTo(output) - } - } - } - return outDir - } - - private fun initMicrophone(): Boolean { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) - != PackageManager.PERMISSION_GRANTED - ) { - ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION) - return false - } - - val numBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) - audioRecord = AudioRecord( - audioSource, - sampleRateInHz, - channelConfig, - audioFormat, - numBytes * 2 - ) - val sessionId = audioRecord?.audioSessionId ?: 0 - if (sessionId != 0) { - if (android.media.audiofx.AcousticEchoCanceler.isAvailable()) { - aec = android.media.audiofx.AcousticEchoCanceler.create(sessionId)?.apply { - enabled = true - } - Log.i(TAG, "AEC enabled=${aec?.enabled}") - } else { - Log.w(TAG, "AEC not available on this device") - } - - if (android.media.audiofx.NoiseSuppressor.isAvailable()) { - ns = android.media.audiofx.NoiseSuppressor.create(sessionId)?.apply { - enabled = true - } - Log.i(TAG, "NS enabled=${ns?.enabled}") - } else { - Log.w(TAG, "NS not available on this device") - } - } - return true - } - private suspend fun processSamplesLoop() { - Log.d(TAG, "processSamplesLoop started") - // Avoid calling vad.front()/vad.pop() (native queue APIs) since it crashes on some builds. - // Use vad.compute() and implement a simple VAD segmenter in Kotlin instead. - val windowSize = 512 + Log.d(AppConfig.TAG, "processSamplesLoop started") + val windowSize = AppConfig.WINDOW_SIZE val buffer = ShortArray(windowSize) - // 双阈值设置 - val startThreshold = 0.2f // 进入语音的阈值 - val endThreshold = 0.15f // 退出语音的阈值 - val minSilenceSamples = (0.5f * sampleRateInHz).toInt() - val minSpeechSamples = (0.1f * sampleRateInHz).toInt() - val maxSpeechSamples = (5.0f * sampleRateInHz).toInt() - - Log.d(TAG, "VAD thresholds: start=$startThreshold, end=$endThreshold, minSilenceSamples=$minSilenceSamples, minSpeechSamples=$minSpeechSamples") - - // VAD 概率数据记录 - val vadProbabilities = mutableListOf() - val vadTimestamps = mutableListOf() - val vadRMSValues = mutableListOf() - val vadSmoothedRMSValues = mutableListOf() - - // 指数平滑相关变量 - var smoothedRms = 0f - val alpha = 0.8f // 平滑系数 - - var inSpeech = false - var silenceSamples = 0 - - var speechBuf = FloatArray(0) - var speechLen = 0 - var processedSpeechBuf = FloatArray(0) - var processedSpeechLen = 0 - var loopCount = 0 - var vadComputeCount = 0 - - fun appendSpeech(chunk: FloatArray, processedChunk: FloatArray) { - // 保存原始音频 - val needed = speechLen + chunk.size - if (speechBuf.size < needed) { - var newCap = maxOf(needed, maxOf(1024, speechBuf.size * 2)) - if (newCap > maxSpeechSamples) newCap = maxSpeechSamples - val n = FloatArray(newCap) - if (speechLen > 0) System.arraycopy(speechBuf, 0, n, 0, speechLen) - speechBuf = n - } - val copyN = minOf(chunk.size, max(0, maxSpeechSamples - speechLen)) - if (copyN > 0) { - System.arraycopy(chunk, 0, speechBuf, speechLen, copyN) - speechLen += copyN - } - - // 保存增益后的音频 - val processedNeeded = processedSpeechLen + processedChunk.size - if (processedSpeechBuf.size < processedNeeded) { - var newCap = maxOf(processedNeeded, maxOf(1024, processedSpeechBuf.size * 2)) - if (newCap > maxSpeechSamples) newCap = maxSpeechSamples - val n = FloatArray(newCap) - if (processedSpeechLen > 0) System.arraycopy(processedSpeechBuf, 0, n, 0, processedSpeechLen) - processedSpeechBuf = n - } - val processedCopyN = minOf(processedChunk.size, max(0, maxSpeechSamples - processedSpeechLen)) - if (processedCopyN > 0) { - System.arraycopy(processedChunk, 0, processedSpeechBuf, processedSpeechLen, processedCopyN) - processedSpeechLen += processedCopyN - } - } - - suspend fun finalizeSegmentIfAny() { - Log.d(TAG, "finalizeSegmentIfAny called: speechLen=$speechLen, minSpeechSamples=$minSpeechSamples, ttsPlaying=${ttsPlaying.get()}, llmInFlight=$llmInFlight") - - if (speechLen < minSpeechSamples) { - Log.d(TAG, "finalizeSegmentIfAny: speech too short, discarding") - speechLen = 0 - processedSpeechLen = 0 - inSpeech = false - silenceSamples = 0 - return - } - // ✅ 新增:如果 TTS 正在播放或 LLM 请求中,丢弃此段(避免回声) - if (ttsPlaying.get() || llmInFlight) { - Log.d(TAG, "finalizeSegmentIfAny: TTS playing or LLM in flight, discarding") - speechLen = 0 - processedSpeechLen = 0 - inSpeech = false - silenceSamples = 0 - return - } - val originalSeg = speechBuf.copyOf(speechLen) - val processedSeg = processedSpeechBuf.copyOf(processedSpeechLen) - speechLen = 0 - processedSpeechLen = 0 - inSpeech = false - silenceSamples = 0 - - // 将语音段加入 ASR 处理队列,异步处理 - Log.d(TAG, "Sending audio segment to ASR queue, size: ${processedSeg.size}") - asrQueue.send(Pair(originalSeg, processedSeg)) - Log.d(TAG, "Calling ensureAsrWorker") - ensureAsrWorker() - } while (isRecording && ioScope.coroutineContext.isActive) { loopCount++ if (loopCount % 100 == 0) { - Log.d(TAG, "processSamplesLoop running, loopCount=$loopCount, ttsPlaying=${ttsPlaying.get()}") + Log.d(AppConfig.TAG, "processSamplesLoop running, loopCount=$loopCount, ttsPlaying=${ttsManager.isPlaying()}") } - // 如果TTS正在播放,跳过VAD处理,避免检测到回声 - if (ttsPlaying.get()) { - // 如果正在语音状态,立即结束它 - if (inSpeech) { - Log.d(TAG, "TTS playing, resetting VAD state") - inSpeech = false - silenceSamples = 0 - speechLen = 0 - processedSpeechLen = 0 + + if (ttsManager.isPlaying()) { + if (vadManager.isInSpeech()) { + Log.d(AppConfig.TAG, "TTS playing, resetting VAD state") + vadManager.clearState() } - // 读取并丢弃音频数据,保持录音状态 - val ret = audioRecord?.read(buffer, 0, buffer.size) ?: break + val ret = audioProcessor.readAudio(buffer) if (ret <= 0) continue continue } - val ret = audioRecord?.read(buffer, 0, buffer.size) ?: break + val ret = audioProcessor.readAudio(buffer) if (ret <= 0) continue if (ret != windowSize) continue - // 在 processSamplesLoop 方法中 - val chunk = FloatArray(ret) { buffer[it] / 32768.0f } - - // 计算当前音频的RMS值(均方根) - val rms = calculateRMS(chunk) - - // 应用指数平滑 - smoothedRms = if (smoothedRms == 0f) rms else alpha * rms + (1 - alpha) * smoothedRms - - // 动态调整增益因子,目标RMS设为0.1(约-20dB) - val targetRMS = 0.1f - var gainFactor = if (smoothedRms > 0) targetRMS / smoothedRms else 3.0f - - // 设置增益的上下限,避免过度增益导致削波 - gainFactor = gainFactor.coerceIn(0.1f, 10.0f) - - // 应用增益因子 - val processedChunk = FloatArray(chunk.size) { - val value = chunk[it] * gainFactor - // 限制音量范围,避免削波 - if (value > 1.0f) 1.0f else if (value < -1.0f) -1.0f else value - } - - // 使用处理后的音频数据 - val prob = synchronized(nativeLock) { vad.compute(processedChunk) } - vadComputeCount++ - - // 记录VAD概率、时间戳、原始RMS值和平滑后的RMS值 - vadProbabilities.add(prob) - vadTimestamps.add(System.currentTimeMillis()) - vadRMSValues.add(rms) - vadSmoothedRMSValues.add(smoothedRms) - - // 每100次循环输出一次VAD概率 - if (vadComputeCount % 100 == 0) { - Log.d(TAG, "VAD prob=$prob, inSpeech=$inSpeech, rms=$rms, smoothedRms=$smoothedRms") - } - - // 双阈值状态机逻辑 - if (!inSpeech && prob >= startThreshold) { - // 进入语音状态 - inSpeech = true - silenceSamples = 0 - appendSpeech(chunk, processedChunk) - Log.d(TAG, "VAD: Entered speech state, prob=$prob, speechLen=$speechLen") - } else if (inSpeech && prob <= endThreshold) { - // 开始计数静音样本 - silenceSamples += ret - if (silenceSamples >= minSilenceSamples) { - // 退出语音状态 - Log.d(TAG, "VAD: Exiting speech state, prob=$prob, silenceSamples=$silenceSamples, speechLen=$speechLen") - finalizeSegmentIfAny() - } else { - // 保留尾音 - appendSpeech(chunk, processedChunk) - } - } else if (inSpeech) { - // 语音过程中,持续添加音频 - appendSpeech(chunk, processedChunk) - silenceSamples = 0 // 重置静音计数 - - if (speechLen >= maxSpeechSamples) { - Log.d(TAG, "VAD: Max speech length reached, finalizing segment") - finalizeSegmentIfAny() - } - } - // 非语音状态且概率低于开始阈值,不做处理 - // 每1000次循环输出一次VAD状态 + val chunk = audioProcessor.convertShortToFloat(buffer) + val processedChunk = audioProcessor.applyGain(chunk) + + val result = vadManager.processAudioChunk(chunk, processedChunk) + + if (vadManager.vadComputeCount % 100 == 0) { + Log.d(AppConfig.TAG, "VAD result: $result, inSpeech=${vadManager.isInSpeech()}") + } + if (loopCount % 1000 == 0) { - Log.d(TAG, "VAD status: inSpeech=$inSpeech, prob=$prob, speechLen=$speechLen") + Log.d(AppConfig.TAG, "VAD status: inSpeech=${vadManager.isInSpeech()}, speechLen=${vadManager.getSpeechLength()}") } - // 时间兜底切段(避免长时间无标点导致首包太慢) val forced = segmenter.maybeForceByTime() - for (seg in forced) enqueueTtsSegment(seg) + for (seg in forced) ttsManager.enqueueSegment(seg) } - // flush last partial segment - finalizeSegmentIfAny() - - // 保存VAD数据到文件 - saveVadData(vadTimestamps, vadProbabilities, vadRMSValues, vadSmoothedRMSValues) - } - - /** - * 计算音频数据的均方根(RMS)值,用于动态调整增益 - */ - private fun calculateRMS(samples: FloatArray): Float { - if (samples.isEmpty()) return 0.0f - - var sumSquared = 0.0f - for (sample in samples) { - sumSquared += sample * sample - } - - val meanSquared = sumSquared / samples.size - return kotlin.math.sqrt(meanSquared) - } - - /** - * 保存VAD数据到文件,方便后续分析和绘图 - */ - private fun saveVadData(timestamps: List, probabilities: List, rmsValues: List, smoothedRmsValues: List) { - try { - // 创建保存目录 - val vadDataDir = File(filesDir, "vad_data") - if (!vadDataDir.exists()) { - vadDataDir.mkdirs() - } - - // 生成唯一的文件名 - val timestamp = System.currentTimeMillis() - val fileName = "vad_data_${timestamp}.csv" - val outputFile = File(vadDataDir, fileName) - - // 写入数据 - FileOutputStream(outputFile).use { fos -> - // 写入表头 - fos.write("timestamp,probability,rms,smoothed_rms\n".toByteArray()) - - // 写入数据行 - for (i in timestamps.indices) { - val line = "${timestamps[i]},${probabilities[i]},${rmsValues[i]},${smoothedRmsValues[i]}\n" - fos.write(line.toByteArray()) - } - } - - Log.d(TAG, "Saved VAD data to: ${outputFile.absolutePath}") - } catch (e: Exception) { - Log.e(TAG, "Error saving VAD data: ${e.message}") - } - } - - private fun removeTokens(text: String): String { - // Remove tokens like <|zh|>, <|NEUTRAL|>, <|Speech|>, <|woitn|> and stray '>' chars - var cleaned = text.replace(Regex("<\\|[^>]+\\|>"), "") - cleaned = cleaned.replace(Regex("[>>≥≫]"), "") - cleaned = cleaned.trim().replace(Regex("\\s+"), " ") - return cleaned - } - - private fun enqueueTtsSegment(seg: String) { - // 移除句末的标点符号 - val cleanedSeg = seg.trimEnd('.', '。', '!', '!', '?', '?', ',', ',', ';', ';', ':', ':') - - currentTrace?.markTtsRequestEnqueued() - ttsQueue.offer(TtsQueueItem.Segment(cleanedSeg)) - ensureTtsWorker() - } - - private fun ensureTtsWorker() { - if (!ttsWorkerRunning.compareAndSet(false, true)) return - ioScope.launch { - try { - runTtsWorker() - } finally { - ttsWorkerRunning.set(false) - } - } - } - - private fun ensureAsrWorker() { - Log.d(TAG, "ensureAsrWorker called, asrWorkerRunning=${asrWorkerRunning.get()}") - if (!asrWorkerRunning.compareAndSet(false, true)) { - Log.d(TAG, "ASR worker already running, returning") - return - } - Log.d(TAG, "Starting ASR worker coroutine") - ioScope.launch { - try { - runAsrWorker() - } finally { - Log.d(TAG, "ASR worker coroutine finished") - asrWorkerRunning.set(false) - } - } - } - - private fun runTtsWorker() { - val t = tts ?: return - val audioTrack = track ?: return - - var firstAudioMarked = false - var isFirstSegment = true - while (true) { - val item = ttsQueue.take() - if (ttsStopped.get()) break - - when (item) { - is TtsQueueItem.Segment -> { - ttsPlaying.set(true) - runOnUiThread { videoPlayerManager?.setSpeaking(true) } - val trace = currentTrace - trace?.markTtsSynthesisStart() - Log.d(TAG, "TTS started: processing segment '${item.text}'") - runOnUiThread { - appendToUi("\n[TTS] 开始合成...\n") - } - - val startMs = System.currentTimeMillis() - var firstPcmMarked = false - - if (isFirstSegment) { - try { - audioTrack.pause() - audioTrack.flush() - audioTrack.play() - } catch (_: Throwable) { - } - isFirstSegment = false - } - - t.generateWithCallback( - text = item.text, - sid = 2, // 这里可以修改说话人 - speed = 1.0f - ) { samples -> - if (ttsStopped.get()) return@generateWithCallback 0 - if (!firstPcmMarked && samples.isNotEmpty()) { - firstPcmMarked = true - trace?.markTtsFirstPcmReady() - } - if (!firstAudioMarked && samples.isNotEmpty()) { - firstAudioMarked = true - trace?.markTtsFirstAudioPlay() - } - audioTrack.write(samples, 0, samples.size, AudioTrack.WRITE_BLOCKING) - ttsTotalSamplesWritten += samples.size - 1 - } - - val ttsMs = System.currentTimeMillis() - startMs - trace?.addDuration("tts_segment_ms_total", ttsMs) - } - - TtsQueueItem.End -> { - // 清空 ASR 队列,丢弃所有未处理的段(这些可能是 TTS 播放期间的回声) - while (asrQueue.tryReceive().isSuccess) { } - - waitForPlaybackComplete(audioTrack) - val ttsCompleteTime = System.currentTimeMillis() - - // 在主线程更新UI - runOnUiThread { - appendToUi("\n[LOG] TTS completed at: ${ttsCompleteTime}\n") - } - - ttsPlaying.set(false) - runOnUiThread { videoPlayerManager?.setSpeaking(false) } - ttsTotalSamplesWritten = 0 - isFirstSegment = true - currentTrace?.markTtsDone() - TraceManager.getInstance().endTurn() - currentTrace = null - break - } - } - } - } - - private fun waitForPlaybackComplete(audioTrack: AudioTrack) { - val totalSamples = ttsTotalSamplesWritten - if (totalSamples <= 0) return - - val sampleRate = audioTrack.sampleRate - val timeoutMs = (totalSamples * 1000 / sampleRate) + 2000 - val startTime = System.currentTimeMillis() - - while (true) { - if (ttsStopped.get()) break - - val playbackPos = audioTrack.playbackHeadPosition.toLong() - if (playbackPos >= totalSamples) { - break - } - - if (System.currentTimeMillis() - startTime > timeoutMs) { - Log.w(TAG, "waitForPlaybackComplete timeout, pos=$playbackPos, total=$totalSamples") - break - } - - Thread.sleep(20) - } - // 直接等待 1000ms,确保所有缓冲区清空 - Thread.sleep(1000) - } - - private suspend fun runAsrWorker() { - Log.d(TAG, "ASR worker started") - try { - while (ioScope.coroutineContext.isActive) { - val (originalSeg, processedSeg) = try { - Log.d(TAG, "ASR worker waiting for audio segment") - asrQueue.receive() - } catch (e: Throwable) { - Log.e(TAG, "ASR worker receive failed: ${e.message}") - break - } - - Log.d(TAG, "ASR worker received audio segment, size=${processedSeg.size}") - - // 每次只允许一个 LLM 请求在飞,避免堆积导致卡死/竞态 - // TTS 播放期间不做 ASR,避免识别到 TTS 播放的声音 - if (llmInFlight || ttsPlaying.get()) { - Log.d(TAG, "ASR worker skipping segment: llmInFlight=$llmInFlight, ttsPlaying=${ttsPlaying.get()}") - continue - } - - val trace = currentTrace - trace?.markASRStart() - Log.d(TAG, "ASR started: processing audio segment") - withContext(Dispatchers.Main) { - appendToUi("\n[ASR] 开始识别...\n") - } - - // 保存ASR音频用于调试 - saveAsrAudio(originalSeg, processedSeg) - - val raw = synchronized(nativeLock) { - val e = senseVoice - if (e == null || !e.isInitialized) { - Log.e(TAG, "ASR failed: SenseVoice engine not initialized") - "" - } else { - try { - e.transcribeBuffer(processedSeg) - } catch (e: Throwable) { - Log.e(TAG, "ASR transcribe failed: ${e.message}") - "" - } - } - } - Log.d(TAG, "ASR raw result: $raw") - val text = removeTokens(raw) - - // 添加过滤逻辑 - if (text.isBlank()) { - Log.d(TAG, "ASR segment skipped: blank text") - continue - } - // 过滤英文单字符"i" - if (text.length == 1 && text[0].equals('i', ignoreCase = true)) { - Log.d(TAG, "ASR segment skipped: single 'i'") - continue - } - // 过滤超过50个字符的长文本 - if (text.length > 50) { - Log.d(TAG, "ASR segment skipped: too long (${text.length} chars)") - continue - } - - trace?.markASREnd() - - withContext(Dispatchers.Main) { - appendToUi("\n\n[ASR] ${text}\n") - } - - trace?.markRecordingDone() - trace?.markLlmResponseReceived() - - if (BuildConfig.LLM_API_KEY.isBlank()) { - withContext(Dispatchers.Main) { - Toast.makeText( - this@MainActivity, - "未配置 LLM_API_KEY(在 local.properties 或 gradle.properties 里设置)", - Toast.LENGTH_LONG - ).show() - } - continue - } - - llmInFlight = true - Log.d(TAG, "Calling LLM with text: $text") - cloudApiManager.callLLM(text) - } - } catch (e: Throwable) { - Log.e(TAG, "ASR worker error: ${e.message}", e) - } finally { - Log.d(TAG, "ASR worker exiting") - } - } - - private fun appendToUi(s: String) { - lastUiText += s - textView.text = lastUiText - } - - /** - * 保存ASR音频用于调试 - */ - private fun saveAsrAudio(originalAudio: FloatArray, processedAudio: FloatArray) { - try { - // 创建保存目录 - val asrAudioDir = File(filesDir, "asr_audio") - if (!asrAudioDir.exists()) { - asrAudioDir.mkdirs() - } - - // 生成唯一的文件名 - val timestamp = System.currentTimeMillis() - - // 保存原始音频 - val originalFile = File(asrAudioDir, "asr_${timestamp}_original.wav") - saveFloatArrayAsWav(originalFile, originalAudio, sampleRateInHz) - Log.d(TAG, "Saved original ASR audio to: ${originalFile.absolutePath}") - - // 保存处理后的音频(增益后) - val processedFile = File(asrAudioDir, "asr_${timestamp}_processed.wav") - saveFloatArrayAsWav(processedFile, processedAudio, sampleRateInHz) - Log.d(TAG, "Saved processed ASR audio to: ${processedFile.absolutePath}") - } catch (e: Exception) { - Log.e(TAG, "Error saving ASR audio: ${e.message}") - } - } - - /** - * 将FloatArray保存为WAV文件 - */ - private fun saveFloatArrayAsWav(file: File, samples: FloatArray, sampleRate: Int) { - FileOutputStream(file).use { fos -> - // WAV文件头 - val header = ByteArray(44) - - // RIFF标识 - header[0] = 'R'.code.toByte() - header[1] = 'I'.code.toByte() - header[2] = 'F'.code.toByte() - header[3] = 'F'.code.toByte() - - // 文件大小(不包括RIFF标识和文件大小字段本身) - val fileSize = 36 + samples.size * 2 - intToByteArray(fileSize, header, 4) - - // WAVE标识 - header[8] = 'W'.code.toByte() - header[9] = 'A'.code.toByte() - header[10] = 'V'.code.toByte() - header[11] = 'E'.code.toByte() - - // fmt标识 - header[12] = 'f'.code.toByte() - header[13] = 'm'.code.toByte() - header[14] = 't'.code.toByte() - header[15] = ' '.code.toByte() - - // 子块大小 - intToByteArray(16, header, 16) - - // 音频格式(1 = PCM) - shortToByteArray(1, header, 20) - - // 声道数(1 = 单声道) - shortToByteArray(1, header, 22) - - // 采样率 - intToByteArray(sampleRate, header, 24) - - // 字节率 = 采样率 * 声道数 * 位深度 / 8 - val byteRate = sampleRate * 1 * 16 / 8 - intToByteArray(byteRate, header, 28) - - // 块对齐 = 声道数 * 位深度 / 8 - val blockAlign = 1 * 16 / 8 - shortToByteArray(blockAlign.toShort(), header, 32) - - // 位深度(16位) - shortToByteArray(16, header, 34) - - // data标识 - header[36] = 'd'.code.toByte() - header[37] = 'a'.code.toByte() - header[38] = 't'.code.toByte() - header[39] = 'a'.code.toByte() - - // 数据大小 - val dataSize = samples.size * 2 - intToByteArray(dataSize, header, 40) - - // 写入文件头 - fos.write(header) - - // 写入音频数据(转换为16位PCM) - for (sample in samples) { - // 确保样本在[-1, 1]范围内 - val clampedSample = sample.coerceIn(-1.0f, 1.0f) - // 转换为16位整数 - val shortSample = (clampedSample * 32767.0f).toInt().toShort() - // 写入小端序 - val bytes = ByteArray(2) - bytes[0] = (shortSample.toInt() and 0xFF).toByte() - bytes[1] = (shortSample.toInt() shr 8 and 0xFF).toByte() - fos.write(bytes) - } - } - } - - /** - * 将int转换为小端序字节数组 - */ - private fun intToByteArray(value: Int, dest: ByteArray, offset: Int) { - dest[offset] = (value and 0xFF).toByte() - dest[offset + 1] = (value shr 8 and 0xFF).toByte() - dest[offset + 2] = (value shr 16 and 0xFF).toByte() - dest[offset + 3] = (value shr 24 and 0xFF).toByte() - } - - /** - * 将short转换为小端序字节数组 - */ - private fun shortToByteArray(value: Short, dest: ByteArray, offset: Int) { - dest[offset] = (value.toInt() and 0xFF).toByte() - dest[offset + 1] = (value.toInt() shr 8 and 0xFF).toByte() + vadManager.forceFinalize() } } \ No newline at end of file diff --git a/app/src/main/java/com/digitalperson/asr/AsrManager.kt b/app/src/main/java/com/digitalperson/asr/AsrManager.kt new file mode 100644 index 0000000..cda741b --- /dev/null +++ b/app/src/main/java/com/digitalperson/asr/AsrManager.kt @@ -0,0 +1,223 @@ +package com.digitalperson.asr + +import android.content.Context +import android.os.SystemClock +import android.util.Log +import com.digitalperson.BuildConfig +import com.digitalperson.audio.AudioProcessor +import com.digitalperson.config.AppConfig +import com.digitalperson.engine.SenseVoiceEngineRKNN +import com.digitalperson.util.FileHelper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.currentCoroutineContext +import kotlinx.coroutines.isActive +import kotlinx.coroutines.withContext +import java.io.File + +class AsrManager(private val context: Context) { + + companion object { + private const val TAG = "AsrManager" + } + + private var senseVoice: SenseVoiceEngineRKNN? = null + private val nativeLock = Any() + + private val asrQueue = Channel>(capacity = Channel.UNLIMITED) + + private var audioProcessor: AudioProcessor? = null + + interface AsrCallback { + fun onAsrStarted() + fun onAsrResult(text: String) + fun onAsrSkipped(reason: String) + fun shouldSkipAsr(): Boolean + fun isLlmInFlight(): Boolean + fun onLlmCalled(text: String) + } + + private var callback: AsrCallback? = null + + fun setCallback(callback: AsrCallback) { + this.callback = callback + } + + fun setAudioProcessor(audioProcessor: AudioProcessor) { + this.audioProcessor = audioProcessor + } + + fun initSenseVoiceModel(): Boolean { + return try { + Log.i(TAG, "ASR: init SenseVoice RKNN (scheme A)") + + val modelDir = FileHelper.copySenseVoiceAssets(context) + val modelPath = File(modelDir, "sense-voice-encoder.rknn").absolutePath + val embeddingPath = File(modelDir, "embedding.npy").absolutePath + val bpePath = File(modelDir, "chn_jpn_yue_eng_ko_spectok.bpe.model").absolutePath + + try { + val libDir = context.applicationInfo.nativeLibraryDir + Log.i(TAG, "nativeLibraryDir=$libDir") + try { + val names = File(libDir).list()?.joinToString(", ") ?: "(empty)" + Log.i(TAG, "nativeLibraryDir files: $names") + } catch (t: Throwable) { + Log.w(TAG, "Failed to list nativeLibraryDir: ${t.message}") + } + } catch (_: Throwable) { + } + + Log.i(TAG, "SenseVoice model paths:") + Log.i(TAG, " model=$modelPath exists=${File(modelPath).exists()} size=${File(modelPath).length()}") + Log.i(TAG, " embedding=$embeddingPath exists=${File(embeddingPath).exists()} size=${File(embeddingPath).length()}") + Log.i(TAG, " bpe=$bpePath exists=${File(bpePath).exists()} size=${File(bpePath).length()}") + + val t0 = SystemClock.elapsedRealtime() + val engine = try { + SenseVoiceEngineRKNN(context) + } catch (e: UnsatisfiedLinkError) { + throw IllegalStateException("Load native libraries failed: ${e.message}", e) + } + + val ok = try { + engine.loadModelDirectly(modelPath, embeddingPath, bpePath) + } catch (t: Throwable) { + throw IllegalStateException("SenseVoice loadModelDirectly crashed: ${t.message}", t) + } + + val dt = SystemClock.elapsedRealtime() - t0 + Log.i(TAG, "SenseVoice loadModelDirectly ok=$ok costMs=$dt") + if (!ok) throw IllegalStateException("SenseVoiceEngineRKNN loadModelDirectly returned false") + + senseVoice = engine + true + } catch (e: Exception) { + Log.e(TAG, "Failed to initialize SenseVoice model: ${e.message}", e) + false + } + } + + fun enqueueAudioSegment(originalAudio: FloatArray, processedAudio: FloatArray) { + try { + asrQueue.trySend(Pair(originalAudio, processedAudio)) + } catch (e: Exception) { + Log.e(TAG, "Failed to enqueue audio segment: ${e.message}") + } + } + + fun clearQueue() { + while (asrQueue.tryReceive().isSuccess) { } + } + + suspend fun runAsrWorker() { + Log.d(TAG, "ASR worker started") + try { + while (currentCoroutineContext().isActive) { + val (originalSeg, processedSeg) = try { + Log.d(TAG, "ASR worker waiting for audio segment") + asrQueue.receive() + } catch (e: Throwable) { + Log.e(TAG, "ASR worker receive failed: ${e.message}") + break + } + + Log.d(TAG, "ASR worker received audio segment, size=${processedSeg.size}") + + if (callback?.shouldSkipAsr() == true || callback?.isLlmInFlight() == true) { + Log.d(TAG, "ASR worker skipping segment: shouldSkip=${callback?.shouldSkipAsr()}, llmInFlight=${callback?.isLlmInFlight()}") + continue + } + + callback?.onAsrStarted() + Log.d(TAG, "ASR started: processing audio segment") + + saveAsrAudio(originalSeg, processedSeg) + + val raw = synchronized(nativeLock) { + val e = senseVoice + if (e == null || !e.isInitialized) { + Log.e(TAG, "ASR failed: SenseVoice engine not initialized") + "" + } else { + try { + e.transcribeBuffer(processedSeg) + } catch (e: Throwable) { + Log.e(TAG, "ASR transcribe failed: ${e.message}") + "" + } + } + } + Log.d(TAG, "ASR raw result: $raw") + val text = removeTokens(raw) + + val filterResult = filterText(text) + if (filterResult != null) { + callback?.onAsrSkipped(filterResult) + continue + } + + callback?.onAsrResult(text) + + if (BuildConfig.LLM_API_KEY.isBlank()) { + Log.w(TAG, "LLM API Key is not configured") + continue + } + + callback?.onLlmCalled(text) + } + } catch (e: Throwable) { + Log.e(TAG, "ASR worker error: ${e.message}", e) + } finally { + Log.d(TAG, "ASR worker exiting") + } + } + + fun release() { + try { + senseVoice?.deinitialize() + } catch (e: Exception) { + Log.e(TAG, "Error deinitializing SenseVoice: ${e.message}") + } + senseVoice = null + clearQueue() + } + + fun isInitialized(): Boolean = senseVoice?.isInitialized ?: false + + private fun saveAsrAudio(originalAudio: FloatArray, processedAudio: FloatArray) { + try { + val timestamp = System.currentTimeMillis() + val asrAudioDir = FileHelper.getAsrAudioDir(context) + + audioProcessor?.let { processor -> + val originalFile = File(asrAudioDir, "asr_${timestamp}_original.wav") + processor.saveAudioAsWav(originalFile, originalAudio, AppConfig.SAMPLE_RATE) + val processedFile = File(asrAudioDir, "asr_${timestamp}_processed.wav") + processor.saveAudioAsWav(processedFile, processedAudio, AppConfig.SAMPLE_RATE) + } + } catch (e: Exception) { + Log.e(TAG, "Error saving ASR audio: ${e.message}") + } + } + + private fun removeTokens(text: String): String { + var cleaned = text.replace(Regex("<\\|[^>]+\\|>"), "") + cleaned = cleaned.replace(Regex("[>>≥≫]"), "") + cleaned = cleaned.trim().replace(Regex("\\s+"), " ") + return cleaned + } + + private fun filterText(text: String): String? { + if (text.isBlank()) { + return "blank text" + } + if (text.length == 1 && text[0].equals('i', ignoreCase = true)) { + return "single 'i'" + } + if (text.length > AppConfig.Asr.MAX_TEXT_LENGTH) { + return "too long (${text.length} chars)" + } + return null + } +} diff --git a/app/src/main/java/com/digitalperson/audio/AudioProcessor.kt b/app/src/main/java/com/digitalperson/audio/AudioProcessor.kt new file mode 100644 index 0000000..dee295d --- /dev/null +++ b/app/src/main/java/com/digitalperson/audio/AudioProcessor.kt @@ -0,0 +1,218 @@ +package com.digitalperson.audio + +import android.Manifest +import android.content.pm.PackageManager +import android.media.AudioFormat +import android.media.AudioRecord +import android.media.MediaRecorder +import android.media.audiofx.AcousticEchoCanceler +import android.media.audiofx.NoiseSuppressor +import android.util.Log +import androidx.core.app.ActivityCompat +import java.io.File +import java.io.FileOutputStream + +private const val TAG = "AudioProcessor" + +class AudioProcessor( + private val context: android.content.Context, + private val sampleRateInHz: Int = 16000, + private val channelConfig: Int = AudioFormat.CHANNEL_IN_MONO, + private val audioFormat: Int = AudioFormat.ENCODING_PCM_16BIT +) { + private val audioSource = MediaRecorder.AudioSource.MIC + private var audioRecord: AudioRecord? = null + private var aec: AcousticEchoCanceler? = null + private var ns: NoiseSuppressor? = null + + private var smoothedRms = 0f + private val alpha = 0.8f + + fun initMicrophone(permissions: Array, requestCode: Int): Boolean { + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) + != PackageManager.PERMISSION_GRANTED + ) { + ActivityCompat.requestPermissions( + context as androidx.appcompat.app.AppCompatActivity, + permissions, + requestCode + ) + return false + } + + val numBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) + audioRecord = AudioRecord( + audioSource, + sampleRateInHz, + channelConfig, + audioFormat, + numBytes * 2 + ) + val sessionId = audioRecord?.audioSessionId ?: 0 + if (sessionId != 0) { + if (AcousticEchoCanceler.isAvailable()) { + aec = AcousticEchoCanceler.create(sessionId)?.apply { + enabled = true + } + Log.i(TAG, "AEC enabled=${aec?.enabled}") + } else { + Log.w(TAG, "AEC not available on this device") + } + + if (NoiseSuppressor.isAvailable()) { + ns = NoiseSuppressor.create(sessionId)?.apply { + enabled = true + } + Log.i(TAG, "NS enabled=${ns?.enabled}") + } else { + Log.w(TAG, "NS not available on this device") + } + } + return true + } + + fun startRecording() { + audioRecord?.startRecording() + Log.d(TAG, "Audio recording started") + } + + fun stopRecording() { + try { + audioRecord?.stop() + } catch (_: Throwable) { + } + Log.d(TAG, "Audio recording stopped") + } + + fun release() { + try { + audioRecord?.stop() + } catch (_: Throwable) { + } + try { + audioRecord?.release() + } catch (_: Throwable) { + } + audioRecord = null + + try { + aec?.release() + } catch (_: Throwable) { + } + try { + ns?.release() + } catch (_: Throwable) { + } + aec = null + ns = null + + Log.d(TAG, "AudioProcessor released") + } + + fun readAudio(buffer: ShortArray): Int { + return audioRecord?.read(buffer, 0, buffer.size) ?: -1 + } + + fun calculateRMS(samples: FloatArray): Float { + if (samples.isEmpty()) return 0.0f + + var sumSquared = 0.0f + for (sample in samples) { + sumSquared += sample * sample + } + + val meanSquared = sumSquared / samples.size + return kotlin.math.sqrt(meanSquared) + } + + fun applyGain(chunk: FloatArray, targetRMS: Float = 0.1f): FloatArray { + val rms = calculateRMS(chunk) + + smoothedRms = if (smoothedRms == 0f) rms else alpha * rms + (1 - alpha) * smoothedRms + + var gainFactor = if (smoothedRms > 0) targetRMS / smoothedRms else 3.0f + gainFactor = gainFactor.coerceIn(0.1f, 10.0f) + + val processedChunk = FloatArray(chunk.size) { + val value = chunk[it] * gainFactor + if (value > 1.0f) 1.0f else if (value < -1.0f) -1.0f else value + } + + return processedChunk + } + + fun convertShortToFloat(buffer: ShortArray): FloatArray { + return FloatArray(buffer.size) { buffer[it] / 32768.0f } + } + + fun saveAudioAsWav(file: File, samples: FloatArray, sampleRate: Int) { + FileOutputStream(file).use { fos -> + val header = ByteArray(44) + + header[0] = 'R'.code.toByte() + header[1] = 'I'.code.toByte() + header[2] = 'F'.code.toByte() + header[3] = 'F'.code.toByte() + + val fileSize = 36 + samples.size * 2 + intToByteArray(fileSize, header, 4) + + header[8] = 'W'.code.toByte() + header[9] = 'A'.code.toByte() + header[10] = 'V'.code.toByte() + header[11] = 'E'.code.toByte() + + header[12] = 'f'.code.toByte() + header[13] = 'm'.code.toByte() + header[14] = 't'.code.toByte() + header[15] = ' '.code.toByte() + + intToByteArray(16, header, 16) + + shortToByteArray(1, header, 20) + + shortToByteArray(1, header, 22) + + intToByteArray(sampleRate, header, 24) + + val byteRate = sampleRate * 1 * 16 / 8 + intToByteArray(byteRate, header, 28) + + val blockAlign = 1 * 16 / 8 + shortToByteArray(blockAlign.toShort(), header, 32) + + shortToByteArray(16, header, 34) + + header[36] = 'd'.code.toByte() + header[37] = 'a'.code.toByte() + header[38] = 't'.code.toByte() + header[39] = 'a'.code.toByte() + + val dataSize = samples.size * 2 + intToByteArray(dataSize, header, 40) + + fos.write(header) + + for (sample in samples) { + val clampedSample = sample.coerceIn(-1.0f, 1.0f) + val shortSample = (clampedSample * 32767.0f).toInt().toShort() + val bytes = ByteArray(2) + bytes[0] = (shortSample.toInt() and 0xFF).toByte() + bytes[1] = (shortSample.toInt() shr 8 and 0xFF).toByte() + fos.write(bytes) + } + } + } + + private fun intToByteArray(value: Int, dest: ByteArray, offset: Int) { + dest[offset] = (value and 0xFF).toByte() + dest[offset + 1] = (value shr 8 and 0xFF).toByte() + dest[offset + 2] = (value shr 16 and 0xFF).toByte() + dest[offset + 3] = (value shr 24 and 0xFF).toByte() + } + + private fun shortToByteArray(value: Short, dest: ByteArray, offset: Int) { + dest[offset] = (value.toInt() and 0xFF).toByte() + dest[offset + 1] = (value.toInt() shr 8 and 0xFF).toByte() + } +} diff --git a/app/src/main/java/com/digitalperson/config/AppConfig.kt b/app/src/main/java/com/digitalperson/config/AppConfig.kt new file mode 100644 index 0000000..bfd7da9 --- /dev/null +++ b/app/src/main/java/com/digitalperson/config/AppConfig.kt @@ -0,0 +1,50 @@ +package com.digitalperson.config + +import com.digitalperson.BuildConfig + +object AppConfig { + const val TAG = "DigitalPerson" + const val REQUEST_RECORD_AUDIO_PERMISSION = 200 + + const val SAMPLE_RATE = 16000 + const val WINDOW_SIZE = 512 + + const val SHOW_DEBUG_TEXT = true + + object Tts { + const val MODEL_DIR = "tts_model/sherpa-onnx-vits-zh-ll" + const val MODEL_NAME = "model.onnx" + const val LEXICON = "lexicon.txt" + const val SPEAKER_ID = 2 + const val SPEED = 1.0f + const val MAX_LEN = 30 + const val MAX_WAIT_MS: Long = 600 + } + + object Vad { + const val START_THRESHOLD = 0.2f + const val END_THRESHOLD = 0.15f + const val MIN_SILENCE_DURATION = 0.5f + const val MIN_SPEECH_DURATION = 0.1f + const val MAX_SPEECH_DURATION = 5.0f + } + + object Asr { + const val MAX_TEXT_LENGTH = 50 + const val MODEL_DIR = "sensevoice_models" + } + + object Audio { + const val GAIN_SMOOTHING_FACTOR = 0.1f + const val TARGET_RMS = 0.1f + } + + object Avatar { + // Compile-time switch in gradle.properties/local.properties: USE_LIVE2D=true|false + const val USE_LIVE2D = BuildConfig.USE_LIVE2D + // const val MODEL_DIR = "live2d_model/mao_pro_zh" + // const val MODEL_JSON = "mao_pro.model3.json" + const val MODEL_DIR = "live2d_model/Haru_pro_jp" + const val MODEL_JSON = "haru_greeter_t05.model3.json" + } +} diff --git a/app/src/main/java/com/digitalperson/live2d/Live2DAvatarManager.kt b/app/src/main/java/com/digitalperson/live2d/Live2DAvatarManager.kt new file mode 100644 index 0000000..3e10edd --- /dev/null +++ b/app/src/main/java/com/digitalperson/live2d/Live2DAvatarManager.kt @@ -0,0 +1,29 @@ +package com.digitalperson.live2d + +import android.opengl.GLSurfaceView + +class Live2DAvatarManager(private val glSurfaceView: GLSurfaceView) { + private val renderer = Live2DRenderer(glSurfaceView.context) + + init { + glSurfaceView.setEGLContextClientVersion(2) + glSurfaceView.setRenderer(renderer) + glSurfaceView.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY + } + + fun setSpeaking(speaking: Boolean) { + renderer.setSpeaking(speaking) + } + + fun onResume() { + glSurfaceView.onResume() + } + + fun onPause() { + glSurfaceView.onPause() + } + + fun release() { + renderer.release() + } +} diff --git a/app/src/main/java/com/digitalperson/live2d/Live2DCharacter.kt b/app/src/main/java/com/digitalperson/live2d/Live2DCharacter.kt new file mode 100644 index 0000000..161c155 --- /dev/null +++ b/app/src/main/java/com/digitalperson/live2d/Live2DCharacter.kt @@ -0,0 +1,182 @@ +package com.digitalperson.live2d + +import android.content.res.AssetManager +import android.graphics.BitmapFactory +import android.opengl.GLES20 +import android.opengl.GLUtils +import com.live2d.sdk.cubism.framework.CubismFramework +import com.live2d.sdk.cubism.framework.CubismModelSettingJson +import com.live2d.sdk.cubism.framework.id.CubismId +import com.live2d.sdk.cubism.framework.math.CubismMatrix44 +import com.live2d.sdk.cubism.framework.model.CubismUserModel +import com.live2d.sdk.cubism.framework.motion.CubismMotion +import com.live2d.sdk.cubism.framework.rendering.android.CubismRendererAndroid +import kotlin.math.sin + +class Live2DCharacter : CubismUserModel() { + private lateinit var setting: CubismModelSettingJson + private val lipSyncParams = mutableListOf() + private val idleMotions = mutableListOf() + private var idleMotionIndex = 0 + private var lastElapsedSec = 0f + private val textureIds = mutableListOf() + + fun loadFromAssets(assets: AssetManager, modelDir: String, modelJsonName: String) { + val settingBytes = readAssetBytes(assets, "$modelDir/$modelJsonName") + setting = CubismModelSettingJson(settingBytes) + + loadModel(readAssetBytes(assets, "$modelDir/${setting.modelFileName}")) + setupRenderer(CubismRendererAndroid.create()) + getModelMatrix().setWidth(2.0f) + getModelMatrix().setCenterPosition(0f, 0f) + + val physicsFile = setting.physicsFileName + if (physicsFile.isNotEmpty()) { + loadPhysics(readAssetBytes(assets, "$modelDir/$physicsFile")) + } + val poseFile = setting.poseFileName + if (poseFile.isNotEmpty()) { + loadPose(readAssetBytes(assets, "$modelDir/$poseFile")) + } + + initLipSyncParams() + loadIdleMotions(assets, modelDir) + startNextIdleMotion() + } + + fun bindTextures(assets: AssetManager, modelDir: String) { + val renderer = getRenderer() + renderer.isPremultipliedAlpha(true) + renderer.isUsingHighPrecisionMask(true) + textureIds.forEach { id -> + GLES20.glDeleteTextures(1, intArrayOf(id), 0) + } + textureIds.clear() + + for (i in 0 until setting.textureCount) { + val texturePath = "$modelDir/${setting.getTextureFileName(i)}" + val texId = loadTexture(assets, texturePath) + renderer.bindTexture(i, texId) + textureIds.add(texId) + } + } + + fun updateFrame(elapsedSec: Float, speaking: Boolean) { + val model = getModel() ?: return + val dt = (elapsedSec - lastElapsedSec).coerceAtLeast(0f).coerceAtMost(0.1f) + lastElapsedSec = elapsedSec + + // Keep motions running. If finished, continue idle loop. + motionManager.updateMotion(model, dt) + if (motionManager.isFinished()) { + startNextIdleMotion() + } + + val mouth = if (speaking) { + 0.2f + 0.35f * ((sin(elapsedSec * 14.0f) + 1.0f) * 0.5f) + } else { + 0.0f + } + + // Apply lip-sync to model-defined LipSync params (this model uses ParamA). + for (id in lipSyncParams) { + model.setParameterValue(id, mouth, 0.8f) + } + + // Add small idle breathing/sway on top, so character is never "frozen". + val sway = sin(elapsedSec * 0.8f) + val breathe = sin(elapsedSec * 1.2f) + model.addParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), sway * 8f, 0.2f) + model.addParameterValue(CubismFramework.getIdManager().getId("ParamAngleY"), sin(elapsedSec * 0.6f) * 4f, 0.2f) + model.addParameterValue(CubismFramework.getIdManager().getId("ParamBodyAngleX"), sway * 6f, 0.15f) + model.addParameterValue(CubismFramework.getIdManager().getId("ParamBreath"), (breathe + 1f) * 0.5f, 0.1f) + + physics?.evaluate(model, dt) + pose?.updateParameters(model, dt) + model.update() + } + + fun draw(mvp: CubismMatrix44) { + val renderer = getRenderer() + renderer.setMvpMatrix(mvp) + renderer.drawModel() + } + + fun release() { + textureIds.forEach { id -> + GLES20.glDeleteTextures(1, intArrayOf(id), 0) + } + textureIds.clear() + delete() + } + + private fun loadTexture(assets: AssetManager, path: String): Int { + val bitmap = assets.open(path).use { stream -> + BitmapFactory.decodeStream(stream) + } ?: error("Decode texture failed: $path") + + val ids = IntArray(1) + GLES20.glGenTextures(1, ids, 0) + val textureId = ids[0] + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId) + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR) + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR) + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE) + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE) + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0) + bitmap.recycle() + return textureId + } + + private fun readAssetBytes(assets: AssetManager, path: String): ByteArray { + return assets.open(path).use { input -> + input.readBytes() + } + } + + private fun initLipSyncParams() { + lipSyncParams.clear() + for (i in 0 until setting.lipSyncParameterCount) { + lipSyncParams.add(setting.getLipSyncParameterId(i)) + } + if (lipSyncParams.isEmpty()) { + lipSyncParams.add(CubismFramework.getIdManager().getId("ParamA")) + lipSyncParams.add(CubismFramework.getIdManager().getId("ParamMouthOpenY")) + } + } + + private fun loadIdleMotions(assets: AssetManager, modelDir: String) { + idleMotions.clear() + val groupName = findIdleGroupName() + if (groupName.isEmpty()) return + + for (i in 0 until setting.getMotionCount(groupName)) { + val fileName = setting.getMotionFileName(groupName, i) + if (fileName.isBlank()) continue + runCatching { + val motion = loadMotion(readAssetBytes(assets, "$modelDir/$fileName")) + motion?.setLoop(true) + motion?.setLoopFadeIn(true) + if (motion != null) idleMotions.add(motion) + } + } + } + + private fun startNextIdleMotion() { + if (idleMotions.isEmpty()) return + val index = idleMotionIndex % idleMotions.size + idleMotionIndex++ + motionManager.startMotionPriority(idleMotions[index], 1) + } + + private fun findIdleGroupName(): String { + for (i in 0 until setting.motionGroupCount) { + val name = setting.getMotionGroupName(i) + if (name.equals("Idle", ignoreCase = true)) return name + } + if (setting.motionGroupCount > 0) { + return setting.getMotionGroupName(0) ?: "" + } + return "" + } +} diff --git a/app/src/main/java/com/digitalperson/live2d/Live2DRenderer.kt b/app/src/main/java/com/digitalperson/live2d/Live2DRenderer.kt new file mode 100644 index 0000000..a061e2c --- /dev/null +++ b/app/src/main/java/com/digitalperson/live2d/Live2DRenderer.kt @@ -0,0 +1,78 @@ +package com.digitalperson.live2d + +import android.content.Context +import android.opengl.GLES20 +import android.opengl.GLSurfaceView +import android.os.SystemClock +import android.util.Log +import com.digitalperson.config.AppConfig +import com.live2d.sdk.cubism.framework.CubismFramework +import com.live2d.sdk.cubism.framework.math.CubismMatrix44 +import javax.microedition.khronos.egl.EGLConfig +import javax.microedition.khronos.opengles.GL10 + +class Live2DRenderer( + private val context: Context +) : GLSurfaceView.Renderer { + @Volatile + private var speaking = false + + private var character: Live2DCharacter? = null + private val mvp = CubismMatrix44.create() + private var startTimeMs: Long = 0L + + override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { + GLES20.glClearColor(0f, 0f, 0f, 0f) + ensureFrameworkInitialized() + startTimeMs = SystemClock.elapsedRealtime() + + runCatching { + val model = Live2DCharacter() + model.loadFromAssets( + assets = context.assets, + modelDir = AppConfig.Avatar.MODEL_DIR, + modelJsonName = AppConfig.Avatar.MODEL_JSON + ) + model.bindTextures(context.assets, AppConfig.Avatar.MODEL_DIR) + character = model + }.onFailure { + Log.e(AppConfig.TAG, "Load Live2D model failed: ${it.message}", it) + character = null + } + } + + override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { + GLES20.glViewport(0, 0, width, height) + mvp.loadIdentity() + if (width > height) { + mvp.scale(1f, width.toFloat() / height.toFloat()) + } else { + mvp.scale(height.toFloat() / width.toFloat(), 1f) + } + } + + override fun onDrawFrame(gl: GL10?) { + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT) + val elapsedSec = (SystemClock.elapsedRealtime() - startTimeMs) / 1000f + character?.updateFrame(elapsedSec = elapsedSec, speaking = speaking) + character?.draw(mvp) + } + + fun setSpeaking(speaking: Boolean) { + this.speaking = speaking + } + + fun release() { + character?.release() + character = null + } + + private fun ensureFrameworkInitialized() { + if (!CubismFramework.isStarted()) { + CubismFramework.startUp(CubismFramework.Option()) + } + if (!CubismFramework.isInitialized()) { + CubismFramework.initialize() + } + } +} diff --git a/app/src/main/java/com/digitalperson/player/VideoPlayerManager.kt b/app/src/main/java/com/digitalperson/player/VideoPlayerManager.kt index 952f8cd..fdb8870 100644 --- a/app/src/main/java/com/digitalperson/player/VideoPlayerManager.kt +++ b/app/src/main/java/com/digitalperson/player/VideoPlayerManager.kt @@ -17,7 +17,7 @@ class VideoPlayerManager( private var playerSilent: ExoPlayer? = null private var playerSpeaking: ExoPlayer? = null private var currentState: Boolean = false - private var transitionDuration = 300L // 淡入淡出时长 + private var transitionDuration = 100L // 淡入淡出时长 init { // 确保初始 alpha diff --git a/app/src/main/java/com/digitalperson/tts/TtsManager.kt b/app/src/main/java/com/digitalperson/tts/TtsManager.kt new file mode 100644 index 0000000..27ca843 --- /dev/null +++ b/app/src/main/java/com/digitalperson/tts/TtsManager.kt @@ -0,0 +1,293 @@ +package com.digitalperson.tts + +import android.content.Context +import android.media.AudioAttributes +import android.media.AudioFormat +import android.media.AudioManager +import android.media.AudioTrack +import android.util.Log +import android.widget.Toast +import com.digitalperson.config.AppConfig +import com.digitalperson.metrics.TraceManager +import com.digitalperson.metrics.TraceSession +import com.k2fsa.sherpa.onnx.OfflineTts +import com.k2fsa.sherpa.onnx.getOfflineTtsConfig +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.atomic.AtomicBoolean + +class TtsManager(private val context: Context) { + + companion object { + private const val TAG = "TtsManager" + } + + private var tts: OfflineTts? = null + private var track: AudioTrack? = null + + private sealed class TtsQueueItem { + data class Segment(val text: String) : TtsQueueItem() + data object End : TtsQueueItem() + } + + private val ttsQueue = LinkedBlockingQueue() + private val ttsStopped = AtomicBoolean(false) + private val ttsWorkerRunning = AtomicBoolean(false) + private val ttsPlaying = AtomicBoolean(false) + @Volatile private var ttsTotalSamplesWritten: Long = 0 + + private var currentTrace: TraceSession? = null + private val ioScope = CoroutineScope(Dispatchers.IO) + + interface TtsCallback { + fun onTtsStarted(text: String) + fun onTtsCompleted() + fun onTtsSegmentCompleted(durationMs: Long) + fun isTtsStopped(): Boolean + fun onClearAsrQueue() + fun onSetSpeaking(speaking: Boolean) + fun getCurrentTrace(): TraceSession? + fun onTraceMarkTtsRequestEnqueued() + fun onTraceMarkTtsSynthesisStart() + fun onTraceMarkTtsFirstPcmReady() + fun onTraceMarkTtsFirstAudioPlay() + fun onTraceMarkTtsDone() + fun onTraceAddDuration(name: String, value: Long) + fun onEndTurn() + } + + private var callback: TtsCallback? = null + + fun setCallback(callback: TtsCallback) { + this.callback = callback + } + + fun initTtsAndAudioTrack(): Boolean { + return try { + val modelDir = AppConfig.Tts.MODEL_DIR + val modelName = AppConfig.Tts.MODEL_NAME + val lexicon = AppConfig.Tts.LEXICON + val dataDir = "" + + val ttsConfig = getOfflineTtsConfig( + modelDir = modelDir, + modelName = modelName, + acousticModelName = "", + vocoder = "", + voices = "", + lexicon = lexicon, + dataDir = dataDir, + dictDir = "", + ruleFsts = "$modelDir/phone.fst,$modelDir/date.fst,$modelDir/number.fst,$modelDir/new_heteronym.fst", + ruleFars = "", + numThreads = null, + isKitten = false + ) + tts = OfflineTts(assetManager = context.assets, config = ttsConfig) + + initAudioTrack() + true + } catch (t: Throwable) { + Log.e(TAG, "Init TTS failed: ${t.message}", t) + tts = null + false + } + } + + private fun initAudioTrack() { + val t = tts ?: return + val sr = t.sampleRate() + val bufLength = AudioTrack.getMinBufferSize( + sr, + AudioFormat.CHANNEL_OUT_MONO, + AudioFormat.ENCODING_PCM_FLOAT + ) + val attr = AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) + .setUsage(AudioAttributes.USAGE_MEDIA) + .build() + val format = AudioFormat.Builder() + .setEncoding(AudioFormat.ENCODING_PCM_FLOAT) + .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) + .setSampleRate(sr) + .build() + track = AudioTrack( + attr, + format, + bufLength, + AudioTrack.MODE_STREAM, + AudioManager.AUDIO_SESSION_ID_GENERATE + ) + track?.play() + } + + fun enqueueSegment(seg: String) { + val cleanedSeg = seg.trimEnd('.', '。', '!', '!', '?', '?', ',', ',', ';', ';', ':', ':') + + callback?.onTraceMarkTtsRequestEnqueued() + ttsQueue.offer(TtsQueueItem.Segment(cleanedSeg)) + ensureTtsWorker() + } + + fun enqueueEnd() { + ttsQueue.offer(TtsQueueItem.End) + } + + fun isPlaying(): Boolean = ttsPlaying.get() + + fun reset() { + ttsStopped.set(false) + ttsPlaying.set(false) + ttsTotalSamplesWritten = 0 + ttsQueue.clear() + } + + fun stop() { + ttsStopped.set(true) + ttsPlaying.set(false) + ttsTotalSamplesWritten = 0 + ttsQueue.clear() + ttsQueue.offer(TtsQueueItem.End) + + try { + track?.pause() + track?.flush() + } catch (_: Throwable) { + } + } + + fun release() { + try { + tts?.release() + } catch (_: Throwable) { + } + try { + track?.release() + } catch (_: Throwable) { + } + tts = null + track = null + } + + fun setCurrentTrace(trace: TraceSession?) { + currentTrace = trace + } + + private fun ensureTtsWorker() { + if (!ttsWorkerRunning.compareAndSet(false, true)) return + ioScope.launch { + try { + runTtsWorker() + } finally { + ttsWorkerRunning.set(false) + } + } + } + + private fun runTtsWorker() { + val t = tts ?: return + val audioTrack = track ?: return + + var firstAudioMarked = false + var isFirstSegment = true + while (true) { + val item = ttsQueue.take() + if (ttsStopped.get()) break + + when (item) { + is TtsQueueItem.Segment -> { + ttsPlaying.set(true) + callback?.onSetSpeaking(true) + val trace = currentTrace + trace?.markTtsSynthesisStart() + callback?.onTraceMarkTtsSynthesisStart() + Log.d(TAG, "TTS started: processing segment '${item.text}'") + callback?.onTtsStarted(item.text) + + val startMs = System.currentTimeMillis() + var firstPcmMarked = false + + if (isFirstSegment) { + try { + audioTrack.pause() + audioTrack.flush() + audioTrack.play() + } catch (_: Throwable) { + } + isFirstSegment = false + } + + t.generateWithCallback( + text = item.text, + sid = AppConfig.Tts.SPEAKER_ID, + speed = AppConfig.Tts.SPEED + ) { samples -> + if (ttsStopped.get()) return@generateWithCallback 0 + if (!firstPcmMarked && samples.isNotEmpty()) { + firstPcmMarked = true + trace?.markTtsFirstPcmReady() + callback?.onTraceMarkTtsFirstPcmReady() + } + if (!firstAudioMarked && samples.isNotEmpty()) { + firstAudioMarked = true + trace?.markTtsFirstAudioPlay() + callback?.onTraceMarkTtsFirstAudioPlay() + } + audioTrack.write(samples, 0, samples.size, AudioTrack.WRITE_BLOCKING) + ttsTotalSamplesWritten += samples.size + 1 + } + + val ttsMs = System.currentTimeMillis() - startMs + trace?.addDuration("tts_segment_ms_total", ttsMs) + callback?.onTraceAddDuration("tts_segment_ms_total", ttsMs) + callback?.onTtsSegmentCompleted(ttsMs) + } + + TtsQueueItem.End -> { + callback?.onClearAsrQueue() + + waitForPlaybackComplete(audioTrack) + + callback?.onTtsCompleted() + + ttsPlaying.set(false) + callback?.onSetSpeaking(false) + ttsTotalSamplesWritten = 0 + currentTrace?.markTtsDone() + callback?.onTraceMarkTtsDone() + callback?.onEndTurn() + break + } + } + } + } + + private fun waitForPlaybackComplete(audioTrack: AudioTrack) { + val totalSamples = ttsTotalSamplesWritten + if (totalSamples <= 0) return + + val sampleRate = audioTrack.sampleRate + val timeoutMs = (totalSamples * 1000 / sampleRate) + 2000 + val startTime = System.currentTimeMillis() + + while (true) { + if (ttsStopped.get()) break + + val playbackPos = audioTrack.playbackHeadPosition.toLong() + if (playbackPos >= totalSamples) { + break + } + + if (System.currentTimeMillis() - startTime > timeoutMs) { + Log.w(TAG, "waitForPlaybackComplete timeout, pos=$playbackPos, total=$totalSamples") + break + } + + Thread.sleep(20) + } + Thread.sleep(1000) + } +} diff --git a/app/src/main/java/com/digitalperson/ui/Live2DUiManager.kt b/app/src/main/java/com/digitalperson/ui/Live2DUiManager.kt new file mode 100644 index 0000000..b9872c9 --- /dev/null +++ b/app/src/main/java/com/digitalperson/ui/Live2DUiManager.kt @@ -0,0 +1,95 @@ +package com.digitalperson.ui + +import android.app.Activity +import android.opengl.GLSurfaceView +import android.text.method.ScrollingMovementMethod +import android.widget.Button +import android.widget.ScrollView +import android.widget.TextView +import android.widget.Toast +import com.digitalperson.live2d.Live2DAvatarManager + +class Live2DUiManager(private val activity: Activity) { + private var textView: TextView? = null + private var scrollView: ScrollView? = null + private var startButton: Button? = null + private var stopButton: Button? = null + private var avatarManager: Live2DAvatarManager? = null + + private var lastUiText: String = "" + + fun initViews( + textViewId: Int, + scrollViewId: Int, + startButtonId: Int, + stopButtonId: Int, + silentPlayerViewId: Int, + speakingPlayerViewId: Int, + live2dViewId: Int + ) { + textView = activity.findViewById(textViewId) + scrollView = activity.findViewById(scrollViewId) + startButton = activity.findViewById(startButtonId) + stopButton = activity.findViewById(stopButtonId) + + textView?.movementMethod = ScrollingMovementMethod() + + val glView = activity.findViewById(live2dViewId) + avatarManager = Live2DAvatarManager(glView) + avatarManager?.setSpeaking(false) + } + + fun setStartButtonListener(listener: () -> Unit) { + startButton?.setOnClickListener { listener() } + } + + fun setStopButtonListener(listener: () -> Unit) { + stopButton?.setOnClickListener { listener() } + } + + fun appendToUi(s: String) { + lastUiText += s + textView?.text = lastUiText + scrollView?.post { scrollView?.fullScroll(ScrollView.FOCUS_DOWN) } + } + + fun clearText() { + lastUiText = "" + textView?.text = "" + } + + fun setText(text: String) { + lastUiText = text + textView?.text = text + } + + fun setButtonsEnabled(startEnabled: Boolean, stopEnabled: Boolean) { + startButton?.isEnabled = startEnabled + stopButton?.isEnabled = stopEnabled + } + + fun setSpeaking(speaking: Boolean) { + activity.runOnUiThread { + avatarManager?.setSpeaking(speaking) + } + } + + fun showToast(message: String, duration: Int = Toast.LENGTH_SHORT) { + activity.runOnUiThread { + Toast.makeText(activity, message, duration).show() + } + } + + fun onResume() { + avatarManager?.onResume() + } + + fun onPause() { + avatarManager?.onPause() + } + + fun release() { + avatarManager?.release() + avatarManager = null + } +} diff --git a/app/src/main/java/com/digitalperson/ui/UiManager.kt b/app/src/main/java/com/digitalperson/ui/UiManager.kt new file mode 100644 index 0000000..baececd --- /dev/null +++ b/app/src/main/java/com/digitalperson/ui/UiManager.kt @@ -0,0 +1,106 @@ +package com.digitalperson.ui + +import android.app.Activity +import android.text.method.ScrollingMovementMethod +import android.util.Log +import android.widget.Button +import android.widget.ScrollView +import android.widget.TextView +import android.widget.Toast +import com.digitalperson.config.AppConfig +import com.digitalperson.player.VideoPlayerManager +import com.google.android.exoplayer2.ui.PlayerView + +class UiManager(private val activity: Activity) { + + private var textView: TextView? = null + private var scrollView: ScrollView? = null + private var startButton: Button? = null + private var stopButton: Button? = null + private var videoPlayerManager: VideoPlayerManager? = null + + private var lastUiText: String = "" + + fun initViews( + textViewId: Int, + scrollViewId: Int, + startButtonId: Int, + stopButtonId: Int, + silentPlayerViewId: Int, + speakingPlayerViewId: Int + ) { + textView = activity.findViewById(textViewId) + scrollView = activity.findViewById(scrollViewId) + startButton = activity.findViewById(startButtonId) + stopButton = activity.findViewById(stopButtonId) + + textView?.movementMethod = ScrollingMovementMethod() + + try { + val silentPv = activity.findViewById(silentPlayerViewId) + val speakingPv = activity.findViewById(speakingPlayerViewId) + videoPlayerManager = VideoPlayerManager(activity, silentPv, speakingPv) + videoPlayerManager?.setSpeaking(false) + } catch (e: Exception) { + Log.w(AppConfig.TAG, "PlayerViews not found or init failed: ${e.message}") + } + } + + fun setStartButtonListener(listener: () -> Unit) { + startButton?.setOnClickListener { listener() } + } + + fun setStopButtonListener(listener: () -> Unit) { + stopButton?.setOnClickListener { listener() } + } + + fun appendToUi(s: String) { + if (!AppConfig.SHOW_DEBUG_TEXT) return + + lastUiText += s + textView?.text = lastUiText + scrollView?.post { + scrollView?.fullScroll(ScrollView.FOCUS_DOWN) + } + } + + fun clearText() { + lastUiText = "" + textView?.text = "" + } + + fun setText(text: String) { + lastUiText = text + textView?.text = text + } + + fun setButtonsEnabled(startEnabled: Boolean, stopEnabled: Boolean) { + startButton?.isEnabled = startEnabled + stopButton?.isEnabled = stopEnabled + } + + fun setSpeaking(speaking: Boolean) { + activity.runOnUiThread { + videoPlayerManager?.setSpeaking(speaking) + } + } + + fun showToast(message: String, duration: Int = Toast.LENGTH_SHORT) { + activity.runOnUiThread { + Toast.makeText(activity, message, duration).show() + } + } + + fun showToastOnUi(message: String, duration: Int = Toast.LENGTH_SHORT) { + Toast.makeText(activity, message, duration).show() + } + + fun release() { + videoPlayerManager?.release() + videoPlayerManager = null + } + + fun reset() { + lastUiText = "" + } +} diff --git a/app/src/main/java/com/digitalperson/util/FileHelper.kt b/app/src/main/java/com/digitalperson/util/FileHelper.kt new file mode 100644 index 0000000..017918f --- /dev/null +++ b/app/src/main/java/com/digitalperson/util/FileHelper.kt @@ -0,0 +1,60 @@ +package com.digitalperson.util + +import android.content.Context +import android.util.Log +import com.digitalperson.config.AppConfig +import java.io.File +import java.io.FileOutputStream + +object FileHelper { + private const val TAG = AppConfig.TAG + + fun assetExists(context: Context, path: String): Boolean { + return try { + context.assets.open(path).close() + true + } catch (_: Throwable) { + false + } + } + + fun copyAssetsToInternal(context: Context, assetDir: String, targetDir: File, files: Array): File { + if (!targetDir.exists()) targetDir.mkdirs() + + for (name in files) { + val assetPath = "$assetDir/$name" + val outFile = File(targetDir, name) + if (outFile.exists() && outFile.length() > 0) continue + try { + context.assets.open(assetPath).use { input -> + FileOutputStream(outFile).use { output -> + input.copyTo(output) + } + } + } catch (e: Exception) { + Log.e(TAG, "Failed to copy asset $assetPath: ${e.message}") + } + } + return targetDir + } + + fun copySenseVoiceAssets(context: Context): File { + val outDir = File(context.filesDir, AppConfig.Asr.MODEL_DIR) + val files = arrayOf( + "am.mvn", + "chn_jpn_yue_eng_ko_spectok.bpe.model", + "embedding.npy", + "sense-voice-encoder.rknn" + ) + return copyAssetsToInternal(context, AppConfig.Asr.MODEL_DIR, outDir, files) + } + + fun ensureDir(dir: File): File { + if (!dir.exists()) dir.mkdirs() + return dir + } + + fun getAsrAudioDir(context: Context): File { + return ensureDir(File(context.filesDir, "asr_audio")) + } +} diff --git a/app/src/main/java/com/digitalperson/vad/VadManager.kt b/app/src/main/java/com/digitalperson/vad/VadManager.kt new file mode 100644 index 0000000..33c2cf7 --- /dev/null +++ b/app/src/main/java/com/digitalperson/vad/VadManager.kt @@ -0,0 +1,216 @@ +package com.digitalperson.vad + +import android.content.Context +import android.util.Log +import com.digitalperson.config.AppConfig +import com.k2fsa.sherpa.onnx.SileroVadModelConfig +import com.k2fsa.sherpa.onnx.Vad +import com.k2fsa.sherpa.onnx.VadModelConfig +import java.io.File +import kotlin.math.max + +class VadManager(private val context: Context) { + + companion object { + private const val TAG = "VadManager" + } + + private var vad: Vad? = null + private val nativeLock = Any() + + private var inSpeech = false + private var silenceSamples = 0 + private var speechBuf = FloatArray(0) + private var speechLen = 0 + private var processedSpeechBuf = FloatArray(0) + private var processedSpeechLen = 0 + + private val minSilenceSamples = (AppConfig.Vad.MIN_SILENCE_DURATION * AppConfig.SAMPLE_RATE).toInt() + private val minSpeechSamples = (AppConfig.Vad.MIN_SPEECH_DURATION * AppConfig.SAMPLE_RATE).toInt() + private val maxSpeechSamples = (AppConfig.Vad.MAX_SPEECH_DURATION * AppConfig.SAMPLE_RATE).toInt() + + var vadComputeCount = 0 + private set + + interface VadCallback { + fun onSpeechSegmentReady(originalAudio: FloatArray, processedAudio: FloatArray) + fun shouldSkipProcessing(): Boolean + } + + private var callback: VadCallback? = null + + fun setCallback(callback: VadCallback) { + this.callback = callback + } + + fun initVadModel(): Boolean { + return try { + val config = VadModelConfig( + sileroVadModelConfig = SileroVadModelConfig( + model = "vad_model/silero_vad.onnx", + threshold = 0.5F, + minSilenceDuration = 0.25F, + minSpeechDuration = 0.25F, + windowSize = AppConfig.WINDOW_SIZE, + ), + sampleRate = AppConfig.SAMPLE_RATE, + numThreads = 1, + provider = "cpu", + ) + vad = Vad(assetManager = context.assets, config = config) + Log.i(TAG, "VAD model initialized successfully") + true + } catch (e: Exception) { + Log.e(TAG, "Failed to initialize VAD model: ${e.message}", e) + false + } + } + + fun reset() { + vad?.reset() + inSpeech = false + silenceSamples = 0 + speechLen = 0 + processedSpeechLen = 0 + vadComputeCount = 0 + } + + fun release() { + try { + vad?.release() + } catch (e: Exception) { + Log.e(TAG, "Error releasing VAD: ${e.message}") + } + vad = null + } + + fun processAudioChunk(chunk: FloatArray, processedChunk: FloatArray): VadResult { + val prob = synchronized(nativeLock) { + vad?.compute(processedChunk) ?: 0f + } + vadComputeCount++ + + val result = when { + !inSpeech && prob >= AppConfig.Vad.START_THRESHOLD -> { + inSpeech = true + silenceSamples = 0 + appendSpeech(chunk, processedChunk) + Log.d(TAG, "VAD: Entered speech state, prob=$prob, speechLen=$speechLen") + VadResult.SpeechStarted(prob) + } + inSpeech && prob <= AppConfig.Vad.END_THRESHOLD -> { + silenceSamples += chunk.size + if (silenceSamples >= minSilenceSamples) { + Log.d(TAG, "VAD: Exiting speech state, prob=$prob, silenceSamples=$silenceSamples, speechLen=$speechLen") + finalizeSegmentIfAny() + VadResult.SpeechEnded(prob) + } else { + appendSpeech(chunk, processedChunk) + VadResult.SpeechContinuing(prob) + } + } + inSpeech -> { + appendSpeech(chunk, processedChunk) + silenceSamples = 0 + + if (speechLen >= maxSpeechSamples) { + Log.d(TAG, "VAD: Max speech length reached, finalizing segment") + finalizeSegmentIfAny() + VadResult.MaxSpeechReached(prob) + } else { + VadResult.SpeechContinuing(prob) + } + } + else -> { + VadResult.Silence(prob) + } + } + + return result + } + + fun forceFinalize() { + finalizeSegmentIfAny() + } + + fun isInSpeech(): Boolean = inSpeech + + fun getSpeechLength(): Int = speechLen + + fun clearState() { + inSpeech = false + silenceSamples = 0 + speechLen = 0 + processedSpeechLen = 0 + } + + private fun appendSpeech(chunk: FloatArray, processedChunk: FloatArray) { + val needed = speechLen + chunk.size + if (speechBuf.size < needed) { + var newCap = maxOf(needed, maxOf(1024, speechBuf.size * 2)) + if (newCap > maxSpeechSamples) newCap = maxSpeechSamples + val n = FloatArray(newCap) + if (speechLen > 0) System.arraycopy(speechBuf, 0, n, 0, speechLen) + speechBuf = n + } + val copyN = minOf(chunk.size, max(0, maxSpeechSamples - speechLen)) + if (copyN > 0) { + System.arraycopy(chunk, 0, speechBuf, speechLen, copyN) + speechLen += copyN + } + + val processedNeeded = processedSpeechLen + processedChunk.size + if (processedSpeechBuf.size < processedNeeded) { + var newCap = maxOf(processedNeeded, maxOf(1024, processedSpeechBuf.size * 2)) + if (newCap > maxSpeechSamples) newCap = maxSpeechSamples + val n = FloatArray(newCap) + if (processedSpeechLen > 0) System.arraycopy(processedSpeechBuf, 0, n, 0, processedSpeechLen) + processedSpeechBuf = n + } + val processedCopyN = minOf(processedChunk.size, max(0, maxSpeechSamples - processedSpeechLen)) + if (processedCopyN > 0) { + System.arraycopy(processedChunk, 0, processedSpeechBuf, processedSpeechLen, processedCopyN) + processedSpeechLen += processedCopyN + } + } + + private fun finalizeSegmentIfAny() { + Log.d(TAG, "finalizeSegmentIfAny called: speechLen=$speechLen, minSpeechSamples=$minSpeechSamples") + + if (speechLen < minSpeechSamples) { + Log.d(TAG, "finalizeSegmentIfAny: speech too short, discarding") + speechLen = 0 + processedSpeechLen = 0 + inSpeech = false + silenceSamples = 0 + return + } + + if (callback?.shouldSkipProcessing() == true) { + Log.d(TAG, "finalizeSegmentIfAny: skipping due to callback") + speechLen = 0 + processedSpeechLen = 0 + inSpeech = false + silenceSamples = 0 + return + } + + val originalSeg = speechBuf.copyOf(speechLen) + val processedSeg = processedSpeechBuf.copyOf(processedSpeechLen) + speechLen = 0 + processedSpeechLen = 0 + inSpeech = false + silenceSamples = 0 + + Log.d(TAG, "Sending audio segment to callback, size: ${processedSeg.size}") + callback?.onSpeechSegmentReady(originalSeg, processedSeg) + } + + sealed class VadResult(val probability: Float) { + class SpeechStarted(prob: Float) : VadResult(prob) + class SpeechEnded(prob: Float) : VadResult(prob) + class SpeechContinuing(prob: Float) : VadResult(prob) + class MaxSpeechReached(prob: Float) : VadResult(prob) + class Silence(prob: Float) : VadResult(prob) + } +} diff --git a/app/src/main/res/layout/activity_live2d_chat.xml b/app/src/main/res/layout/activity_live2d_chat.xml new file mode 100644 index 0000000..9936451 --- /dev/null +++ b/app/src/main/res/layout/activity_live2d_chat.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + +