diff --git a/.eslintrc.yml b/.eslintrc.yml index b792a58..e30c320 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -15,6 +15,7 @@ rules: prettier/prettier: - error - singleQuote: true + trailingComma: none camelcase: "off" '@typescript-eslint/naming-convention': - warn @@ -59,6 +60,8 @@ rules: '@typescript-eslint/no-unsafe-member-access': off '@typescript-eslint/no-unsafe-argument': off '@typescript-eslint/no-unsafe-call': off + '@typescript-eslint/no-explicit-any': off + '@typescript-eslint/no-unused-vars': off 'no-inner-declarations': off 'no-global-assign': off 'prefer-const': warn diff --git a/CHANGELOG.md b/CHANGELOG.md index 504a93b..e9c2eb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,42 @@ 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.1-beta.3] - 2023-11-30 + + +## [5-r.1-beta.2] - 2023-09-28 + +### Added + +* Add a comment for clarity for the function whose usage is not intuitive. + + +## [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 visibility of the `CubismId` constructor to private. + * Please use `CubismFramework.getIdManager().getId()` to get `CubismId`. +* Change the word `DrawMesh` to `DrawMeshWebGL`. + +### Fixed + +* Fix a bug that the value applied by multiply was not appropriate during expression transitions. +* Fix the structure of the class in renderer. +* Fix a issue where `ARRAY_BUFFER` was used on multiple targets. +* Separate shader class from `cubismrenderer` class. +* Separate the high precision mask process from the clipping mask setup process. + +### Removed + +* Remove several arguments of `DrawMesh` function. + + ## [4-r.7] - 2023-05-25 ### Added @@ -182,6 +218,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Reformat code using Prettier and ESLint. +[5-r.1-beta.3]: https://github.com/Live2D/CubismWebFramework/compare/5-r.1-beta.2...5-r.1-beta.3 +[5-r.1-beta.2]: https://github.com/Live2D/CubismWebFramework/compare/5-r.1-beta.1...5-r.1-beta.2 +[5-r.1-beta.1]: https://github.com/Live2D/CubismWebFramework/compare/4-r.7...5-r.1-beta.1 [4-r.7]: https://github.com/Live2D/CubismWebFramework/compare/4-r.6.2...4-r.7 [4-r.6.2]: https://github.com/Live2D/CubismWebFramework/compare/4-r.6.1...4-r.6.2 [4-r.6.1]: https://github.com/Live2D/CubismWebFramework/compare/4-r.6...4-r.6.1 diff --git a/README.ja.md b/README.ja.md index ea02b89..f4fd2ec 100644 --- a/README.ja.md +++ b/README.ja.md @@ -21,14 +21,13 @@ Live2D Cubism 4 Editor で出力したモデルをアプリケーションで利 ### Node.js -* 20.1.0 -* 18.16.0 -* 16.20.0 +* 21.2.0 +* 20.10.0 ### TypeScript -5.0.4 +5.3.2 ## 開発環境構築 @@ -156,9 +155,9 @@ Live2Dコミュニティでは、問題のレポートと機能リクエスト SDKの将来についてのフィードバックにも関心があります。Live2Dコミュニティで提案や機能のリクエストを送信できます。このプロセスをより効果的にするために、それらをより明確に定義するのに役立つより多くの情報を含めるようお願いしています。 -## コミュニティ +## フォーラム -ユーザー同士でCubism SDKの活用方法の提案や質問をしたい場合は、是非コミュニティをご活用ください。 +ユーザー同士でCubism SDKの活用方法の提案や質問をしたい場合は、是非フォーラムをご活用ください。 -- [Live2D 公式コミュニティ](https://creatorsforum.live2d.com/) -- [Live2D community(English)](https://community.live2d.com/) +- [Live2D 公式クリエイターズフォーラム](https://creatorsforum.live2d.com/) +- [Live2D Creator's Forum(English)](https://community.live2d.com/) diff --git a/README.md b/README.md index 04d0759..0cd11cf 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,12 @@ Please check the [license](LICENSE.md) before using this SDK. ### Node.js -* 20.1.0 -* 18.16.0 -* 16.20.0 +* 21.2.0 +* 20.10.0 ### TypeScript -5.0.4 +5.3.2 ## Development environment construction @@ -155,9 +154,9 @@ We are regularly checking issue-reports and feature requests at Live2D Community 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. -## Community +## Forum -If you want to suggest or ask questions about how to use the Cubism SDK between users, please use the community. +If you want to suggest or ask questions about how to use the Cubism SDK between users, please use the forum. -- [Live2D community](https://community.live2d.com/) -- [Live2D 公式コミュニティ (Japanese)](https://creatorsforum.live2d.com/) +- [Live2D Creator's Forum](https://community.live2d.com/) +- [Live2D 公式クリエイターズフォーラム (Japanese)](https://creatorsforum.live2d.com/) diff --git a/package-lock.json b/package-lock.json index a75338f..89ec947 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,27 @@ { - "name": "Framework", + "name": "SDKWebFrameWorkDev", "lockfileVersion": 2, "requires": true, "packages": { "": { "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", - "eslint": "^8.40.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "typescript": "^5.0.4" + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", + "eslint": "^8.54.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.1", + "prettier": "^3.1.0", + "rimraf": "^5.0.5", + "typescript": "^5.3.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -40,9 +49,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -63,21 +72,21 @@ } }, "node_modules/@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -99,9 +108,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -194,27 +203,28 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz", - "integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", + "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/type-utils": "5.59.5", - "@typescript-eslint/utils": "5.59.5", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/type-utils": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -240,14 +250,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz", - "integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", + "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/typescript-estree": "5.59.5", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4" }, "engines": { @@ -267,13 +278,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz", - "integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", + "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/visitor-keys": "5.59.5" + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -284,13 +295,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz", - "integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", + "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.5", - "@typescript-eslint/utils": "5.59.5", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/utils": "6.12.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -311,9 +322,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz", - "integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", + "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -324,13 +335,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz", - "integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", + "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/visitor-keys": "5.59.5", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -351,19 +362,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz", - "integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", + "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/typescript-estree": "5.59.5", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "semver": "^7.5.4" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -377,13 +387,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz", - "integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", + "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.5", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.12.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -393,10 +403,16 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -632,19 +648,20 @@ } }, "node_modules/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.54.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", @@ -701,9 +718,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0" @@ -1038,9 +1055,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1192,9 +1209,9 @@ "dev": true }, "node_modules/jackspeak": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz", - "integrity": "sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -1324,9 +1341,9 @@ } }, "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, "engines": { "node": ">=8" @@ -1462,9 +1479,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -1501,9 +1518,9 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -1528,9 +1545,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -1576,15 +1593,15 @@ } }, "node_modules/rimraf": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", "dev": true, "dependencies": { - "glob": "^10.0.0" + "glob": "^10.3.7" }, "bin": { - "rimraf": "dist/cjs/src/bin.js" + "rimraf": "dist/esm/bin.mjs" }, "engines": { "node": ">=14" @@ -1603,19 +1620,19 @@ } }, "node_modules/rimraf/node_modules/glob": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.3.tgz", - "integrity": "sha512-Kb4rfmBVE3eQTAimgmeqc2LwSnN0wIOkkUL6HmxEFxNJ4fHghYHVbFba/HcGcRjE6s9KoMNK3rSOwkL4PioZjg==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" }, "bin": { - "glob": "dist/cjs/src/bin.js" + "glob": "dist/esm/bin.mjs" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -1897,9 +1914,9 @@ } }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", + "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2078,9 +2095,9 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -2095,18 +2112,18 @@ } }, "@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" } @@ -2118,9 +2135,9 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "@isaacs/cliui": { @@ -2188,27 +2205,28 @@ "optional": true }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz", - "integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", + "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", "dev": true, "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/type-utils": "5.59.5", - "@typescript-eslint/utils": "5.59.5", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/type-utils": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -2218,53 +2236,54 @@ } }, "@typescript-eslint/parser": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz", - "integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", + "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/typescript-estree": "5.59.5", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz", - "integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", + "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/visitor-keys": "5.59.5" + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0" } }, "@typescript-eslint/type-utils": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz", - "integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", + "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.59.5", - "@typescript-eslint/utils": "5.59.5", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/utils": "6.12.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz", - "integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", + "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz", - "integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", + "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/visitor-keys": "5.59.5", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2273,35 +2292,40 @@ } }, "@typescript-eslint/utils": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz", - "integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", + "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", "dev": true, "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.5", - "@typescript-eslint/types": "5.59.5", - "@typescript-eslint/typescript-estree": "5.59.5", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "5.59.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz", - "integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", + "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.59.5", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.12.0", + "eslint-visitor-keys": "^3.4.1" } }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true }, "acorn-jsx": { @@ -2475,19 +2499,20 @@ "dev": true }, "eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.54.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", @@ -2548,9 +2573,9 @@ "requires": {} }, "eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -2781,9 +2806,9 @@ } }, "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -2893,9 +2918,9 @@ "dev": true }, "jackspeak": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz", - "integrity": "sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "requires": { "@isaacs/cliui": "^8.0.2", @@ -2989,9 +3014,9 @@ } }, "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true }, "ms": { @@ -3091,9 +3116,9 @@ }, "dependencies": { "lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", "dev": true } } @@ -3117,9 +3142,9 @@ "dev": true }, "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true }, "prettier-linter-helpers": { @@ -3132,9 +3157,9 @@ } }, "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "queue-microtask": { @@ -3156,12 +3181,12 @@ "dev": true }, "rimraf": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", "dev": true, "requires": { - "glob": "^10.0.0" + "glob": "^10.3.7" }, "dependencies": { "brace-expansion": { @@ -3174,16 +3199,16 @@ } }, "glob": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.3.tgz", - "integrity": "sha512-Kb4rfmBVE3eQTAimgmeqc2LwSnN0wIOkkUL6HmxEFxNJ4fHghYHVbFba/HcGcRjE6s9KoMNK3rSOwkL4PioZjg==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "requires": { "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" } }, "minimatch": { @@ -3368,9 +3393,15 @@ "dev": true }, "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", + "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "dev": true + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true }, "uri-js": { diff --git a/package.json b/package.json index a065f4a..4370e6c 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,13 @@ "clean": "rimraf dist" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", - "eslint": "^8.40.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "typescript": "^5.0.4" + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", + "eslint": "^8.54.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.1", + "prettier": "^3.1.0", + "rimraf": "^5.0.5", + "typescript": "^5.3.2" } } diff --git a/src/effect/cubismeyeblink.ts b/src/effect/cubismeyeblink.ts index 5c142d0..eb5e47b 100644 --- a/src/effect/cubismeyeblink.ts +++ b/src/effect/cubismeyeblink.ts @@ -73,8 +73,9 @@ export class CubismEyeBlink { this._userTimeSeconds += deltaTimeSeconds; let parameterValue: number; let t = 0.0; + const blinkingState: EyeState = this._blinkingState; - switch (this._blinkingState) { + switch (blinkingState) { case EyeState.EyeState_Closing: t = (this._userTimeSeconds - this._stateStartTimeSeconds) / diff --git a/src/effect/cubismpose.ts b/src/effect/cubismpose.ts index a75e738..3ae0850 100644 --- a/src/effect/cubismpose.ts +++ b/src/effect/cubismpose.ts @@ -24,6 +24,9 @@ export class CubismPose { */ public static create(pose3json: CubismSpec.PoseJSON): CubismPose { const ret: CubismPose = new CubismPose(); + if(!pose3json){ + return null + } // フェード時間の指定 if (typeof pose3json.FadeInTime === 'number') { diff --git a/src/math/cubismmatrix44.ts b/src/math/cubismmatrix44.ts index 6182930..fac0930 100644 --- a/src/math/cubismmatrix44.ts +++ b/src/math/cubismmatrix44.ts @@ -255,8 +255,10 @@ export class CubismMatrix44 { } /** - * 現在の行列に行列を乗算 + * 引数で与えられた行列にこの行列を乗算する。 + * (引数で与えられた行列) * (この行列) * + * @note 関数名と実際の計算内容に乖離があるため、今後計算順が修正される可能性があります。 * @param m 行列 */ public multiplyByMatrix(m: CubismMatrix44): void { diff --git a/src/model/cubismmodel.ts b/src/model/cubismmodel.ts index 9b4246b..89b6555 100644 --- a/src/model/cubismmodel.ts +++ b/src/model/cubismmodel.ts @@ -833,6 +833,12 @@ export class CubismModel { return this._model.parameters.defaultValues[parameterIndex]; } + public getParameterId(parameterIndex: number): number { + return CubismFramework.getIdManager().getId( + this._model.parameters.ids[parameterIndex] + ); + } + /** * パラメータの値の取得 * @param parameterIndex パラメータのインデックス @@ -1192,10 +1198,10 @@ export class CubismModel { ) ? CubismBlendMode.CubismBlendMode_Additive : Live2DCubismCore.Utils.hasBlendMultiplicativeBit( - constantFlags[drawableIndex] - ) - ? CubismBlendMode.CubismBlendMode_Multiplicative - : CubismBlendMode.CubismBlendMode_Normal; + constantFlags[drawableIndex] + ) + ? CubismBlendMode.CubismBlendMode_Multiplicative + : CubismBlendMode.CubismBlendMode_Normal; } /** diff --git a/src/model/cubismmodeluserdata.ts b/src/model/cubismmodeluserdata.ts index d477b1d..8144a6d 100644 --- a/src/model/cubismmodeluserdata.ts +++ b/src/model/cubismmodeluserdata.ts @@ -61,6 +61,9 @@ export class CubismModelUserData { * @param size バッファのサイズ */ public parseUserData(data: CubismSpec.UserDataJSON, size: number): void { + if(!data){ + return; + } const json: CubismModelUserDataJson = new CubismModelUserDataJson( data, size diff --git a/src/motion/acubismmotion.ts b/src/motion/acubismmotion.ts index 699c859..3c3eac0 100644 --- a/src/motion/acubismmotion.ts +++ b/src/motion/acubismmotion.ts @@ -64,6 +64,35 @@ export abstract class ACubismMotion { // duration == -1 の場合はループする } } + const fadeWeight = this.updateFadeWeight(motionQueueEntry, userTimeSeconds); + //---- 全てのパラメータIDをループする ---- + this.doUpdateParameters( + model, + userTimeSeconds, + fadeWeight, + motionQueueEntry + ); + // 後処理 + // 終了時刻を過ぎたら終了フラグを立てる(CubismMotionQueueManager) + if ( + motionQueueEntry.getEndTime() > 0 && + motionQueueEntry.getEndTime() < userTimeSeconds + ) { + motionQueueEntry.setIsFinished(true); // 終了 + } + } + /** + * @brief モデルのウェイト更新 + * + * モーションのウェイトを更新する。 + * + * @param[in] motionQueueEntry CubismMotionQueueManagerで管理されているモーション + * @param[in] userTimeSeconds デルタ時間の積算値[秒] + */ + public updateFadeWeight( + motionQueueEntry: CubismMotionQueueEntry, + userTimeSeconds: number + ): number { let fadeWeight: number = this._weight; // 現在の値と掛け合わせる割合 @@ -73,17 +102,17 @@ export abstract class ACubismMotion { this._fadeInSeconds == 0.0 ? 1.0 : CubismMath.getEasingSine( - (userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / - this._fadeInSeconds - ); + (userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / + this._fadeInSeconds + ); const fadeOut: number = this._fadeOutSeconds == 0.0 || motionQueueEntry.getEndTime() < 0.0 ? 1.0 : CubismMath.getEasingSine( - (motionQueueEntry.getEndTime() - userTimeSeconds) / - this._fadeOutSeconds - ); + (motionQueueEntry.getEndTime() - userTimeSeconds) / + this._fadeOutSeconds + ); fadeWeight = fadeWeight * fadeIn * fadeOut; @@ -91,22 +120,7 @@ export abstract class ACubismMotion { CSM_ASSERT(0.0 <= fadeWeight && fadeWeight <= 1.0); - //---- 全てのパラメータIDをループする ---- - this.doUpdateParameters( - model, - userTimeSeconds, - fadeWeight, - motionQueueEntry - ); - - // 後処理 - // 終了時刻を過ぎたら終了フラグを立てる(CubismMotionQueueManager) - if ( - motionQueueEntry.getEndTime() > 0 && - motionQueueEntry.getEndTime() < userTimeSeconds - ) { - motionQueueEntry.setIsFinished(true); // 終了 - } + return fadeWeight; } /** diff --git a/src/motion/cubismexpressionmotion.ts b/src/motion/cubismexpressionmotion.ts index 2d5dc86..80d9d5d 100644 --- a/src/motion/cubismexpressionmotion.ts +++ b/src/motion/cubismexpressionmotion.ts @@ -19,6 +19,8 @@ const DefaultFadeTime = 1.0; * 表情のモーションクラス。 */ export class CubismExpressionMotion extends ACubismMotion { + static readonly DefaultAdditiveValue = 0.0; // 加算適用の初期値 + static readonly DefaultMultiplyValue = 1.0; // 乗算適用の初期値 /** * インスタンスを作成する。 * @param json expファイルが読み込まれているバッファ @@ -50,7 +52,7 @@ export class CubismExpressionMotion extends ACubismMotion { const parameter: ExpressionParameter = this._parameters[i]; switch (parameter.blendType) { - case ExpressionBlendType.ExpressionBlendType_Add: { + case ExpressionBlendType.Additive: { model.addParameterValueById( parameter.parameterId, parameter.value, @@ -58,7 +60,7 @@ export class CubismExpressionMotion extends ACubismMotion { ); break; } - case ExpressionBlendType.ExpressionBlendType_Multiply: { + case ExpressionBlendType.Multiply: { model.multiplyParameterValueById( parameter.parameterId, parameter.value, @@ -66,7 +68,7 @@ export class CubismExpressionMotion extends ACubismMotion { ); break; } - case ExpressionBlendType.ExpressionBlendType_Overwrite: { + case ExpressionBlendType.Overwrite: { model.setParameterValueById( parameter.parameterId, parameter.value, @@ -81,7 +83,149 @@ export class CubismExpressionMotion extends ACubismMotion { } } + /** + * @brief 表情によるモデルのパラメータの計算 + * + * モデルの表情に関するパラメータを計算する。 + * + * @param[in] model 対象のモデル + * @param[in] userTimeSeconds デルタ時間の積算値[秒] + * @param[in] motionQueueEntry CubismMotionQueueManagerで管理されているモーション + * @param[in] expressionParameterValues モデルに適用する各パラメータの値 + * @param[in] expressionIndex 表情のインデックス + */ + public calculateExpressionParameters( + model: CubismModel, + userTimeSeconds: number, + motionQueueEntry: CubismMotionQueueEntry, + expressionParameterValues: ExpressionParameterValue[], + expressionIndex: number + ) { + if (!motionQueueEntry.isAvailable()) { + return; + } + if (!motionQueueEntry.isStarted()) { + motionQueueEntry.setIsStarted(true); + motionQueueEntry.setStartTime(userTimeSeconds - this._offsetSeconds); // モーションの開始時刻を記録 + motionQueueEntry.setFadeInStartTime(userTimeSeconds); // フェードインの開始時刻 + const duration = this.getDuration(); + if (motionQueueEntry.getEndTime() < 0.0) { + // 開始していないうちに終了設定している場合がある + motionQueueEntry.setEndTime( + duration <= 0.0 ? -1 : motionQueueEntry.getStartTime() + duration + ); + // duration == -1 の場合はループする + } + } + this._fadeWeight = this.updateFadeWeight(motionQueueEntry, userTimeSeconds); + // モデルに適用する値を計算 + for (let i = 0; i < expressionParameterValues.length; ++i) { + const expressionParameterValue = expressionParameterValues[i]; + if (expressionParameterValue.parameterId == null) { + continue; + } + const currentParameterValue = (expressionParameterValue.overwriteValue = + model.getParameterValueById(expressionParameterValue.parameterId)); + const expressionParameters = this.getExpressionParameters(); + let parameterIndex = -1; + for (let j = 0; j < expressionParameters.length; ++j) { + if ( + expressionParameterValue.parameterId != + expressionParameters[j].parameterId + ) { + continue; + } + parameterIndex = j; + break; + } + // 再生中のExpressionが参照していないパラメータは初期値を適用 + if (parameterIndex < 0) { + if (expressionIndex == 0) { + expressionParameterValue.additiveValue = + CubismExpressionMotion.DefaultAdditiveValue; + expressionParameterValue.multiplyValue = + CubismExpressionMotion.DefaultMultiplyValue; + expressionParameterValue.overwriteValue = currentParameterValue; + } else { + expressionParameterValue.additiveValue = this.calculateValue( + expressionParameterValue.additiveValue, + CubismExpressionMotion.DefaultAdditiveValue + ); + expressionParameterValue.multiplyValue = this.calculateValue( + expressionParameterValue.multiplyValue, + CubismExpressionMotion.DefaultMultiplyValue + ); + expressionParameterValue.overwriteValue = this.calculateValue( + expressionParameterValue.overwriteValue, + currentParameterValue + ); + } + continue; + } + // 値を計算 + const value = expressionParameters[parameterIndex].value; + let newAdditiveValue, newMultiplyValue, newOverwriteValue; + switch (expressionParameters[parameterIndex].blendType) { + case ExpressionBlendType.Additive: + newAdditiveValue = value; + newMultiplyValue = CubismExpressionMotion.DefaultMultiplyValue; + newOverwriteValue = currentParameterValue; + break; + case ExpressionBlendType.Multiply: + newAdditiveValue = CubismExpressionMotion.DefaultAdditiveValue; + newMultiplyValue = value; + newOverwriteValue = currentParameterValue; + break; + case ExpressionBlendType.Overwrite: + newAdditiveValue = CubismExpressionMotion.DefaultAdditiveValue; + newMultiplyValue = CubismExpressionMotion.DefaultMultiplyValue; + newOverwriteValue = value; + break; + default: + return; + } + if (expressionIndex == 0) { + expressionParameterValue.additiveValue = newAdditiveValue; + expressionParameterValue.multiplyValue = newMultiplyValue; + expressionParameterValue.overwriteValue = newOverwriteValue; + } else { + expressionParameterValue.additiveValue = + expressionParameterValue.additiveValue * (1.0 - this._fadeWeight) + + newAdditiveValue * this._fadeWeight; + expressionParameterValue.multiplyValue = + expressionParameterValue.multiplyValue * (1.0 - this._fadeWeight) + + newMultiplyValue * this._fadeWeight; + expressionParameterValue.overwriteValue = + expressionParameterValue.overwriteValue * (1.0 - this._fadeWeight) + + newOverwriteValue * this._fadeWeight; + } + } + } + /** + * @brief 表情が参照しているパラメータを取得 + * + * 表情が参照しているパラメータを取得する + * + * @return 表情パラメータ + */ + public getExpressionParameters() { + return this._parameters; + } + /** + * @brief 表情のフェードの値を取得 + * + * 現在の表情のフェードのウェイト値を取得する + * + * @returns 表情のフェードのウェイト値 + */ + public getFadeWeight() { + return this._fadeWeight; + } + protected parse(json: CubismSpec.ExpressionJSON) { + if(!json){ + return; + } this.setFadeInTime( json.FadeInTime != undefined ? json.FadeInTime : DefaultFadeTime ); // フェードイン @@ -102,14 +246,14 @@ export class CubismExpressionMotion extends ACubismMotion { let blendType: ExpressionBlendType; if (!param.Blend || param.Blend === 'Add') { - blendType = ExpressionBlendType.ExpressionBlendType_Add; + blendType = ExpressionBlendType.Additive; } else if (param.Blend === 'Multiply') { - blendType = ExpressionBlendType.ExpressionBlendType_Multiply; + blendType = ExpressionBlendType.Multiply; } else if (param.Blend === 'Overwrite') { - blendType = ExpressionBlendType.ExpressionBlendType_Overwrite; + blendType = ExpressionBlendType.Overwrite; } else { // その他 仕様にない値を設定した時は加算モードにすることで復旧 - blendType = ExpressionBlendType.ExpressionBlendType_Add; + blendType = ExpressionBlendType.Additive; } // 設定オブジェクトを作成してリストに追加する @@ -123,6 +267,21 @@ export class CubismExpressionMotion extends ACubismMotion { } } + /** + * @brief ブレンド計算 + * + * 入力された値でブレンド計算をする。 + * + * @param source 現在の値 + * @param destination 適用する値 + * @param weight ウェイト + * @returns 計算結果 + */ + public calculateValue(source: number, destination: number): number { + return source * (1.0 - this._fadeWeight) + destination * this._fadeWeight; + } + + /** * コンストラクタ */ @@ -130,18 +289,20 @@ export class CubismExpressionMotion extends ACubismMotion { super(); this._parameters = []; + this._fadeWeight = 0.0; } _parameters: ExpressionParameter[]; // 表情のパラメータ情報リスト + _fadeWeight: number; // 表情の現在のウェイト } /** * 表情パラメータ値の計算方式 */ export enum ExpressionBlendType { - ExpressionBlendType_Add = 0, // 加算 - ExpressionBlendType_Multiply = 1, // 乗算 - ExpressionBlendType_Overwrite = 2, // 上書き + Additive = 0, // 加算 + Multiply = 1, // 乗算 + Overwrite = 2 // 上書き } /** @@ -152,3 +313,5 @@ export interface ExpressionParameter { blendType: ExpressionBlendType; // パラメータの演算種類 value: number; // 値 } + +import { ExpressionParameterValue } from './cubismexpressionmotionmanager'; \ No newline at end of file diff --git a/src/motion/cubismexpressionmotionmanager.ts b/src/motion/cubismexpressionmotionmanager.ts new file mode 100644 index 0000000..e6d757a --- /dev/null +++ b/src/motion/cubismexpressionmotionmanager.ts @@ -0,0 +1,229 @@ +import { CubismModel } from '../model/cubismmodel'; +import { ACubismMotion } from './acubismmotion'; +import { CubismExpressionMotion } from './cubismexpressionmotion'; +import { CubismMotionQueueEntry } from './cubismmotionqueueentry'; +import { + CubismMotionQueueEntryHandle, + CubismMotionQueueManager +} from './cubismmotionqueuemanager'; +/** + * @brief パラメータに適用する表情の値を持たせる構造体 + */ +export class ExpressionParameterValue { + parameterId: string; // パラメーターID + additiveValue: number; // 加算値 + multiplyValue: number; // 乗算値 + overwriteValue: number; // 上書き値 +} +/** + * @brief 表情モーションの管理 + * + * 表情モーションの管理をおこなうクラス。 + */ +export class CubismExpressionMotionManager extends CubismMotionQueueManager { + /** + * コンストラクタ + */ + public constructor() { + super(); + this._currentPriority = 0; + this._reservePriority = 0; + this._expressionParameterValues = []; + } + /** + * デストラクタ相当の処理 + */ + public release(): void { + if (this._expressionParameterValues) { + this._expressionParameterValues = []; + } + } + /** + * @brief 再生中のモーションの優先度の取得 + * + * 再生中のモーションの優先度を取得する。 + * + * @returns モーションの優先度 + */ + public getCurrentPriority(): number { + return this._currentPriority; + } + /** + * @brief 予約中のモーションの優先度の取得 + * + * 予約中のモーションの優先度を取得する。 + * + * @return モーションの優先度 + */ + public getReservePriority(): number { + return this._reservePriority; + } + /** + * @brief 予約中のモーションの優先度の設定 + * + * 予約中のモーションの優先度を設定する。 + * + * @param[in] priority 優先度 + */ + public setReservePriority(priority: number) { + this._reservePriority = priority; + } + /** + * @brief 優先度を設定してモーションの開始 + * + * 優先度を設定してモーションを開始する。 + * + * @param[in] motion モーション + * @param[in] autoDelete 再生が終了したモーションのインスタンスを削除するならtrue + * @param[in] priority 優先度 + * @return 開始したモーションの識別番号を返す。個別のモーションが終了したか否かを判定するIsFinished()の引数で使用する。開始できない時は「-1」 + */ + public startMotionPriority( + motion: ACubismMotion, + autoDelete: boolean, + priority: number + ): CubismMotionQueueEntryHandle { + if (priority == this.getReservePriority()) { + this.setReservePriority(0); + } + this._currentPriority = priority; + return this.startMotion(motion, autoDelete, this._userTimeSeconds); + } + /** + * @brief モーションの更新 + * + * モーションを更新して、モデルにパラメータ値を反映する。 + * + * @param[in] model 対象のモデル + * @param[in] deltaTimeSeconds デルタ時間[秒] + * @retval true 更新されている + * @retval false 更新されていない + */ + public updateMotion(model: CubismModel, deltaTimeSeconds: number): boolean { + this._userTimeSeconds += deltaTimeSeconds; + let updated = false; + const motions = this.getCubismMotionQueueEntries(); + let expressionWeight = 0.0; + let expressionIndex = 0; + // ------- 処理を行う -------- + // 既にモーションがあれば終了フラグを立てる + for(let i =0 ;i < this._motions.length ; i++ ){ + // for ( + // let ite: iterator = this._motions.begin(); + // ite.notEqual(this._motions.end()); + // ) { + const motionQueueEntry = this._motions[i]; + if (motionQueueEntry == null) { + // ite = motions.erase(ite); //削除 + continue; + } + const expressionMotion = ( + motionQueueEntry.getCubismMotion() + ); + if (expressionMotion == null) { + // ite = motions.erase(ite); //削除 + continue; + } + const expressionParameters = expressionMotion.getExpressionParameters(); + if (motionQueueEntry.isAvailable()) { + // 再生中のExpressionが参照しているパラメータをすべてリストアップ + for (let i = 0; i < expressionParameters.length; ++i) { + if (expressionParameters[i].parameterId == null) { + continue; + } + let index = -1; + // リストにパラメータIDが存在するか検索 + for (let j = 0; j < this._expressionParameterValues.length; ++j) { + if ( + this._expressionParameterValues[j].parameterId != + expressionParameters[i].parameterId + ) { + continue; + } + index = j; + break; + } + if (index >= 0) { + continue; + } + // パラメータがリストに存在しないなら新規追加 + const item: ExpressionParameterValue = new ExpressionParameterValue(); + item.parameterId = expressionParameters[i].parameterId; + item.additiveValue = CubismExpressionMotion.DefaultAdditiveValue; + item.multiplyValue = CubismExpressionMotion.DefaultMultiplyValue; + item.overwriteValue = model.getParameterValueById(item.parameterId); + this._expressionParameterValues.push(item); + } + } + // ------ 値を計算する ------ + expressionMotion.calculateExpressionParameters( + model, + this._userTimeSeconds, + motionQueueEntry, + this._expressionParameterValues, + expressionIndex + ); + expressionWeight += + expressionMotion.getFadeInTime() == 0.0 + ? 1.0 + : CubismMath.getEasingSine( + (this._userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / + expressionMotion.getFadeInTime() + ); + updated = true; + if (motionQueueEntry.isTriggeredFadeOut()) { + // フェードアウト開始 + motionQueueEntry.startFadeOut( + motionQueueEntry.getFadeOutSeconds(), + this._userTimeSeconds + ); + } + // ite.preIncrement(); + ++expressionIndex; + } + // ----- 最新のExpressionのフェードが完了していればそれ以前を削除する ------ + if (motions.length > 1) { + const expressionMotion = ( + motions[motions.length - 1].getCubismMotion() + ); + if (expressionMotion.getFadeWeight() >= 1.0) { + // 配列の最後の要素は削除しない + for (let i = motions.length - 2; i >= 0; --i) { + const motionQueueEntry = motions.at(i); + motions.splice(i, 1); + } + } + } + if (expressionWeight > 1.0) { + expressionWeight = 1.0; + } + // モデルに各値を適用 + for (let i = 0; i < this._expressionParameterValues.length; ++i) { + const expressionParameterValue = this._expressionParameterValues[i]; + model.setParameterValueById( + expressionParameterValue.parameterId, + (expressionParameterValue.overwriteValue + + expressionParameterValue.additiveValue) * + expressionParameterValue.multiplyValue, + expressionWeight + ); + expressionParameterValue.additiveValue = + CubismExpressionMotion.DefaultAdditiveValue; + expressionParameterValue.multiplyValue = + CubismExpressionMotion.DefaultMultiplyValue; + } + return updated; + } + private _expressionParameterValues: ExpressionParameterValue[]; ///< モデルに適用する各パラメータの値 + private _currentPriority: number; ///< 現在再生中のモーションの優先度 + private _reservePriority: number; ///< 再生予定のモーションの優先度。再生中は0になる。モーションファイルを別スレッドで読み込むときの機能。 +// private _startExpressionTime: number; ///< 表情の再生開始時刻 +} +// Namespace definition for compatibility. +import * as $ from './cubismexpressionmotionmanager'; +import { CubismMath } from '../math/cubismmath'; +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace Live2DCubismFramework { + export const CubismExpressionMotionManager = $.CubismExpressionMotionManager; + export type CubismExpressionMotionManager = $.CubismExpressionMotionManager; +} \ No newline at end of file diff --git a/src/motion/cubismmotion.ts b/src/motion/cubismmotion.ts index 2c15ec2..987c28c 100644 --- a/src/motion/cubismmotion.ts +++ b/src/motion/cubismmotion.ts @@ -210,7 +210,7 @@ function evaluateCurve( // Get first point of next segment. pointPosition = motionData.segments[i].basePointIndex + - (motionData.segments[i].segmentType == + ((motionData.segments[i].segmentType as CubismMotionSegmentType) == CubismMotionSegmentType.CubismMotionSegmentType_Bezier ? 3 : 1); @@ -715,6 +715,9 @@ export class CubismMotion extends ACubismMotion { this._motionData = new CubismMotionData(); const json: CubismMotionJson = new CubismMotionJson(motionJson); + if (!json) { + return; + } this._motionData.duration = json.getMotionDuration(); this._motionData.loop = json.isMotionLoop(); @@ -820,7 +823,9 @@ export class CubismMotion extends ACubismMotion { curveCount, segmentPosition ); - switch (segment) { + + const segmentType: CubismMotionSegmentType = segment; + switch (segmentType) { case CubismMotionSegmentType.CubismMotionSegmentType_Linear: { this._motionData.segments[totalSegmentCount].segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Linear; diff --git a/src/motion/cubismmotionjson.ts b/src/motion/cubismmotionjson.ts index 426342c..da5438c 100644 --- a/src/motion/cubismmotionjson.ts +++ b/src/motion/cubismmotionjson.ts @@ -43,7 +43,7 @@ export class CubismMotionJson { return this._json.Meta.Loop || false; } - public getEvaluationOptionFlag(flagType: number): boolean { + public getEvaluationOptionFlag(flagType: EvaluationOptionFlag): boolean { if ( EvaluationOptionFlag.EvaluationOptionFlag_AreBeziersRistricted == flagType ) { diff --git a/src/motion/cubismmotionqueueentry.ts b/src/motion/cubismmotionqueueentry.ts index c70ea55..b6d6105 100644 --- a/src/motion/cubismmotionqueueentry.ts +++ b/src/motion/cubismmotionqueueentry.ts @@ -225,6 +225,15 @@ export class CubismMotionQueueEntry { return this._fadeOutSeconds; } + /** + * モーションの取得 + * + * @return モーション + */ + public getCubismMotion(): ACubismMotion { + return this._motion; + } + _autoDelete: boolean; // 自動削除 _motion!: ACubismMotion; // モーション diff --git a/src/motion/cubismmotionqueuemanager.ts b/src/motion/cubismmotionqueuemanager.ts index 2b021e5..dd6c5db 100644 --- a/src/motion/cubismmotionqueuemanager.ts +++ b/src/motion/cubismmotionqueuemanager.ts @@ -166,9 +166,20 @@ export class CubismMotionQueueManager { this._motions = []; } + /** + * @brief CubismMotionQueueEntryの配列の取得 + * + * CubismMotionQueueEntryの配列を取得する。 + * + * @return CubismMotionQueueEntryの配列へのポインタ + * @retval NULL 見つからなかった + */ + public getCubismMotionQueueEntries(): CubismMotionQueueEntry[] { + return this._motions; + } + /** * 指定したCubismMotionQueueEntryの取得 - * @param motionQueueEntryNumber モーションの識別番号 * @return 指定したCubismMotionQueueEntry * @return null 見つからなかった diff --git a/src/rendering/cubismclippingmanager.ts b/src/rendering/cubismclippingmanager.ts new file mode 100644 index 0000000..5b5ab03 --- /dev/null +++ b/src/rendering/cubismclippingmanager.ts @@ -0,0 +1,625 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ +import { Constant } from '../live2dcubismframework'; +import { csmRect } from '../type/csmrectf'; +import { CubismMatrix44 } from '../math/cubismmatrix44'; +import { CubismModel } from '../model/cubismmodel'; +import { CubismClippingContext, CubismTextureColor } from './cubismrenderer'; +import { CubismLogError, CubismLogWarning } from '../utils/cubismdebug'; +const ColorChannelCount = 4; // 実験時に1チャンネルの場合は1、RGBだけの場合は3、アルファも含める場合は4 +const ClippingMaskMaxCountOnDefault = 36; // 通常のフレームバッファ一枚あたりのマスク最大数 +const ClippingMaskMaxCountOnMultiRenderTexture = 32; // フレームバッファが2枚以上ある場合のフレームバッファ一枚あたりのマスク最大数 +export type ClippingContextConstructor< + T_ClippingContext extends CubismClippingContext +> = new ( + manager: CubismClippingManager, + drawableMasks: Int32Array, + drawableMaskCounts: number +) => T_ClippingContext; +export interface ICubismClippingManager { + getClippingMaskBufferSize(): number; +} +export abstract class CubismClippingManager< + T_ClippingContext extends CubismClippingContext +> implements ICubismClippingManager { + /** + * コンストラクタ + */ + public constructor( + clippingContextFactory: ClippingContextConstructor + ) { + this._renderTextureCount = 0; + this._clippingMaskBufferSize = 256; + this._clippingContextListForMask = []; + this._clippingContextListForDraw = []; + this._channelColors = []; + this._tmpBoundsOnModel = new csmRect(); + this._tmpMatrix = new CubismMatrix44(); + this._tmpMatrixForMask = new CubismMatrix44(); + this._tmpMatrixForDraw = new CubismMatrix44(); + this._clippingContexttConstructor = clippingContextFactory; + let tmp: CubismTextureColor = new CubismTextureColor(); + tmp.R = 1.0; + tmp.G = 0.0; + tmp.B = 0.0; + tmp.A = 0.0; + this._channelColors.push(tmp); + tmp = new CubismTextureColor(); + tmp.R = 0.0; + tmp.G = 1.0; + tmp.B = 0.0; + tmp.A = 0.0; + this._channelColors.push(tmp); + tmp = new CubismTextureColor(); + tmp.R = 0.0; + tmp.G = 0.0; + tmp.B = 1.0; + tmp.A = 0.0; + this._channelColors.push(tmp); + tmp = new CubismTextureColor(); + tmp.R = 0.0; + tmp.G = 0.0; + tmp.B = 0.0; + tmp.A = 1.0; + this._channelColors.push(tmp); + } + /** + * デストラクタ相当の処理 + */ + public release(): void { + for (let i = 0; i < this._clippingContextListForMask.length; i++) { + if (this._clippingContextListForMask[i]) { + this._clippingContextListForMask[i].release(); + this._clippingContextListForMask[i] = null; + } + this._clippingContextListForMask[i] = null; + } + this._clippingContextListForMask = null; + // _clippingContextListForDrawは_clippingContextListForMaskにあるインスタンスを指している。上記の処理により要素ごとのDELETEは不要。 + for (let i = 0; i < this._clippingContextListForDraw.length; i++) { + this._clippingContextListForDraw[i] = null; + } + this._clippingContextListForDraw = null; + for (let i = 0; i < this._channelColors.length; i++) { + this._channelColors[i] = null; + } + this._channelColors = null; + if (this._clearedFrameBufferFlags != null) { + this._clearedFrameBufferFlags = []; + } + this._clearedFrameBufferFlags = null; + } + /** + * マネージャの初期化処理 + * クリッピングマスクを使う描画オブジェクトの登録を行う + * @param model モデルのインスタンス + * @param renderTextureCount バッファの生成数 + */ + public initialize(model: CubismModel, renderTextureCount: number): void { + // レンダーテクスチャの合計枚数の設定 + // 1以上の整数でない場合はそれぞれ警告を出す + if (renderTextureCount % 1 != 0) { + CubismLogWarning( + 'The number of render textures must be specified as an integer. The decimal point is rounded down and corrected to an integer.' + ); + // 小数点以下を除去 + renderTextureCount = ~~renderTextureCount; + } + if (renderTextureCount < 1) { + CubismLogWarning( + 'The number of render textures must be an integer greater than or equal to 1. Set the number of render textures to 1.' + ); + } + // 負の値が使われている場合は強制的に1枚と設定する + this._renderTextureCount = renderTextureCount < 1 ? 1 : renderTextureCount; + this._clearedFrameBufferFlags = []; + // クリッピングマスクを使う描画オブジェクトをすべて登録する + // クリッピングマスクは、通常数個程度に限定して使うものとする + for (let i = 0; i < model.getDrawableCount(); i++) { + if (model.getDrawableMaskCounts()[i] <= 0) { + // クリッピングマスクが使用されていないアートメッシュ(多くの場合使用しない) + this._clippingContextListForDraw.push(null); + continue; + } + // 既にあるClipContextと同じかチェックする + let clippingContext: T_ClippingContext = this.findSameClip( + model.getDrawableMasks()[i], + model.getDrawableMaskCounts()[i] + ); + if (clippingContext == null) { + // 同一のマスクが存在していない場合は生成する + clippingContext = new this._clippingContexttConstructor( + this, + model.getDrawableMasks()[i], + model.getDrawableMaskCounts()[i] + ); + this._clippingContextListForMask.push(clippingContext); + } + clippingContext.addClippedDrawable(i); + this._clippingContextListForDraw.push(clippingContext); + } + } + /** + * 既にマスクを作っているかを確認 + * 作っている様であれば該当するクリッピングマスクのインスタンスを返す + * 作っていなければNULLを返す + * @param drawableMasks 描画オブジェクトをマスクする描画オブジェクトのリスト + * @param drawableMaskCounts 描画オブジェクトをマスクする描画オブジェクトの数 + * @return 該当するクリッピングマスクが存在すればインスタンスを返し、なければNULLを返す + */ + public findSameClip( + drawableMasks: Int32Array, + drawableMaskCounts: number + ): T_ClippingContext { + // 作成済みClippingContextと一致するか確認 + for (let i = 0; i < this._clippingContextListForMask.length; i++) { + const clippingContext: T_ClippingContext = + this._clippingContextListForMask[i]; + const count: number = clippingContext._clippingIdCount; + // 個数が違う場合は別物 + if (count != drawableMaskCounts) { + continue; + } + let sameCount = 0; + // 同じIDを持つか確認。配列の数が同じなので、一致した個数が同じなら同じ物を持つとする + for (let j = 0; j < count; j++) { + const clipId: number = clippingContext._clippingIdList[j]; + for (let k = 0; k < count; k++) { + if (drawableMasks[k] == clipId) { + sameCount++; + break; + } + } + } + if (sameCount == count) { + return clippingContext; + } + } + return null; // 見つからなかった + } + /** + * 高精細マスク処理用の行列を計算する + * @param model モデルのインスタンス + * @param isRightHanded 処理が右手系であるか + */ + public setupMatrixForHighPrecision( + model: CubismModel, + isRightHanded: boolean + ): void { + // 全てのクリッピングを用意する + // 同じクリップ(複数の場合はまとめて一つのクリップ)を使う場合は1度だけ設定する + let usingClipCount = 0; + for ( + let clipIndex = 0; + clipIndex < this._clippingContextListForMask.length; + clipIndex++ + ) { + // 1つのクリッピングマスクに関して + const cc: T_ClippingContext = + this._clippingContextListForMask[clipIndex]; + // このクリップを利用する描画オブジェクト群全体を囲む矩形を計算 + this.calcClippedDrawTotalBounds(model, cc); + if (cc._isUsing) { + usingClipCount++; // 使用中としてカウント + } + } + // マスク行列作成処理 + if (usingClipCount > 0) { + this.setupLayoutBounds(0); + // サイズがレンダーテクスチャの枚数と合わない場合は合わせる + if (this._clearedFrameBufferFlags.length != this._renderTextureCount) { + this._clearedFrameBufferFlags = []; + for (let i = 0; i < this._renderTextureCount; i++) { + this._clearedFrameBufferFlags.push(false); + } + } else { + // マスクのクリアフラグを毎フレーム開始時に初期化 + for (let i = 0; i < this._renderTextureCount; i++) { + this._clearedFrameBufferFlags[i] = false; + } + } + // 実際にマスクを生成する + // 全てのマスクをどの様にレイアウトして描くかを決定し、ClipContext , ClippedDrawContext に記憶する + for ( + let clipIndex = 0; + clipIndex < this._clippingContextListForMask.length; + clipIndex++ + ) { + // --- 実際に1つのマスクを描く --- + const clipContext: T_ClippingContext = + this._clippingContextListForMask[clipIndex]; + const allClippedDrawRect: csmRect = clipContext._allClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形 + const layoutBoundsOnTex01 = clipContext._layoutBounds; //この中にマスクを収める + const MARGIN = 0.05; + let scaleX = 0.0; + let scaleY = 0.0; + const ppu: number = model.getPixelsPerUnit(); + const maskPixelSize: number = clipContext + .getClippingManager() + .getClippingMaskBufferSize(); + const physicalMaskWidth: number = + layoutBoundsOnTex01.width * maskPixelSize; + const physicalMaskHeight: number = + layoutBoundsOnTex01.height * maskPixelSize; + this._tmpBoundsOnModel.setRect(allClippedDrawRect); + if (this._tmpBoundsOnModel.width * ppu > physicalMaskWidth) { + this._tmpBoundsOnModel.expand(allClippedDrawRect.width * MARGIN, 0.0); + scaleX = layoutBoundsOnTex01.width / this._tmpBoundsOnModel.width; + } else { + scaleX = ppu / physicalMaskWidth; + } + if (this._tmpBoundsOnModel.height * ppu > physicalMaskHeight) { + this._tmpBoundsOnModel.expand( + 0.0, + allClippedDrawRect.height * MARGIN + ); + scaleY = layoutBoundsOnTex01.height / this._tmpBoundsOnModel.height; + } else { + scaleY = ppu / physicalMaskHeight; + } + // マスク生成時に使う行列を求める + this.createMatrixForMask( + isRightHanded, + layoutBoundsOnTex01, + scaleX, + scaleY + ); + clipContext._matrixForMask.setMatrix(this._tmpMatrixForMask.getArray()); + clipContext._matrixForDraw.setMatrix(this._tmpMatrixForDraw.getArray()); + } + } + } + /** + * マスク作成・描画用の行列を作成する。 + * @param isRightHanded 座標を右手系として扱うかを指定 + * @param layoutBoundsOnTex01 マスクを収める領域 + * @param scaleX 描画オブジェクトの伸縮率 + * @param scaleY 描画オブジェクトの伸縮率 + */ + public createMatrixForMask( + isRightHanded: boolean, + layoutBoundsOnTex01: csmRect, + scaleX: number, + scaleY: number + ): void { + this._tmpMatrix.loadIdentity(); + { + // Layout0..1 を -1..1に変換 + this._tmpMatrix.translateRelative(-1.0, -1.0); + this._tmpMatrix.scaleRelative(2.0, 2.0); + } + { + // view to Layout0..1 + this._tmpMatrix.translateRelative( + layoutBoundsOnTex01.x, + layoutBoundsOnTex01.y + ); //new = [translate] + this._tmpMatrix.scaleRelative(scaleX, scaleY); //new = [translate][scale] + this._tmpMatrix.translateRelative( + -this._tmpBoundsOnModel.x, + -this._tmpBoundsOnModel.y + ); //new = [translate][scale][translate] + } + // tmpMatrixForMask が計算結果 + this._tmpMatrixForMask.setMatrix(this._tmpMatrix.getArray()); + this._tmpMatrix.loadIdentity(); + { + this._tmpMatrix.translateRelative( + layoutBoundsOnTex01.x, + layoutBoundsOnTex01.y * (isRightHanded ? -1.0 : 1.0) + ); //new = [translate] + this._tmpMatrix.scaleRelative( + scaleX, + scaleY * (isRightHanded ? -1.0 : 1.0) + ); //new = [translate][scale] + this._tmpMatrix.translateRelative( + -this._tmpBoundsOnModel.x, + -this._tmpBoundsOnModel.y + ); //new = [translate][scale][translate] + } + this._tmpMatrixForDraw.setMatrix(this._tmpMatrix.getArray()); + } + /** + * クリッピングコンテキストを配置するレイアウト + * 指定された数のレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトする + * マスクグループの数が4以下ならRGBA各チャンネルに一つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する。 + * + * @param usingClipCount 配置するクリッピングコンテキストの数 + */ + public setupLayoutBounds(usingClipCount: number): void { + const useClippingMaskMaxCount = + this._renderTextureCount <= 1 + ? ClippingMaskMaxCountOnDefault + : ClippingMaskMaxCountOnMultiRenderTexture * this._renderTextureCount; + if (usingClipCount <= 0 || usingClipCount > useClippingMaskMaxCount) { + if (usingClipCount > useClippingMaskMaxCount) { + // マスクの制限数の警告を出す + CubismLogError( + 'not supported mask count : {0}\n[Details] render texture count : {1}, mask count : {2}', + usingClipCount - useClippingMaskMaxCount, + this._renderTextureCount, + usingClipCount + ); + } + // この場合は一つのマスクターゲットを毎回クリアして使用する + for ( + let index = 0; + index < this._clippingContextListForMask.length; + index++ + ) { + const clipContext: T_ClippingContext = + this._clippingContextListForMask[index]; + clipContext._layoutChannelIndex = 0; // どうせ毎回消すので固定 + clipContext._layoutBounds.x = 0.0; + clipContext._layoutBounds.y = 0.0; + clipContext._layoutBounds.width = 1.0; + clipContext._layoutBounds.height = 1.0; + clipContext._bufferIndex = 0; + } + return; + } + // レンダーテクスチャが1枚なら9分割する(最大36枚) + const layoutCountMaxValue = this._renderTextureCount <= 1 ? 9 : 8; + + // 指定された数のレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトする(デフォルトなら1)。 + // マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する。 + let countPerSheetDiv: number = usingClipCount / this._renderTextureCount; // レンダーテクスチャ1枚あたり何枚割り当てるか。 + const reduceLayoutTextureCount: number = + usingClipCount % this._renderTextureCount; // レイアウトの数を1枚減らすレンダーテクスチャの数(この数だけのレンダーテクスチャが対象)。 + + // 1枚に割り当てるマスクの分割数を取りたいため、小数点は切り上げる + countPerSheetDiv = Math.ceil(countPerSheetDiv); + + // RGBAを順番に使っていく + let divCount: number = countPerSheetDiv / ColorChannelCount; // 1チャンネルに配置する基本のマスク + const modCount: number = countPerSheetDiv % ColorChannelCount; // 余り、この番号のチャンネルまでに一つずつ配分する(インデックスではない) + + // 小数点は切り捨てる + divCount = ~~divCount; + + // RGBAそれぞれのチャンネルを用意していく(0:R, 1:G, 2:B, 3:A) + let curClipIndex = 0; // 順番に設定していく + for ( + let renderTextureIndex = 0; + renderTextureIndex < this._renderTextureCount; + renderTextureIndex++ + ) { + for ( + let channelIndex = 0; + channelIndex < ColorChannelCount; + channelIndex++ + ) { + let layoutCount: number = divCount + (channelIndex < modCount ? 1 : 0); + // レイアウトの数を1枚減らす場合にそれを行うチャンネルを決定 + // divが0の時は正常なインデックスの範囲内になるように調整 + const 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) { + // 全てをそのまま使う + const clipContext: T_ClippingContext = + this._clippingContextListForMask[curClipIndex++]; + clipContext._layoutChannelIndex = channelIndex; + clipContext._layoutBounds.x = 0.0; + clipContext._layoutBounds.y = 0.0; + clipContext._layoutBounds.width = 1.0; + clipContext._layoutBounds.height = 1.0; + clipContext._bufferIndex = renderTextureIndex; + } else if (layoutCount == 2) { + for (let i = 0; i < layoutCount; i++) { + let xpos: number = i % 2; + // 小数点は切り捨てる + xpos = ~~xpos; + const cc: T_ClippingContext = this._clippingContextListForMask[curClipIndex++]; + cc._layoutChannelIndex = channelIndex; + // UVを2つに分解して使う + cc._layoutBounds.x = xpos * 0.5; + cc._layoutBounds.y = 0.0; + cc._layoutBounds.width = 0.5; + cc._layoutBounds.height = 1.0; + cc._bufferIndex = renderTextureIndex; + } + } else if (layoutCount <= 4) { + // 4分割して使う + for (let i = 0; i < layoutCount; i++) { + let xpos: number = i % 2; + let ypos: number = i / 2; + // 小数点は切り捨てる + xpos = ~~xpos; + ypos = ~~ypos; + const cc = this._clippingContextListForMask[curClipIndex++]; + cc._layoutChannelIndex = channelIndex; + cc._layoutBounds.x = xpos * 0.5; + cc._layoutBounds.y = ypos * 0.5; + cc._layoutBounds.width = 0.5; + cc._layoutBounds.height = 0.5; + cc._bufferIndex = renderTextureIndex; + } + } else if (layoutCount <= layoutCountMaxValue) { + // 9分割して使う + for (let i = 0; i < layoutCount; i++) { + let xpos = i % 3; + let ypos = i / 3; + // 小数点は切り捨てる + xpos = ~~xpos; + ypos = ~~ypos; + const cc: T_ClippingContext = this._clippingContextListForMask[curClipIndex++]; + cc._layoutChannelIndex = channelIndex; + cc._layoutBounds.x = xpos / 3.0; + cc._layoutBounds.y = ypos / 3.0; + cc._layoutBounds.width = 1.0 / 3.0; + cc._layoutBounds.height = 1.0 / 3.0; + cc._bufferIndex = renderTextureIndex; + } + } else { + // マスクの制限枚数を超えた場合の処理 + CubismLogError( + 'not supported mask count : {0}\n[Details] render texture count : {1}, mask count : {2}', + usingClipCount - useClippingMaskMaxCount, + this._renderTextureCount, + usingClipCount + ); + // SetupShaderProgramでオーバーアクセスが発生するので仮で数値を入れる + // もちろん描画結果は正しいものではなくなる + for (let index = 0; index < layoutCount; index++) { + const cc: T_ClippingContext = this._clippingContextListForMask[curClipIndex++]; + cc._layoutChannelIndex = 0; + cc._layoutBounds.x = 0.0; + cc._layoutBounds.y = 0.0; + cc._layoutBounds.width = 1.0; + cc._layoutBounds.height = 1.0; + cc._bufferIndex = 0; + } + } + } + } + } + /** + * マスクされる描画オブジェクト群全体を囲む矩形(モデル座標系)を計算する + * @param model モデルのインスタンス + * @param clippingContext クリッピングマスクのコンテキスト + */ + public calcClippedDrawTotalBounds( + model: CubismModel, + clippingContext: T_ClippingContext + ): void { + // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 + let clippedDrawTotalMinX: number = Number.MAX_VALUE; + let clippedDrawTotalMinY: number = Number.MAX_VALUE; + let clippedDrawTotalMaxX: number = Number.MIN_VALUE; + let clippedDrawTotalMaxY: number = Number.MIN_VALUE; + // このマスクが実際に必要か判定する + // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある + const clippedDrawCount: number = + clippingContext._clippedDrawableIndexList.length; + for ( + let clippedDrawableIndex = 0; + clippedDrawableIndex < clippedDrawCount; + clippedDrawableIndex++ + ) { + // マスクを使用する描画オブジェクトの描画される矩形を求める + const drawableIndex: number = + clippingContext._clippedDrawableIndexList[clippedDrawableIndex]; + const drawableVertexCount: number = + model.getDrawableVertexCount(drawableIndex); + const drawableVertexes: Float32Array = + model.getDrawableVertices(drawableIndex); + let minX: number = Number.MAX_VALUE; + let minY: number = Number.MAX_VALUE; + let maxX: number = -Number.MAX_VALUE; + let maxY: number = -Number.MAX_VALUE; + const loop: number = drawableVertexCount * Constant.vertexStep; + for ( + let pi: number = Constant.vertexOffset; + pi < loop; + pi += Constant.vertexStep + ) { + const x: number = drawableVertexes[pi]; + const y: number = drawableVertexes[pi + 1]; + if (x < minX) { + minX = x; + } + if (x > maxX) { + maxX = x; + } + if (y < minY) { + minY = y; + } + if (y > maxY) { + maxY = y; + } + } + // 有効な点が一つも取れなかったのでスキップ + if (minX == Number.MAX_VALUE) { + continue; + } + // 全体の矩形に反映 + if (minX < clippedDrawTotalMinX) { + clippedDrawTotalMinX = minX; + } + if (minY < clippedDrawTotalMinY) { + clippedDrawTotalMinY = minY; + } + if (maxX > clippedDrawTotalMaxX) { + clippedDrawTotalMaxX = maxX; + } + if (maxY > clippedDrawTotalMaxY) { + clippedDrawTotalMaxY = maxY; + } + if (clippedDrawTotalMinX == Number.MAX_VALUE) { + clippingContext._allClippedDrawRect.x = 0.0; + clippingContext._allClippedDrawRect.y = 0.0; + clippingContext._allClippedDrawRect.width = 0.0; + clippingContext._allClippedDrawRect.height = 0.0; + clippingContext._isUsing = false; + } else { + clippingContext._isUsing = true; + const w: number = clippedDrawTotalMaxX - clippedDrawTotalMinX; + const h: number = clippedDrawTotalMaxY - clippedDrawTotalMinY; + clippingContext._allClippedDrawRect.x = clippedDrawTotalMinX; + clippingContext._allClippedDrawRect.y = clippedDrawTotalMinY; + clippingContext._allClippedDrawRect.width = w; + clippingContext._allClippedDrawRect.height = h; + } + } + } + /** + * 画面描画に使用するクリッピングマスクのリストを取得する + * @return 画面描画に使用するクリッピングマスクのリスト + */ + public getClippingContextListForDraw(): csmVector { + return this._clippingContextListForDraw; + } + /** + * クリッピングマスクバッファのサイズを取得する + * @return クリッピングマスクバッファのサイズ + */ + public getClippingMaskBufferSize(): number { + return this._clippingMaskBufferSize; + } + /** + * このバッファのレンダーテクスチャの枚数を取得する + * @return このバッファのレンダーテクスチャの枚数 + */ + public getRenderTextureCount(): number { + return this._renderTextureCount; + } + /** + * カラーチャンネル(RGBA)のフラグを取得する + * @param channelNo カラーチャンネル(RGBA)の番号(0:R, 1:G, 2:B, 3:A) + */ + public getChannelFlagAsColor(channelNo: number): CubismTextureColor { + return this._channelColors[channelNo]; + } + /** + * クリッピングマスクバッファのサイズを設定する + * @param size クリッピングマスクバッファのサイズ + */ + public setClippingMaskBufferSize(size: number): void { + this._clippingMaskBufferSize = size; + } + protected _clearedFrameBufferFlags: boolean[]; //マスクのクリアフラグの配列 + protected _channelColors: CubismTextureColor[]; + protected _clippingContextListForMask: T_ClippingContext[]; // マスク用クリッピングコンテキストのリスト + protected _clippingContextListForDraw: T_ClippingContext[]; // 描画用クリッピングコンテキストのリスト + protected _clippingMaskBufferSize: number; // クリッピングマスクのバッファサイズ(初期値:256) + protected _renderTextureCount: number; // 生成するレンダーテクスチャの枚数 + protected _tmpMatrix: CubismMatrix44; // マスク計算用の行列 + protected _tmpMatrixForMask: CubismMatrix44; // マスク計算用の行列 + protected _tmpMatrixForDraw: CubismMatrix44; // マスク計算用の行列 + protected _tmpBoundsOnModel: csmRect; // マスク配置計算用の矩形 + protected _clippingContexttConstructor: ClippingContextConstructor; +} \ No newline at end of file diff --git a/src/rendering/cubismrenderer.ts b/src/rendering/cubismrenderer.ts index 88e3698..a9e0419 100644 --- a/src/rendering/cubismrenderer.ts +++ b/src/rendering/cubismrenderer.ts @@ -7,6 +7,8 @@ import { CubismMatrix44 } from '../math/cubismmatrix44'; import { CubismModel } from '../model/cubismmodel'; +import { csmRect } from '../type/csmrectf'; +import { ICubismClippingManager } from './cubismclippingmanager'; /** * モデル描画を処理するレンダラ @@ -107,6 +109,25 @@ export abstract class CubismRenderer { return Object.assign({}, this._modelColor); } + /** + * 透明度を考慮したモデルの色を計算する。 + * + * @param opacity 透明度 + * + * @return RGBAのカラー情報 + */ + getModelColorWithOpacity(opacity: number): CubismTextureColor { + const modelColorRGBA: CubismTextureColor = this.getModelColor(); + modelColorRGBA.A *= opacity; + if (this.isPremultipliedAlpha()) { + modelColorRGBA.R *= modelColorRGBA.A; + modelColorRGBA.G *= modelColorRGBA.A; + modelColorRGBA.B *= modelColorRGBA.A; + } + return modelColorRGBA; + } + + /** * 乗算済みαの有効・無効をセットする * 有効にするならtrue、無効にするならfalseをセットする @@ -207,33 +228,6 @@ export abstract class CubismRenderer { */ public abstract doDrawModel(): void; - /** - * 描画オブジェクト(アートメッシュ)を描画する - * ポリゴンメッシュとテクスチャ番号をセットで渡す。 - * @param textureNo 描画するテクスチャ番号 - * @param indexCount 描画オブジェクトのインデックス値 - * @param vertexCount ポリゴンメッシュの頂点数 - * @param indexArray ポリゴンメッシュ頂点のインデックス配列 - * @param vertexArray ポリゴンメッシュの頂点配列 - * @param uvArray uv配列 - * @param opacity 不透明度 - * @param colorBlendMode カラーブレンディングのタイプ - * @param invertedMask マスク使用時のマスクの反転使用 - */ - public abstract drawMesh( - textureNo: number, - indexCount: number, - vertexCount: number, - indexArray: Uint16Array, - vertexArray: Float32Array, - uvArray: Float32Array, - multiplyColor: CubismTextureColor, - screenColor: CubismTextureColor, - opacity: number, - colorBlendMode: CubismBlendMode, - invertedMask: boolean - ): void; - /** * モデル描画直前のレンダラのステートを保持する */ @@ -283,3 +277,62 @@ export class CubismTextureColor { B: number; // 青チャンネル A: number; // αチャンネル } + +/** + * クリッピングマスクのコンテキスト + */ +export abstract class CubismClippingContext { + /** + * 引数付きコンストラクタ + */ + public constructor(clippingDrawableIndices: Int32Array, clipCount: number) { + // クリップしている(=マスク用の)Drawableのインデックスリスト + this._clippingIdList = clippingDrawableIndices; + // マスクの数 + this._clippingIdCount = clipCount; + this._allClippedDrawRect = new csmRect(); + this._layoutBounds = new csmRect(); + this._clippedDrawableIndexList = []; + this._matrixForMask = new CubismMatrix44(); + this._matrixForDraw = new CubismMatrix44(); + this._bufferIndex = 0; + } + /** + * このマスクを管理するマネージャのインスタンスを取得する + * @return クリッピングマネージャのインスタンス + */ + public abstract getClippingManager(): ICubismClippingManager; + /** + * デストラクタ相当の処理 + */ + public release(): void { + if (this._layoutBounds != null) { + this._layoutBounds = null; + } + if (this._allClippedDrawRect != null) { + this._allClippedDrawRect = null; + } + if (this._clippedDrawableIndexList != null) { + this._clippedDrawableIndexList = null; + } + } + + /** + * このマスクにクリップされる描画オブジェクトを追加する + * + * @param drawableIndex クリッピング対象に追加する描画オブジェクトのインデックス + */ + public addClippedDrawable(drawableIndex: number) { + this._clippedDrawableIndexList.push(drawableIndex); + } + public _isUsing: boolean; // 現在の描画状態でマスクの準備が必要ならtrue + public readonly _clippingIdList: Int32Array; // クリッピングマスクのIDリスト + public _clippingIdCount: number; // クリッピングマスクの数 + public _layoutChannelIndex: number; // RGBAのいずれのチャンネルにこのクリップを配置するか(0:R, 1:G, 2:B, 3:A) + public _layoutBounds: csmRect; // マスク用チャンネルのどの領域にマスクを入れるか(View座標-1~1, UVは0~1に直す) + public _allClippedDrawRect: csmRect; // このクリッピングで、クリッピングされるすべての描画オブジェクトの囲み矩形(毎回更新) + public _matrixForMask: CubismMatrix44; // マスクの位置計算結果を保持する行列 + public _matrixForDraw: CubismMatrix44; // 描画オブジェクトの位置計算結果を保持する行列 + public _clippedDrawableIndexList: number[]; // このマスクにクリップされる描画オブジェクトのリスト + public _bufferIndex: number; // このマスクが割り当てられるレンダーテクスチャ(フレームバッファ)やカラーバッファのインデックス +} diff --git a/src/rendering/cubismrenderer_webgl.ts b/src/rendering/cubismrenderer_webgl.ts index e8c904b..895966d 100644 --- a/src/rendering/cubismrenderer_webgl.ts +++ b/src/rendering/cubismrenderer_webgl.ts @@ -5,39 +5,20 @@ * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ -import { Constant } from '../live2dcubismframework'; -import { CubismMatrix44 } from '../math/cubismmatrix44'; import { CubismModel } from '../model/cubismmodel'; import { csmRect } from '../type/csmrectf'; -import { CubismLogError, CubismLogWarning } from '../utils/cubismdebug'; -import { - CubismBlendMode, - CubismRenderer, - CubismTextureColor, -} from './cubismrenderer'; -import { CubismConfig } from '../config'; - -const ColorChannelCount = 4; // 実験時に1チャンネルの場合は1、RGBだけの場合は3、アルファも含める場合は4 -const ClippingMaskMaxCountOnDefault = 36; // 通常のフレームバッファ一枚あたりのマスク最大数 -const ClippingMaskMaxCountOnMultiRenderTexture = 32; // フレームバッファが2枚以上ある場合のフレームバッファ一枚あたりのマスク最大数 - -const ShaderCount = 10; // シェーダーの数 = マスク生成用 + (通常用 + 加算 + 乗算) * (マスク無の乗算済アルファ対応版 + マスク有の乗算済アルファ対応版 + マスク有反転の乗算済アルファ対応版) -let s_instance: CubismShader_WebGL | undefined; +import { CubismLogError } from '../utils/cubismdebug'; +import { CubismClippingManager } from './cubismclippingmanager'; +import { CubismClippingContext, CubismRenderer } from './cubismrenderer'; +import { CubismShader_WebGL } from './cubismshader_webgl'; + let s_viewport: number[]; let s_fbo: WebGLFramebuffer; /** * クリッピングマスクの処理を実行するクラス */ -export class CubismClippingManager_WebGL { - /** - * カラーチャンネル(RGBA)のフラグを取得する - * @param channelNo カラーチャンネル(RGBA)の番号(0:R, 1:G, 2:B, 3:A) - */ - public getChannelFlagAsColor(channelNo: number): CubismTextureColor { - return this._channelColors[channelNo]; - } - +export class CubismClippingManager_WebGL extends CubismClippingManager { /** * テンポラリのレンダーテクスチャのアドレスを取得する * FrameBufferObjectが存在しない場合、新しく生成する @@ -50,15 +31,27 @@ export class CubismClippingManager_WebGL { // 前回使ったものを返す this._maskTexture.frameNo = this._currentFrameNo; } else { + // FrameBufferObjectが存在しない場合、新しく生成する + if (this._maskRenderTextures != null) { + this._maskRenderTextures = [] + } this._maskRenderTextures = []; + + // ColorBufferObjectが存在しない場合、新しく生成する + if (this._maskColorBuffers != null) { + this._maskColorBuffers = [] + } this._maskColorBuffers = []; // クリッピングバッファサイズを取得 const size: number = this._clippingMaskBufferSize; for (let index = 0; index < this._renderTextureCount; index++) { - this._maskColorBuffers.push(this.gl.createTexture()!); // 直接代入 - this.gl.bindTexture(this.gl.TEXTURE_2D, this._maskColorBuffers[index]); + this._maskColorBuffers.push(this.gl.createTexture()); // 直接代入 + this.gl.bindTexture( + this.gl.TEXTURE_2D, + this._maskColorBuffers[index] + ); this.gl.texImage2D( this.gl.TEXTURE_2D, 0, @@ -92,7 +85,7 @@ export class CubismClippingManager_WebGL { ); this.gl.bindTexture(this.gl.TEXTURE_2D, null); - this._maskRenderTextures.push(this.gl.createFramebuffer()!); + this._maskRenderTextures.push(this.gl.createFramebuffer()); this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this._maskRenderTextures[index] @@ -124,249 +117,11 @@ export class CubismClippingManager_WebGL { this.gl = gl; } - /** - * マスクされる描画オブジェクト群全体を囲む矩形(モデル座標系)を計算する - * @param model モデルのインスタンス - * @param clippingContext クリッピングマスクのコンテキスト - */ - public calcClippedDrawTotalBounds( - model: CubismModel, - clippingContext: CubismClippingContext - ): void { - // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 - let clippedDrawTotalMinX: number = Number.MAX_VALUE; - let clippedDrawTotalMinY: number = Number.MAX_VALUE; - let clippedDrawTotalMaxX: number = Number.MIN_VALUE; - let clippedDrawTotalMaxY: number = Number.MIN_VALUE; - - // このマスクが実際に必要か判定する - // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある - const clippedDrawCount: number = - clippingContext._clippedDrawableIndexList.length; - - for ( - let clippedDrawableIndex = 0; - clippedDrawableIndex < clippedDrawCount; - clippedDrawableIndex++ - ) { - // マスクを使用する描画オブジェクトの描画される矩形を求める - const drawableIndex: number = - clippingContext._clippedDrawableIndexList[clippedDrawableIndex]; - - const drawableVertexCount: number = - model.getDrawableVertexCount(drawableIndex); - const drawableVertexes: Float32Array = - model.getDrawableVertices(drawableIndex); - - let minX: number = Number.MAX_VALUE; - let minY: number = Number.MAX_VALUE; - let maxX: number = -Number.MAX_VALUE; - let maxY: number = -Number.MAX_VALUE; - - const loop: number = drawableVertexCount * Constant.vertexStep; - for ( - let pi: number = Constant.vertexOffset; - pi < loop; - pi += Constant.vertexStep - ) { - const x: number = drawableVertexes[pi]; - const y: number = drawableVertexes[pi + 1]; - - if (x < minX) { - minX = x; - } - if (x > maxX) { - maxX = x; - } - if (y < minY) { - minY = y; - } - if (y > maxY) { - maxY = y; - } - } - - // 有効な点が一つも取れなかったのでスキップ - if (minX == Number.MAX_VALUE) { - continue; - } - - // 全体の矩形に反映 - if (minX < clippedDrawTotalMinX) { - clippedDrawTotalMinX = minX; - } - if (minY < clippedDrawTotalMinY) { - clippedDrawTotalMinY = minY; - } - if (maxX > clippedDrawTotalMaxX) { - clippedDrawTotalMaxX = maxX; - } - if (maxY > clippedDrawTotalMaxY) { - clippedDrawTotalMaxY = maxY; - } - - if (clippedDrawTotalMinX == Number.MAX_VALUE) { - clippingContext._allClippedDrawRect.x = 0.0; - clippingContext._allClippedDrawRect.y = 0.0; - clippingContext._allClippedDrawRect.width = 0.0; - clippingContext._allClippedDrawRect.height = 0.0; - clippingContext._isUsing = false; - } else { - clippingContext._isUsing = true; - const w: number = clippedDrawTotalMaxX - clippedDrawTotalMinX; - const h: number = clippedDrawTotalMaxY - clippedDrawTotalMinY; - clippingContext._allClippedDrawRect.x = clippedDrawTotalMinX; - clippingContext._allClippedDrawRect.y = clippedDrawTotalMinY; - clippingContext._allClippedDrawRect.width = w; - clippingContext._allClippedDrawRect.height = h; - } - } - } - /** * コンストラクタ */ public constructor() { - this._currentMaskRenderTexture = null; - this._currentFrameNo = 0; - this._renderTextureCount = 0; - this._clippingMaskBufferSize = 256; - this._clippingContextListForMask = []; - this._clippingContextListForDraw = []; - this._channelColors = []; - this._tmpBoundsOnModel = new csmRect(); - this._tmpMatrix = new CubismMatrix44(); - this._tmpMatrixForMask = new CubismMatrix44(); - this._tmpMatrixForDraw = new CubismMatrix44(); - - let tmp: CubismTextureColor = new CubismTextureColor(); - tmp.R = 1.0; - tmp.G = 0.0; - tmp.B = 0.0; - tmp.A = 0.0; - this._channelColors.push(tmp); - - tmp = new CubismTextureColor(); - tmp.R = 0.0; - tmp.G = 1.0; - tmp.B = 0.0; - tmp.A = 0.0; - this._channelColors.push(tmp); - - tmp = new CubismTextureColor(); - tmp.R = 0.0; - tmp.G = 0.0; - tmp.B = 1.0; - tmp.A = 0.0; - this._channelColors.push(tmp); - - tmp = new CubismTextureColor(); - tmp.R = 0.0; - tmp.G = 0.0; - tmp.B = 0.0; - tmp.A = 1.0; - this._channelColors.push(tmp); - } - - /** - * デストラクタ相当の処理 - */ - public release(): void { - const self = this as Partial; - - for (let i = 0; i < this._clippingContextListForMask.length; i++) { - if (this._clippingContextListForMask[i]) { - this._clippingContextListForMask[i]?.release(); - } - } - self._clippingContextListForMask = undefined; - - // _clippingContextListForDrawは_clippingContextListForMaskにあるインスタンスを指している。上記の処理により要素ごとのDELETEは不要。 - self._clippingContextListForDraw = undefined; - - if (this._maskTexture) { - for (let i = 0; i < this._maskTexture.textures.length; i++) { - this.gl.deleteFramebuffer(this._maskTexture.textures[i]); - } - this._maskTexture = undefined; - } - - self._channelColors = undefined; - - // テクスチャ解放 - if (this._maskColorBuffers) { - for (let index = 0; index < this._maskColorBuffers.length; index++) { - this.gl.deleteTexture(this._maskColorBuffers[index]); - } - } - this._maskColorBuffers = undefined; - this._maskRenderTextures = undefined; - this._clearedFrameBufferflags = undefined; - } - - /** - * マネージャの初期化処理 - * クリッピングマスクを使う描画オブジェクトの登録を行う - * @param model モデルのインスタンス - * @param drawableCount 描画オブジェクトの数 - * @param drawableMasks 描画オブジェクトをマスクする描画オブジェクトのインデックスのリスト - * @param drawableMaskCounts 描画オブジェクトをマスクする描画オブジェクトの数 - * @param renderTextureCount バッファの生成数 - */ - public initialize( - model: CubismModel, - drawableCount: number, - drawableMasks: Int32Array[], - drawableMaskCounts: Int32Array, - renderTextureCount: number - ): void { - // レンダーテクスチャの合計枚数の設定 - // 1以上の整数でない場合はそれぞれ警告を出す - if (renderTextureCount % 1 != 0) { - CubismLogWarning( - 'The number of render textures must be specified as an integer. The decimal point is rounded down and corrected to an integer.' - ); - // 小数点以下を除去 - renderTextureCount = ~~renderTextureCount; - } - if (renderTextureCount < 1) { - CubismLogWarning( - 'The number of render textures must be an integer greater than or equal to 1. Set the number of render textures to 1.' - ); - } - // 負の値が使われている場合は強制的に1枚と設定する - this._renderTextureCount = renderTextureCount < 1 ? 1 : renderTextureCount; - - this._clearedFrameBufferflags = []; - - // クリッピングマスクを使う描画オブジェクトをすべて登録する - // クリッピングマスクは、通常数個程度に限定して使うものとする - for (let i = 0; i < drawableCount; i++) { - if (drawableMaskCounts[i] <= 0) { - // クリッピングマスクが使用されていないアートメッシュ(多くの場合使用しない) - this._clippingContextListForDraw.push(null); - continue; - } - - // 既にあるClipContextと同じかチェックする - let clippingContext = this.findSameClip( - drawableMasks[i], - drawableMaskCounts[i] - ); - if (clippingContext == null) { - // 同一のマスクが存在していない場合は生成する - clippingContext = new CubismClippingContext( - this, - drawableMasks[i], - drawableMaskCounts[i] - ); - this._clippingContextListForMask.push(clippingContext); - } - - clippingContext.addClippedDrawable(i); - - this._clippingContextListForDraw.push(clippingContext); - } + super(CubismClippingContext_WebGL); } /** @@ -389,7 +144,8 @@ export class CubismClippingManager_WebGL { clipIndex++ ) { // 1つのクリッピングマスクに関して - const cc = this._clippingContextListForMask[clipIndex]; + const cc: CubismClippingContext_WebGL = + this._clippingContextListForMask[clipIndex]; // このクリップを利用する描画オブジェクト群全体を囲む矩形を計算 this.calcClippedDrawTotalBounds(model, cc); @@ -401,40 +157,40 @@ export class CubismClippingManager_WebGL { // マスク作成処理 if (usingClipCount > 0) { - // 各マスクのレイアウトを決定していく - this.setupLayoutBounds( - renderer.isUsingHighPrecisionMask() ? 0 : usingClipCount + // 生成したFrameBufferと同じサイズでビューポートを設定 + this.gl.viewport( + 0, + 0, + this._clippingMaskBufferSize, + this._clippingMaskBufferSize ); - if (!renderer.isUsingHighPrecisionMask()) { - // 生成したFrameBufferと同じサイズでビューポートを設定 - this.gl.viewport( - 0, - 0, - this._clippingMaskBufferSize, - this._clippingMaskBufferSize - ); + // 後の計算のためにインデックスの最初をセット + this._currentMaskRenderTexture = this.getMaskRenderTexture()[0]; - // 後の計算のためにインデックスの最初をセット - this._currentMaskRenderTexture = this.getMaskRenderTexture()[0]; + renderer.preDraw(); // バッファをクリアする - renderer.preDraw(); // バッファをクリアする + this.setupLayoutBounds(usingClipCount); - // ---------- マスク描画処理 ---------- - // マスク用RenderTextureをactiveにセット - this.gl.bindFramebuffer( - this.gl.FRAMEBUFFER, - this._currentMaskRenderTexture - ); - } + // ---------- マスク描画処理 ---------- + // マスク用RenderTextureをactiveにセット + this.gl.bindFramebuffer( + this.gl.FRAMEBUFFER, + this._currentMaskRenderTexture + ); - if (!this._clearedFrameBufferflags) { - this._clearedFrameBufferflags = []; + // サイズがレンダーテクスチャの枚数と合わない場合は合わせる + if (this._clearedFrameBufferFlags.length != this._renderTextureCount) { + this._clearedFrameBufferFlags = [] } // マスクのクリアフラグを毎フレーム開始時に初期化 - for (let index = 0; index < this._renderTextureCount; index++) { - this._clearedFrameBufferflags[index] = false; + for ( + let index = 0; + index < this._clearedFrameBufferFlags.length; + index++ + ) { + this._clearedFrameBufferFlags[index] = false; } // 実際にマスクを生成する @@ -445,7 +201,7 @@ export class CubismClippingManager_WebGL { clipIndex++ ) { // --- 実際に1つのマスクを描く --- - const clipContext: CubismClippingContext = + const clipContext: CubismClippingContext_WebGL = this._clippingContextListForMask[clipIndex]; const allClipedDrawRect: csmRect = clipContext._allClippedDrawRect; // このマスクを使う、すべての描画オブジェクトの論理座標上の囲み矩形 const layoutBoundsOnTex01: csmRect = clipContext._layoutBounds; // この中にマスクを収める @@ -454,14 +210,10 @@ export class CubismClippingManager_WebGL { let scaleY = 0; // clipContextに設定したレンダーテクスチャをインデックスで取得 - const clipContextRenderTexture = - this.getMaskRenderTexture()[clipContext._bufferIndex]; + const clipContextRenderTexture = this.getMaskRenderTexture()[clipContext._bufferIndex]; // 現在のレンダーテクスチャがclipContextのものと異なる場合 - if ( - this._currentMaskRenderTexture != clipContextRenderTexture && - !renderer.isUsingHighPrecisionMask() - ) { + if (this._currentMaskRenderTexture != clipContextRenderTexture) { this._currentMaskRenderTexture = clipContextRenderTexture; renderer.preDraw(); // バッファをクリアする // マスク用RenderTextureをactiveにセット @@ -471,49 +223,17 @@ export class CubismClippingManager_WebGL { ); } - if (renderer.isUsingHighPrecisionMask()) { - const ppu: number = model.getPixelsPerUnit(); - const maskPixelSize: number = - clipContext.getClippingManager()._clippingMaskBufferSize; - const physicalMaskWidth: number = - layoutBoundsOnTex01.width * maskPixelSize; - const physicalMaskHeight: number = - layoutBoundsOnTex01.height * maskPixelSize; - - this._tmpBoundsOnModel.setRect(allClipedDrawRect); - - if (this._tmpBoundsOnModel.width * ppu > physicalMaskWidth) { - this._tmpBoundsOnModel.expand( - allClipedDrawRect.width * MARGIN, - 0.0 - ); - scaleX = layoutBoundsOnTex01.width / this._tmpBoundsOnModel.width; - } else { - scaleX = ppu / physicalMaskWidth; - } - - if (this._tmpBoundsOnModel.height * ppu > physicalMaskHeight) { - this._tmpBoundsOnModel.expand( - 0.0, - allClipedDrawRect.height * MARGIN - ); - scaleY = layoutBoundsOnTex01.height / this._tmpBoundsOnModel.height; - } else { - scaleY = ppu / physicalMaskHeight; - } - } else { - this._tmpBoundsOnModel.setRect(allClipedDrawRect); - this._tmpBoundsOnModel.expand( - allClipedDrawRect.width * MARGIN, - allClipedDrawRect.height * MARGIN - ); - //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + this._tmpBoundsOnModel.setRect(allClipedDrawRect); + this._tmpBoundsOnModel.expand( + allClipedDrawRect.width * MARGIN, + allClipedDrawRect.height * MARGIN + ); + //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい - // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり - // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] - scaleX = layoutBoundsOnTex01.width / this._tmpBoundsOnModel.width; - scaleY = layoutBoundsOnTex01.height / this._tmpBoundsOnModel.height; - } + // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり + // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] + scaleX = layoutBoundsOnTex01.width / this._tmpBoundsOnModel.width; + scaleY = layoutBoundsOnTex01.height / this._tmpBoundsOnModel.height; // マスク生成時に使う行列を求める { @@ -562,309 +282,48 @@ export class CubismClippingManager_WebGL { clipContext._matrixForMask.setMatrix(this._tmpMatrixForMask.getArray()); clipContext._matrixForDraw.setMatrix(this._tmpMatrixForDraw.getArray()); - if (!renderer.isUsingHighPrecisionMask()) { - const clipDrawCount: number = clipContext._clippingIdCount; - for (let i = 0; i < clipDrawCount; i++) { - const clipDrawIndex: number = clipContext._clippingIdList[i]; + const clipDrawCount: number = clipContext._clippingIdCount; + for (let i = 0; i < clipDrawCount; i++) { + const clipDrawIndex: number = clipContext._clippingIdList[i]; - // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする - if ( - !model.getDrawableDynamicFlagVertexPositionsDidChange( - clipDrawIndex - ) - ) { - continue; - } - - renderer.setIsCulling( - model.getDrawableCulling(clipDrawIndex) != false - ); - - // マスクがクリアされていないなら処理する - if (!this._clearedFrameBufferflags[clipContext._bufferIndex]) { - // マスクをクリアする - // (仮仕様) 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダーCd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない) - this.gl.clearColor(1.0, 1.0, 1.0, 1.0); - this.gl.clear(this.gl.COLOR_BUFFER_BIT); - this._clearedFrameBufferflags[clipContext._bufferIndex] = true; - } - - // 今回専用の変換を適用して描く - // チャンネルも切り替える必要がある(A,R,G,B) - renderer.setClippingContextBufferForMask(clipContext); - renderer.drawMesh( - model.getDrawableTextureIndex(clipDrawIndex), - model.getDrawableVertexIndexCount(clipDrawIndex), - model.getDrawableVertexCount(clipDrawIndex), - model.getDrawableVertexIndices(clipDrawIndex), - model.getDrawableVertices(clipDrawIndex), - model.getDrawableVertexUvs(clipDrawIndex), - model.getMultiplyColor(clipDrawIndex), - model.getScreenColor(clipDrawIndex), - model.getDrawableOpacity(clipDrawIndex), - CubismBlendMode.CubismBlendMode_Normal, // クリッピングは通常描画を強制 - false // マスク生成時はクリッピングの反転使用は全く関係がない - ); + // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする + if ( + !model.getDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex) + ) { + continue; } - } - } - - if (!renderer.isUsingHighPrecisionMask()) { - // --- 後処理 --- - this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, s_fbo); // 描画対象を戻す - renderer.setClippingContextBufferForMask(null); - - this.gl.viewport( - s_viewport[0], - s_viewport[1], - s_viewport[2], - s_viewport[3] - ); - } - } - } - - /** - * 既にマスクを作っているかを確認 - * 作っている様であれば該当するクリッピングマスクのインスタンスを返す - * 作っていなければNULLを返す - * @param drawableMasks 描画オブジェクトをマスクする描画オブジェクトのリスト - * @param drawableMaskCounts 描画オブジェクトをマスクする描画オブジェクトの数 - * @return 該当するクリッピングマスクが存在すればインスタンスを返し、なければNULLを返す - */ - public findSameClip( - drawableMasks: Int32Array, - drawableMaskCounts: number - ): CubismClippingContext | null { - // 作成済みClippingContextと一致するか確認 - for (let i = 0; i < this._clippingContextListForMask.length; i++) { - const clippingContext: CubismClippingContext = - this._clippingContextListForMask[i]; - const count: number = clippingContext._clippingIdCount; - - // 個数が違う場合は別物 - if (count != drawableMaskCounts) { - continue; - } - let sameCount = 0; - - // 同じIDを持つか確認。配列の数が同じなので、一致した個数が同じなら同じ物を持つとする - for (let j = 0; j < count; j++) { - const clipId: number = clippingContext._clippingIdList[j]; + renderer.setIsCulling( + model.getDrawableCulling(clipDrawIndex) != false + ); - for (let k = 0; k < count; k++) { - if (drawableMasks[k] == clipId) { - sameCount++; - break; + // マスクがクリアされていないなら処理する + if (!this._clearedFrameBufferFlags[clipContext._bufferIndex]) { + // マスクをクリアする + // (仮仕様) 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダーCd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない) + this.gl.clearColor(1.0, 1.0, 1.0, 1.0); + this.gl.clear(this.gl.COLOR_BUFFER_BIT); + this._clearedFrameBufferFlags[clipContext._bufferIndex] = true; } - } - } - - if (sameCount == count) { - return clippingContext; - } - } - - return null; // 見つからなかった - } - - /** - * クリッピングコンテキストを配置するレイアウト - * 指定された数のレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトする - * マスクグループの数が4以下ならRGBA各チャンネルに一つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する。 - * - * @param usingClipCount 配置するクリッピングコンテキストの数 - */ - public setupLayoutBounds(usingClipCount: number): void { - const useClippingMaskMaxCount = - this._renderTextureCount <= 1 - ? ClippingMaskMaxCountOnDefault - : ClippingMaskMaxCountOnMultiRenderTexture * this._renderTextureCount; - - if (usingClipCount <= 0 || usingClipCount > useClippingMaskMaxCount) { - if (usingClipCount > useClippingMaskMaxCount) { - // マスクの制限数の警告を出す - CubismLogError( - 'not supported mask count : {0}\n[Details] render texture count : {1}, mask count : {2}', - usingClipCount - useClippingMaskMaxCount, - this._renderTextureCount, - usingClipCount - ); - } - // この場合は一つのマスクターゲットを毎回クリアして使用する - for ( - let index = 0; - index < this._clippingContextListForMask.length; - index++ - ) { - const clipContext: CubismClippingContext = - this._clippingContextListForMask[index]; - clipContext._layoutChannelNo = 0; // どうせ毎回消すので固定 - clipContext._layoutBounds.x = 0.0; - clipContext._layoutBounds.y = 0.0; - clipContext._layoutBounds.width = 1.0; - clipContext._layoutBounds.height = 1.0; - clipContext._bufferIndex = 0; - } - return; - } - - // レンダーテクスチャが1枚なら9分割する(最大36枚) - const layoutCountMaxValue = this._renderTextureCount <= 1 ? 9 : 8; - - // 指定された数のレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトする(デフォルトなら1) - // マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する - let countPerSheetDiv: number = usingClipCount / this._renderTextureCount; // レンダーテクスチャ1枚あたり何枚割り当てるか - let countPerSheetMod: number = usingClipCount % this._renderTextureCount; // この番号のレンダーテクスチャまでに一つずつ配分する - // 小数点は切り捨てる - countPerSheetDiv = ~~countPerSheetDiv; - countPerSheetMod = ~~countPerSheetMod; + // 今回専用の変換を適用して描く + // チャンネルも切り替える必要がある(A,R,G,B) + renderer.setClippingContextBufferForMask(clipContext); - // RGBAを順番に使っていく - let div: number = countPerSheetDiv / ColorChannelCount; // 1チャンネルに配置する基本のマスク - let mod: number = countPerSheetDiv % ColorChannelCount; // 余り、この番号のチャンネルまでに一つずつ配分する - - // 小数点は切り捨てる - div = ~~div; - mod = ~~mod; - - // RGBAそれぞれのチャンネルを用意していく(0:R, 1:G, 2:B, 3:A) - let curClipIndex = 0; // 順番に設定していく - - for ( - let renderTextureNo = 0; - renderTextureNo < this._renderTextureCount; - renderTextureNo++ - ) { - for (let channelNo = 0; channelNo < ColorChannelCount; channelNo++) { - // このチャンネルにレイアウトする数 - let layoutCount: number = div + (channelNo < mod ? 1 : 0); - - // このレンダーテクスチャにまだ割り当てられていなければ追加する - const checkChannelNo = mod + 1 >= ColorChannelCount ? 0 : mod + 1; - if (layoutCount < layoutCountMaxValue && channelNo == checkChannelNo) { - layoutCount += renderTextureNo < countPerSheetMod ? 1 : 0; + renderer.drawMeshWebGL(model, clipDrawIndex); } + } - // 分割方法を決定する - if (layoutCount == 0) { - // 何もしない - } else if (layoutCount == 1) { - // 全てをそのまま使う - const clipContext: CubismClippingContext = - this._clippingContextListForMask[curClipIndex++]; - clipContext._layoutChannelNo = channelNo; - clipContext._layoutBounds.x = 0.0; - clipContext._layoutBounds.y = 0.0; - clipContext._layoutBounds.width = 1.0; - clipContext._layoutBounds.height = 1.0; - clipContext._bufferIndex = renderTextureNo; - } else if (layoutCount == 2) { - for (let i = 0; i < layoutCount; i++) { - let xpos: number = i % 2; - - // 小数点は切り捨てる - xpos = ~~xpos; - - const cc: CubismClippingContext = - this._clippingContextListForMask[curClipIndex++]; - cc._layoutChannelNo = channelNo; - - // UVを2つに分解して使う - cc._layoutBounds.x = xpos * 0.5; - cc._layoutBounds.y = 0.0; - cc._layoutBounds.width = 0.5; - cc._layoutBounds.height = 1.0; - cc._bufferIndex = renderTextureNo; - } - } else if (layoutCount <= 4) { - // 4分割して使う - for (let i = 0; i < layoutCount; i++) { - let xpos: number = i % 2; - let ypos: number = i / 2; - - // 小数点は切り捨てる - xpos = ~~xpos; - ypos = ~~ypos; - - const cc = this._clippingContextListForMask[curClipIndex++]; - cc._layoutChannelNo = channelNo; - - cc._layoutBounds.x = xpos * 0.5; - cc._layoutBounds.y = ypos * 0.5; - cc._layoutBounds.width = 0.5; - cc._layoutBounds.height = 0.5; - cc._bufferIndex = renderTextureNo; - } - } else if (layoutCount <= layoutCountMaxValue) { - // 9分割して使う - for (let i = 0; i < layoutCount; i++) { - let xpos = i % 3; - let ypos = i / 3; - - // 小数点は切り捨てる - xpos = ~~xpos; - ypos = ~~ypos; - - const cc: CubismClippingContext = - this._clippingContextListForMask[curClipIndex++]; - cc._layoutChannelNo = channelNo; - - cc._layoutBounds.x = xpos / 3.0; - cc._layoutBounds.y = ypos / 3.0; - cc._layoutBounds.width = 1.0 / 3.0; - cc._layoutBounds.height = 1.0 / 3.0; - cc._bufferIndex = renderTextureNo; - } - } else if (CubismConfig.supportMoreMaskDivisions && layoutCount <= 16) { - // support 4x4 division - // https://docs.live2d.com/cubism-sdk-manual/ow-sdk-mask-premake-web/?locale=en_us - - for (let i = 0; i < layoutCount; i++) { - let xpos = i % 4; - let ypos = i / 4; - - // 小数点は切り捨てる - xpos = ~~xpos; - ypos = ~~ypos; - - const cc: CubismClippingContext = - this._clippingContextListForMask[curClipIndex++]; - cc._layoutChannelNo = channelNo; - - cc._layoutBounds.x = xpos / 4.0; - cc._layoutBounds.y = ypos / 4.0; - cc._layoutBounds.width = 1.0 / 4.0; - cc._layoutBounds.height = 1.0 / 4.0; - cc._bufferIndex = renderTextureNo; - } - } else { - // マスクの制限枚数を超えた場合の処理 - CubismLogError( - 'not supported mask count : {0}\n[Details] render texture count : {1}, mask count : {2}', - usingClipCount - useClippingMaskMaxCount, - this._renderTextureCount, - usingClipCount - ); - - // SetupShaderProgramでオーバーアクセスが発生するので仮で数値を入れる - // もちろん描画結果は正しいものではなくなる - for (let index = 0; index < layoutCount; index++) { - const cc: CubismClippingContext = - this._clippingContextListForMask[curClipIndex++]; - - cc._layoutChannelNo = 0; + // --- 後処理 --- + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, s_fbo); // 描画対象を戻す + renderer.setClippingContextBufferForMask(null); - cc._layoutBounds.x = 0.0; - cc._layoutBounds.y = 0.0; - cc._layoutBounds.width = 1.0; - cc._layoutBounds.height = 1.0; - cc._bufferIndex = 0; - } - } - } + this.gl.viewport( + s_viewport[0], + s_viewport[1], + s_viewport[2], + s_viewport[3] + ); } } @@ -872,18 +331,10 @@ export class CubismClippingManager_WebGL { * カラーバッファを取得する * @return カラーバッファ */ - public getColorBuffer(): WebGLTexture[] | undefined { + public getColorBuffer(): WebGLTexture[] { return this._maskColorBuffers; } - /** - * 画面描画に使用するクリッピングマスクのリストを取得する - * @return 画面描画に使用するクリッピングマスクのリスト - */ - public getClippingContextListForDraw(): (CubismClippingContext | null)[] { - return this._clippingContextListForDraw; - } - /** * マスクの合計数をカウント * @returns @@ -892,49 +343,14 @@ export class CubismClippingManager_WebGL { return this._clippingContextListForMask.length; } - /** - * クリッピングマスクバッファのサイズを設定する - * @param size クリッピングマスクバッファのサイズ - */ - public setClippingMaskBufferSize(size: number): void { - this._clippingMaskBufferSize = size; - } - - /** - * クリッピングマスクバッファのサイズを取得する - * @return クリッピングマスクバッファのサイズ - */ - public getClippingMaskBufferSize(): number { - return this._clippingMaskBufferSize; - } - - /** - * このバッファのレンダーテクスチャの枚数を取得する - * @return このバッファのレンダーテクスチャの枚数 - */ - public getRenderTextureCount(): number { - return this._renderTextureCount; - } - - public _currentMaskRenderTexture: WebGLFramebuffer | null; // マスク用レンダーテクスチャのアドレス - public _maskRenderTextures?: WebGLFramebuffer[]; // レンダーテクスチャのリスト - public _maskColorBuffers?: WebGLTexture[]; // マスク用カラーバッファーのアドレスのリスト + public _currentMaskRenderTexture: WebGLFramebuffer; // マスク用レンダーテクスチャのアドレス + public _maskRenderTextures: WebGLFramebuffer[]; // レンダーテクスチャのリスト + public _maskColorBuffers: WebGLTexture[]; // マスク用カラーバッファーのアドレスのリスト public _currentFrameNo: number; // マスクテクスチャに与えるフレーム番号 - public _channelColors: CubismTextureColor[]; - public _maskTexture?: CubismRenderTextureResource; // マスク用のテクスチャリソースのリスト - public _clippingContextListForMask: CubismClippingContext[]; // マスク用クリッピングコンテキストのリスト - public _clippingContextListForDraw: (CubismClippingContext | null)[]; // 描画用クリッピングコンテキストのリスト - public _clippingMaskBufferSize: number; // クリッピングマスクのバッファサイズ(初期値:256) - public _renderTextureCount: number; // 生成するレンダーテクスチャの枚数 - - private _tmpMatrix: CubismMatrix44; // マスク計算用の行列 - private _tmpMatrixForMask: CubismMatrix44; // マスク計算用の行列 - private _tmpMatrixForDraw: CubismMatrix44; // マスク計算用の行列 - private _tmpBoundsOnModel: csmRect; // マスク配置計算用の矩形 - private _clearedFrameBufferflags?: boolean[]; //マスクのクリアフラグの配列 + public _maskTexture: CubismRenderTextureResource; // マスク用のテクスチャリソースのリスト - gl!: WebGLRenderingContext; // WebGLレンダリングコンテキスト + gl: WebGLRenderingContext; // WebGLレンダリングコンテキスト } /** @@ -959,7 +375,7 @@ export class CubismRenderTextureResource { /** * クリッピングマスクのコンテキスト */ -export class CubismClippingContext { +export class CubismClippingContext_WebGL extends CubismClippingContext { /** * 引数付きコンストラクタ */ @@ -968,42 +384,8 @@ export class CubismClippingContext { clippingDrawableIndices: Int32Array, clipCount: number ) { + super(clippingDrawableIndices, clipCount); this._owner = manager; - - // クリップしている(=マスク用の)Drawableのインデックスリスト - this._clippingIdList = clippingDrawableIndices; - - // マスクの数 - this._clippingIdCount = clipCount; - - this._allClippedDrawRect = new csmRect(); - this._layoutBounds = new csmRect(); - - this._clippedDrawableIndexList = []; - - this._matrixForMask = new CubismMatrix44(); - this._matrixForDraw = new CubismMatrix44(); - - this._bufferIndex = 0; - } - - /** - * デストラクタ相当の処理 - */ - public release(): void { - const self = this as Partial; - self._layoutBounds = undefined; - self._allClippedDrawRect = undefined; - self._clippedDrawableIndexList = undefined; - } - - /** - * このマスクにクリップされる描画オブジェクトを追加する - * - * @param drawableIndex クリッピング対象に追加する描画オブジェクトのインデックス - */ - public addClippedDrawable(drawableIndex: number) { - this._clippedDrawableIndexList.push(drawableIndex); } /** @@ -1018,17 +400,6 @@ export class CubismClippingContext { this._owner.setGL(gl); } - public _isUsing = false; // 現在の描画状態でマスクの準備が必要ならtrue - public readonly _clippingIdList: Int32Array; // クリッピングマスクのIDリスト - public _clippingIdCount: number; // クリッピングマスクの数 - public _layoutChannelNo!: number; // RGBAのいずれのチャンネルにこのクリップを配置するか(0:R, 1:G, 2:B, 3:A) - public _layoutBounds: csmRect; // マスク用チャンネルのどの領域にマスクを入れるか(View座標-1~1, UVは0~1に直す) - public _allClippedDrawRect: csmRect; // このクリッピングで、クリッピングされるすべての描画オブジェクトの囲み矩形(毎回更新) - public _matrixForMask: CubismMatrix44; // マスクの位置計算結果を保持する行列 - public _matrixForDraw: CubismMatrix44; // 描画オブジェクトの位置計算結果を保持する行列 - public _clippedDrawableIndexList: number[]; // このマスクにクリップされる描画オブジェクトのリスト - public _bufferIndex: number; // このマスクが割り当てられるレンダーテクスチャ(フレームバッファ)やカラーバッファのインデックス - private _owner: CubismClippingManager_WebGL; // このマスクを管理しているマネージャのインスタンス } @@ -1057,7 +428,7 @@ export class CubismRendererProfile_WebGL { this._lastArrayBufferBinding = this.gl.getParameter( this.gl.ARRAY_BUFFER_BINDING ); - this._lastArrayBufferBinding = this.gl.getParameter( + this._lastElementArrayBufferBinding = this.gl.getParameter( this.gl.ELEMENT_ARRAY_BUFFER_BINDING ); this._lastProgram = this.gl.getParameter(this.gl.CURRENT_PROGRAM); @@ -1173,1090 +544,27 @@ export class CubismRendererProfile_WebGL { this._lastViewport = new Array(4); } - private _lastArrayBufferBinding!: GLint; ///< モデル描画直前の頂点バッファ - private _lastElementArrayBufferBinding!: GLint; ///< モデル描画直前のElementバッファ - private _lastProgram!: GLint; ///< モデル描画直前のシェーダプログラムバッファ - private _lastActiveTexture!: GLint; ///< モデル描画直前のアクティブなテクスチャ - private _lastTexture0Binding2D!: GLint; ///< モデル描画直前のテクスチャユニット0 - private _lastTexture1Binding2D!: GLint; ///< モデル描画直前のテクスチャユニット1 + private _lastArrayBufferBinding: GLint; ///< モデル描画直前の頂点バッファ + private _lastElementArrayBufferBinding: GLint; ///< モデル描画直前のElementバッファ + private _lastProgram: GLint; ///< モデル描画直前のシェーダプログラムバッファ + private _lastActiveTexture: GLint; ///< モデル描画直前のアクティブなテクスチャ + private _lastTexture0Binding2D: GLint; ///< モデル描画直前のテクスチャユニット0 + private _lastTexture1Binding2D: GLint; ///< モデル描画直前のテクスチャユニット1 private _lastVertexAttribArrayEnabled: GLboolean[]; ///< モデル描画直前のテクスチャユニット1 - private _lastScissorTest!: GLboolean; ///< モデル描画直前のGL_VERTEX_ATTRIB_ARRAY_ENABLEDパラメータ - private _lastBlend!: GLboolean; ///< モデル描画直前のGL_SCISSOR_TESTパラメータ - private _lastStencilTest!: GLboolean; ///< モデル描画直前のGL_STENCIL_TESTパラメータ - private _lastDepthTest!: GLboolean; ///< モデル描画直前のGL_DEPTH_TESTパラメータ - private _lastCullFace!: GLboolean; ///< モデル描画直前のGL_CULL_FACEパラメータ - private _lastFrontFace!: GLint; ///< モデル描画直前のGL_CULL_FACEパラメータ + private _lastScissorTest: GLboolean; ///< モデル描画直前のGL_VERTEX_ATTRIB_ARRAY_ENABLEDパラメータ + private _lastBlend: GLboolean; ///< モデル描画直前のGL_SCISSOR_TESTパラメータ + private _lastStencilTest: GLboolean; ///< モデル描画直前のGL_STENCIL_TESTパラメータ + private _lastDepthTest: GLboolean; ///< モデル描画直前のGL_DEPTH_TESTパラメータ + private _lastCullFace: GLboolean; ///< モデル描画直前のGL_CULL_FACEパラメータ + private _lastFrontFace: GLint; ///< モデル描画直前のGL_CULL_FACEパラメータ private _lastColorMask: GLboolean[]; ///< モデル描画直前のGL_COLOR_WRITEMASKパラメータ private _lastBlending: GLint[]; ///< モデル描画直前のカラーブレンディングパラメータ - private _lastFBO!: GLint; ///< モデル描画直前のフレームバッファ + private _lastFBO: GLint; ///< モデル描画直前のフレームバッファ private _lastViewport: GLint[]; ///< モデル描画直前のビューポート - gl!: WebGLRenderingContext; -} - -/** - * WebGL用のシェーダープログラムを生成・破棄するクラス - * シングルトンなクラスであり、CubismShader_WebGL.getInstanceからアクセスする。 - */ -export class CubismShader_WebGL { - /** - * インスタンスを取得する(シングルトン) - * @return インスタンス - */ - public static getInstance(): CubismShader_WebGL { - if (s_instance == null) { - s_instance = new CubismShader_WebGL(); - - return s_instance; - } - return s_instance; - } - - /** - * インスタンスを開放する(シングルトン) - */ - public static deleteInstance(): void { - if (s_instance) { - s_instance.release(); - s_instance = undefined; - } - } - - /** - * privateなコンストラクタ - */ - private constructor() { - this._shaderSets = []; - } - - /** - * デストラクタ相当の処理 - */ - public release(): void { - this.releaseShaderProgram(); - } - - /** - * シェーダープログラムの一連のセットアップを実行する - * @param renderer レンダラのインスタンス - * @param textureId GPUのテクスチャID - * @param vertexCount ポリゴンメッシュの頂点数 - * @param vertexArray ポリゴンメッシュの頂点配列 - * @param indexArray インデックスバッファの頂点配列 - * @param uvArray uv配列 - * @param opacity 不透明度 - * @param colorBlendMode カラーブレンディングのタイプ - * @param baseColor ベースカラー - * @param isPremultipliedAlpha 乗算済みアルファかどうか - * @param matrix4x4 Model-View-Projection行列 - * @param invertedMask マスクを反転して使用するフラグ - */ - public setupShaderProgram( - renderer: CubismRenderer_WebGL, - textureId: WebGLTexture | null, - vertexCount: number, - vertexArray: Float32Array, - indexArray: Uint16Array, - uvArray: Float32Array, - bufferData: { - vertex: WebGLBuffer | null; - uv: WebGLBuffer | null; - index: WebGLBuffer | null; - }, - opacity: number, - colorBlendMode: CubismBlendMode, - baseColor: CubismTextureColor, - multiplyColor: CubismTextureColor, - screenColor: CubismTextureColor, - isPremultipliedAlpha: boolean, - matrix4x4: CubismMatrix44, - invertedMask: boolean - ): void { - if (!isPremultipliedAlpha) { - CubismLogError('NoPremultipliedAlpha is not allowed'); - } - - if (this._shaderSets.length == 0) { - this.generateShaders(); - } - - // Blending - let SRC_COLOR: number; - let DST_COLOR: number; - let SRC_ALPHA: number; - let DST_ALPHA: number; - - const clippingContextBufferForMask = - renderer.getClippingContextBufferForMask(); - - if (clippingContextBufferForMask != null) { - // マスク生成時 - const shaderSet: CubismShaderSet = - this._shaderSets[ShaderNames.ShaderNames_SetupMask]; - this.gl.useProgram(shaderSet.shaderProgram); - - // テクスチャ設定 - this.gl.activeTexture(this.gl.TEXTURE0); - this.gl.bindTexture(this.gl.TEXTURE_2D, textureId); - this.gl.uniform1i(shaderSet.samplerTexture0Location, 0); - - // 頂点配列の設定(VBO) - if (bufferData.vertex == null) { - bufferData.vertex = this.gl.createBuffer(); - } - this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.vertex); - this.gl.bufferData( - this.gl.ARRAY_BUFFER, - vertexArray, - this.gl.DYNAMIC_DRAW - ); - this.gl.enableVertexAttribArray(shaderSet.attributePositionLocation); - this.gl.vertexAttribPointer( - shaderSet.attributePositionLocation, - 2, - this.gl.FLOAT, - false, - 0, - 0 - ); - - // テクスチャ頂点の設定 - if (bufferData.uv == null) { - bufferData.uv = this.gl.createBuffer(); - } - this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.uv); - this.gl.bufferData(this.gl.ARRAY_BUFFER, uvArray, this.gl.DYNAMIC_DRAW); - this.gl.enableVertexAttribArray(shaderSet.attributeTexCoordLocation); - this.gl.vertexAttribPointer( - shaderSet.attributeTexCoordLocation, - 2, - this.gl.FLOAT, - false, - 0, - 0 - ); - - // チャンネル - const channelNo: number = clippingContextBufferForMask._layoutChannelNo; - const colorChannel: CubismTextureColor = clippingContextBufferForMask - .getClippingManager() - .getChannelFlagAsColor(channelNo); - this.gl.uniform4f( - shaderSet.uniformChannelFlagLocation, - colorChannel.R, - colorChannel.G, - colorChannel.B, - colorChannel.A - ); - - this.gl.uniformMatrix4fv( - shaderSet.uniformClipMatrixLocation, - false, - clippingContextBufferForMask._matrixForMask.getArray() - ); - - const rect: csmRect = clippingContextBufferForMask._layoutBounds; - - this.gl.uniform4f( - shaderSet.uniformBaseColorLocation, - rect.x * 2.0 - 1.0, - rect.y * 2.0 - 1.0, - rect.getRight() * 2.0 - 1.0, - rect.getBottom() * 2.0 - 1.0 - ); - - this.gl.uniform4f( - shaderSet.uniformMultiplyColorLocation, - multiplyColor.R, - multiplyColor.G, - multiplyColor.B, - multiplyColor.A - ); - - this.gl.uniform4f( - shaderSet.uniformScreenColorLocation, - screenColor.R, - screenColor.G, - screenColor.B, - screenColor.A - ); - - SRC_COLOR = this.gl.ZERO; - DST_COLOR = this.gl.ONE_MINUS_SRC_COLOR; - SRC_ALPHA = this.gl.ZERO; - DST_ALPHA = this.gl.ONE_MINUS_SRC_ALPHA; - } // マスク生成以外の場合 - else { - const clippingContextBufferForDraw = - renderer.getClippingContextBufferForDraw(); - const masked = clippingContextBufferForDraw != null; // この描画オブジェクトはマスク対象か - const offset: number = masked ? (invertedMask ? 2 : 1) : 0; - - let shaderSet; - - switch (colorBlendMode) { - case CubismBlendMode.CubismBlendMode_Normal: - default: - shaderSet = - this._shaderSets[ - ShaderNames.ShaderNames_NormalPremultipliedAlpha + offset - ]; - SRC_COLOR = this.gl.ONE; - DST_COLOR = this.gl.ONE_MINUS_SRC_ALPHA; - SRC_ALPHA = this.gl.ONE; - DST_ALPHA = this.gl.ONE_MINUS_SRC_ALPHA; - break; - - case CubismBlendMode.CubismBlendMode_Additive: - shaderSet = - this._shaderSets[ - ShaderNames.ShaderNames_AddPremultipliedAlpha + offset - ]; - SRC_COLOR = this.gl.ONE; - DST_COLOR = this.gl.ONE; - SRC_ALPHA = this.gl.ZERO; - DST_ALPHA = this.gl.ONE; - break; - - case CubismBlendMode.CubismBlendMode_Multiplicative: - shaderSet = - this._shaderSets[ - ShaderNames.ShaderNames_MultPremultipliedAlpha + offset - ]; - SRC_COLOR = this.gl.DST_COLOR; - DST_COLOR = this.gl.ONE_MINUS_SRC_ALPHA; - SRC_ALPHA = this.gl.ZERO; - DST_ALPHA = this.gl.ONE; - break; - } - - this.gl.useProgram(shaderSet.shaderProgram); - - // 頂点配列の設定 - if (bufferData.vertex == null) { - bufferData.vertex = this.gl.createBuffer(); - } - this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.vertex); - this.gl.bufferData( - this.gl.ARRAY_BUFFER, - vertexArray, - this.gl.DYNAMIC_DRAW - ); - this.gl.enableVertexAttribArray(shaderSet.attributePositionLocation); - this.gl.vertexAttribPointer( - shaderSet.attributePositionLocation, - 2, - this.gl.FLOAT, - false, - 0, - 0 - ); - - // テクスチャ頂点の設定 - if (bufferData.uv == null) { - bufferData.uv = this.gl.createBuffer(); - } - this.gl.bindBuffer(this.gl.ARRAY_BUFFER, bufferData.uv); - this.gl.bufferData(this.gl.ARRAY_BUFFER, uvArray, this.gl.DYNAMIC_DRAW); - this.gl.enableVertexAttribArray(shaderSet.attributeTexCoordLocation); - this.gl.vertexAttribPointer( - shaderSet.attributeTexCoordLocation, - 2, - this.gl.FLOAT, - false, - 0, - 0 - ); - - // この描画オブジェクトはマスク対象か - if (clippingContextBufferForDraw != null) { - this.gl.activeTexture(this.gl.TEXTURE1); - const tex = clippingContextBufferForDraw - .getClippingManager() - .getColorBuffer()![ - renderer.getClippingContextBufferForDraw()!._bufferIndex - ]; - this.gl.bindTexture(this.gl.TEXTURE_2D, tex); - this.gl.uniform1i(shaderSet.samplerTexture1Location, 1); - - // view座標をClippingContextの座標に変換するための行列を設定 - this.gl.uniformMatrix4fv( - shaderSet.uniformClipMatrixLocation, - false, - clippingContextBufferForDraw._matrixForDraw.getArray() - ); - - // 使用するカラーチャンネルを設定 - const channelNo: number = clippingContextBufferForDraw._layoutChannelNo; - const colorChannel: CubismTextureColor = clippingContextBufferForDraw - .getClippingManager() - .getChannelFlagAsColor(channelNo); - this.gl.uniform4f( - shaderSet.uniformChannelFlagLocation, - colorChannel.R, - colorChannel.G, - colorChannel.B, - colorChannel.A - ); - } - - // テクスチャ設定 - this.gl.activeTexture(this.gl.TEXTURE0); - this.gl.bindTexture(this.gl.TEXTURE_2D, textureId); - this.gl.uniform1i(shaderSet.samplerTexture0Location, 0); - - // 座標変換 - this.gl.uniformMatrix4fv( - shaderSet.uniformMatrixLocation, - false, - matrix4x4.getArray() - ); - - this.gl.uniform4f( - shaderSet.uniformBaseColorLocation, - baseColor.R, - baseColor.G, - baseColor.B, - baseColor.A - ); - - this.gl.uniform4f( - shaderSet.uniformMultiplyColorLocation, - multiplyColor.R, - multiplyColor.G, - multiplyColor.B, - multiplyColor.A - ); - - this.gl.uniform4f( - shaderSet.uniformScreenColorLocation, - screenColor.R, - screenColor.G, - screenColor.B, - screenColor.A - ); - } - - // IBOを作成し、データを転送 - if (bufferData.index == null) { - bufferData.index = this.gl.createBuffer(); - } - this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, bufferData.index); - this.gl.bufferData( - this.gl.ELEMENT_ARRAY_BUFFER, - indexArray, - this.gl.DYNAMIC_DRAW - ); - this.gl.blendFuncSeparate(SRC_COLOR, DST_COLOR, SRC_ALPHA, DST_ALPHA); - } - - /** - * シェーダープログラムを解放する - */ - public releaseShaderProgram(): void { - for (let i = 0; i < this._shaderSets.length; i++) { - this.gl.deleteProgram(this._shaderSets[i].shaderProgram); - this._shaderSets[i].shaderProgram = 0; - } - - this._shaderSets = []; - } - - /** - * シェーダープログラムを初期化する - * @param vertShaderSrc 頂点シェーダのソース - * @param fragShaderSrc フラグメントシェーダのソース - */ - public generateShaders(): void { - for (let i = 0; i < ShaderCount; i++) { - this._shaderSets.push({} as any); - } - - this._shaderSets[0].shaderProgram = this.loadShaderProgram( - vertexShaderSrcSetupMask, - fragmentShaderSrcsetupMask - ); - - this._shaderSets[1].shaderProgram = this.loadShaderProgram( - vertexShaderSrc, - fragmentShaderSrcPremultipliedAlpha - ); - this._shaderSets[2].shaderProgram = this.loadShaderProgram( - vertexShaderSrcMasked, - fragmentShaderSrcMaskPremultipliedAlpha - ); - this._shaderSets[3].shaderProgram = this.loadShaderProgram( - vertexShaderSrcMasked, - fragmentShaderSrcMaskInvertedPremultipliedAlpha - ); - - // 加算も通常と同じシェーダーを利用する - this._shaderSets[4].shaderProgram = this._shaderSets[1].shaderProgram; - this._shaderSets[5].shaderProgram = this._shaderSets[2].shaderProgram; - this._shaderSets[6].shaderProgram = this._shaderSets[3].shaderProgram; - - // 乗算も通常と同じシェーダーを利用する - this._shaderSets[7].shaderProgram = this._shaderSets[1].shaderProgram; - this._shaderSets[8].shaderProgram = this._shaderSets[2].shaderProgram; - this._shaderSets[9].shaderProgram = this._shaderSets[3].shaderProgram; - - // SetupMask - this._shaderSets[0].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[0].shaderProgram, - 'a_position' - ); - this._shaderSets[0].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[0].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[0].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[0].shaderProgram, - 's_texture0' - ); - this._shaderSets[0].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[0].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[0].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[0].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[0].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[0].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[0].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[0].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[0].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[0].shaderProgram, - 'u_screenColor' - ); - - // 通常(PremultipliedAlpha) - this._shaderSets[1].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[1].shaderProgram, - 'a_position' - ); - this._shaderSets[1].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[1].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[1].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[1].shaderProgram, - 's_texture0' - ); - this._shaderSets[1].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[1].shaderProgram, - 'u_matrix' - ); - this._shaderSets[1].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[1].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[1].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[1].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[1].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[1].shaderProgram, - 'u_screenColor' - ); - - // 通常(クリッピング、PremultipliedAlpha) - this._shaderSets[2].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[2].shaderProgram, - 'a_position' - ); - this._shaderSets[2].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[2].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[2].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 's_texture0' - ); - this._shaderSets[2].samplerTexture1Location = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 's_texture1' - ); - this._shaderSets[2].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 'u_matrix' - ); - this._shaderSets[2].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[2].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[2].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[2].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[2].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[2].shaderProgram, - 'u_screenColor' - ); - - // 通常(クリッピング・反転, PremultipliedAlpha) - this._shaderSets[3].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[3].shaderProgram, - 'a_position' - ); - this._shaderSets[3].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[3].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[3].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 's_texture0' - ); - this._shaderSets[3].samplerTexture1Location = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 's_texture1' - ); - this._shaderSets[3].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 'u_matrix' - ); - this._shaderSets[3].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[3].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[3].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[3].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[3].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[3].shaderProgram, - 'u_screenColor' - ); - - // 加算(PremultipliedAlpha) - this._shaderSets[4].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[4].shaderProgram, - 'a_position' - ); - this._shaderSets[4].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[4].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[4].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[4].shaderProgram, - 's_texture0' - ); - this._shaderSets[4].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[4].shaderProgram, - 'u_matrix' - ); - this._shaderSets[4].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[4].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[4].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[4].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[4].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[4].shaderProgram, - 'u_screenColor' - ); - - // 加算(クリッピング、PremultipliedAlpha) - this._shaderSets[5].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[5].shaderProgram, - 'a_position' - ); - this._shaderSets[5].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[5].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[5].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 's_texture0' - ); - this._shaderSets[5].samplerTexture1Location = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 's_texture1' - ); - this._shaderSets[5].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 'u_matrix' - ); - this._shaderSets[5].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[5].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[5].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[5].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[5].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[5].shaderProgram, - 'u_screenColor' - ); - - // 加算(クリッピング・反転、PremultipliedAlpha) - this._shaderSets[6].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[6].shaderProgram, - 'a_position' - ); - this._shaderSets[6].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[6].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[6].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 's_texture0' - ); - this._shaderSets[6].samplerTexture1Location = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 's_texture1' - ); - this._shaderSets[6].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 'u_matrix' - ); - this._shaderSets[6].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[6].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[6].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[6].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[6].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[6].shaderProgram, - 'u_screenColor' - ); - - // 乗算(PremultipliedAlpha) - this._shaderSets[7].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[7].shaderProgram, - 'a_position' - ); - this._shaderSets[7].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[7].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[7].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[7].shaderProgram, - 's_texture0' - ); - this._shaderSets[7].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[7].shaderProgram, - 'u_matrix' - ); - this._shaderSets[7].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[7].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[7].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[7].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[7].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[7].shaderProgram, - 'u_screenColor' - ); - - // 乗算(クリッピング、PremultipliedAlpha) - this._shaderSets[8].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[8].shaderProgram, - 'a_position' - ); - this._shaderSets[8].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[8].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[8].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 's_texture0' - ); - this._shaderSets[8].samplerTexture1Location = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 's_texture1' - ); - this._shaderSets[8].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 'u_matrix' - ); - this._shaderSets[8].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[8].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[8].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[8].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[8].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[8].shaderProgram, - 'u_screenColor' - ); - - // 乗算(クリッピング・反転、PremultipliedAlpha) - this._shaderSets[9].attributePositionLocation = this.gl.getAttribLocation( - this._shaderSets[9].shaderProgram, - 'a_position' - ); - this._shaderSets[9].attributeTexCoordLocation = this.gl.getAttribLocation( - this._shaderSets[9].shaderProgram, - 'a_texCoord' - ); - this._shaderSets[9].samplerTexture0Location = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 's_texture0' - ); - this._shaderSets[9].samplerTexture1Location = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 's_texture1' - ); - this._shaderSets[9].uniformMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 'u_matrix' - ); - this._shaderSets[9].uniformClipMatrixLocation = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 'u_clipMatrix' - ); - this._shaderSets[9].uniformChannelFlagLocation = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 'u_channelFlag' - ); - this._shaderSets[9].uniformBaseColorLocation = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 'u_baseColor' - ); - this._shaderSets[9].uniformMultiplyColorLocation = - this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 'u_multiplyColor' - ); - this._shaderSets[9].uniformScreenColorLocation = this.gl.getUniformLocation( - this._shaderSets[9].shaderProgram, - 'u_screenColor' - ); - } - - /** - * シェーダプログラムをロードしてアドレスを返す - * @param vertexShaderSource 頂点シェーダのソース - * @param fragmentShaderSource フラグメントシェーダのソース - * @return シェーダプログラムのアドレス - */ - public loadShaderProgram( - vertexShaderSource: string, - fragmentShaderSource: string - ): WebGLProgram { - // Create Shader Program - const shaderProgram = this.gl.createProgram()!; - - const vertShader = this.compileShaderSource( - this.gl.VERTEX_SHADER, - vertexShaderSource - ); - - if (!vertShader) { - CubismLogError('Vertex shader compile error!'); - return 0; - } - - const fragShader = this.compileShaderSource( - this.gl.FRAGMENT_SHADER, - fragmentShaderSource - ); - if (!fragShader) { - CubismLogError('Vertex shader compile error!'); - return 0; - } - - // Attach vertex shader to program - this.gl.attachShader(shaderProgram, vertShader); - - // Attach fragment shader to program - this.gl.attachShader(shaderProgram, fragShader); - - // link program - this.gl.linkProgram(shaderProgram); - const linkStatus = this.gl.getProgramParameter( - shaderProgram, - this.gl.LINK_STATUS - ); - - // リンクに失敗したらシェーダーを削除 - if (!linkStatus) { - CubismLogError('Failed to link program: {0}', shaderProgram); - - this.gl.deleteShader(vertShader); - - this.gl.deleteShader(fragShader); - - if (shaderProgram) { - this.gl.deleteProgram(shaderProgram); - } - - return 0; - } - - // Release vertex and fragment shaders. - this.gl.deleteShader(vertShader); - this.gl.deleteShader(fragShader); - - return shaderProgram; - } - - /** - * シェーダープログラムをコンパイルする - * @param shaderType シェーダタイプ(Vertex/Fragment) - * @param shaderSource シェーダソースコード - * - * @return コンパイルされたシェーダープログラム - */ - public compileShaderSource( - shaderType: GLenum, - shaderSource: string - ): WebGLProgram | null { - const source: string = shaderSource; - - const shader = this.gl.createShader(shaderType)!; - this.gl.shaderSource(shader, source); - this.gl.compileShader(shader); - - if (!shader) { - const log = this.gl.getShaderInfoLog(shader); - CubismLogError('Shader compile log: {0} ', log); - } - - const status: any = this.gl.getShaderParameter( - shader, - this.gl.COMPILE_STATUS - ); - if (!status) { - this.gl.deleteShader(shader); - return null; - } - - return shader; - } - - public setGl(gl: WebGLRenderingContext): void { - this.gl = gl; - } - - _shaderSets: CubismShaderSet[]; // ロードしたシェーダープログラムを保持する変数 - gl!: WebGLRenderingContext; // webglコンテキスト -} - -/** - * CubismShader_WebGLのインナークラス - */ -export interface CubismShaderSet { - shaderProgram: WebGLProgram; // シェーダープログラムのアドレス - attributePositionLocation: GLuint; // シェーダープログラムに渡す変数のアドレス(Position) - attributeTexCoordLocation: GLuint; // シェーダープログラムに渡す変数のアドレス(TexCoord) - uniformMatrixLocation: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(Matrix) - uniformClipMatrixLocation: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(ClipMatrix) - samplerTexture0Location: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(Texture0) - samplerTexture1Location: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(Texture1) - uniformBaseColorLocation: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(BaseColor) - uniformChannelFlagLocation: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(ChannelFlag) - uniformMultiplyColorLocation: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(MultiplyColor) - uniformScreenColorLocation: WebGLUniformLocation | null; // シェーダープログラムに渡す変数のアドレス(ScreenColor) -} - -export enum ShaderNames { - // SetupMask - ShaderNames_SetupMask, - - // Normal - ShaderNames_NormalPremultipliedAlpha, - ShaderNames_NormalMaskedPremultipliedAlpha, - ShaderNames_NomralMaskedInvertedPremultipliedAlpha, - - // Add - ShaderNames_AddPremultipliedAlpha, - ShaderNames_AddMaskedPremultipliedAlpha, - ShaderNames_AddMaskedPremultipliedAlphaInverted, - - // Mult - ShaderNames_MultPremultipliedAlpha, - ShaderNames_MultMaskedPremultipliedAlpha, - ShaderNames_MultMaskedPremultipliedAlphaInverted, + gl: WebGLRenderingContext; } -export const vertexShaderSrcSetupMask = - 'attribute vec4 a_position;' + - 'attribute vec2 a_texCoord;' + - 'varying vec2 v_texCoord;' + - 'varying vec4 v_myPos;' + - 'uniform mat4 u_clipMatrix;' + - 'void main()' + - '{' + - ' gl_Position = u_clipMatrix * a_position;' + - ' v_myPos = u_clipMatrix * a_position;' + - ' v_texCoord = a_texCoord;' + - ' v_texCoord.y = 1.0 - v_texCoord.y;' + - '}'; -export const fragmentShaderSrcsetupMask = - 'precision mediump float;' + - 'varying vec2 v_texCoord;' + - 'varying vec4 v_myPos;' + - 'uniform vec4 u_baseColor;' + - 'uniform vec4 u_channelFlag;' + - 'uniform sampler2D s_texture0;' + - 'void main()' + - '{' + - ' float isInside = ' + - ' step(u_baseColor.x, v_myPos.x/v_myPos.w)' + - ' * step(u_baseColor.y, v_myPos.y/v_myPos.w)' + - ' * step(v_myPos.x/v_myPos.w, u_baseColor.z)' + - ' * step(v_myPos.y/v_myPos.w, u_baseColor.w);' + - ' gl_FragColor = u_channelFlag * texture2D(s_texture0, v_texCoord).a * isInside;' + - '}'; - -//----- バーテックスシェーダプログラム ----- -// Normal & Add & Mult 共通 -export const vertexShaderSrc = - 'attribute vec4 a_position;' + //v.vertex - 'attribute vec2 a_texCoord;' + //v.texcoord - 'varying vec2 v_texCoord;' + //v2f.texcoord - 'uniform mat4 u_matrix;' + - 'void main()' + - '{' + - ' gl_Position = u_matrix * a_position;' + - ' v_texCoord = a_texCoord;' + - ' v_texCoord.y = 1.0 - v_texCoord.y;' + - '}'; - -// Normal & Add & Mult 共通(クリッピングされたものの描画用) -export const vertexShaderSrcMasked = - 'attribute vec4 a_position;' + - 'attribute vec2 a_texCoord;' + - 'varying vec2 v_texCoord;' + - 'varying vec4 v_clipPos;' + - 'uniform mat4 u_matrix;' + - 'uniform mat4 u_clipMatrix;' + - 'void main()' + - '{' + - ' gl_Position = u_matrix * a_position;' + - ' v_clipPos = u_clipMatrix * a_position;' + - ' v_texCoord = a_texCoord;' + - ' v_texCoord.y = 1.0 - v_texCoord.y;' + - '}'; - -//----- フラグメントシェーダプログラム ----- -// Normal & Add & Mult 共通 (PremultipliedAlpha) -export const fragmentShaderSrcPremultipliedAlpha = - 'precision mediump float;' + - 'varying vec2 v_texCoord;' + //v2f.texcoord - 'uniform vec4 u_baseColor;' + - 'uniform sampler2D s_texture0;' + //_MainTex - 'uniform vec4 u_multiplyColor;' + - 'uniform vec4 u_screenColor;' + - 'void main()' + - '{' + - ' vec4 texColor = texture2D(s_texture0, v_texCoord);' + - ' texColor.rgb = texColor.rgb * u_multiplyColor.rgb;' + - ' texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);' + - ' vec4 color = texColor * u_baseColor;' + - ' gl_FragColor = vec4(color.rgb, color.a);' + - '}'; - -// Normal (クリッピングされたものの描画用、PremultipliedAlpha兼用) -export const fragmentShaderSrcMaskPremultipliedAlpha = - 'precision mediump float;' + - 'varying vec2 v_texCoord;' + - 'varying vec4 v_clipPos;' + - 'uniform vec4 u_baseColor;' + - 'uniform vec4 u_channelFlag;' + - 'uniform sampler2D s_texture0;' + - 'uniform sampler2D s_texture1;' + - 'uniform vec4 u_multiplyColor;' + - 'uniform vec4 u_screenColor;' + - 'void main()' + - '{' + - ' vec4 texColor = texture2D(s_texture0, v_texCoord);' + - ' texColor.rgb = texColor.rgb * u_multiplyColor.rgb;' + - ' texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);' + - ' vec4 col_formask = texColor * u_baseColor;' + - ' vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;' + - ' float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;' + - ' col_formask = col_formask * maskVal;' + - ' gl_FragColor = col_formask;' + - '}'; - -// Normal & Add & Mult 共通(クリッピングされて反転使用の描画用、PremultipliedAlphaの場合) -export const fragmentShaderSrcMaskInvertedPremultipliedAlpha = - 'precision mediump float;' + - 'varying vec2 v_texCoord;' + - 'varying vec4 v_clipPos;' + - 'uniform sampler2D s_texture0;' + - 'uniform sampler2D s_texture1;' + - 'uniform vec4 u_channelFlag;' + - 'uniform vec4 u_baseColor;' + - 'uniform vec4 u_multiplyColor;' + - 'uniform vec4 u_screenColor;' + - 'void main()' + - '{' + - ' vec4 texColor = texture2D(s_texture0, v_texCoord);' + - ' texColor.rgb = texColor.rgb * u_multiplyColor.rgb;' + - ' texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);' + - ' vec4 col_formask = texColor * u_baseColor;' + - ' vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;' + - ' float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;' + - ' col_formask = col_formask * (1.0 - maskVal);' + - ' gl_FragColor = col_formask;' + - '}'; - /** * WebGL用の描画命令を実装したクラス */ @@ -2271,18 +579,10 @@ export class CubismRenderer_WebGL extends CubismRenderer { public initialize(model: CubismModel, maskBufferCount = 1): void { if (model.isUsingMasking()) { this._clippingManager = new CubismClippingManager_WebGL(); // クリッピングマスク・バッファ前処理方式を初期化 - this._clippingManager.initialize( - model, - model.getDrawableCount(), - model.getDrawableMasks(), - model.getDrawableMaskCounts(), - maskBufferCount - ); + this._clippingManager.initialize(model, maskBufferCount); } - for (let i = model.getDrawableCount() - 1; i >= 0; i--) { - this._sortedDrawableIndexList[i] = 0; - } + this._sortedDrawableIndexList = new Array(model.getDrawableCount()).fill(0); super.initialize(model); // 親クラスの処理を呼ぶ } @@ -2294,7 +594,7 @@ export class CubismRenderer_WebGL extends CubismRenderer { * @param glTextureNo WebGLテクスチャの番号 */ public bindTexture(modelTextureNo: number, glTexture: WebGLTexture): void { - this._textures[modelTextureNo] = glTexture; + this._textures[modelTextureNo] = glTexture; } /** @@ -2322,6 +622,8 @@ export class CubismRenderer_WebGL extends CubismRenderer { // FrameBufferのサイズを変更するためにインスタンスを破棄・再作成する this._clippingManager.release(); + this._clippingManager = void 0; + this._clippingManager = null; this._clippingManager = new CubismClippingManager_WebGL(); @@ -2329,9 +631,6 @@ export class CubismRenderer_WebGL extends CubismRenderer { this._clippingManager.initialize( this.getModel(), - this.getModel().getDrawableCount(), - this.getModel().getDrawableMasks(), - this.getModel().getDrawableMaskCounts(), renderTextureCount // インスタンス破棄前に保存したレンダーテクスチャの数 ); } @@ -2368,30 +667,37 @@ export class CubismRenderer_WebGL extends CubismRenderer { this._textures = {}; this._sortedDrawableIndexList = []; this._bufferData = { - vertex: null, - uv: null, - index: null, + vertex: (WebGLBuffer = null), + uv: (WebGLBuffer = null), + index: (WebGLBuffer = null) }; + + // テクスチャ対応マップの容量を確保しておく + // this._textures.prepareCapacity(32, true); } /** * デストラクタ相当の処理 */ public release(): void { - const self = this as Partial; - - this._clippingManager.release(); - self._clippingManager = undefined; + if (this._clippingManager) { + this._clippingManager.release(); + this._clippingManager = void 0; + this._clippingManager = null; + } - this.gl?.deleteBuffer(this._bufferData.vertex); + if (this.gl == null) { + return; + } + this.gl.deleteBuffer(this._bufferData.vertex); this._bufferData.vertex = null; - this.gl?.deleteBuffer(this._bufferData.uv); + this.gl.deleteBuffer(this._bufferData.uv); this._bufferData.uv = null; - this.gl?.deleteBuffer(this._bufferData.index); + this.gl.deleteBuffer(this._bufferData.index); this._bufferData.index = null; - self._bufferData = undefined; + this._bufferData = null; - self._textures = undefined; + this._textures = null; } /** @@ -2408,7 +714,15 @@ export class CubismRenderer_WebGL extends CubismRenderer { //------------ クリッピングマスク・バッファ前処理方式の場合 ------------ if (this._clippingManager != null) { this.preDraw(); - this._clippingManager.setupClippingContext(this.getModel(), this); + + if (this.isUsingHighPrecisionMask()) { + this._clippingManager.setupMatrixForHighPrecision( + this.getModel(), + false + ); + } else { + this._clippingManager.setupClippingContext(this.getModel(), this); + } } // 上記クリッピング処理内でも一度PreDrawを呼ぶので注意!! @@ -2420,7 +734,7 @@ export class CubismRenderer_WebGL extends CubismRenderer { // インデックスを描画順でソート for (let i = 0; i < drawableCount; ++i) { const order: number = renderOrder[i]; - this._sortedDrawableIndexList[order] = i; + this._sortedDrawableIndexList[order] = i; } // 描画 @@ -2434,7 +748,8 @@ export class CubismRenderer_WebGL extends CubismRenderer { const clipContext = this._clippingManager != null - ? this._clippingManager.getClippingContextListForDraw()[drawableIndex] + ? this._clippingManager + .getClippingContextListForDraw()[drawableIndex] : null; if (clipContext != null && this.isUsingHighPrecisionMask()) { @@ -2454,9 +769,9 @@ export class CubismRenderer_WebGL extends CubismRenderer { // マスク用RenderTextureをactiveにセット this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, - clipContext.getClippingManager().getMaskRenderTexture()[ - clipContext._bufferIndex - ] + clipContext + .getClippingManager() + .getMaskRenderTexture()[clipContext._bufferIndex] ); // マスクをクリアする @@ -2488,19 +803,7 @@ export class CubismRenderer_WebGL extends CubismRenderer { // チャンネルも切り替える必要がある(A,R,G,B) this.setClippingContextBufferForMask(clipContext); - this.drawMesh( - this.getModel().getDrawableTextureIndex(clipDrawIndex), - this.getModel().getDrawableVertexIndexCount(clipDrawIndex), - this.getModel().getDrawableVertexCount(clipDrawIndex), - this.getModel().getDrawableVertexIndices(clipDrawIndex), - this.getModel().getDrawableVertices(clipDrawIndex), - this.getModel().getDrawableVertexUvs(clipDrawIndex), - this.getModel().getMultiplyColor(clipDrawIndex), - this.getModel().getScreenColor(clipDrawIndex), - this.getModel().getDrawableOpacity(clipDrawIndex), - CubismBlendMode.CubismBlendMode_Normal, // クリッピングは通常描画を強制 - false // マスク生成時はクリッピングの反転使用は全く関係がない - ); + this.drawMeshWebGL(this._model, clipDrawIndex); } } @@ -2525,49 +828,16 @@ export class CubismRenderer_WebGL extends CubismRenderer { this.setIsCulling(this.getModel().getDrawableCulling(drawableIndex)); - this.drawMesh( - this.getModel().getDrawableTextureIndex(drawableIndex), - this.getModel().getDrawableVertexIndexCount(drawableIndex), - this.getModel().getDrawableVertexCount(drawableIndex), - this.getModel().getDrawableVertexIndices(drawableIndex), - this.getModel().getDrawableVertices(drawableIndex), - this.getModel().getDrawableVertexUvs(drawableIndex), - this.getModel().getMultiplyColor(drawableIndex), - this.getModel().getScreenColor(drawableIndex), - this.getModel().getDrawableOpacity(drawableIndex), - this.getModel().getDrawableBlendMode(drawableIndex), - this.getModel().getDrawableInvertedMaskBit(drawableIndex) - ); + this.drawMeshWebGL(this._model, drawableIndex); } } /** - * [オーバーライド] * 描画オブジェクト(アートメッシュ)を描画する。 - * ポリゴンメッシュとテクスチャ番号をセットで渡す。 - * @param textureNo 描画するテクスチャ番号 - * @param indexCount 描画オブジェクトのインデックス値 - * @param vertexCount ポリゴンメッシュの頂点数 - * @param indexArray ポリゴンメッシュのインデックス配列 - * @param vertexArray ポリゴンメッシュの頂点配列 - * @param uvArray uv配列 - * @param opacity 不透明度 - * @param colorBlendMode カラー合成タイプ - * @param invertedMask マスク使用時のマスクの反転使用 + * @param model 描画対象のモデル + * @param index 描画対象のメッシュのインデックス */ - public drawMesh( - textureNo: number, - indexCount: number, - vertexCount: number, - indexArray: Uint16Array, - vertexArray: Float32Array, - uvArray: Float32Array, - multiplyColor: CubismTextureColor, - screenColor: CubismTextureColor, - opacity: number, - colorBlendMode: CubismBlendMode, - invertedMask: boolean - ): void { + public drawMeshWebGL(model: Readonly, index: number): void { // 裏面描画の有効・無効 if (this.isCulling()) { this.gl.enable(this.gl.CULL_FACE); @@ -2577,52 +847,30 @@ export class CubismRenderer_WebGL extends CubismRenderer { this.gl.frontFace(this.gl.CCW); // Cubism SDK OpenGLはマスク・アートメッシュ共にCCWが表面 - const modelColorRGBA: CubismTextureColor = this.getModelColor(); - - if (this.getClippingContextBufferForMask() == null) { - // マスク生成時以外 - modelColorRGBA.A *= opacity; - if (this.isPremultipliedAlpha()) { - modelColorRGBA.R *= modelColorRGBA.A; - modelColorRGBA.G *= modelColorRGBA.A; - modelColorRGBA.B *= modelColorRGBA.A; - } + if (this.isGeneratingMask()) { + CubismShader_WebGL.getInstance().setupShaderProgramForMask( + this, + model, + index + ); + } else { + CubismShader_WebGL.getInstance().setupShaderProgramForDraw( + this, + model, + index + ); } - let drawtexture: WebGLTexture | null = null; // シェーダに渡すテクスチャ - - // テクスチャマップからバインド済みテクスチャIDを取得 - // バインドされていなければダミーのテクスチャIDをセットする - if (this._textures[textureNo] != null) { - drawtexture = this._textures[textureNo]; + { + const indexCount: number = model.getDrawableVertexIndexCount(index); + this.gl.drawElements( + this.gl.TRIANGLES, + indexCount, + this.gl.UNSIGNED_SHORT, + 0 + ); } - CubismShader_WebGL.getInstance().setupShaderProgram( - this, - drawtexture, - vertexCount, - vertexArray, - indexArray, - uvArray, - this._bufferData, - opacity, - colorBlendMode, - modelColorRGBA, - multiplyColor, - screenColor, - this.isPremultipliedAlpha(), - this.getMvpMatrix(), - invertedMask - ); - - // ポリゴンメッシュを描画する - this.gl.drawElements( - this.gl.TRIANGLES, - indexCount, - this.gl.UNSIGNED_SHORT, - 0 - ); - // 後処理 this.gl.useProgram(null); this.setClippingContextBufferForDraw(null); @@ -2679,8 +927,8 @@ export class CubismRenderer_WebGL extends CubismRenderer { // 異方性フィルタリングを適用する if (this.getAnisotropy() > 0.0 && this._extension) { - for (const tex of Object.entries(this._textures)) { - this.gl.bindTexture(this.gl.TEXTURE_2D, tex); + for (let i = 0; i < Object.keys(this._textures).length; ++i) { + this.gl.bindTexture(this.gl.TEXTURE_2D, this._textures[i]); this.gl.texParameterf( this.gl.TEXTURE_2D, this._extension.TEXTURE_MAX_ANISOTROPY_EXT, @@ -2693,7 +941,7 @@ export class CubismRenderer_WebGL extends CubismRenderer { /** * マスクテクスチャに描画するクリッピングコンテキストをセットする */ - public setClippingContextBufferForMask(clip: CubismClippingContext | null) { + public setClippingContextBufferForMask(clip: CubismClippingContext_WebGL) { this._clippingContextBufferForMask = clip; } @@ -2701,7 +949,7 @@ export class CubismRenderer_WebGL extends CubismRenderer { * マスクテクスチャに描画するクリッピングコンテキストを取得する * @return マスクテクスチャに描画するクリッピングコンテキスト */ - public getClippingContextBufferForMask(): CubismClippingContext | null { + public getClippingContextBufferForMask(): CubismClippingContext_WebGL { return this._clippingContextBufferForMask; } @@ -2709,7 +957,7 @@ export class CubismRenderer_WebGL extends CubismRenderer { * 画面上に描画するクリッピングコンテキストをセットする */ public setClippingContextBufferForDraw( - clip: CubismClippingContext | null + clip: CubismClippingContext_WebGL ): void { this._clippingContextBufferForDraw = clip; } @@ -2718,10 +966,18 @@ export class CubismRenderer_WebGL extends CubismRenderer { * 画面上に描画するクリッピングコンテキストを取得する * @return 画面上に描画するクリッピングコンテキスト */ - public getClippingContextBufferForDraw(): CubismClippingContext | null { + public getClippingContextBufferForDraw(): CubismClippingContext_WebGL { return this._clippingContextBufferForDraw; } + /** + * マスク生成時かを判定する + * @returns 判定値 + */ + public isGeneratingMask() { + return this.getClippingContextBufferForMask() != null; + } + /** * glの設定 */ @@ -2744,18 +1000,18 @@ export class CubismRenderer_WebGL extends CubismRenderer { _textures: Record; // モデルが参照するテクスチャとレンダラでバインドしているテクスチャとのマップ _sortedDrawableIndexList: number[]; // 描画オブジェクトのインデックスを描画順に並べたリスト - _clippingManager!: CubismClippingManager_WebGL; // クリッピングマスク管理オブジェクト - _clippingContextBufferForMask: CubismClippingContext | null; // マスクテクスチャに描画するためのクリッピングコンテキスト - _clippingContextBufferForDraw: CubismClippingContext | null; // 画面上描画するためのクリッピングコンテキスト + _clippingManager: CubismClippingManager_WebGL; // クリッピングマスク管理オブジェクト + _clippingContextBufferForMask: CubismClippingContext_WebGL; // マスクテクスチャに描画するためのクリッピングコンテキスト + _clippingContextBufferForDraw: CubismClippingContext_WebGL; // 画面上描画するためのクリッピングコンテキスト _rendererProfile: CubismRendererProfile_WebGL; firstDraw: boolean; _bufferData: { - vertex: WebGLBuffer | null; - uv: WebGLBuffer | null; - index: WebGLBuffer | null; + vertex: WebGLBuffer; + uv: WebGLBuffer; + index: WebGLBuffer; }; // 頂点バッファデータ _extension: any; // 拡張機能 - gl!: WebGLRenderingContext; // webglコンテキスト + gl: WebGLRenderingContext; // webglコンテキスト } /** diff --git a/src/rendering/cubismshader_webgl.ts b/src/rendering/cubismshader_webgl.ts new file mode 100644 index 0000000..dfcb808 --- /dev/null +++ b/src/rendering/cubismshader_webgl.ts @@ -0,0 +1,1074 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ +import { CubismMatrix44 } from '../math/cubismmatrix44'; +import { CubismModel } from '../model/cubismmodel'; +import { csmRect } from '../type/csmrectf'; +import { CubismLogError } from '../utils/cubismdebug'; +import { CubismBlendMode, CubismTextureColor } from './cubismrenderer'; +import { CubismRenderer_WebGL } from './cubismrenderer_webgl'; +let s_instance: CubismShader_WebGL; +const ShaderCount = 10; // シェーダーの数 = マスク生成用 + (通常用 + 加算 + 乗算) * (マスク無の乗算済アルファ対応版 + マスク有の乗算済アルファ対応版 + マスク有反転の乗算済アルファ対応版) +/** + * WebGL用のシェーダープログラムを生成・破棄するクラス + * シングルトンなクラスであり、CubismShader_WebGL.getInstanceからアクセスする。 + */ +export class CubismShader_WebGL { + /** + * インスタンスを取得する(シングルトン) + * @return インスタンス + */ + public static getInstance(): CubismShader_WebGL { + if (s_instance == null) { + s_instance = new CubismShader_WebGL(); + return s_instance; + } + return s_instance; + } + /** + * インスタンスを開放する(シングルトン) + */ + public static deleteInstance(): void { + if (s_instance) { + s_instance.release(); + s_instance = null; + } + } + /** + * privateなコンストラクタ + */ + private constructor() { + this._shaderSets = []; + } + /** + * デストラクタ相当の処理 + */ + public release(): void { + this.releaseShaderProgram(); + } + /** + * 描画用のシェーダプログラムの一連のセットアップを実行する + * @param renderer レンダラー + * @param model 描画対象のモデル + * @param index 描画対象のメッシュのインデックス + */ + public setupShaderProgramForDraw( + renderer: CubismRenderer_WebGL, + model: Readonly, + index: number + ): void { + if (!renderer.isPremultipliedAlpha()) { + CubismLogError('NoPremultipliedAlpha is not allowed'); + } + if (this._shaderSets.length == 0) { + this.generateShaders(); + } + // Blending + let SRC_COLOR: number; + let DST_COLOR: number; + let SRC_ALPHA: number; + let DST_ALPHA: number; + // _shaderSets用のオフセット計算 + const masked: boolean = renderer.getClippingContextBufferForDraw() != null; // この描画オブジェクトはマスク対象か + const invertedMask: boolean = model.getDrawableInvertedMaskBit(index); + const offset: number = masked ? (invertedMask ? 2 : 1) : 0; + let shaderSet: CubismShaderSet; + switch (model.getDrawableBlendMode(index)) { + case CubismBlendMode.CubismBlendMode_Normal: + default: + shaderSet = this._shaderSets[ShaderNames.ShaderNames_NormalPremultipliedAlpha + offset]; + SRC_COLOR = this.gl.ONE; + DST_COLOR = this.gl.ONE_MINUS_SRC_ALPHA; + SRC_ALPHA = this.gl.ONE; + DST_ALPHA = this.gl.ONE_MINUS_SRC_ALPHA; + break; + case CubismBlendMode.CubismBlendMode_Additive: + shaderSet = this._shaderSets[ + ShaderNames.ShaderNames_AddPremultipliedAlpha + offset]; + SRC_COLOR = this.gl.ONE; + DST_COLOR = this.gl.ONE; + SRC_ALPHA = this.gl.ZERO; + DST_ALPHA = this.gl.ONE; + break; + case CubismBlendMode.CubismBlendMode_Multiplicative: + shaderSet = this._shaderSets[ + ShaderNames.ShaderNames_MultPremultipliedAlpha + offset] + SRC_COLOR = this.gl.DST_COLOR; + DST_COLOR = this.gl.ONE_MINUS_SRC_ALPHA; + SRC_ALPHA = this.gl.ZERO; + DST_ALPHA = this.gl.ONE; + break; + } + this.gl.useProgram(shaderSet.shaderProgram); + // 頂点配列の設定 + if (renderer._bufferData.vertex == null) { + renderer._bufferData.vertex = this.gl.createBuffer(); + } + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, renderer._bufferData.vertex); + // 頂点配列の設定 + const vertexArray: Float32Array = model.getDrawableVertices(index); + this.gl.bufferData(this.gl.ARRAY_BUFFER, vertexArray, this.gl.DYNAMIC_DRAW); + this.gl.enableVertexAttribArray(shaderSet.attributePositionLocation); + this.gl.vertexAttribPointer( + shaderSet.attributePositionLocation, + 2, + this.gl.FLOAT, + false, + 0, + 0 + ); + // テクスチャ頂点の設定 + if (renderer._bufferData.uv == null) { + renderer._bufferData.uv = this.gl.createBuffer(); + } + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, renderer._bufferData.uv); + const uvArray: Float32Array = model.getDrawableVertexUvs(index); + this.gl.bufferData(this.gl.ARRAY_BUFFER, uvArray, this.gl.DYNAMIC_DRAW); + this.gl.enableVertexAttribArray(shaderSet.attributeTexCoordLocation); + this.gl.vertexAttribPointer( + shaderSet.attributeTexCoordLocation, + 2, + this.gl.FLOAT, + false, + 0, + 0 + ); + if (masked) { + this.gl.activeTexture(this.gl.TEXTURE1); + // frameBufferに書かれたテクスチャ + const tex: WebGLTexture = renderer + .getClippingContextBufferForDraw() + .getClippingManager() + .getColorBuffer() + [renderer.getClippingContextBufferForDraw()._bufferIndex]; + this.gl.bindTexture(this.gl.TEXTURE_2D, tex); + this.gl.uniform1i(shaderSet.samplerTexture1Location, 1); + // view座標をClippingContextの座標に変換するための行列を設定 + this.gl.uniformMatrix4fv( + shaderSet.uniformClipMatrixLocation, + false, + renderer.getClippingContextBufferForDraw()._matrixForDraw.getArray() + ); + // 使用するカラーチャンネルを設定 + const channelIndex: number = + renderer.getClippingContextBufferForDraw()._layoutChannelIndex; + const colorChannel: CubismTextureColor = renderer + .getClippingContextBufferForDraw() + .getClippingManager() + .getChannelFlagAsColor(channelIndex); + this.gl.uniform4f( + shaderSet.uniformChannelFlagLocation, + colorChannel.R, + colorChannel.G, + colorChannel.B, + colorChannel.A + ); + } + // テクスチャ設定 + const textureNo: number = model.getDrawableTextureIndex(index); + const textureId: WebGLTexture = renderer + .getBindedTextures()[textureNo]; + this.gl.activeTexture(this.gl.TEXTURE0); + this.gl.bindTexture(this.gl.TEXTURE_2D, textureId); + this.gl.uniform1i(shaderSet.samplerTexture0Location, 0); + //座標変換 + const matrix4x4: CubismMatrix44 = renderer.getMvpMatrix(); + this.gl.uniformMatrix4fv( + shaderSet.uniformMatrixLocation, + false, + matrix4x4.getArray() + ); + //ベース色の取得 + const baseColor: CubismTextureColor = renderer.getModelColorWithOpacity( + model.getDrawableOpacity(index) + ); + const multiplyColor: CubismTextureColor = model.getMultiplyColor(index); + const screenColor: CubismTextureColor = model.getScreenColor(index); + this.gl.uniform4f( + shaderSet.uniformBaseColorLocation, + baseColor.R, + baseColor.G, + baseColor.B, + baseColor.A + ); + this.gl.uniform4f( + shaderSet.uniformMultiplyColorLocation, + multiplyColor.R, + multiplyColor.G, + multiplyColor.B, + multiplyColor.A + ); + this.gl.uniform4f( + shaderSet.uniformScreenColorLocation, + screenColor.R, + screenColor.G, + screenColor.B, + screenColor.A + ); + // IBOを作成し、データを転送 + if (renderer._bufferData.index == null) { + renderer._bufferData.index = this.gl.createBuffer(); + } + const indexArray: Uint16Array = model.getDrawableVertexIndices(index); + this.gl.bindBuffer( + this.gl.ELEMENT_ARRAY_BUFFER, + renderer._bufferData.index + ); + this.gl.bufferData( + this.gl.ELEMENT_ARRAY_BUFFER, + indexArray, + this.gl.DYNAMIC_DRAW + ); + this.gl.blendFuncSeparate(SRC_COLOR, DST_COLOR, SRC_ALPHA, DST_ALPHA); + } + /** + * マスク用のシェーダプログラムの一連のセットアップを実行する + * @param renderer レンダラー + * @param model 描画対象のモデル + * @param index 描画対象のメッシュのインデックス + */ + public setupShaderProgramForMask( + renderer: CubismRenderer_WebGL, + model: Readonly, + index: number + ): void { + if (!renderer.isPremultipliedAlpha()) { + CubismLogError('NoPremultipliedAlpha is not allowed'); + } + if (this._shaderSets.length == 0) { + this.generateShaders(); + } + // Blending + let SRC_COLOR: number; + let DST_COLOR: number; + let SRC_ALPHA: number; + let DST_ALPHA: number; + const shaderSet: CubismShaderSet = this._shaderSets[ + ShaderNames.ShaderNames_SetupMask]; + this.gl.useProgram(shaderSet.shaderProgram); + // 頂点配列の設定 + if (renderer._bufferData.vertex == null) { + renderer._bufferData.vertex = this.gl.createBuffer(); + } + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, renderer._bufferData.vertex); + const vertexArray: Float32Array = model.getDrawableVertices(index); + this.gl.bufferData(this.gl.ARRAY_BUFFER, vertexArray, this.gl.DYNAMIC_DRAW); + this.gl.enableVertexAttribArray(shaderSet.attributePositionLocation); + this.gl.vertexAttribPointer( + shaderSet.attributePositionLocation, + 2, + this.gl.FLOAT, + false, + 0, + 0 + ); + //テクスチャ設定 + if (renderer._bufferData.uv == null) { + renderer._bufferData.uv = this.gl.createBuffer(); + } + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, renderer._bufferData.uv); + const textureNo: number = model.getDrawableTextureIndex(index); + const textureId: WebGLTexture = renderer + .getBindedTextures()[textureNo]; + this.gl.activeTexture(this.gl.TEXTURE0); + this.gl.bindTexture(this.gl.TEXTURE_2D, textureId); + this.gl.uniform1i(shaderSet.samplerTexture0Location, 0); + // テクスチャ頂点の設定 + if (renderer._bufferData.uv == null) { + renderer._bufferData.uv = this.gl.createBuffer(); + } + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, renderer._bufferData.uv); + const uvArray: Float32Array = model.getDrawableVertexUvs(index); + this.gl.bufferData(this.gl.ARRAY_BUFFER, uvArray, this.gl.DYNAMIC_DRAW); + this.gl.enableVertexAttribArray(shaderSet.attributeTexCoordLocation); + this.gl.vertexAttribPointer( + shaderSet.attributeTexCoordLocation, + 2, + this.gl.FLOAT, + false, + 0, + 0 + ); + // チャンネル + const context = renderer.getClippingContextBufferForMask(); + const channelIndex: number = + renderer.getClippingContextBufferForMask()._layoutChannelIndex; + const colorChannel: CubismTextureColor = renderer + .getClippingContextBufferForMask() + .getClippingManager() + .getChannelFlagAsColor(channelIndex); + this.gl.uniform4f( + shaderSet.uniformChannelFlagLocation, + colorChannel.R, + colorChannel.G, + colorChannel.B, + colorChannel.A + ); + this.gl.uniformMatrix4fv( + shaderSet.uniformClipMatrixLocation, + false, + renderer.getClippingContextBufferForMask()._matrixForMask.getArray() + ); + const rect: csmRect = + renderer.getClippingContextBufferForMask()._layoutBounds; + this.gl.uniform4f( + shaderSet.uniformBaseColorLocation, + rect.x * 2.0 - 1.0, + rect.y * 2.0 - 1.0, + rect.getRight() * 2.0 - 1.0, + rect.getBottom() * 2.0 - 1.0 + ); + const multiplyColor: CubismTextureColor = model.getMultiplyColor(index); + const screenColor: CubismTextureColor = model.getScreenColor(index); + this.gl.uniform4f( + shaderSet.uniformMultiplyColorLocation, + multiplyColor.R, + multiplyColor.G, + multiplyColor.B, + multiplyColor.A + ); + this.gl.uniform4f( + shaderSet.uniformScreenColorLocation, + screenColor.R, + screenColor.G, + screenColor.B, + screenColor.A + ); + SRC_COLOR = this.gl.ZERO; + DST_COLOR = this.gl.ONE_MINUS_SRC_COLOR; + SRC_ALPHA = this.gl.ZERO; + DST_ALPHA = this.gl.ONE_MINUS_SRC_ALPHA; + // IBOを作成し、データを転送 + if (renderer._bufferData.index == null) { + renderer._bufferData.index = this.gl.createBuffer(); + } + const indexArray: Uint16Array = model.getDrawableVertexIndices(index); + this.gl.bindBuffer( + this.gl.ELEMENT_ARRAY_BUFFER, + renderer._bufferData.index + ); + this.gl.bufferData( + this.gl.ELEMENT_ARRAY_BUFFER, + indexArray, + this.gl.DYNAMIC_DRAW + ); + this.gl.blendFuncSeparate(SRC_COLOR, DST_COLOR, SRC_ALPHA, DST_ALPHA); + } + /** + * シェーダープログラムを解放する + */ + public releaseShaderProgram(): void { + for (let i = 0; i < this._shaderSets.length; i++) { + this.gl.deleteProgram(this._shaderSets[i].shaderProgram); + this._shaderSets[i].shaderProgram = 0; + this._shaderSets[i] = null; + } + } + /** + * シェーダープログラムを初期化する + * @param vertShaderSrc 頂点シェーダのソース + * @param fragShaderSrc フラグメントシェーダのソース + */ + public generateShaders(): void { + for (let i = 0; i < ShaderCount; i++) { + this._shaderSets.push(new CubismShaderSet()); + } + this._shaderSets[0].shaderProgram = this.loadShaderProgram( + vertexShaderSrcSetupMask, + fragmentShaderSrcsetupMask + ); + this._shaderSets[1].shaderProgram = this.loadShaderProgram( + vertexShaderSrc, + fragmentShaderSrcPremultipliedAlpha + ); + this._shaderSets[2].shaderProgram = this.loadShaderProgram( + vertexShaderSrcMasked, + fragmentShaderSrcMaskPremultipliedAlpha + ); + this._shaderSets[3].shaderProgram = this.loadShaderProgram( + vertexShaderSrcMasked, + fragmentShaderSrcMaskInvertedPremultipliedAlpha + ); + // 加算も通常と同じシェーダーを利用する + this._shaderSets[4].shaderProgram = this._shaderSets[1].shaderProgram; + this._shaderSets[5].shaderProgram = this._shaderSets[2].shaderProgram; + this._shaderSets[6].shaderProgram = this._shaderSets[3].shaderProgram; + // 乗算も通常と同じシェーダーを利用する + this._shaderSets[7].shaderProgram = this._shaderSets[1].shaderProgram; + this._shaderSets[8].shaderProgram = this._shaderSets[2].shaderProgram; + this._shaderSets[9].shaderProgram = this._shaderSets[3].shaderProgram; + // SetupMask + this._shaderSets[0].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[0].shaderProgram, + 'a_position' + ); + this._shaderSets[0].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[0].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[0].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[0].shaderProgram, + 's_texture0' + ); + this._shaderSets[0].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[0].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[0].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[0].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[0].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[0].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[0].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[0].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[0].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[0].shaderProgram, + 'u_screenColor' + ); + // 通常(PremultipliedAlpha) + this._shaderSets[1].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[1].shaderProgram, + 'a_position' + ); + this._shaderSets[1].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[1].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[1].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[1].shaderProgram, + 's_texture0' + ); + this._shaderSets[1].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[1].shaderProgram, + 'u_matrix' + ); + this._shaderSets[1].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[1].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[1].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[1].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[1].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[1].shaderProgram, + 'u_screenColor' + ); + // 通常(クリッピング、PremultipliedAlpha) + this._shaderSets[2].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[2].shaderProgram, + 'a_position' + ); + this._shaderSets[2].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[2].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[2].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 's_texture0' + ); + this._shaderSets[2].samplerTexture1Location = this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 's_texture1' + ); + this._shaderSets[2].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 'u_matrix' + ); + this._shaderSets[2].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[2].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[2].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[2].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[2].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[2].shaderProgram, + 'u_screenColor' + ); + // 通常(クリッピング・反転, PremultipliedAlpha) + this._shaderSets[3].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[3].shaderProgram, + 'a_position' + ); + this._shaderSets[3].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[3].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[3].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 's_texture0' + ); + this._shaderSets[3].samplerTexture1Location = this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 's_texture1' + ); + this._shaderSets[3].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 'u_matrix' + ); + this._shaderSets[3].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[3].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[3].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[3].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[3].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[3].shaderProgram, + 'u_screenColor' + ); + // 加算(PremultipliedAlpha) + this._shaderSets[4].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[4].shaderProgram, + 'a_position' + ); + this._shaderSets[4].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[4].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[4].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[4].shaderProgram, + 's_texture0' + ); + this._shaderSets[4].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[4].shaderProgram, + 'u_matrix' + ); + this._shaderSets[4].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[4].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[4].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[4].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[4].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[4].shaderProgram, + 'u_screenColor' + ); + // 加算(クリッピング、PremultipliedAlpha) + this._shaderSets[5].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[5].shaderProgram, + 'a_position' + ); + this._shaderSets[5].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[5].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[5].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 's_texture0' + ); + this._shaderSets[5].samplerTexture1Location = this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 's_texture1' + ); + this._shaderSets[5].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 'u_matrix' + ); + this._shaderSets[5].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[5].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[5].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[5].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[5].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[5].shaderProgram, + 'u_screenColor' + ); + // 加算(クリッピング・反転、PremultipliedAlpha) + this._shaderSets[6].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[6].shaderProgram, + 'a_position' + ); + this._shaderSets[6].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[6].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[6].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 's_texture0' + ); + this._shaderSets[6].samplerTexture1Location = this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 's_texture1' + ); + this._shaderSets[6].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 'u_matrix' + ); + this._shaderSets[6].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[6].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[6].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[6].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[6].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[6].shaderProgram, + 'u_screenColor' + ); + // 乗算(PremultipliedAlpha) + this._shaderSets[7].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[7].shaderProgram, + 'a_position' + ); + this._shaderSets[7].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[7].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[7].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[7].shaderProgram, + 's_texture0' + ); + this._shaderSets[7].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[7].shaderProgram, + 'u_matrix' + ); + this._shaderSets[7].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[7].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[7].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[7].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[7].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[7].shaderProgram, + 'u_screenColor' + ); + // 乗算(クリッピング、PremultipliedAlpha) + this._shaderSets[8].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[8].shaderProgram, + 'a_position' + ); + this._shaderSets[8].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[8].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[8].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 's_texture0' + ); + this._shaderSets[8].samplerTexture1Location = this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 's_texture1' + ); + this._shaderSets[8].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 'u_matrix' + ); + this._shaderSets[8].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[8].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[8].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[8].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[8].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[8].shaderProgram, + 'u_screenColor' + ); + // 乗算(クリッピング・反転、PremultipliedAlpha) + this._shaderSets[9].attributePositionLocation = + this.gl.getAttribLocation( + this._shaderSets[9].shaderProgram, + 'a_position' + ); + this._shaderSets[9].attributeTexCoordLocation = + this.gl.getAttribLocation( + this._shaderSets[9].shaderProgram, + 'a_texCoord' + ); + this._shaderSets[9].samplerTexture0Location = this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 's_texture0' + ); + this._shaderSets[9].samplerTexture1Location = this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 's_texture1' + ); + this._shaderSets[9].uniformMatrixLocation = this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 'u_matrix' + ); + this._shaderSets[9].uniformClipMatrixLocation = + this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 'u_clipMatrix' + ); + this._shaderSets[9].uniformChannelFlagLocation = + this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 'u_channelFlag' + ); + this._shaderSets[9].uniformBaseColorLocation = + this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 'u_baseColor' + ); + this._shaderSets[9].uniformMultiplyColorLocation = + this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 'u_multiplyColor' + ); + this._shaderSets[9].uniformScreenColorLocation = + this.gl.getUniformLocation( + this._shaderSets[9].shaderProgram, + 'u_screenColor' + ); + } + /** + * シェーダプログラムをロードしてアドレスを返す + * @param vertexShaderSource 頂点シェーダのソース + * @param fragmentShaderSource フラグメントシェーダのソース + * @return シェーダプログラムのアドレス + */ + public loadShaderProgram( + vertexShaderSource: string, + fragmentShaderSource: string + ): WebGLProgram { + // Create Shader Program + let shaderProgram: WebGLProgram = this.gl.createProgram(); + let vertShader = this.compileShaderSource( + this.gl.VERTEX_SHADER, + vertexShaderSource + ); + if (!vertShader) { + CubismLogError('Vertex shader compile error!'); + return 0; + } + let fragShader = this.compileShaderSource( + this.gl.FRAGMENT_SHADER, + fragmentShaderSource + ); + if (!fragShader) { + CubismLogError('Vertex shader compile error!'); + return 0; + } + // Attach vertex shader to program + this.gl.attachShader(shaderProgram, vertShader); + // Attach fragment shader to program + this.gl.attachShader(shaderProgram, fragShader); + // link program + this.gl.linkProgram(shaderProgram); + const linkStatus = this.gl.getProgramParameter( + shaderProgram, + this.gl.LINK_STATUS + ); + // リンクに失敗したらシェーダーを削除 + if (!linkStatus) { + CubismLogError('Failed to link program: {0}', shaderProgram); + this.gl.deleteShader(vertShader); + vertShader = 0; + this.gl.deleteShader(fragShader); + fragShader = 0; + if (shaderProgram) { + this.gl.deleteProgram(shaderProgram); + shaderProgram = 0; + } + return 0; + } + // Release vertex and fragment shaders. + this.gl.deleteShader(vertShader); + this.gl.deleteShader(fragShader); + return shaderProgram; + } + /** + * シェーダープログラムをコンパイルする + * @param shaderType シェーダタイプ(Vertex/Fragment) + * @param shaderSource シェーダソースコード + * + * @return コンパイルされたシェーダープログラム + */ + public compileShaderSource( + shaderType: GLenum, + shaderSource: string + ): WebGLProgram { + const source: string = shaderSource; + const shader: WebGLProgram = this.gl.createShader(shaderType); + this.gl.shaderSource(shader, source); + this.gl.compileShader(shader); + if (!shader) { + const log: string = this.gl.getShaderInfoLog(shader); + CubismLogError('Shader compile log: {0} ', log); + } + const status: any = this.gl.getShaderParameter( + shader, + this.gl.COMPILE_STATUS + ); + if (!status) { + this.gl.deleteShader(shader); + return null; + } + return shader; + } + public setGl(gl: WebGLRenderingContext): void { + this.gl = gl; + } + _shaderSets: CubismShaderSet[]; // ロードしたシェーダープログラムを保持する変数 + gl: WebGLRenderingContext; // webglコンテキスト +} +/** + * CubismShader_WebGLのインナークラス + */ +export class CubismShaderSet { + shaderProgram: WebGLProgram; // シェーダープログラムのアドレス + attributePositionLocation: GLuint; // シェーダープログラムに渡す変数のアドレス(Position) + attributeTexCoordLocation: GLuint; // シェーダープログラムに渡す変数のアドレス(TexCoord) + uniformMatrixLocation: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(Matrix) + uniformClipMatrixLocation: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(ClipMatrix) + samplerTexture0Location: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(Texture0) + samplerTexture1Location: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(Texture1) + uniformBaseColorLocation: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(BaseColor) + uniformChannelFlagLocation: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(ChannelFlag) + uniformMultiplyColorLocation: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(MultiplyColor) + uniformScreenColorLocation: WebGLUniformLocation; // シェーダープログラムに渡す変数のアドレス(ScreenColor) +} +export enum ShaderNames { + // SetupMask + ShaderNames_SetupMask, + // Normal + ShaderNames_NormalPremultipliedAlpha, + ShaderNames_NormalMaskedPremultipliedAlpha, + ShaderNames_NomralMaskedInvertedPremultipliedAlpha, + // Add + ShaderNames_AddPremultipliedAlpha, + ShaderNames_AddMaskedPremultipliedAlpha, + ShaderNames_AddMaskedPremultipliedAlphaInverted, + // Mult + ShaderNames_MultPremultipliedAlpha, + ShaderNames_MultMaskedPremultipliedAlpha, + ShaderNames_MultMaskedPremultipliedAlphaInverted +} +export const vertexShaderSrcSetupMask = + 'attribute vec4 a_position;' + + 'attribute vec2 a_texCoord;' + + 'varying vec2 v_texCoord;' + + 'varying vec4 v_myPos;' + + 'uniform mat4 u_clipMatrix;' + + 'void main()' + + '{' + + ' gl_Position = u_clipMatrix * a_position;' + + ' v_myPos = u_clipMatrix * a_position;' + + ' v_texCoord = a_texCoord;' + + ' v_texCoord.y = 1.0 - v_texCoord.y;' + + '}'; +export const fragmentShaderSrcsetupMask = + 'precision mediump float;' + + 'varying vec2 v_texCoord;' + + 'varying vec4 v_myPos;' + + 'uniform vec4 u_baseColor;' + + 'uniform vec4 u_channelFlag;' + + 'uniform sampler2D s_texture0;' + + 'void main()' + + '{' + + ' float isInside = ' + + ' step(u_baseColor.x, v_myPos.x/v_myPos.w)' + + ' * step(u_baseColor.y, v_myPos.y/v_myPos.w)' + + ' * step(v_myPos.x/v_myPos.w, u_baseColor.z)' + + ' * step(v_myPos.y/v_myPos.w, u_baseColor.w);' + + ' gl_FragColor = u_channelFlag * texture2D(s_texture0, v_texCoord).a * isInside;' + + '}'; +//----- バーテックスシェーダプログラム ----- +// Normal & Add & Mult 共通 +export const vertexShaderSrc = + 'attribute vec4 a_position;' + //v.vertex + 'attribute vec2 a_texCoord;' + //v.texcoord + 'varying vec2 v_texCoord;' + //v2f.texcoord + 'uniform mat4 u_matrix;' + + 'void main()' + + '{' + + ' gl_Position = u_matrix * a_position;' + + ' v_texCoord = a_texCoord;' + + ' v_texCoord.y = 1.0 - v_texCoord.y;' + + '}'; +// Normal & Add & Mult 共通(クリッピングされたものの描画用) +export const vertexShaderSrcMasked = + 'attribute vec4 a_position;' + + 'attribute vec2 a_texCoord;' + + 'varying vec2 v_texCoord;' + + 'varying vec4 v_clipPos;' + + 'uniform mat4 u_matrix;' + + 'uniform mat4 u_clipMatrix;' + + 'void main()' + + '{' + + ' gl_Position = u_matrix * a_position;' + + ' v_clipPos = u_clipMatrix * a_position;' + + ' v_texCoord = a_texCoord;' + + ' v_texCoord.y = 1.0 - v_texCoord.y;' + + '}'; +//----- フラグメントシェーダプログラム ----- +// Normal & Add & Mult 共通 (PremultipliedAlpha) +export const fragmentShaderSrcPremultipliedAlpha = + 'precision mediump float;' + + 'varying vec2 v_texCoord;' + //v2f.texcoord + 'uniform vec4 u_baseColor;' + + 'uniform sampler2D s_texture0;' + //_MainTex + 'uniform vec4 u_multiplyColor;' + + 'uniform vec4 u_screenColor;' + + 'void main()' + + '{' + + ' vec4 texColor = texture2D(s_texture0, v_texCoord);' + + ' texColor.rgb = texColor.rgb * u_multiplyColor.rgb;' + + ' texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);' + + ' vec4 color = texColor * u_baseColor;' + + ' gl_FragColor = vec4(color.rgb, color.a);' + + '}'; +// Normal (クリッピングされたものの描画用、PremultipliedAlpha兼用) +export const fragmentShaderSrcMaskPremultipliedAlpha = + 'precision mediump float;' + + 'varying vec2 v_texCoord;' + + 'varying vec4 v_clipPos;' + + 'uniform vec4 u_baseColor;' + + 'uniform vec4 u_channelFlag;' + + 'uniform sampler2D s_texture0;' + + 'uniform sampler2D s_texture1;' + + 'uniform vec4 u_multiplyColor;' + + 'uniform vec4 u_screenColor;' + + 'void main()' + + '{' + + ' vec4 texColor = texture2D(s_texture0, v_texCoord);' + + ' texColor.rgb = texColor.rgb * u_multiplyColor.rgb;' + + ' texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);' + + ' vec4 col_formask = texColor * u_baseColor;' + + ' vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;' + + ' float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;' + + ' col_formask = col_formask * maskVal;' + + ' gl_FragColor = col_formask;' + + '}'; +// Normal & Add & Mult 共通(クリッピングされて反転使用の描画用、PremultipliedAlphaの場合) +export const fragmentShaderSrcMaskInvertedPremultipliedAlpha = + 'precision mediump float;' + + 'varying vec2 v_texCoord;' + + 'varying vec4 v_clipPos;' + + 'uniform sampler2D s_texture0;' + + 'uniform sampler2D s_texture1;' + + 'uniform vec4 u_channelFlag;' + + 'uniform vec4 u_baseColor;' + + 'uniform vec4 u_multiplyColor;' + + 'uniform vec4 u_screenColor;' + + 'void main()' + + '{' + + ' vec4 texColor = texture2D(s_texture0, v_texCoord);' + + ' texColor.rgb = texColor.rgb * u_multiplyColor.rgb;' + + ' texColor.rgb = (texColor.rgb + u_screenColor.rgb * texColor.a) - (texColor.rgb * u_screenColor.rgb);' + + ' vec4 col_formask = texColor * u_baseColor;' + + ' vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;' + + ' float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;' + + ' col_formask = col_formask * (1.0 - maskVal);' + + ' gl_FragColor = col_formask;' + + '}'; diff --git a/src/utils/cubismdebug.ts b/src/utils/cubismdebug.ts index dff0cfb..637e921 100644 --- a/src/utils/cubismdebug.ts +++ b/src/utils/cubismdebug.ts @@ -7,7 +7,8 @@ import { CubismFramework, LogLevel } from '../live2dcubismframework'; -export const CSM_ASSERT = +export const CSM_ASSERT = + typeof process !== "undefined" && process.env.NODE_ENV === 'production' ? () => {} : (expr: any) => console.assert(expr); diff --git a/tsconfig.json b/tsconfig.json index f69d49f..9e241ba 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "strict": true, "moduleResolution": "node", "esModuleInterop": true,